several changes to lludp FetchInventoryDescendents

master
UbitUmarov 2020-03-01 21:45:28 +00:00
parent dc225e348d
commit 693492a3f1
6 changed files with 78 additions and 88 deletions

View File

@ -1207,8 +1207,8 @@ namespace OpenSim.Framework
void FlushPrimUpdates();
void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List<InventoryItemBase> items,
List<InventoryFolderBase> folders, int version, bool fetchFolders,
bool fetchItems);
List<InventoryFolderBase> folders, int version, int descendents,
bool fetchFolders, bool fetchItems);
void SendInventoryItemDetails(InventoryItemBase[] items);

View File

@ -2318,7 +2318,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <param name="fetchFolders">Do we need to send folder information?</param>
/// <param name="fetchItems">Do we need to send item information?</param>
public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List<InventoryItemBase> items,
List<InventoryFolderBase> folders, int version,
List<InventoryFolderBase> folders, int version, int descendents,
bool fetchFolders, bool fetchItems)
{
// An inventory descendents packet consists of a single agent section and an inventory details
@ -2339,7 +2339,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Handle empty folders
//
if (totalItems == 0 && totalFolders == 0)
currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, items.Count + folders.Count, 0, 0);
currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, descendents, 0, 0);
// To preserve SL compatibility, we will NOT combine folders and items in one packet
//
@ -2358,7 +2358,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
itemsToSend = MAX_ITEMS_PER_PACKET;
}
currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, items.Count + folders.Count, foldersToSend, itemsToSend);
currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, descendents, foldersToSend, itemsToSend);
}
if (foldersToSend-- > 0)
@ -10190,9 +10190,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (Fetch.AgentData.SessionID != SessionId || Fetch.AgentData.AgentID != AgentId)
return;
OnFetchInventoryDescendents?.Invoke(this, Fetch.InventoryData.FolderID, Fetch.InventoryData.OwnerID,
Fetch.InventoryData.FetchFolders, Fetch.InventoryData.FetchItems,
Fetch.InventoryData.SortOrder);
FetchInventoryDescendentsPacket.InventoryDataBlock data = Fetch.InventoryData;
OnFetchInventoryDescendents?.Invoke(this, data.FolderID, data.OwnerID,
data.FetchFolders, data.FetchItems,
data.SortOrder);
}
private void HandlePurgeInventoryDescendents(Packet Pack)

View File

@ -1586,9 +1586,11 @@ namespace OpenSim.Region.Framework.Scenes
{
if ((fold = LibraryService.LibraryRootFolder.FindFolder(folder.ID)) != null)
{
List<InventoryItemBase> its = fold.RequestListOfItems();
List<InventoryFolderBase> fds = fold.RequestListOfFolders();
client.SendInventoryFolderDetails(
fold.Owner, folder.ID, fold.RequestListOfItems(),
fold.RequestListOfFolders(), fold.Version, fetchFolders, fetchItems);
fold.Owner, folder.ID, its, fds,
fold.Version, its.Count + fds.Count, fetchFolders, fetchItems);
return;
}
}
@ -1602,37 +1604,41 @@ namespace OpenSim.Region.Framework.Scenes
// m_log.DebugFormat("[AGENT INVENTORY]: Sending inventory folder contents ({0} nodes) for \"{1}\" to {2} {3}",
// contents.Folders.Count + contents.Items.Count, containingFolder.Name, client.FirstName, client.LastName);
if (containingFolder != null)
if (containingFolder != null )
{
// If the folder requested contains links, then we need to send those folders first, otherwise the links
// will be broken in the viewer.
HashSet<UUID> linkedItemFolderIdsToSend = new HashSet<UUID>();
foreach (InventoryItemBase item in contents.Items)
{
if (item.AssetType == (int)AssetType.Link)
{
InventoryItemBase linkedItem = InventoryService.GetItem(client.AgentId, item.AssetID);
int descendents = contents.Folders.Count + contents.Items.Count;
// Take care of genuinely broken links where the target doesn't exist
// HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
// but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
// rather than having to keep track of every folder requested in the recursion.
if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
if(fetchItems && contents.Items.Count > 0)
{
var linksIDs = new HashSet<UUID>();
var links = new List<InventoryItemBase>();
for (int i = 0; i < contents.Items.Count; ++i)
{
InventoryItemBase item = contents.Items[i];
if (item.AssetType == (int)AssetType.Link)
{
// We don't need to send the folder if source and destination of the link are in the same
// folder.
if (linkedItem.Folder != containingFolder.ID)
linkedItemFolderIdsToSend.Add(linkedItem.Folder);
UUID linkid = item.AssetID;
if(linksIDs.Contains(linkid))
continue;
InventoryItemBase linkedItem = InventoryService.GetItem(item.Owner, linkid);
if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link && linkedItem.AssetType != (int)AssetType.LinkFolder)
{
links.Add(linkedItem);
linksIDs.Add(linkedItem.ID);
}
}
}
if(links.Count > 0)
{
links.AddRange(contents.Items);
contents.Items = links;
}
}
foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend)
SendInventoryUpdate(client, new InventoryFolderBase(linkedItemFolderId), false, true);
client.SendInventoryFolderDetails(
client.AgentId, folder.ID, contents.Items, contents.Folders,
containingFolder.Version, fetchFolders, fetchItems);
containingFolder.Version, descendents, fetchFolders, fetchItems);
}
}

