several changes to lludp FetchInventoryDescendents
parent
dc225e348d
commit
693492a3f1
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
int descendents = contents.Folders.Count + contents.Items.Count;
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
// 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)
|
||||
InventoryItemBase linkedItem = InventoryService.GetItem(item.Owner, linkid);
|
||||
if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link && linkedItem.AssetType != (int)AssetType.LinkFolder)
|
||||
{
|
||||
// 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);
|
||||
links.Add(linkedItem);
|
||||
linksIDs.Add(linkedItem.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend)
|
||||
SendInventoryUpdate(client, new InventoryFolderBase(linkedItemFolderId), false, true);
|
||||
if(links.Count > 0)
|
||||
{
|
||||
links.AddRange(contents.Items);
|
||||
contents.Items = links;
|
||||
}
|
||||
}
|
||||
|
||||
client.SendInventoryFolderDetails(
|
||||
client.AgentId, folder.ID, contents.Items, contents.Folders,
|
||||
containingFolder.Version, fetchFolders, fetchItems);
|
||||
containingFolder.Version, descendents, fetchFolders, fetchItems);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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();
|
||||
req.RemoteClient = remoteClient;
|
||||
req.FolderID = folderID;
|
||||
req.OwnerID = ownerID;
|
||||
//req.OwnerID = ownerID;
|
||||
req.FetchFolders = fetchFolders;
|
||||
req.FetchItems = fetchItems;
|
||||
req.SortOrder = sortOrder;
|
||||
//req.SortOrder = sortOrder;
|
||||
|
||||
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(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder)
|
||||
void SendInventoryAsync()
|
||||
{
|
||||
lock(m_descendentsRequestLock)
|
||||
{
|
||||
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)
|
||||
{
|
||||
m_log.Error(
|
||||
string.Format(
|
||||
"[AGENT INVENTORY]: Error in SendInventoryAsync() for {0} with folder ID {1}. Exception ", e, folderID));
|
||||
m_log.ErrorFormat("[AGENT INVENTORY]: Error in SendInventoryAsync(). Exception {0}", e);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -842,6 +842,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
|||
List<InventoryItemBase> items,
|
||||
List<InventoryFolderBase> folders,
|
||||
int version,
|
||||
int descendents,
|
||||
bool fetchFolders,
|
||||
bool fetchItems)
|
||||
{
|
||||
|
|
|
@ -791,6 +791,7 @@ namespace OpenSim.Tests.Common
|
|||
List<InventoryItemBase> items,
|
||||
List<InventoryFolderBase> folders,
|
||||
int version,
|
||||
int descendents,
|
||||
bool fetchFolders,
|
||||
bool fetchItems)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue