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

View File

@ -1586,9 +1586,11 @@ namespace OpenSim.Region.Framework.Scenes
{ {
if ((fold = LibraryService.LibraryRootFolder.FindFolder(folder.ID)) != null) if ((fold = LibraryService.LibraryRootFolder.FindFolder(folder.ID)) != null)
{ {
List<InventoryItemBase> its = fold.RequestListOfItems();
List<InventoryFolderBase> fds = fold.RequestListOfFolders();
client.SendInventoryFolderDetails( client.SendInventoryFolderDetails(
fold.Owner, folder.ID, fold.RequestListOfItems(), fold.Owner, folder.ID, its, fds,
fold.RequestListOfFolders(), fold.Version, fetchFolders, fetchItems); fold.Version, its.Count + fds.Count, fetchFolders, fetchItems);
return; 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}", // 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); // 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 int descendents = contents.Folders.Count + contents.Items.Count;
// will be broken in the viewer.
HashSet<UUID> linkedItemFolderIdsToSend = new HashSet<UUID>(); if(fetchItems && contents.Items.Count > 0)
foreach (InventoryItemBase item in contents.Items)
{ {
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) if (item.AssetType == (int)AssetType.Link)
{ {
InventoryItemBase linkedItem = InventoryService.GetItem(client.AgentId, item.AssetID); UUID linkid = item.AssetID;
if(linksIDs.Contains(linkid))
continue;
// Take care of genuinely broken links where the target doesn't exist InventoryItemBase linkedItem = InventoryService.GetItem(item.Owner, linkid);
// HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link && linkedItem.AssetType != (int)AssetType.LinkFolder)
// 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)
{ {
// We don't need to send the folder if source and destination of the link are in the same links.Add(linkedItem);
// folder. linksIDs.Add(linkedItem.ID);
if (linkedItem.Folder != containingFolder.ID)
linkedItemFolderIdsToSend.Add(linkedItem.Folder);
} }
} }
} }
if(links.Count > 0)
foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend) {
SendInventoryUpdate(client, new InventoryFolderBase(linkedItemFolderId), false, true); links.AddRange(contents.Items);
contents.Items = links;
}
}
client.SendInventoryFolderDetails( client.SendInventoryFolderDetails(
client.AgentId, folder.ID, contents.Items, contents.Folders, 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Threading; using System.Threading;
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.Packets; using OpenMetaverse.Packets;
@ -504,15 +505,15 @@ namespace OpenSim.Region.Framework.Scenes
{ {
public IClientAPI RemoteClient; public IClientAPI RemoteClient;
public UUID FolderID; public UUID FolderID;
public UUID OwnerID; //public UUID OwnerID;
public bool FetchFolders; public bool FetchFolders;
public bool FetchItems; public bool FetchItems;
public int SortOrder; //public int SortOrder;
} }
private Queue<DescendentsRequestData> m_descendentsRequestQueue = new Queue<DescendentsRequestData>(); static private ConcurrentQueue<DescendentsRequestData> m_descendentsRequestQueue = new ConcurrentQueue<DescendentsRequestData>();
private Object m_descendentsRequestLock = new Object(); static private Object m_descendentsRequestLock = new Object();
private bool m_descendentsRequestProcessing = false; static private bool m_descendentsRequestProcessing = false;
/// <summary> /// <summary>
/// Tell the client about the various child items and folders contained in the requested folder. /// 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) if ((fold = LibraryService.LibraryRootFolder.FindFolder(folderID)) != null)
{ {
List<InventoryItemBase> its = fold.RequestListOfItems();
List<InventoryFolderBase> fds = fold.RequestListOfFolders();
remoteClient.SendInventoryFolderDetails( remoteClient.SendInventoryFolderDetails(
fold.Owner, folderID, fold.RequestListOfItems(), fold.Owner, folderID, its, fds,
fold.RequestListOfFolders(), fold.Version, fetchFolders, fetchItems); fold.Version, its.Count + fds.Count, fetchFolders, fetchItems);
return; return;
} }
} }
lock (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;
}
DescendentsRequestData req = new DescendentsRequestData(); DescendentsRequestData req = new DescendentsRequestData();
req.RemoteClient = remoteClient; req.RemoteClient = remoteClient;
req.FolderID = folderID; req.FolderID = folderID;
req.OwnerID = ownerID; //req.OwnerID = ownerID;
req.FetchFolders = fetchFolders; req.FetchFolders = fetchFolders;
req.FetchItems = fetchItems; req.FetchItems = fetchItems;
req.SortOrder = sortOrder; //req.SortOrder = sortOrder;
m_descendentsRequestQueue.Enqueue(req); m_descendentsRequestQueue.Enqueue(req);
if (Monitor.TryEnter(m_descendentsRequestLock))
{
if (!m_descendentsRequestProcessing)
{
m_descendentsRequestProcessing = true;
Util.FireAndForget(x => SendInventoryAsync());
}
Monitor.Exit(m_descendentsRequestLock);
} }
} }
delegate void SendInventoryDelegate(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder); void SendInventoryAsync()
{
void SendInventoryAsync(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder) lock(m_descendentsRequestLock)
{ {
try try
{ {
SendInventoryUpdate(remoteClient, new InventoryFolderBase(folderID), fetchFolders, fetchItems); 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) catch (Exception e)
{ {
m_log.Error( m_log.ErrorFormat("[AGENT INVENTORY]: Error in SendInventoryAsync(). Exception {0}", e);
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)
{
DescendentsRequestData req = m_descendentsRequestQueue.Dequeue();
d = SendInventoryAsync;
d.BeginInvoke(req.RemoteClient, req.FolderID, req.OwnerID, req.FetchFolders, req.FetchItems, req.SortOrder, SendInventoryComplete, d);
return;
}
m_descendentsRequestProcessing = false; m_descendentsRequestProcessing = false;
} }
} }

View File

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

View File

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