View File

@ -27,6 +27,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
@ -504,15 +505,15 @@ namespace OpenSim.Region.Framework.Scenes
{
public IClientAPI RemoteClient;
public UUID FolderID;
public UUID OwnerID;
//public UUID OwnerID;
public bool FetchFolders;
public bool FetchItems;
public int SortOrder;
//public int SortOrder;
}
private Queue<DescendentsRequestData> m_descendentsRequestQueue = new Queue<DescendentsRequestData>();
private Object m_descendentsRequestLock = new Object();
private bool m_descendentsRequestProcessing = false;
static private ConcurrentQueue<DescendentsRequestData> m_descendentsRequestQueue = new ConcurrentQueue<DescendentsRequestData>();
static private Object m_descendentsRequestLock = new Object();
static private bool m_descendentsRequestProcessing = false;
/// <summary>
/// Tell the client about the various child items and folders contained in the requested folder.
@ -543,74 +544,54 @@ namespace OpenSim.Region.Framework.Scenes
{
if ((fold = LibraryService.LibraryRootFolder.FindFolder(folderID)) != null)
{
List<InventoryItemBase> its = fold.RequestListOfItems();
List<InventoryFolderBase> fds = fold.RequestListOfFolders();
remoteClient.SendInventoryFolderDetails(
fold.Owner, folderID, fold.RequestListOfItems(),
fold.RequestListOfFolders(), fold.Version, fetchFolders, fetchItems);
fold.Owner, folderID, its, fds,
fold.Version, its.Count + fds.Count, fetchFolders, fetchItems);
return;
}
}
lock (m_descendentsRequestLock)
DescendentsRequestData req = new DescendentsRequestData();
req.RemoteClient = remoteClient;
req.FolderID = folderID;
//req.OwnerID = ownerID;
req.FetchFolders = fetchFolders;
req.FetchItems = fetchItems;
//req.SortOrder = sortOrder;
m_descendentsRequestQueue.Enqueue(req);
if (Monitor.TryEnter(m_descendentsRequestLock))
{
if (!m_descendentsRequestProcessing)
{
m_descendentsRequestProcessing = true;
// We're going to send the reply async, because there may be
// an enormous quantity of packets -- basically the entire inventory!
// We don't want to block the client thread while all that is happening.
SendInventoryDelegate d = SendInventoryAsync;
d.BeginInvoke(remoteClient, folderID, ownerID, fetchFolders, fetchItems, sortOrder, SendInventoryComplete, d);
return;
Util.FireAndForget(x => SendInventoryAsync());
}
DescendentsRequestData req = new DescendentsRequestData();
req.RemoteClient = remoteClient;
req.FolderID = folderID;
req.OwnerID = ownerID;
req.FetchFolders = fetchFolders;
req.FetchItems = fetchItems;
req.SortOrder = sortOrder;
m_descendentsRequestQueue.Enqueue(req);
Monitor.Exit(m_descendentsRequestLock);
}
}
delegate void SendInventoryDelegate(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder);
void SendInventoryAsync(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder)
void SendInventoryAsync()
{
try
lock(m_descendentsRequestLock)
{
SendInventoryUpdate(remoteClient, new InventoryFolderBase(folderID), fetchFolders, fetchItems);
}
catch (Exception e)
{
m_log.Error(
string.Format(
"[AGENT INVENTORY]: Error in SendInventoryAsync() for {0} with folder ID {1}. Exception ", e, folderID));
}
Thread.Sleep(20);
}
void SendInventoryComplete(IAsyncResult iar)
{
SendInventoryDelegate d = (SendInventoryDelegate)iar.AsyncState;
d.EndInvoke(iar);
lock (m_descendentsRequestLock)
{
if (m_descendentsRequestQueue.Count > 0)
try
{
DescendentsRequestData req = m_descendentsRequestQueue.Dequeue();
d = SendInventoryAsync;
d.BeginInvoke(req.RemoteClient, req.FolderID, req.OwnerID, req.FetchFolders, req.FetchItems, req.SortOrder, SendInventoryComplete, d);
return;
while(m_descendentsRequestQueue.TryDequeue(out DescendentsRequestData req))
{
if(!req.RemoteClient.IsActive)
continue;
SendInventoryUpdate(req.RemoteClient, new InventoryFolderBase(req.FolderID), req.FetchFolders, req.FetchItems);
Thread.Sleep(50);
}
}
catch (Exception e)
{
m_log.ErrorFormat("[AGENT INVENTORY]: Error in SendInventoryAsync(). Exception {0}", e);
}
m_descendentsRequestProcessing = false;
}
}

View File

@ -842,6 +842,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
List<InventoryItemBase> items,
List<InventoryFolderBase> folders,
int version,
int descendents,
bool fetchFolders,
bool fetchItems)
{

View File

@ -791,6 +791,7 @@ namespace OpenSim.Tests.Common
List<InventoryItemBase> items,
List<InventoryFolderBase> folders,
int version,
int descendents,
bool fetchFolders,
bool fetchItems)
{