diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs deleted file mode 100644 index 7197049f16..0000000000 --- a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs +++ /dev/null @@ -1,848 +0,0 @@ -/* - * 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 System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using log4net; -using Nini.Config; -using OpenMetaverse; -using OpenMetaverse.StructuredData; -using OpenSim.Framework; -using OpenSim.Framework.Capabilities; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Services.Interfaces; -using Caps = OpenSim.Framework.Capabilities.Caps; - -namespace OpenSim.Capabilities.Handlers -{ - public class FetchInvDescHandler - { - private static readonly ILog m_log = - LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private IInventoryService m_InventoryService; - private ILibraryService m_LibraryService; - private IScene m_Scene; -// private object m_fetchLock = new Object(); - - public FetchInvDescHandler(IInventoryService invService, ILibraryService libService, IScene s) - { - m_InventoryService = invService; - m_LibraryService = libService; - m_Scene = s; - } - - - public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); - - // nasty temporary hack here, the linden client falsely - // identifies the uuid 00000000-0000-0000-0000-000000000000 - // as a string which breaks us - // - // correctly mark it as a uuid - // - request = request.Replace("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000"); - - // another hack 1 results in a - // System.ArgumentException: Object type System.Int32 cannot - // be converted to target type: System.Boolean - // - request = request.Replace("fetch_folders0", "fetch_folders0"); - request = request.Replace("fetch_folders1", "fetch_folders1"); - - Hashtable hash = new Hashtable(); - try - { - hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); - } - catch (LLSD.LLSDParseException e) - { - m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); - m_log.Error("Request: " + request); - } - - ArrayList foldersrequested = (ArrayList)hash["folders"]; - - string response = ""; - string bad_folders_response = ""; - - List folders = new List(); - for (int i = 0; i < foldersrequested.Count; i++) - { - Hashtable inventoryhash = (Hashtable)foldersrequested[i]; - - LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); - - try - { - LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); - } - catch (Exception e) - { - m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); - continue; - } - - // Filter duplicate folder ids that bad viewers may send - if (folders.Find(f => f.folder_id == llsdRequest.folder_id) == null) - folders.Add(llsdRequest); - - } - - if (folders.Count > 0) - { - List bad_folders = new List(); - List invcollSet = Fetch(folders, bad_folders); - //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count); - - if (invcollSet == null) - { - m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Multiple folder fetch failed. Trying old protocol."); -#pragma warning disable 0612 - return FetchInventoryDescendentsRequest(foldersrequested, httpRequest, httpResponse); -#pragma warning restore 0612 - } - - string inventoryitemstr = string.Empty; - foreach (InventoryCollectionWithDescendents icoll in invcollSet) - { - LLSDInventoryDescendents reply = ToLLSD(icoll.Collection, icoll.Descendents); - - inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); - inventoryitemstr = inventoryitemstr.Replace("folders", ""); - inventoryitemstr = inventoryitemstr.Replace("", ""); - - response += inventoryitemstr; - } - - //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders)); - foreach (UUID bad in bad_folders) - bad_folders_response += "" + bad + ""; - } - - if (response.Length == 0) - { - /* Viewers expect a bad_folders array when not available */ - if (bad_folders_response.Length != 0) - { - response = "bad_folders" + bad_folders_response + ""; - } - else - { - response = "folders"; - } - } - else - { - if (bad_folders_response.Length != 0) - { - response = "folders" + response + "bad_folders" + bad_folders_response + ""; - } - else - { - response = "folders" + response + ""; - } - } - - //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request for {0} folders. Item count {1}", folders.Count, item_count); - //m_log.Debug("[WEB FETCH INV DESC HANDLER] " + response); - - return response; - - } - - /// - /// Construct an LLSD reply packet to a CAPS inventory request - /// - /// - /// - private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) - { - LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); - LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); - contents.agent_id = invFetch.owner_id; - contents.owner_id = invFetch.owner_id; - contents.folder_id = invFetch.folder_id; - - reply.folders.Array.Add(contents); - InventoryCollection inv = new InventoryCollection(); - inv.Folders = new List(); - inv.Items = new List(); - int version = 0; - int descendents = 0; - -#pragma warning disable 0612 - inv = Fetch( - invFetch.owner_id, invFetch.folder_id, invFetch.owner_id, - invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version, out descendents); -#pragma warning restore 0612 - - if (inv != null && inv.Folders != null) - { - foreach (InventoryFolderBase invFolder in inv.Folders) - { - contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); - } - - descendents += inv.Folders.Count; - } - - if (inv != null && inv.Items != null) - { - foreach (InventoryItemBase invItem in inv.Items) - { - contents.items.Array.Add(ConvertInventoryItem(invItem)); - } - } - - contents.descendents = descendents; - contents.version = version; - - //m_log.DebugFormat( - // "[WEB FETCH INV DESC HANDLER]: Replying to request for folder {0} (fetch items {1}, fetch folders {2}) with {3} items and {4} folders for agent {5}", - // invFetch.folder_id, - // invFetch.fetch_items, - // invFetch.fetch_folders, - // contents.items.Array.Count, - // contents.categories.Array.Count, - // invFetch.owner_id); - - return reply; - } - - private LLSDInventoryDescendents ToLLSD(InventoryCollection inv, int descendents) - { - LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); - LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); - contents.agent_id = inv.OwnerID; - contents.owner_id = inv.OwnerID; - contents.folder_id = inv.FolderID; - - reply.folders.Array.Add(contents); - - if (inv.Folders != null) - { - foreach (InventoryFolderBase invFolder in inv.Folders) - { - contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); - } - - descendents += inv.Folders.Count; - } - - if (inv.Items != null) - { - foreach (InventoryItemBase invItem in inv.Items) - { - contents.items.Array.Add(ConvertInventoryItem(invItem)); - } - } - - contents.descendents = descendents; - contents.version = inv.Version; - - return reply; - } - /// - /// Old style. Soon to be deprecated. - /// - /// - /// - /// - /// - [Obsolete] - private string FetchInventoryDescendentsRequest(ArrayList foldersrequested, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request for {0} folders", foldersrequested.Count); - - string response = ""; - string bad_folders_response = ""; - - for (int i = 0; i < foldersrequested.Count; i++) - { - string inventoryitemstr = ""; - Hashtable inventoryhash = (Hashtable)foldersrequested[i]; - - LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); - - try - { - LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); - } - catch (Exception e) - { - m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); - } - - LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); - - if (null == reply) - { - bad_folders_response += "" + llsdRequest.folder_id.ToString() + ""; - } - else - { - inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); - inventoryitemstr = inventoryitemstr.Replace("folders", ""); - inventoryitemstr = inventoryitemstr.Replace("", ""); - } - - response += inventoryitemstr; - } - - if (response.Length == 0) - { - /* Viewers expect a bad_folders array when not available */ - if (bad_folders_response.Length != 0) - { - response = "bad_folders" + bad_folders_response + ""; - } - else - { - response = "folders"; - } - } - else - { - if (bad_folders_response.Length != 0) - { - response = "folders" + response + "bad_folders" + bad_folders_response + ""; - } - else - { - response = "folders" + response + ""; - } - } - - // m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request"); - //m_log.Debug("[WEB FETCH INV DESC HANDLER] "+response); - - return response; - - // } - } - - /// - /// Handle the caps inventory descendents fetch. - /// - /// - /// - /// - /// - /// - /// - /// - /// An empty InventoryCollection if the inventory look up failed - [Obsolete] - private InventoryCollection Fetch( - UUID agentID, UUID folderID, UUID ownerID, - bool fetchFolders, bool fetchItems, int sortOrder, out int version, out int descendents) - { - //m_log.DebugFormat( - // "[WEB FETCH INV DESC HANDLER]: Fetching folders ({0}), items ({1}) from {2} for agent {3}", - // fetchFolders, fetchItems, folderID, agentID); - - // FIXME MAYBE: We're not handling sortOrder! - - version = 0; - descendents = 0; - - InventoryFolderImpl fold; - if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null && agentID == m_LibraryService.LibraryRootFolder.Owner) - { - if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(folderID)) != null) - { - InventoryCollection ret = new InventoryCollection(); - ret.Folders = new List(); - ret.Items = fold.RequestListOfItems(); - descendents = ret.Folders.Count + ret.Items.Count; - - return ret; - } - } - - InventoryCollection contents = new InventoryCollection(); - - if (folderID != UUID.Zero) - { - InventoryCollection fetchedContents = m_InventoryService.GetFolderContent(agentID, folderID); - - if (fetchedContents == null) - { - m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Could not get contents of folder {0} for user {1}", folderID, agentID); - return contents; - } - contents = fetchedContents; - InventoryFolderBase containingFolder = new InventoryFolderBase(); - containingFolder.ID = folderID; - containingFolder.Owner = agentID; - containingFolder = m_InventoryService.GetFolder(containingFolder); - - if (containingFolder != null) - { - //m_log.DebugFormat( - // "[WEB FETCH INV DESC HANDLER]: Retrieved folder {0} {1} for agent id {2}", - // containingFolder.Name, containingFolder.ID, agentID); - - version = containingFolder.Version; - - if (fetchItems) - { - List itemsToReturn = contents.Items; - List originalItems = new List(itemsToReturn); - - // descendents must only include the links, not the linked items we add - descendents = originalItems.Count; - - // Add target items for links in this folder before the links themselves. - foreach (InventoryItemBase item in originalItems) - { - if (item.AssetType == (int)AssetType.Link) - { - InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID)); - - // 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) - itemsToReturn.Insert(0, linkedItem); - } - } - - // Now scan for folder links and insert the items they target and those links at the head of the return data - foreach (InventoryItemBase item in originalItems) - { - if (item.AssetType == (int)AssetType.LinkFolder) - { - InventoryCollection linkedFolderContents = m_InventoryService.GetFolderContent(ownerID, item.AssetID); - List links = linkedFolderContents.Items; - - itemsToReturn.InsertRange(0, links); - - foreach (InventoryItemBase link in linkedFolderContents.Items) - { - // 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 (link != null) - { -// m_log.DebugFormat( -// "[WEB FETCH INV DESC HANDLER]: Adding item {0} {1} from folder {2} linked from {3}", -// link.Name, (AssetType)link.AssetType, item.AssetID, containingFolder.Name); - - InventoryItemBase linkedItem - = m_InventoryService.GetItem(new InventoryItemBase(link.AssetID)); - - if (linkedItem != null) - itemsToReturn.Insert(0, linkedItem); - } - } - } - } - } - -// foreach (InventoryItemBase item in contents.Items) -// { -// m_log.DebugFormat( -// "[WEB FETCH INV DESC HANDLER]: Returning item {0}, type {1}, parent {2} in {3} {4}", -// item.Name, (AssetType)item.AssetType, item.Folder, containingFolder.Name, containingFolder.ID); -// } - - // ===== - -// -// foreach (InventoryItemBase linkedItem in linkedItemsToAdd) -// { -// m_log.DebugFormat( -// "[WEB FETCH INV DESC HANDLER]: Inserted linked item {0} for link in folder {1} for agent {2}", -// linkedItem.Name, folderID, agentID); -// -// contents.Items.Add(linkedItem); -// } -// -// // If the folder requested contains links, then we need to send those folders first, otherwise the links -// // will be broken in the viewer. -// HashSet linkedItemFolderIdsToSend = new HashSet(); -// foreach (InventoryItemBase item in contents.Items) -// { -// if (item.AssetType == (int)AssetType.Link) -// { -// InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID)); -// -// // 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) -// { -// // 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); -// } -// } -// } -// -// foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend) -// { -// m_log.DebugFormat( -// "[WEB FETCH INV DESC HANDLER]: Recursively fetching folder {0} linked by item in folder {1} for agent {2}", -// linkedItemFolderId, folderID, agentID); -// -// int dummyVersion; -// InventoryCollection linkedCollection -// = Fetch( -// agentID, linkedItemFolderId, ownerID, fetchFolders, fetchItems, sortOrder, out dummyVersion); -// -// InventoryFolderBase linkedFolder = new InventoryFolderBase(linkedItemFolderId); -// linkedFolder.Owner = agentID; -// linkedFolder = m_InventoryService.GetFolder(linkedFolder); -// -//// contents.Folders.AddRange(linkedCollection.Folders); -// -// contents.Folders.Add(linkedFolder); -// contents.Items.AddRange(linkedCollection.Items); -// } -// } - } - } - else - { - // Lost items don't really need a version - version = 1; - } - - return contents; - - } - - private void AddLibraryFolders(List fetchFolders, List result) - { - InventoryFolderImpl fold; - if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null) - { - List libfolders = fetchFolders.FindAll(f => f.owner_id == m_LibraryService.LibraryRootFolder.Owner); - fetchFolders.RemoveAll(f => libfolders.Contains(f)); - - //m_log.DebugFormat("[XXX]: Found {0} library folders in request", libfolders.Count); - - foreach (LLSDFetchInventoryDescendents f in libfolders) - { - if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(f.folder_id)) != null) - { - InventoryCollectionWithDescendents ret = new InventoryCollectionWithDescendents(); - ret.Collection = new InventoryCollection(); - ret.Collection.Folders = new List(); - ret.Collection.Items = fold.RequestListOfItems(); - ret.Collection.OwnerID = m_LibraryService.LibraryRootFolder.Owner; - ret.Collection.FolderID = f.folder_id; - ret.Collection.Version = fold.Version; - - ret.Descendents = ret.Collection.Items.Count; - result.Add(ret); - - //m_log.DebugFormat("[XXX]: Added libfolder {0} ({1}) {2}", ret.Collection.FolderID, ret.Collection.OwnerID); - } - } - } - } - - private List Fetch(List fetchFolders, List bad_folders) - { - //m_log.DebugFormat( - // "[WEB FETCH INV DESC HANDLER]: Fetching {0} folders for owner {1}", fetchFolders.Count, fetchFolders[0].owner_id); - - // FIXME MAYBE: We're not handling sortOrder! - - List result = new List(); - - AddLibraryFolders(fetchFolders, result); - - // Filter folder Zero right here. Some viewers (Firestorm) send request for folder Zero, which doesn't make sense - // and can kill the sim (all root folders have parent_id Zero) - LLSDFetchInventoryDescendents zero = fetchFolders.Find(f => f.folder_id == UUID.Zero); - if (zero != null) - { - fetchFolders.Remove(zero); - BadFolder(zero, null, bad_folders); - } - - if (fetchFolders.Count > 0) - { - UUID[] fids = new UUID[fetchFolders.Count]; - int i = 0; - foreach (LLSDFetchInventoryDescendents f in fetchFolders) - fids[i++] = f.folder_id; - - //m_log.DebugFormat("[XXX]: {0}", string.Join(",", fids)); - - InventoryCollection[] fetchedContents = m_InventoryService.GetMultipleFoldersContent(fetchFolders[0].owner_id, fids); - - if (fetchedContents == null || (fetchedContents != null && fetchedContents.Length == 0)) - { - m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Could not get contents of multiple folders for user {0}", fetchFolders[0].owner_id); - foreach (LLSDFetchInventoryDescendents freq in fetchFolders) - BadFolder(freq, null, bad_folders); - return null; - } - - i = 0; - // Do some post-processing. May need to fetch more from inv server for links - foreach (InventoryCollection contents in fetchedContents) - { - // Find the original request - LLSDFetchInventoryDescendents freq = fetchFolders[i++]; - - InventoryCollectionWithDescendents coll = new InventoryCollectionWithDescendents(); - coll.Collection = contents; - - if (BadFolder(freq, contents, bad_folders)) - continue; - - // Next: link management - ProcessLinks(freq, coll); - - result.Add(coll); - } - } - - return result; - } - - private bool BadFolder(LLSDFetchInventoryDescendents freq, InventoryCollection contents, List bad_folders) - { - bool bad = false; - if (contents == null) - { - bad_folders.Add(freq.folder_id); - bad = true; - } - - // The inventory server isn't sending FolderID in the collection... - // Must fetch it individually - else if (contents.FolderID == UUID.Zero) - { - InventoryFolderBase containingFolder = new InventoryFolderBase(); - containingFolder.ID = freq.folder_id; - containingFolder.Owner = freq.owner_id; - containingFolder = m_InventoryService.GetFolder(containingFolder); - - if (containingFolder != null) - { - contents.FolderID = containingFolder.ID; - contents.OwnerID = containingFolder.Owner; - contents.Version = containingFolder.Version; - } - else - { - // Was it really a request for folder Zero? - // This is an overkill, but Firestorm really asks for folder Zero. - // I'm leaving the code here for the time being, but commented. - if (freq.folder_id == UUID.Zero) - { - //coll.Collection.OwnerID = freq.owner_id; - //coll.Collection.FolderID = contents.FolderID; - //containingFolder = m_InventoryService.GetRootFolder(freq.owner_id); - //if (containingFolder != null) - //{ - // m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Request for parent of folder {0}", containingFolder.ID); - // coll.Collection.Folders.Clear(); - // coll.Collection.Folders.Add(containingFolder); - // if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null) - // { - // InventoryFolderBase lib = new InventoryFolderBase(m_LibraryService.LibraryRootFolder.ID, m_LibraryService.LibraryRootFolder.Owner); - // lib.Name = m_LibraryService.LibraryRootFolder.Name; - // lib.Type = m_LibraryService.LibraryRootFolder.Type; - // lib.Version = m_LibraryService.LibraryRootFolder.Version; - // coll.Collection.Folders.Add(lib); - // } - // coll.Collection.Items.Clear(); - //} - } - else - { - m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Unable to fetch folder {0}", freq.folder_id); - bad_folders.Add(freq.folder_id); - } - bad = true; - } - } - - return bad; - } - - private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollectionWithDescendents coll) - { - InventoryCollection contents = coll.Collection; - - if (freq.fetch_items && contents.Items != null) - { - List itemsToReturn = contents.Items; - - // descendents must only include the links, not the linked items we add - coll.Descendents = itemsToReturn.Count; - - // Add target items for links in this folder before the links themselves. - List itemIDs = new List(); - List folderIDs = new List(); - foreach (InventoryItemBase item in itemsToReturn) - { - //m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType); - if (item.AssetType == (int)AssetType.Link) - itemIDs.Add(item.AssetID); - - else if (item.AssetType == (int)AssetType.LinkFolder) - folderIDs.Add(item.AssetID); - } - - //m_log.DebugFormat("[XXX]: folder {0} has {1} links and {2} linkfolders", contents.FolderID, itemIDs.Count, folderIDs.Count); - - // Scan for folder links and insert the items they target and those links at the head of the return data - if (folderIDs.Count > 0) - { - InventoryCollection[] linkedFolders = m_InventoryService.GetMultipleFoldersContent(coll.Collection.OwnerID, folderIDs.ToArray()); - foreach (InventoryCollection linkedFolderContents in linkedFolders) - { - if (linkedFolderContents == null) - continue; - - List links = linkedFolderContents.Items; - - itemsToReturn.InsertRange(0, links); - - } - } - - if (itemIDs.Count > 0) - { - InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray()); - if (linked == null) - { - // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated - m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); - linked = new InventoryItemBase[itemIDs.Count]; - int i = 0; - InventoryItemBase item = new InventoryItemBase(); - item.Owner = freq.owner_id; - foreach (UUID id in itemIDs) - { - item.ID = id; - linked[i++] = m_InventoryService.GetItem(item); - } - } - - //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Processing folder {0}. Existing items:", freq.folder_id); - //foreach (InventoryItemBase item in itemsToReturn) - // m_log.DebugFormat("[XXX]: {0} {1} {2}", item.Name, item.AssetType, item.Folder); - - if (linked != null) - { - foreach (InventoryItemBase linkedItem in linked) - { - // 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) - { - itemsToReturn.Insert(0, linkedItem); - //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder); - } - } - } - } - } - - } - - /// - /// Convert an internal inventory folder object into an LLSD object. - /// - /// - /// - private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder) - { - LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder(); - llsdFolder.folder_id = invFolder.ID; - llsdFolder.parent_id = invFolder.ParentID; - llsdFolder.name = invFolder.Name; - llsdFolder.type = invFolder.Type; - llsdFolder.preferred_type = -1; - - return llsdFolder; - } - - /// - /// Convert an internal inventory item object into an LLSD object. - /// - /// - /// - private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem) - { - LLSDInventoryItem llsdItem = new LLSDInventoryItem(); - llsdItem.asset_id = invItem.AssetID; - llsdItem.created_at = invItem.CreationDate; - llsdItem.desc = invItem.Description; - llsdItem.flags = (int)invItem.Flags; - llsdItem.item_id = invItem.ID; - llsdItem.name = invItem.Name; - llsdItem.parent_id = invItem.Folder; - llsdItem.type = invItem.AssetType; - llsdItem.inv_type = invItem.InvType; - - llsdItem.permissions = new LLSDPermissions(); - llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; - llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions; - llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions; - llsdItem.permissions.group_id = invItem.GroupID; - llsdItem.permissions.group_mask = (int)invItem.GroupPermissions; - llsdItem.permissions.is_owner_group = invItem.GroupOwned; - llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions; - llsdItem.permissions.owner_id = invItem.Owner; - llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; - llsdItem.sale_info = new LLSDSaleInfo(); - llsdItem.sale_info.sale_price = invItem.SalePrice; - llsdItem.sale_info.sale_type = invItem.SaleType; - - return llsdItem; - } - } - - class InventoryCollectionWithDescendents - { - public InventoryCollection Collection; - public int Descendents; - } -} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs deleted file mode 100644 index 8af3c6485d..0000000000 --- a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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 System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text.RegularExpressions; -using log4net; -using log4net.Config; -using NUnit.Framework; -using OpenMetaverse; -using OpenSim.Capabilities.Handlers; -using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Services.Interfaces; -using OpenSim.Tests.Common; - -namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests -{ - [TestFixture] - public class FetchInventory2HandlerTests : OpenSimTestCase - { - private UUID m_userID = UUID.Random(); - private Scene m_scene; - private UUID m_rootFolderID; - private UUID m_notecardsFolder; - private UUID m_objectsFolder; - - private void Init() - { - // Create an inventory that looks like this: - // - // /My Inventory - // - // /Objects - // Object 1 - // Object 2 - // Object 3 - // /Notecards - // Notecard 1 - // Notecard 2 - // Notecard 3 - // Notecard 4 - // Notecard 5 - - m_scene = new SceneHelpers().SetupScene(); - - m_scene.InventoryService.CreateUserInventory(m_userID); - - m_rootFolderID = m_scene.InventoryService.GetRootFolder(m_userID).ID; - - InventoryFolderBase of = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object); - m_objectsFolder = of.ID; - - // Add 3 objects - InventoryItemBase item; - for (int i = 1; i <= 3; i++) - { - item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-0000000000b" + i), m_userID); - item.AssetID = UUID.Random(); - item.AssetType = (int)AssetType.Object; - item.Folder = m_objectsFolder; - item.Name = "Object " + i; - m_scene.InventoryService.AddItem(item); - } - - InventoryFolderBase ncf = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Notecard); - m_notecardsFolder = ncf.ID; - - // Add 5 notecards - for (int i = 1; i <= 5; i++) - { - item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-00000000000" + i), m_userID); - item.AssetID = UUID.Random(); - item.AssetType = (int)AssetType.Notecard; - item.Folder = m_notecardsFolder; - item.Name = "Notecard " + i; - m_scene.InventoryService.AddItem(item); - } - - } - - [Test] - public void Test_001_RequestOne() - { - TestHelpers.InMethod(); - - Init(); - - FetchInventory2Handler handler = new FetchInventory2Handler(m_scene.InventoryService, m_userID); - TestOSHttpRequest req = new TestOSHttpRequest(); - TestOSHttpResponse resp = new TestOSHttpResponse(); - - string request = "itemsitem_id"; - request += "10000000-0000-0000-0000-000000000001"; // Notecard 1 - request += ""; - - string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp); - - Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); - Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); - Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID"); - - Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Response does not contain item uuid"); - Assert.That(llsdresponse.Contains("Notecard 1"), Is.True, "Response does not contain item Name"); - Console.WriteLine(llsdresponse); - } - - [Test] - public void Test_002_RequestMany() - { - TestHelpers.InMethod(); - - Init(); - - FetchInventory2Handler handler = new FetchInventory2Handler(m_scene.InventoryService, m_userID); - TestOSHttpRequest req = new TestOSHttpRequest(); - TestOSHttpResponse resp = new TestOSHttpResponse(); - - string request = "items"; - request += "item_id10000000-0000-0000-0000-000000000001"; // Notecard 1 - request += "item_id10000000-0000-0000-0000-000000000002"; // Notecard 2 - request += "item_id10000000-0000-0000-0000-000000000003"; // Notecard 3 - request += "item_id10000000-0000-0000-0000-000000000004"; // Notecard 4 - request += "item_id10000000-0000-0000-0000-000000000005"; // Notecard 5 - request += ""; - - string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp); - - Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); - Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); - Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID"); - - Console.WriteLine(llsdresponse); - Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Response does not contain notecard 1"); - Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000002"), Is.True, "Response does not contain notecard 2"); - Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000003"), Is.True, "Response does not contain notecard 3"); - Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000004"), Is.True, "Response does not contain notecard 4"); - Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000005"), Is.True, "Response does not contain notecard 5"); - } - - } - -} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs deleted file mode 100644 index 2d5531a1ef..0000000000 --- a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs +++ /dev/null @@ -1,292 +0,0 @@ -/* - * 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 System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text.RegularExpressions; -using log4net; -using log4net.Config; -using NUnit.Framework; -using OpenMetaverse; -using OpenSim.Capabilities.Handlers; -using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Services.Interfaces; -using OpenSim.Tests.Common; - -namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests -{ - [TestFixture] - public class FetchInventoryDescendents2HandlerTests : OpenSimTestCase - { - private UUID m_userID = UUID.Zero; - private Scene m_scene; - private UUID m_rootFolderID; - private int m_rootDescendents; - private UUID m_notecardsFolder; - private UUID m_objectsFolder; - - private void Init() - { - // Create an inventory that looks like this: - // - // /My Inventory - // - // /Objects - // Some Object - // /Notecards - // Notecard 1 - // Notecard 2 - // /Test Folder - // Link to notecard -> /Notecards/Notecard 2 - // Link to Objects folder -> /Objects - - m_scene = new SceneHelpers().SetupScene(); - - m_scene.InventoryService.CreateUserInventory(m_userID); - - m_rootFolderID = m_scene.InventoryService.GetRootFolder(m_userID).ID; - - InventoryFolderBase of = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object); - m_objectsFolder = of.ID; - - // Add an object - InventoryItemBase item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-00000000000b"), m_userID); - item.AssetID = UUID.Random(); - item.AssetType = (int)AssetType.Object; - item.Folder = m_objectsFolder; - item.Name = "Some Object"; - m_scene.InventoryService.AddItem(item); - - InventoryFolderBase ncf = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Notecard); - m_notecardsFolder = ncf.ID; - - // Add a notecard - item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-000000000001"), m_userID); - item.AssetID = UUID.Random(); - item.AssetType = (int)AssetType.Notecard; - item.Folder = m_notecardsFolder; - item.Name = "Test Notecard 1"; - m_scene.InventoryService.AddItem(item); - // Add another notecard - item.ID = new UUID("20000000-0000-0000-0000-000000000002"); - item.AssetID = new UUID("a0000000-0000-0000-0000-00000000000a"); - item.Name = "Test Notecard 2"; - m_scene.InventoryService.AddItem(item); - - // Add a folder - InventoryFolderBase folder = new InventoryFolderBase(new UUID("f0000000-0000-0000-0000-00000000000f"), "Test Folder", m_userID, m_rootFolderID); - m_scene.InventoryService.AddFolder(folder); - - // Add a link to notecard 2 in Test Folder - item.AssetID = item.ID; // use item ID of notecard 2 - item.ID = new UUID("40000000-0000-0000-0000-000000000004"); - item.AssetType = (int)AssetType.Link; - item.Folder = folder.ID; - item.Name = "Link to notecard"; - m_scene.InventoryService.AddItem(item); - - // Add a link to the Objects folder in Test Folder - item.AssetID = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object).ID; // use item ID of Objects folder - item.ID = new UUID("50000000-0000-0000-0000-000000000005"); - item.AssetType = (int)AssetType.LinkFolder; - item.Folder = folder.ID; - item.Name = "Link to Objects folder"; - m_scene.InventoryService.AddItem(item); - - InventoryCollection coll = m_scene.InventoryService.GetFolderContent(m_userID, m_rootFolderID); - m_rootDescendents = coll.Items.Count + coll.Folders.Count; - Console.WriteLine("Number of descendents: " + m_rootDescendents); - } - - [Test] - public void Test_001_SimpleFolder() - { - TestHelpers.InMethod(); - - Init(); - - FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); - TestOSHttpRequest req = new TestOSHttpRequest(); - TestOSHttpResponse resp = new TestOSHttpResponse(); - - string request = "foldersfetch_folders1fetch_items1folder_id"; - request += m_rootFolderID; - request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; - - string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); - - Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); - Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); - Assert.That(llsdresponse.Contains("00000000-0000-0000-0000-000000000000"), Is.True, "Response should contain userID"); - - string descendents = "descendents" + m_rootDescendents + ""; - Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents"); - Console.WriteLine(llsdresponse); - } - - [Test] - public void Test_002_MultipleFolders() - { - TestHelpers.InMethod(); - - FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); - TestOSHttpRequest req = new TestOSHttpRequest(); - TestOSHttpResponse resp = new TestOSHttpResponse(); - - string request = "folders"; - request += "fetch_folders1fetch_items1folder_id"; - request += m_rootFolderID; - request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; - request += "fetch_folders1fetch_items1folder_id"; - request += m_notecardsFolder; - request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; - request += ""; - - string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); - Console.WriteLine(llsdresponse); - - string descendents = "descendents" + m_rootDescendents + ""; - Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for root folder"); - descendents = "descendents2"; - Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for Notecard folder"); - - Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Notecard 1 is missing from response"); - Assert.That(llsdresponse.Contains("20000000-0000-0000-0000-000000000002"), Is.True, "Notecard 2 is missing from response"); - } - - [Test] - public void Test_003_Links() - { - TestHelpers.InMethod(); - - FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); - TestOSHttpRequest req = new TestOSHttpRequest(); - TestOSHttpResponse resp = new TestOSHttpResponse(); - - string request = "foldersfetch_folders1fetch_items1folder_id"; - request += "f0000000-0000-0000-0000-00000000000f"; - request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; - - string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); - Console.WriteLine(llsdresponse); - - string descendents = "descendents2"; - Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for Test Folder"); - - // Make sure that the note card link is included - Assert.That(llsdresponse.Contains("Link to notecard"), Is.True, "Link to notecard is missing"); - - //Make sure the notecard item itself is included - Assert.That(llsdresponse.Contains("Test Notecard 2"), Is.True, "Notecard 2 item (the source) is missing"); - - // Make sure that the source item is before the link item - int pos1 = llsdresponse.IndexOf("Test Notecard 2"); - int pos2 = llsdresponse.IndexOf("Link to notecard"); - Assert.Less(pos1, pos2, "Source of link is after link"); - - // Make sure the folder link is included - Assert.That(llsdresponse.Contains("Link to Objects folder"), Is.True, "Link to Objects folder is missing"); - - // Make sure the objects inside the Objects folder are included - // Note: I'm not entirely sure this is needed, but that's what I found in the implementation - Assert.That(llsdresponse.Contains("Some Object"), Is.True, "Some Object item (contents of the source) is missing"); - - // Make sure that the source item is before the link item - pos1 = llsdresponse.IndexOf("Some Object"); - pos2 = llsdresponse.IndexOf("Link to Objects folder"); - Assert.Less(pos1, pos2, "Contents of source of folder link is after folder link"); - } - - [Test] - public void Test_004_DuplicateFolders() - { - TestHelpers.InMethod(); - - FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); - TestOSHttpRequest req = new TestOSHttpRequest(); - TestOSHttpResponse resp = new TestOSHttpResponse(); - - string request = "folders"; - request += "fetch_folders1fetch_items1folder_id"; - request += m_rootFolderID; - request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; - request += "fetch_folders1fetch_items1folder_id"; - request += m_notecardsFolder; - request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; - request += "fetch_folders1fetch_items1folder_id"; - request += m_rootFolderID; - request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; - request += "fetch_folders1fetch_items1folder_id"; - request += m_notecardsFolder; - request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; - request += ""; - - string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); - Console.WriteLine(llsdresponse); - - string root_folder = "folder_id" + m_rootFolderID + ""; - string notecards_folder = "folder_id" + m_notecardsFolder + ""; - - Assert.That(llsdresponse.Contains(root_folder), "Missing root folder"); - Assert.That(llsdresponse.Contains(notecards_folder), "Missing notecards folder"); - int count = Regex.Matches(llsdresponse, root_folder).Count; - Assert.AreEqual(1, count, "More than 1 root folder in response"); - count = Regex.Matches(llsdresponse, notecards_folder).Count; - Assert.AreEqual(2, count, "More than 1 notecards folder in response"); // Notecards will also be under root, so 2 - } - - [Test] - public void Test_005_FolderZero() - { - TestHelpers.InMethod(); - - Init(); - - FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); - TestOSHttpRequest req = new TestOSHttpRequest(); - TestOSHttpResponse resp = new TestOSHttpResponse(); - - string request = "foldersfetch_folders1fetch_items1folder_id"; - request += UUID.Zero; - request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; - - string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); - - Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); - Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); - Assert.That(llsdresponse.Contains("bad_folders00000000-0000-0000-0000-000000000000"), Is.True, "Folder Zero should be a bad folder"); - - Console.WriteLine(llsdresponse); - } - - } - -} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs similarity index 78% rename from OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs rename to OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs index 638e8bc9db..d1503ee15c 100644 --- a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs +++ b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs @@ -25,36 +25,39 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System; +using System.Collections; +using System.Collections.Generic; using System.Reflection; +using log4net; +using Nini.Config; using OpenMetaverse; using OpenMetaverse.StructuredData; using OpenSim.Framework; using OpenSim.Framework.Capabilities; +using OpenSim.Region.Framework.Interfaces; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; +using Caps = OpenSim.Framework.Capabilities.Caps; using OSDArray = OpenMetaverse.StructuredData.OSDArray; using OSDMap = OpenMetaverse.StructuredData.OSDMap; -using log4net; - namespace OpenSim.Capabilities.Handlers { public class FetchInventory2Handler { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IInventoryService m_inventoryService; - private UUID m_agentID; - public FetchInventory2Handler(IInventoryService invService, UUID agentId) + public FetchInventory2Handler(IInventoryService invService) { m_inventoryService = invService; - m_agentID = agentId; } public string FetchInventoryRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { - //m_log.DebugFormat("[FETCH INVENTORY HANDLER]: Received FetchInventory capability request {0}", request); +// m_log.DebugFormat("[FETCH INVENTORY HANDLER]: Received FetchInventory capabilty request"); OSDMap requestmap = (OSDMap)OSDParser.DeserializeLLSDXml(Utils.StringToBytes(request)); OSDArray itemsRequested = (OSDArray)requestmap["items"]; @@ -62,32 +65,12 @@ namespace OpenSim.Capabilities.Handlers string reply; LLSDFetchInventory llsdReply = new LLSDFetchInventory(); - UUID[] itemIDs = new UUID[itemsRequested.Count]; - int i = 0; foreach (OSDMap osdItemId in itemsRequested) { - itemIDs[i++] = osdItemId["item_id"].AsUUID(); - } + UUID itemId = osdItemId["item_id"].AsUUID(); - InventoryItemBase[] items = m_inventoryService.GetMultipleItems(m_agentID, itemIDs); + InventoryItemBase item = m_inventoryService.GetItem(new InventoryItemBase(itemId)); - if (items == null) - { - // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated - m_log.WarnFormat("[FETCH INVENTORY HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); - items = new InventoryItemBase[itemsRequested.Count]; - i = 0; - InventoryItemBase item = new InventoryItemBase(); - item.Owner = m_agentID; - foreach (UUID id in itemIDs) - { - item.ID = id; - items[i++] = m_inventoryService.GetItem(item); - } - } - - foreach (InventoryItemBase item in items) - { if (item != null) { // We don't know the agent that this request belongs to so we'll use the agent id of the item diff --git a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2ServerConnector.cs b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2ServerConnector.cs new file mode 100644 index 0000000000..5bab52fe94 --- /dev/null +++ b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2ServerConnector.cs @@ -0,0 +1,71 @@ +/* + * 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 System; +using Nini.Config; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; +using OpenMetaverse; + +namespace OpenSim.Capabilities.Handlers +{ + public class FetchInventory2ServerConnector : ServiceConnector + { + private IInventoryService m_InventoryService; + private string m_ConfigName = "CapsService"; + + public FetchInventory2ServerConnector(IConfigSource config, IHttpServer server, string configName) + : base(config, server, configName) + { + if (configName != String.Empty) + m_ConfigName = configName; + + IConfig serverConfig = config.Configs[m_ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName)); + + string invService = serverConfig.GetString("InventoryService", String.Empty); + + if (invService == String.Empty) + throw new Exception("No InventoryService in config file"); + + Object[] args = new Object[] { config }; + m_InventoryService = ServerUtils.LoadPlugin(invService, args); + + if (m_InventoryService == null) + throw new Exception(String.Format("Failed to load InventoryService from {0}; config is {1}", invService, m_ConfigName)); + + FetchInventory2Handler fiHandler = new FetchInventory2Handler(m_InventoryService); + IRequestHandler reqHandler + = new RestStreamHandler( + "POST", "/CAPS/FetchInventory/", fiHandler.FetchInventoryRequest, "FetchInventory", null); + server.AddStreamHandler(reqHandler); + } + } +} diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescServerConnector.cs b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs similarity index 91% rename from OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescServerConnector.cs rename to OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs index 9dcfaa48f1..5d86557dc3 100644 --- a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescServerConnector.cs +++ b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs @@ -35,13 +35,13 @@ using OpenMetaverse; namespace OpenSim.Capabilities.Handlers { - public class FetchInvDescServerConnector : ServiceConnector + public class WebFetchInvDescServerConnector : ServiceConnector { private IInventoryService m_InventoryService; private ILibraryService m_LibraryService; private string m_ConfigName = "CapsService"; - public FetchInvDescServerConnector(IConfigSource config, IHttpServer server, string configName) : + public WebFetchInvDescServerConnector(IConfigSource config, IHttpServer server, string configName) : base(config, server, configName) { if (configName != String.Empty) @@ -67,13 +67,13 @@ namespace OpenSim.Capabilities.Handlers m_LibraryService = ServerUtils.LoadPlugin(libService, args); - FetchInvDescHandler webFetchHandler = new FetchInvDescHandler(m_InventoryService, m_LibraryService, null); + WebFetchInvDescHandler webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); IRequestHandler reqHandler = new RestStreamHandler( "POST", "/CAPS/WebFetchInvDesc/" /*+ UUID.Random()*/, webFetchHandler.FetchInventoryDescendentsRequest, - "FetchInvDescendents", + "WebFetchInvDesc", null); server.AddStreamHandler(reqHandler); } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs b/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs index e0a11ccff6..87d3d1c676 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs @@ -25,16 +25,20 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using Mono.Addins; +using System; +using System.Collections; +using System.Reflection; +using log4net; using Nini.Config; +using Mono.Addins; using OpenMetaverse; -using OpenSim.Capabilities.Handlers; +using OpenSim.Framework; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; -using System; using Caps = OpenSim.Framework.Capabilities.Caps; +using OpenSim.Capabilities.Handlers; namespace OpenSim.Region.ClientStack.Linden { @@ -54,6 +58,8 @@ namespace OpenSim.Region.ClientStack.Linden private string m_fetchInventory2Url; + private FetchInventory2Handler m_fetchHandler; + #region ISharedRegionModule Members public void Initialise(IConfigSource source) @@ -92,6 +98,10 @@ namespace OpenSim.Region.ClientStack.Linden m_inventoryService = m_scene.InventoryService; + // We'll reuse the same handler for all requests. + if (m_fetchInventory2Url == "localhost") + m_fetchHandler = new FetchInventory2Handler(m_inventoryService); + m_scene.EventManager.OnRegisterCaps += RegisterCaps; } @@ -121,11 +131,9 @@ namespace OpenSim.Region.ClientStack.Linden { capUrl = "/CAPS/" + UUID.Random(); - FetchInventory2Handler fetchHandler = new FetchInventory2Handler(m_inventoryService, agentID); - IRequestHandler reqHandler = new RestStreamHandler( - "POST", capUrl, fetchHandler.FetchInventoryRequest, capName, agentID.ToString()); + "POST", capUrl, m_fetchHandler.FetchInventoryRequest, capName, agentID.ToString()); caps.RegisterHandler(capName, reqHandler); } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 2a252e17af..5f3e66a0b6 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -66,26 +66,7 @@ namespace OpenSim.Region.ClientStack.Linden private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - /// - /// Control whether requests will be processed asynchronously. - /// - /// - /// Defaults to true. Can currently not be changed once a region has been added to the module. - /// - public bool ProcessQueuedRequestsAsync { get; private set; } - - /// - /// Number of inventory requests processed by this module. - /// - /// - /// It's the PollServiceRequestManager that actually sends completed requests back to the requester. - /// - public static int ProcessedRequestsCount { get; set; } - - private static Stat s_queuedRequestsStat; - private static Stat s_processedRequestsStat; - - public Scene Scene { get; private set; } + private Scene m_scene; private IInventoryService m_InventoryService; private ILibraryService m_LibraryService; @@ -95,7 +76,7 @@ namespace OpenSim.Region.ClientStack.Linden private string m_fetchInventoryDescendents2Url; private string m_webFetchInventoryDescendentsUrl; - private static FetchInvDescHandler m_webFetchHandler; + private static WebFetchInvDescHandler m_webFetchHandler; private static Thread[] m_workerThreads = null; @@ -104,13 +85,6 @@ namespace OpenSim.Region.ClientStack.Linden #region ISharedRegionModule Members - public WebFetchInvDescModule() : this(true) {} - - public WebFetchInvDescModule(bool processQueuedResultsAsync) - { - ProcessQueuedRequestsAsync = processQueuedResultsAsync; - } - public void Initialise(IConfigSource source) { IConfig config = source.Configs["ClientStack.LindenCaps"]; @@ -118,9 +92,8 @@ namespace OpenSim.Region.ClientStack.Linden return; m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty); -// m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); + m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); -// if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) { m_Enabled = true; @@ -132,7 +105,7 @@ namespace OpenSim.Region.ClientStack.Linden if (!m_Enabled) return; - Scene = s; + m_scene = s; } public void RemoveRegion(Scene s) @@ -140,23 +113,12 @@ namespace OpenSim.Region.ClientStack.Linden if (!m_Enabled) return; - Scene.EventManager.OnRegisterCaps -= RegisterCaps; + m_scene.EventManager.OnRegisterCaps -= RegisterCaps; - StatsManager.DeregisterStat(s_processedRequestsStat); - StatsManager.DeregisterStat(s_queuedRequestsStat); + foreach (Thread t in m_workerThreads) + Watchdog.AbortThread(t.ManagedThreadId); - if (ProcessQueuedRequestsAsync) - { - if (m_workerThreads != null) - { - foreach (Thread t in m_workerThreads) - Watchdog.AbortThread(t.ManagedThreadId); - - m_workerThreads = null; - } - } - - Scene = null; + m_scene = null; } public void RegionLoaded(Scene s) @@ -164,51 +126,19 @@ namespace OpenSim.Region.ClientStack.Linden if (!m_Enabled) return; - if (s_processedRequestsStat == null) - s_processedRequestsStat = - new Stat( - "ProcessedFetchInventoryRequests", - "Number of processed fetch inventory requests", - "These have not necessarily yet been dispatched back to the requester.", - "", - "inventory", - "httpfetch", - StatType.Pull, - MeasuresOfInterest.AverageChangeOverTime, - stat => { stat.Value = ProcessedRequestsCount; }, - StatVerbosity.Debug); - - if (s_queuedRequestsStat == null) - s_queuedRequestsStat = - new Stat( - "QueuedFetchInventoryRequests", - "Number of fetch inventory requests queued for processing", - "", - "", - "inventory", - "httpfetch", - StatType.Pull, - MeasuresOfInterest.AverageChangeOverTime, - stat => { stat.Value = m_queue.Count; }, - StatVerbosity.Debug); - - StatsManager.RegisterStat(s_processedRequestsStat); - StatsManager.RegisterStat(s_queuedRequestsStat); - - m_InventoryService = Scene.InventoryService; - m_LibraryService = Scene.LibraryService; + m_InventoryService = m_scene.InventoryService; + m_LibraryService = m_scene.LibraryService; // We'll reuse the same handler for all requests. - m_webFetchHandler = new FetchInvDescHandler(m_InventoryService, m_LibraryService, Scene); + m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); - Scene.EventManager.OnRegisterCaps += RegisterCaps; + m_scene.EventManager.OnRegisterCaps += RegisterCaps; - int nworkers = 2; // was 2 - if (ProcessQueuedRequestsAsync && m_workerThreads == null) + if (m_workerThreads == null) { - m_workerThreads = new Thread[nworkers]; + m_workerThreads = new Thread[2]; - for (uint i = 0; i < nworkers; i++) + for (uint i = 0; i < 2; i++) { m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests, String.Format("InventoryWorkerThread{0}", i), @@ -243,12 +173,12 @@ namespace OpenSim.Region.ClientStack.Linden private Dictionary responses = new Dictionary(); - private WebFetchInvDescModule m_module; + private Scene m_scene; - public PollServiceInventoryEventArgs(WebFetchInvDescModule module, string url, UUID pId) : - base(null, url, null, null, null, pId, int.MaxValue) + public PollServiceInventoryEventArgs(Scene scene, string url, UUID pId) : + base(null, url, null, null, null, pId, int.MaxValue) { - m_module = module; + m_scene = scene; HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); }; GetEvents = (x, y) => @@ -268,7 +198,12 @@ namespace OpenSim.Region.ClientStack.Linden Request = (x, y) => { - ScenePresence sp = m_module.Scene.GetScenePresence(Id); + ScenePresence sp = m_scene.GetScenePresence(Id); + if (sp == null) + { + m_log.ErrorFormat("[INVENTORY]: Unable to find ScenePresence for {0}", Id); + return; + } aPollRequest reqinfo = new aPollRequest(); reqinfo.thepoll = this; @@ -363,13 +298,7 @@ namespace OpenSim.Region.ClientStack.Linden requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); lock (responses) - { - if (responses.ContainsKey(requestID)) - m_log.WarnFormat("[FETCH INVENTORY DESCENDENTS2 MODULE]: Caught in the act of loosing responses! Please report this on mantis #7054"); responses[requestID] = response; - } - - WebFetchInvDescModule.ProcessedRequestsCount++; } } @@ -393,7 +322,7 @@ namespace OpenSim.Region.ClientStack.Linden capUrl = "/CAPS/" + UUID.Random() + "/"; // Register this as a poll service - PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(this, capUrl, agentID); + PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, capUrl, agentID); args.Type = PollServiceEventArgs.EventType.Inventory; caps.RegisterPollHandler(capName, args); @@ -402,7 +331,7 @@ namespace OpenSim.Region.ClientStack.Linden else { capUrl = url; - IExternalCapsModule handler = Scene.RequestModuleInterface(); + IExternalCapsModule handler = m_scene.RequestModuleInterface(); if (handler != null) handler.RegisterExternalUserCapsHandler(agentID,caps,capName,capUrl); else @@ -431,26 +360,10 @@ namespace OpenSim.Region.ClientStack.Linden { Watchdog.UpdateThread(); - WaitProcessQueuedInventoryRequest(); - } - } + aPollRequest poolreq = m_queue.Dequeue(); - public void WaitProcessQueuedInventoryRequest() - { - aPollRequest poolreq = m_queue.Dequeue(); - - if (poolreq != null && poolreq.thepoll != null) - { - try - { + if (poolreq != null && poolreq.thepoll != null) poolreq.thepoll.Process(poolreq); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[INVENTORY]: Failed to process queued inventory request {0} for {1} in {2}. Exception {3}", - poolreq.reqID, poolreq.presence != null ? poolreq.presence.Name : "unknown", Scene.Name, e); - } } } }