From af0febf6a72434d5fd68b7acc6ed6ff01544a012 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Fri, 11 Sep 2015 19:55:38 +0100 Subject: [PATCH] inventory mess --- .../Framework/Scenes/Scene.Inventory.cs | 50 ++-- .../Inventory/XInventoryServicesConnector.cs | 283 ++++++++++++++---- 2 files changed, 243 insertions(+), 90 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 2f37483964..edb881f6ca 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -898,33 +898,33 @@ namespace OpenSim.Region.Framework.Scenes } - if (remoteClient.AgentId == oldAgentID - || (LibraryService != null - && LibraryService.LibraryRootFolder != null - && oldAgentID == LibraryService.LibraryRootFolder.Owner)) - { - CreateNewInventoryItem( - remoteClient, item.CreatorId, item.CreatorData, newFolderID, - newName, item.Description, item.Flags, callbackID, item.AssetID, (sbyte)item.AssetType, (sbyte)item.InvType, - item.BasePermissions, item.CurrentPermissions, item.EveryOnePermissions, - item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch(), false); - } - else - { - // If item is transfer or permissions are off or calling agent is allowed to copy item owner's inventory item. - if (((item.CurrentPermissions & (uint)PermissionMask.Transfer) != 0) - && (m_permissions.BypassPermissions() - || m_permissions.CanCopyUserInventory(remoteClient.AgentId, oldItemID))) - { - CreateNewInventoryItem( - remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Description, item.Flags, callbackID, - item.AssetID, (sbyte)item.AssetType, (sbyte)item.InvType, - item.NextPermissions, item.NextPermissions, item.EveryOnePermissions & item.NextPermissions, - item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch(), false); - } - } + if (remoteClient.AgentId == oldAgentID + || (LibraryService != null + && LibraryService.LibraryRootFolder != null + && oldAgentID == LibraryService.LibraryRootFolder.Owner)) + { + CreateNewInventoryItem( + remoteClient, item.CreatorId, item.CreatorData, newFolderID, + newName, item.Description, item.Flags, callbackID, item.AssetID, (sbyte)item.AssetType, (sbyte)item.InvType, + item.BasePermissions, item.CurrentPermissions, item.EveryOnePermissions, + item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch(), false); } else + { + // If item is transfer or permissions are off or calling agent is allowed to copy item owner's inventory item. + if (((item.CurrentPermissions & (uint)PermissionMask.Transfer) != 0) + && (m_permissions.BypassPermissions() + || m_permissions.CanCopyUserInventory(remoteClient.AgentId, oldItemID))) + { + CreateNewInventoryItem( + remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Description, item.Flags, callbackID, + item.AssetID, (sbyte)item.AssetType, (sbyte) item.InvType, + item.NextPermissions, item.NextPermissions, item.EveryOnePermissions & item.NextPermissions, + item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch(), false); + } + } + } + else { m_log.ErrorFormat( "[AGENT INVENTORY]: Could not copy item {0} since asset {1} could not be found", diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs index 36d4ae25f0..f235446ac9 100644 --- a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs @@ -33,22 +33,37 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Console; -using OpenSim.Framework.Communications; + +using OpenSim.Framework.Monitoring; using OpenSim.Services.Interfaces; using OpenSim.Server.Base; using OpenMetaverse; namespace OpenSim.Services.Connectors { - public class XInventoryServicesConnector : IInventoryService + public class XInventoryServicesConnector : BaseServiceConnector, IInventoryService { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Number of requests made to the remote inventory service. + /// + public int RequestsMade { get; private set; } + private string m_ServerURI = String.Empty; - private object m_Lock = new object(); + /// + /// Timeout for remote requests. + /// + /// + /// In this case, -1 is default timeout (100 seconds), not infinite. + /// + private int m_requestTimeoutSecs = -1; + + private const double CACHE_EXPIRATION_SECONDS = 20.0; + private static ExpiringCache m_ItemCache = new ExpiringCache(); public XInventoryServicesConnector() { @@ -60,20 +75,21 @@ namespace OpenSim.Services.Connectors } public XInventoryServicesConnector(IConfigSource source) + : base(source, "InventoryService") { Initialise(source); } public virtual void Initialise(IConfigSource source) { - IConfig assetConfig = source.Configs["InventoryService"]; - if (assetConfig == null) + IConfig config = source.Configs["InventoryService"]; + if (config == null) { m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); throw new Exception("Inventory connector init error"); } - string serviceURI = assetConfig.GetString("InventoryServerURI", + string serviceURI = config.GetString("InventoryServerURI", String.Empty); if (serviceURI == String.Empty) @@ -82,6 +98,21 @@ namespace OpenSim.Services.Connectors throw new Exception("Inventory connector init error"); } m_ServerURI = serviceURI; + + m_requestTimeoutSecs = config.GetInt("RemoteRequestTimeout", m_requestTimeoutSecs); + + StatsManager.RegisterStat( + new Stat( + "RequestsMade", + "Requests made", + "Number of requests made to the remove inventory service", + "requests", + "inventory", + serviceURI, + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + s => s.Value = RequestsMade, + StatVerbosity.Debug)); } private bool CheckReturn(Dictionary ret) @@ -158,7 +189,7 @@ namespace OpenSim.Services.Connectors return BuildFolder((Dictionary)ret["folder"]); } - public InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) + public InventoryFolderBase GetFolderForType(UUID principalID, FolderType type) { Dictionary ret = MakeRequest("GETFOLDERFORTYPE", new Dictionary { @@ -177,7 +208,7 @@ namespace OpenSim.Services.Connectors InventoryCollection inventory = new InventoryCollection(); inventory.Folders = new List(); inventory.Items = new List(); - inventory.UserID = principalID; + inventory.OwnerID = principalID; try { @@ -190,15 +221,17 @@ namespace OpenSim.Services.Connectors if (!CheckReturn(ret)) return null; - Dictionary folders = - (Dictionary)ret["FOLDERS"]; - Dictionary items = - (Dictionary)ret["ITEMS"]; + Dictionary folders = ret.ContainsKey("FOLDERS") ? + (Dictionary)ret["FOLDERS"] : null; + Dictionary items = ret.ContainsKey("ITEMS") ? + (Dictionary)ret["ITEMS"] : null; - foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i - inventory.Folders.Add(BuildFolder((Dictionary)o)); - foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i - inventory.Items.Add(BuildItem((Dictionary)o)); + if (folders != null) + foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i + inventory.Folders.Add(BuildFolder((Dictionary)o)); + if (items != null) + foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i + inventory.Items.Add(BuildItem((Dictionary)o)); } catch (Exception e) { @@ -207,6 +240,87 @@ namespace OpenSim.Services.Connectors return inventory; } + + public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs) + { + InventoryCollection[] inventoryArr = new InventoryCollection[folderIDs.Length]; + // m_log.DebugFormat("[XXX]: In GetMultipleFoldersContent {0}", String.Join(",", folderIDs)); + try + { + Dictionary resultSet = MakeRequest("GETMULTIPLEFOLDERSCONTENT", + new Dictionary { + { "PRINCIPAL", principalID.ToString() }, + { "FOLDERS", String.Join(",", folderIDs) }, + { "COUNT", folderIDs.Length.ToString() } + }); + + if (!CheckReturn(resultSet)) + return null; + + int i = 0; + foreach (KeyValuePair kvp in resultSet) + { + InventoryCollection inventory = new InventoryCollection(); + if (kvp.Key.StartsWith("F_")) + { + UUID fid = UUID.Zero; + if (UUID.TryParse(kvp.Key.Substring(2), out fid) && fid == folderIDs[i]) + { + inventory.Folders = new List(); + inventory.Items = new List(); + + Dictionary ret = (Dictionary)kvp.Value; + + if (ret.ContainsKey("FID")) + { + if (!UUID.TryParse(ret["FID"].ToString(), out inventory.FolderID)) + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Could not parse folder id {0}", ret["FID"].ToString()); + } + else + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: FID key not present in response"); + + inventory.Version = -1; + if (ret.ContainsKey("VERSION")) + Int32.TryParse(ret["VERSION"].ToString(), out inventory.Version); + if (ret.ContainsKey("OWNER")) + UUID.TryParse(ret["OWNER"].ToString(), out inventory.OwnerID); + + //m_log.DebugFormat("[XXX]: Received {0} ({1}) {2} {3}", inventory.FolderID, fid, inventory.Version, inventory.OwnerID); + + Dictionary folders = + (Dictionary)ret["FOLDERS"]; + Dictionary items = + (Dictionary)ret["ITEMS"]; + + foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i + { + inventory.Folders.Add(BuildFolder((Dictionary)o)); + } + foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i + { + inventory.Items.Add(BuildItem((Dictionary)o)); + } + + inventoryArr[i] = inventory; + } + else + { + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Folder id does not match. Expected {0} got {1}", + folderIDs[i], fid); + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: {0} {1}", String.Join(",", folderIDs), String.Join(",", resultSet.Keys)); + } + + i += 1; + } + } + } + catch (Exception e) + { + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Exception in GetMultipleFoldersContent: {0}", e.Message); + } + + return inventoryArr; + } public List GetFolderItems(UUID principalID, UUID folderID) { @@ -297,9 +411,13 @@ namespace OpenSim.Services.Connectors public bool AddItem(InventoryItemBase item) { + if (item.Description == null) + item.Description = String.Empty; if (item.CreatorData == null) item.CreatorData = String.Empty; - Dictionary ret = MakeRequest("ADDITEM", + if (item.CreatorId == null) + item.CreatorId = String.Empty; + Dictionary ret = MakeRequest("ADDITEM", new Dictionary { { "AssetID", item.AssetID.ToString() }, { "AssetType", item.AssetType.ToString() }, @@ -398,6 +516,10 @@ namespace OpenSim.Services.Connectors public InventoryItemBase GetItem(InventoryItemBase item) { + InventoryItemBase retrieved = null; + if (m_ItemCache.TryGetValue(item.ID, out retrieved)) + return retrieved; + try { Dictionary ret = MakeRequest("GETITEM", @@ -408,14 +530,78 @@ namespace OpenSim.Services.Connectors if (!CheckReturn(ret)) return null; - return BuildItem((Dictionary)ret["item"]); + retrieved = BuildItem((Dictionary)ret["item"]); } catch (Exception e) { m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception in GetItem: ", e); } - return null; + m_ItemCache.AddOrUpdate(item.ID, retrieved, CACHE_EXPIRATION_SECONDS); + + return retrieved; + } + + public virtual InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs) + { + //m_log.DebugFormat("[XXX]: In GetMultipleItems {0}", String.Join(",", itemIDs)); + + InventoryItemBase[] itemArr = new InventoryItemBase[itemIDs.Length]; + // Try to get them from the cache + List pending = new List(); + InventoryItemBase item = null; + int i = 0; + foreach (UUID id in itemIDs) + { + if (m_ItemCache.TryGetValue(id, out item)) + itemArr[i++] = item; + else + pending.Add(id); + } + + if (pending.Count == 0) // we're done, everything was in the cache + return itemArr; + + try + { + Dictionary resultSet = MakeRequest("GETMULTIPLEITEMS", + new Dictionary { + { "PRINCIPAL", principalID.ToString() }, + { "ITEMS", String.Join(",", pending.ToArray()) }, + { "COUNT", pending.Count.ToString() } + }); + + if (!CheckReturn(resultSet)) + { + if (i == 0) + return null; + else + return itemArr; + } + + // carry over index i where we left above + foreach (KeyValuePair kvp in resultSet) + { + InventoryCollection inventory = new InventoryCollection(); + if (kvp.Key.StartsWith("item_")) + { + if (kvp.Value is Dictionary) + { + item = BuildItem((Dictionary)kvp.Value); + m_ItemCache.AddOrUpdate(item.ID, item, CACHE_EXPIRATION_SECONDS); + itemArr[i++] = item; + } + else + itemArr[i++] = null; + } + } + } + catch (Exception e) + { + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Exception in GetMultipleItems: {0}", e.Message); + } + + return itemArr; } public InventoryFolderBase GetFolder(InventoryFolderBase folder) @@ -484,45 +670,6 @@ namespace OpenSim.Services.Connectors return 0; } - public InventoryCollection GetUserInventory(UUID principalID) - { - InventoryCollection inventory = new InventoryCollection(); - inventory.Folders = new List(); - inventory.Items = new List(); - inventory.UserID = principalID; - - try - { - Dictionary ret = MakeRequest("GETUSERINVENTORY", - new Dictionary { - { "PRINCIPAL", principalID.ToString() } - }); - - if (!CheckReturn(ret)) - return null; - - Dictionary folders = - (Dictionary)ret["FOLDERS"]; - Dictionary items = - (Dictionary)ret["ITEMS"]; - - foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i - inventory.Folders.Add(BuildFolder((Dictionary)o)); - foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i - inventory.Items.Add(BuildItem((Dictionary)o)); - } - catch (Exception e) - { - m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception in GetUserInventory: ", e); - } - - return inventory; - } - - public void GetUserInventory(UUID principalID, InventoryReceiptCallback callback) - { - } - public bool HasInventoryForUser(UUID principalID) { return false; @@ -533,13 +680,19 @@ namespace OpenSim.Services.Connectors private Dictionary MakeRequest(string method, Dictionary sendData) { - sendData["METHOD"] = method; + // Add "METHOD" as the first key in the dictionary. This ensures that it will be + // visible even when using partial logging ("debug http all 5"). + Dictionary temp = sendData; + sendData = new Dictionary{ { "METHOD", method } }; + foreach (KeyValuePair kvp in temp) + sendData.Add(kvp.Key, kvp.Value); - string reply = string.Empty; - lock (m_Lock) - reply = SynchronousRestFormsRequester.MakeRequest("POST", - m_ServerURI + "/xinventory", - ServerUtils.BuildQueryString(sendData)); + RequestsMade++; + + string reply + = SynchronousRestFormsRequester.MakeRequest( + "POST", m_ServerURI + "/xinventory", + ServerUtils.BuildQueryString(sendData), m_requestTimeoutSecs, m_Auth); Dictionary replyData = ServerUtils.ParseXmlResponse( reply); @@ -607,4 +760,4 @@ namespace OpenSim.Services.Connectors return item; } } -} \ No newline at end of file +}