several changes to lludp FetchInventoryDescendents
parent
dc225e348d
commit
693492a3f1
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1604,35 +1606,39 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue