diff --git a/MultiGridClient/XInventoryServicesConnector.cs b/MultiGridClient/XInventoryServicesConnector.cs new file mode 100644 index 0000000..0876400 --- /dev/null +++ b/MultiGridClient/XInventoryServicesConnector.cs @@ -0,0 +1,1041 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using log4net; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Console; + +using OpenSim.Framework.Monitoring; +using OpenSim.Services.Interfaces; +using OpenSim.Server.Base; +using OpenMetaverse; + +namespace OpenSim.Services.Connectors +{ + 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 List m_inventoryURLs = new List(); + + /// + /// Timeout for remote requests. + /// + /// + /// In this case, -1 is default timeout (100 seconds), not infinite. + /// + private int m_requestTimeoutSecs = -1; + private string m_configName = "InventoryService"; + + private const double CACHE_EXPIRATION_SECONDS = 20.0; + private static ExpiringCache m_ItemCache = new ExpiringCache(); + + public XInventoryServicesConnector() + { + } + + public XInventoryServicesConnector(string serverURI) + { + m_inventoryURLs.AddRange(serverURI.TrimEnd('/').Split(';')); + } + + public XInventoryServicesConnector(IConfigSource source, string configName) + : base(source, configName) + { + m_configName = configName; + Initialise(source); + } + + public XInventoryServicesConnector(IConfigSource source) + : base(source, "InventoryService") + { + Initialise(source); + } + + public virtual void Initialise(IConfigSource source) + { + IConfig config = source.Configs[m_configName]; + if (config == null) + { + m_log.ErrorFormat("[INVENTORY CONNECTOR]: {0} missing from OpenSim.ini", m_configName); + throw new Exception("Inventory connector init error"); + } + + string serviceURI = config.GetString("InventoryServerURI", + String.Empty); + + if (serviceURI == String.Empty) + { + m_log.Error("[INVENTORY CONNECTOR]: No Server URI named in section InventoryService"); + throw new Exception("Inventory connector init error"); + } + + m_inventoryURLs.AddRange(serviceURI.Split(';')); + + 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) + { + if (ret == null) + return false; + + if (ret.Count == 0) + return false; + + if (ret.ContainsKey("RESULT")) + { + if (ret["RESULT"] is string) + { + bool result; + + if (bool.TryParse((string)ret["RESULT"], out result)) + return result; + + return false; + } + } + + return true; + } + + public bool CreateUserInventory(UUID principalID) + { + foreach(String serverURL in m_inventoryURLs) + { + bool result = CreateUserInventory(serverURL, principalID); + + if (result == true) + return result; + } + + return false; + } + + public bool CreateUserInventory(String m_ServerURI, UUID principalID) + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "CREATEUSERINVENTORY"}, + { "PRINCIPAL", principalID.ToString() } + }); + + return CheckReturn(ret); + } + + public List GetInventorySkeleton(UUID principalID) + { + List skeleton = new List(); + + foreach (String serverURL in m_inventoryURLs) + { + skeleton.AddRange(GetInventorySkeleton(serverURL, principalID)); + } + + return skeleton; + } + + public List GetInventorySkeleton(String m_ServerURI, UUID principalID) + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "GETINVENTORYSKELETON"}, + { "PRINCIPAL", principalID.ToString() } + }); + + if (!CheckReturn(ret)) + return null; + + Dictionary folders = (Dictionary)ret["FOLDERS"]; + + List fldrs = new List(); + + try + { + foreach (Object o in folders.Values) + fldrs.Add(BuildFolder((Dictionary)o)); + } + catch (Exception e) + { + m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception unwrapping folder list: ", e); + } + + return fldrs; + } + + public InventoryFolderBase GetRootFolder(UUID principalID) + { + foreach (String serverURL in m_inventoryURLs) + { + InventoryFolderBase result = GetRootFolder(serverURL, principalID); + + if (result != null) + return result; + } + + return null; + } + + public InventoryFolderBase GetRootFolder(String m_ServerURI, UUID principalID) + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "GETROOTFOLDER"}, + { "PRINCIPAL", principalID.ToString() } + }); + + if (!CheckReturn(ret)) + return null; + + return BuildFolder((Dictionary)ret["folder"]); + } + + public InventoryFolderBase GetFolderForType(UUID principalID, FolderType type) + { + foreach (String serverURL in m_inventoryURLs) + { + InventoryFolderBase result = GetFolderForType(serverURL, principalID, type); + + if (result != null) + return result; + } + + return null; + } + + public InventoryFolderBase GetFolderForType(String m_ServerURI, UUID principalID, FolderType type) + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "GETFOLDERFORTYPE"}, + { "PRINCIPAL", principalID.ToString() }, + { "TYPE", ((int)type).ToString() } + }); + + if (!CheckReturn(ret)) + return null; + + return BuildFolder((Dictionary)ret["folder"]); + } + + public InventoryCollection GetFolderContent(UUID principalID, UUID folderID) + { + foreach (String serverURL in m_inventoryURLs) + { + InventoryCollection result = GetFolderContent(serverURL, principalID, folderID); + + if (result != null) + return result; + } + + return null; + } + + public InventoryCollection GetFolderContent(String m_ServerURI, UUID principalID, UUID folderID) + { + InventoryCollection inventory = new InventoryCollection(); + inventory.Folders = new List(); + inventory.Items = new List(); + inventory.OwnerID = principalID; + + try + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "GETFOLDERCONTENT"}, + { "PRINCIPAL", principalID.ToString() }, + { "FOLDER", folderID.ToString() } + }); + + if (!CheckReturn(ret)) + return null; + + Dictionary folders = ret.ContainsKey("FOLDERS") ? + (Dictionary)ret["FOLDERS"] : null; + Dictionary items = ret.ContainsKey("ITEMS") ? + (Dictionary)ret["ITEMS"] : null; + + 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) + { + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Exception in GetFolderContent: {0}", e.Message); + } + + return inventory; + } + + public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs) + { + List collection = new List(); + + foreach (String serverURL in m_inventoryURLs) + { + collection.AddRange(GetMultipleFoldersContent(serverURL, principalID, folderIDs)); + } + + return collection.ToArray(); + } + + public virtual InventoryCollection[] GetMultipleFoldersContent(String m_ServerURI, UUID principalID, UUID[] folderIDs) + { + InventoryCollection[] inventoryArr = new InventoryCollection[folderIDs.Length]; + // m_log.DebugFormat("[XXX]: In GetMultipleFoldersContent {0}", String.Join(",", folderIDs)); + try + { + Dictionary resultSet = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "GETMULTIPLEFOLDERSCONTENT"}, + { "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); + + if (ret.TryGetValue("FOLDERS", out object ofolders) && ofolders is Dictionary) + { + var folders = ofolders as Dictionary; + 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 (ret.TryGetValue("ITEMS", out object oitems) && oitems is Dictionary) + { + var items = oitems as Dictionary; + 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) + { + List collection = new List(); + + foreach (String serverURL in m_inventoryURLs) + { + collection.AddRange(GetFolderItems(serverURL, principalID, folderID)); + } + + return collection; + } + + public List GetFolderItems(String m_ServerURI, UUID principalID, UUID folderID) + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "GETFOLDERITEMS"}, + { "PRINCIPAL", principalID.ToString() }, + { "FOLDER", folderID.ToString() } + }); + + if (!CheckReturn(ret)) + return null; + + Dictionary items = (Dictionary)ret["ITEMS"]; + List fitems = new List(); + foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i + fitems.Add(BuildItem((Dictionary)o)); + + return fitems; + } + + public bool AddFolder(InventoryFolderBase folder) + { + foreach (String serverURL in m_inventoryURLs) + { + AddFolder(serverURL, folder); + } + + return true; + } + + public bool AddFolder(String m_ServerURI, InventoryFolderBase folder) + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "ADDFOLDER"}, + { "ParentID", folder.ParentID.ToString() }, + { "Type", folder.Type.ToString() }, + { "Version", folder.Version.ToString() }, + { "Name", folder.Name.ToString() }, + { "Owner", folder.Owner.ToString() }, + { "ID", folder.ID.ToString() } + }); + + return CheckReturn(ret); + } + + public bool UpdateFolder(InventoryFolderBase folder) + { + foreach (String serverURL in m_inventoryURLs) + { + UpdateFolder(serverURL, folder); + } + + return true; + } + + public bool UpdateFolder(String m_ServerURI, InventoryFolderBase folder) + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "UPDATEFOLDER"}, + { "ParentID", folder.ParentID.ToString() }, + { "Type", folder.Type.ToString() }, + { "Version", folder.Version.ToString() }, + { "Name", folder.Name.ToString() }, + { "Owner", folder.Owner.ToString() }, + { "ID", folder.ID.ToString() } + }); + + return CheckReturn(ret); + } + + public bool MoveFolder(InventoryFolderBase folder) + { + foreach (String serverURL in m_inventoryURLs) + { + MoveFolder(serverURL, folder); + } + + return true; + } + + public bool MoveFolder(String m_ServerURI, InventoryFolderBase folder) + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "MOVEFOLDER"}, + { "ParentID", folder.ParentID.ToString() }, + { "ID", folder.ID.ToString() }, + { "PRINCIPAL", folder.Owner.ToString() } + }); + + return CheckReturn(ret); + } + + public bool DeleteFolders(UUID principalID, List folderIDs) + { + foreach (String serverURL in m_inventoryURLs) + { + DeleteFolders(serverURL, principalID, folderIDs); + } + + return true; + } + + public bool DeleteFolders(String m_ServerURI, UUID principalID, List folderIDs) + { + List slist = new List(); + + foreach (UUID f in folderIDs) + slist.Add(f.ToString()); + + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "DELETEFOLDERS"}, + { "PRINCIPAL", principalID.ToString() }, + { "FOLDERS", slist } + }); + + return CheckReturn(ret); + } + + public bool PurgeFolder(InventoryFolderBase folder) + { + foreach (String serverURL in m_inventoryURLs) + { + PurgeFolder(serverURL, folder); + } + + return true; + } + + public bool PurgeFolder(String m_ServerURI, InventoryFolderBase folder) + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "PURGEFOLDER"}, + { "ID", folder.ID.ToString() } + }); + + return CheckReturn(ret); + } + + public bool AddItem(InventoryItemBase item) + { + foreach (String serverURL in m_inventoryURLs) + { + AddItem(serverURL, item); + } + + return true; + } + + public bool AddItem(String m_ServerURI, InventoryItemBase item) + { + if (item.Description == null) + item.Description = String.Empty; + if (item.CreatorData == null) + item.CreatorData = String.Empty; + if (item.CreatorId == null) + item.CreatorId = String.Empty; + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "ADDITEM"}, + { "AssetID", item.AssetID.ToString() }, + { "AssetType", item.AssetType.ToString() }, + { "Name", item.Name.ToString() }, + { "Owner", item.Owner.ToString() }, + { "ID", item.ID.ToString() }, + { "InvType", item.InvType.ToString() }, + { "Folder", item.Folder.ToString() }, + { "CreatorId", item.CreatorId.ToString() }, + { "CreatorData", item.CreatorData.ToString() }, + { "Description", item.Description.ToString() }, + { "NextPermissions", item.NextPermissions.ToString() }, + { "CurrentPermissions", item.CurrentPermissions.ToString() }, + { "BasePermissions", item.BasePermissions.ToString() }, + { "EveryOnePermissions", item.EveryOnePermissions.ToString() }, + { "GroupPermissions", item.GroupPermissions.ToString() }, + { "GroupID", item.GroupID.ToString() }, + { "GroupOwned", item.GroupOwned.ToString() }, + { "SalePrice", item.SalePrice.ToString() }, + { "SaleType", item.SaleType.ToString() }, + { "Flags", item.Flags.ToString() }, + { "CreationDate", item.CreationDate.ToString() } + }); + + return CheckReturn(ret); + } + + public bool UpdateItem(InventoryItemBase item) + { + foreach (String serverURL in m_inventoryURLs) + { + UpdateItem(serverURL, item); + } + + return true; + } + + public bool UpdateItem(String m_ServerURI, InventoryItemBase item) + { + if (item.CreatorData == null) + item.CreatorData = String.Empty; + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "UPDATEITEM"}, + { "AssetID", item.AssetID.ToString() }, + { "AssetType", item.AssetType.ToString() }, + { "Name", item.Name.ToString() }, + { "Owner", item.Owner.ToString() }, + { "ID", item.ID.ToString() }, + { "InvType", item.InvType.ToString() }, + { "Folder", item.Folder.ToString() }, + { "CreatorId", item.CreatorId.ToString() }, + { "CreatorData", item.CreatorData.ToString() }, + { "Description", item.Description.ToString() }, + { "NextPermissions", item.NextPermissions.ToString() }, + { "CurrentPermissions", item.CurrentPermissions.ToString() }, + { "BasePermissions", item.BasePermissions.ToString() }, + { "EveryOnePermissions", item.EveryOnePermissions.ToString() }, + { "GroupPermissions", item.GroupPermissions.ToString() }, + { "GroupID", item.GroupID.ToString() }, + { "GroupOwned", item.GroupOwned.ToString() }, + { "SalePrice", item.SalePrice.ToString() }, + { "SaleType", item.SaleType.ToString() }, + { "Flags", item.Flags.ToString() }, + { "CreationDate", item.CreationDate.ToString() } + }); + + bool result = CheckReturn(ret); + if (result) + { + m_ItemCache.AddOrUpdate(item.ID, item, CACHE_EXPIRATION_SECONDS); + } + + return result; + } + + public bool MoveItems(UUID principalID, List items) + { + foreach (String serverURL in m_inventoryURLs) + { + MoveItems(serverURL, principalID, items); + } + + return true; + } + + public bool MoveItems(String m_ServerURI, UUID principalID, List items) + { + List idlist = new List(); + List destlist = new List(); + + foreach (InventoryItemBase item in items) + { + idlist.Add(item.ID.ToString()); + destlist.Add(item.Folder.ToString()); + } + + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "MOVEITEMS"}, + { "PRINCIPAL", principalID.ToString() }, + { "IDLIST", idlist }, + { "DESTLIST", destlist } + }); + + return CheckReturn(ret); + } + + public bool DeleteItems(UUID principalID, List itemIDs) + { + foreach (String serverURL in m_inventoryURLs) + { + DeleteItems(serverURL, principalID, itemIDs); + } + + return true; + } + + public bool DeleteItems(String m_ServerURI, UUID principalID, List itemIDs) + { + List slist = new List(); + + foreach (UUID f in itemIDs) + slist.Add(f.ToString()); + + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "DELETEITEMS"}, + { "PRINCIPAL", principalID.ToString() }, + { "ITEMS", slist } + }); + + return CheckReturn(ret); + } + + public InventoryItemBase GetItem(UUID principalID, UUID itemID) + { + foreach (String serverURL in m_inventoryURLs) + { + InventoryItemBase result = GetItem(serverURL, principalID, itemID); + + if (result != null) + return result; + } + + return null; + } + + public InventoryItemBase GetItem(String m_ServerURI, UUID principalID, UUID itemID) + { + InventoryItemBase retrieved = null; + if (m_ItemCache.TryGetValue(itemID, out retrieved)) + { + return retrieved; + } + + try + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "GETITEM"}, + { "ID", itemID.ToString() }, + { "PRINCIPAL", principalID.ToString() } + }); + + if (!CheckReturn(ret)) + return null; + + retrieved = BuildItem((Dictionary)ret["item"]); + } + catch (Exception e) + { + m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception in GetItem: ", e); + } + + m_ItemCache.AddOrUpdate(itemID, retrieved, CACHE_EXPIRATION_SECONDS); + + return retrieved; + } + + public virtual InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs) + { + List itembases = new List(); + + foreach (String serverURL in m_inventoryURLs) + { + itembases.AddRange(GetMultipleItems(serverURL, principalID, itemIDs)); + } + + return itembases.ToArray(); + } + + public virtual InventoryItemBase[] GetMultipleItems(String m_ServerURI, 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(m_ServerURI, + new Dictionary { + { "METHOD", "GETMULTIPLEITEMS"}, + { "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(UUID principalID, UUID folderID) + { + foreach (String serverURL in m_inventoryURLs) + { + InventoryFolderBase result = GetFolder(serverURL, principalID, folderID); + + if (result != null) + return result; + } + + return null; + } + + public InventoryFolderBase GetFolder(String m_ServerURI, UUID principalID, UUID folderID) + { + try + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "GETFOLDER"}, + { "ID", folderID.ToString() }, + { "PRINCIPAL", principalID.ToString() } + }); + + if (!CheckReturn(ret)) + return null; + + return BuildFolder((Dictionary)ret["folder"]); + } + catch (Exception e) + { + m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception in GetFolder: ", e); + } + + return null; + } + + public List GetActiveGestures(UUID principalID) + { + List active = new List(); + + foreach (String serverURL in m_inventoryURLs) + { + active.AddRange(GetActiveGestures(serverURL, principalID)); + } + + return active; + } + + public List GetActiveGestures(String m_ServerURI, UUID principalID) + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "GETACTIVEGESTURES"}, + { "PRINCIPAL", principalID.ToString() } + }); + + if (!CheckReturn(ret)) + return null; + + List items = new List(); + + foreach (Object o in ((Dictionary)ret["ITEMS"]).Values) + items.Add(BuildItem((Dictionary)o)); + + return items; + } + + public int GetAssetPermissions(UUID principalID, UUID assetID) + { + foreach (String serverURL in m_inventoryURLs) + { + int result = GetAssetPermissions(serverURL, principalID, assetID); + + if (result != 0) + return result; + } + + return 0; + } + + public int GetAssetPermissions(String m_ServerURI, UUID principalID, UUID assetID) + { + Dictionary ret = MakeRequest(m_ServerURI, + new Dictionary { + { "METHOD", "GETASSETPERMISSIONS"}, + { "PRINCIPAL", principalID.ToString() }, + { "ASSET", assetID.ToString() } + }); + + // We cannot use CheckReturn() here because valid values for RESULT are "false" (in the case of request failure) or an int + if (ret == null) + return 0; + + if (ret.ContainsKey("RESULT")) + { + if (ret["RESULT"] is string) + { + int intResult; + + if (int.TryParse ((string)ret["RESULT"], out intResult)) + return intResult; + } + } + + return 0; + } + + public bool HasInventoryForUser(UUID principalID) + { + return false; + } + + // Helpers + // + private Dictionary MakeRequest(String m_ServerURI, Dictionary sendData) + { + RequestsMade++; + + string reply = String.Empty; + + reply = SynchronousRestFormsRequester.MakePostRequest( + m_ServerURI + "/xinventory", + ServerUtils.BuildQueryString(sendData), m_Auth, m_requestTimeoutSecs); + + if(string.IsNullOrWhiteSpace(reply)) + return new Dictionary(); + + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + return replyData; + } + + private InventoryFolderBase BuildFolder(Dictionary data) + { + InventoryFolderBase folder = new InventoryFolderBase(); + + try + { + folder.ParentID = new UUID(data["ParentID"].ToString()); + folder.Type = short.Parse(data["Type"].ToString()); + folder.Version = ushort.Parse(data["Version"].ToString()); + folder.Name = data["Name"].ToString(); + folder.Owner = new UUID(data["Owner"].ToString()); + folder.ID = new UUID(data["ID"].ToString()); + } + catch (Exception e) + { + m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception building folder: ", e); + } + + return folder; + } + + private InventoryItemBase BuildItem(Dictionary data) + { + InventoryItemBase item = new InventoryItemBase(); + + try + { + item.AssetID = new UUID(data["AssetID"].ToString()); + item.AssetType = int.Parse(data["AssetType"].ToString()); + item.Name = data["Name"].ToString(); + item.Owner = new UUID(data["Owner"].ToString()); + item.ID = new UUID(data["ID"].ToString()); + item.InvType = int.Parse(data["InvType"].ToString()); + item.Folder = new UUID(data["Folder"].ToString()); + item.CreatorId = data["CreatorId"].ToString(); + if (data.ContainsKey("CreatorData")) + item.CreatorData = data["CreatorData"].ToString(); + item.Description = data["Description"].ToString(); + item.NextPermissions = uint.Parse(data["NextPermissions"].ToString()); + item.CurrentPermissions = uint.Parse(data["CurrentPermissions"].ToString()); + item.BasePermissions = uint.Parse(data["BasePermissions"].ToString()); + item.EveryOnePermissions = uint.Parse(data["EveryOnePermissions"].ToString()); + item.GroupPermissions = uint.Parse(data["GroupPermissions"].ToString()); + item.GroupID = new UUID(data["GroupID"].ToString()); + item.GroupOwned = bool.Parse(data["GroupOwned"].ToString()); + item.SalePrice = int.Parse(data["SalePrice"].ToString()); + item.SaleType = byte.Parse(data["SaleType"].ToString()); + item.Flags = uint.Parse(data["Flags"].ToString()); + item.CreationDate = int.Parse(data["CreationDate"].ToString()); + } + catch (Exception e) + { + m_log.Error("[XINVENTORY CONNECTOR]: Exception building item: ", e); + } + + return item; + } + } +}