From 74a2bd237aed26b49d88045fe6afa526ed19c00d Mon Sep 17 00:00:00 2001 From: Mike Mazur Date: Mon, 16 Feb 2009 02:26:27 +0000 Subject: Add OpenSim & Simple inventory storage plugins and Null metrics plugin. --- .../AssetInventoryServer/AssetInventoryServer.cs | 7 +- .../Extensions/OpenSimMySQLInventory.cs | 804 -------------------- .../Extensions/SimpleInventory.cs | 602 --------------- OpenSim/Grid/AssetInventoryServer/Interfaces.cs | 2 +- .../AssetInventoryServer/Plugins/NullMetrics.cs | 150 ---- .../Plugins/NullMetricsPlugin.cs | 150 ++++ .../OpenSim/OpenSimInventoryStoragePlugin.cs | 835 +++++++++++++++++++++ .../AssetInventoryServerOpenSimPlugins.addin.xml | 3 + .../AssetInventoryServerPlugins.addin.xml | 2 +- .../AssetInventoryServerSimplePlugins.addin.xml | 3 + .../Plugins/Simple/SimpleInventoryStoragePlugin.cs | 627 ++++++++++++++++ bin/OpenSim.Grid.AssetInventoryServer.addin.xml | 2 +- prebuild.xml | 1 + 13 files changed, 1626 insertions(+), 1562 deletions(-) delete mode 100644 OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLInventory.cs delete mode 100644 OpenSim/Grid/AssetInventoryServer/Extensions/SimpleInventory.cs delete mode 100644 OpenSim/Grid/AssetInventoryServer/Plugins/NullMetrics.cs create mode 100644 OpenSim/Grid/AssetInventoryServer/Plugins/NullMetricsPlugin.cs create mode 100644 OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimInventoryStoragePlugin.cs create mode 100644 OpenSim/Grid/AssetInventoryServer/Plugins/Simple/SimpleInventoryStoragePlugin.cs diff --git a/OpenSim/Grid/AssetInventoryServer/AssetInventoryServer.cs b/OpenSim/Grid/AssetInventoryServer/AssetInventoryServer.cs index e51f559..e100377 100644 --- a/OpenSim/Grid/AssetInventoryServer/AssetInventoryServer.cs +++ b/OpenSim/Grid/AssetInventoryServer/AssetInventoryServer.cs @@ -50,7 +50,7 @@ namespace OpenSim.Grid.AssetInventoryServer public IniConfigSource ConfigFile; public IAssetStorageProvider StorageProvider; - public IInventoryProvider InventoryProvider; + public IInventoryStorageProvider InventoryProvider; public IAuthenticationProvider AuthenticationProvider; public IAuthorizationProvider AuthorizationProvider; public IMetricsProvider MetricsProvider; @@ -107,7 +107,8 @@ namespace OpenSim.Grid.AssetInventoryServer } StorageProvider = LoadAssetInventoryServerPlugin("/OpenSim/AssetInventoryServer/StorageProvider", "OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll") as IAssetStorageProvider; - MetricsProvider = LoadAssetInventoryServerPlugin("/OpenSim/AssetInventoryServer/MetricsProvider", "") as IMetricsProvider; + InventoryProvider = LoadAssetInventoryServerPlugin("/OpenSim/AssetInventoryServer/InventoryProvider", "OpenSim.Grid.AssetInventoryServer.Plugins.Simple.dll") as IInventoryStorageProvider; + MetricsProvider = LoadAssetInventoryServerPlugin("/OpenSim/AssetInventoryServer/MetricsProvider", String.Empty) as IMetricsProvider; try { @@ -120,7 +121,7 @@ namespace OpenSim.Grid.AssetInventoryServer return false; } - frontend = LoadAssetInventoryServerPlugin("/OpenSim/AssetInventoryServer/Frontend", ""); + frontend = LoadAssetInventoryServerPlugin("/OpenSim/AssetInventoryServer/Frontend", String.Empty); return true; } diff --git a/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLInventory.cs b/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLInventory.cs deleted file mode 100644 index 07bf92f..0000000 --- a/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLInventory.cs +++ /dev/null @@ -1,804 +0,0 @@ -/* - * Copyright (c) 2008 Intel Corporation - * All rights reserved. - * 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 Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``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 INTEL OR ITS - * 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.Net; -using System.Data; -using MySql.Data.MySqlClient; -using ExtensionLoader; -using ExtensionLoader.Config; -using OpenMetaverse; -using OpenMetaverse.StructuredData; - -namespace OpenSim.Grid.AssetInventoryServer.Extensions -{ - public class OpenSimMySQLInventory : IExtension, IInventoryProvider - { - const string EXTENSION_NAME = "OpenSimMySQLInventory"; // Used in metrics reporting - - AssetInventoryServer server; - - public OpenSimMySQLInventory() - { - } - - #region Required Interfaces - - public void Start(AssetInventoryServer server) - { - this.server = server; - - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - try - { - dbConnection.Open(); - Logger.Log.Info("Connected to MySQL inventory backend: " + dbConnection.ServerVersion); - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL inventory backend failed: " + ex.Message); - } - } - } - - public void Stop() - { - } - - public BackendResponse TryFetchItem(Uri owner, UUID itemID, out InventoryItem item) - { - item = null; - BackendResponse ret; - - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - IDataReader reader; - - try - { - dbConnection.Open(); - - IDbCommand command = dbConnection.CreateCommand(); - command.CommandText = String.Format("SELECT assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," + - "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," + - "creationDate,groupID,groupOwned,flags,avatarID,parentFolderID,inventoryGroupPermissions FROM inventoryitems WHERE inventoryID='{0}'", - itemID.ToString()); - reader = command.ExecuteReader(); - - if (reader.Read()) - { - item = new InventoryItem(); - item.ID = itemID; - item.AssetID = UUID.Parse(reader.GetString(0)); - item.AssetType = reader.GetInt32(1); - item.Name = reader.GetString(2); - item.Description = reader.GetString(3); - item.NextPermissions = (uint)reader.GetInt32(4); - item.CurrentPermissions = (uint)reader.GetInt32(5); - item.InvType = reader.GetInt32(6); - item.Creator = UUID.Parse(reader.GetString(7)); - item.BasePermissions = (uint)reader.GetInt32(8); - item.EveryOnePermissions = (uint)reader.GetInt32(9); - item.SalePrice = reader.GetInt32(10); - item.SaleType = reader.GetByte(11); - item.CreationDate = reader.GetInt32(12); - item.GroupID = UUID.Parse(reader.GetString(13)); - item.GroupOwned = reader.GetBoolean(14); - item.Flags = (uint)reader.GetInt32(15); - item.Owner = UUID.Parse(reader.GetString(16)); - item.Folder = UUID.Parse(reader.GetString(17)); - item.GroupPermissions = (uint)reader.GetInt32(18); - - ret = BackendResponse.Success; - } - else - { - ret = BackendResponse.NotFound; - } - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); - ret = BackendResponse.Failure; - } - } - - server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now); - return ret; - } - - public BackendResponse TryFetchFolder(Uri owner, UUID folderID, out InventoryFolder folder) - { - folder = null; - BackendResponse ret; - - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - IDataReader reader; - - try - { - dbConnection.Open(); - - IDbCommand command = dbConnection.CreateCommand(); - command.CommandText = String.Format("SELECT folderName,type,version,agentID,parentFolderID FROM inventoryfolders WHERE folderID='{0}'", - folderID.ToString()); - reader = command.ExecuteReader(); - - if (reader.Read()) - { - folder = new InventoryFolder(); - folder.Children = null; // This call only returns data for the folder itself, no children data - folder.ID = folderID; - folder.Name = reader.GetString(0); - folder.Type = reader.GetInt16(1); - folder.Version = (ushort)reader.GetInt16(2); - folder.Owner = UUID.Parse(reader.GetString(3)); - folder.ParentID = UUID.Parse(reader.GetString(4)); - - ret = BackendResponse.Success; - } - else - { - ret = BackendResponse.NotFound; - } - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); - ret = BackendResponse.Failure; - } - } - - server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now); - return ret; - } - - public BackendResponse TryFetchFolderContents(Uri owner, UUID folderID, out InventoryCollection contents) - { - contents = null; - BackendResponse ret; - - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - IDataReader reader; - - try - { - dbConnection.Open(); - - contents = new InventoryCollection(); - - #region Folder retrieval - - IDbCommand command = dbConnection.CreateCommand(); - command.CommandText = String.Format("SELECT folderName,type,version,agentID,folderID FROM inventoryfolders WHERE parentFolderID='{0}'", - folderID.ToString()); - reader = command.ExecuteReader(); - - contents.Folders = new Dictionary(); - - while (reader.Read()) - { - InventoryFolder folder = new InventoryFolder(); - folder.ParentID = folderID; - folder.Children = null; // This call doesn't do recursion - folder.Name = reader.GetString(0); - folder.Type = reader.GetInt16(1); - folder.Version = (ushort)reader.GetInt16(2); - folder.Owner = UUID.Parse(reader.GetString(3)); - folder.ID = UUID.Parse(reader.GetString(4)); - - contents.Folders.Add(folder.ID, folder); - contents.UserID = folder.Owner; - } - - reader.Close(); - - #endregion Folder retrieval - - #region Item retrieval - - command = dbConnection.CreateCommand(); - command.CommandText = String.Format("SELECT assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," + - "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," + - "creationDate,groupID,groupOwned,flags,avatarID,inventoryID,inventoryGroupPermissions FROM inventoryitems WHERE parentFolderID='{0}'", - folderID.ToString()); - reader = command.ExecuteReader(); - - contents.Items = new Dictionary(); - - while (reader.Read()) - { - InventoryItem item = new InventoryItem(); - item.Folder = folderID; - item.AssetID = UUID.Parse(reader.GetString(0)); - item.AssetType = reader.GetInt32(1); - item.Name = reader.GetString(2); - item.Description = reader.GetString(3); - item.NextPermissions = (uint)reader.GetInt32(4); - item.CurrentPermissions = (uint)reader.GetInt32(5); - item.InvType = reader.GetInt32(6); - item.Creator = UUID.Parse(reader.GetString(7)); - item.BasePermissions = (uint)reader.GetInt32(8); - item.EveryOnePermissions = (uint)reader.GetInt32(9); - item.SalePrice = reader.GetInt32(10); - item.SaleType = reader.GetByte(11); - item.CreationDate = reader.GetInt32(12); - item.GroupID = UUID.Parse(reader.GetString(13)); - item.GroupOwned = reader.GetBoolean(14); - item.Flags = (uint)reader.GetInt32(15); - item.Owner = UUID.Parse(reader.GetString(16)); - item.ID = UUID.Parse(reader.GetString(17)); - item.GroupPermissions = (uint)reader.GetInt32(18); - - contents.Items.Add(item.ID, item); - contents.UserID = item.Owner; - } - - #endregion Item retrieval - - ret = BackendResponse.Success; - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); - ret = BackendResponse.Failure; - } - } - - server.MetricsProvider.LogInventoryFetchFolderContents(EXTENSION_NAME, ret, owner, folderID, DateTime.Now); - return ret; - } - - public BackendResponse TryFetchFolderList(Uri owner, out List folders) - { - folders = null; - BackendResponse ret; - UUID ownerID; - - if (Utils.TryGetOpenSimUUID(owner, out ownerID)) - { - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - IDataReader reader; - - try - { - dbConnection.Open(); - folders = new List(); - - IDbCommand command = dbConnection.CreateCommand(); - command.CommandText = String.Format("SELECT folderName,type,version,folderID,parentFolderID FROM inventoryfolders WHERE agentID='{0}'", - ownerID.ToString()); - reader = command.ExecuteReader(); - - while (reader.Read()) - { - InventoryFolder folder = new InventoryFolder(); - folder.Owner = ownerID; - folder.Children = null; // This call does not create a folder hierarchy - folder.Name = reader.GetString(0); - folder.Type = reader.GetInt16(1); - folder.Version = (ushort)reader.GetInt16(2); - folder.ID = UUID.Parse(reader.GetString(3)); - folder.ParentID = UUID.Parse(reader.GetString(4)); - - folders.Add(folder); - } - - ret = BackendResponse.Success; - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); - ret = BackendResponse.Failure; - } - } - } - else - { - ret = BackendResponse.NotFound; - } - - server.MetricsProvider.LogInventoryFetchFolderList(EXTENSION_NAME, ret, owner, DateTime.Now); - return ret; - } - - public BackendResponse TryFetchInventory(Uri owner, out InventoryCollection inventory) - { - inventory = null; - BackendResponse ret; - List folders; - UUID ownerID; - - ret = TryFetchFolderList(owner, out folders); - - if (ret == BackendResponse.Success) - { - // Add the retrieved folders to the inventory collection - inventory = new InventoryCollection(); - inventory.Folders = new Dictionary(folders.Count); - foreach (InventoryFolder folder in folders) - inventory.Folders[folder.ID] = folder; - - // Fetch inventory items - if (Utils.TryGetOpenSimUUID(owner, out ownerID)) - { - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - IDataReader reader; - - try - { - dbConnection.Open(); - - IDbCommand command = dbConnection.CreateCommand(); - command.CommandText = String.Format("SELECT assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," + - "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," + - "creationDate,groupID,groupOwned,flags,inventoryID,parentFolderID,inventoryGroupPermissions FROM inventoryitems WHERE " + - "avatarID='{0}'", ownerID.ToString()); - reader = command.ExecuteReader(); - - inventory.UserID = ownerID; - inventory.Items = new Dictionary(); - - while (reader.Read()) - { - InventoryItem item = new InventoryItem(); - item.Owner = ownerID; - item.AssetID = UUID.Parse(reader.GetString(0)); - item.AssetType = reader.GetInt32(1); - item.Name = reader.GetString(2); - item.Description = reader.GetString(3); - item.NextPermissions = (uint)reader.GetInt32(4); - item.CurrentPermissions = (uint)reader.GetInt32(5); - item.InvType = reader.GetInt32(6); - item.Creator = UUID.Parse(reader.GetString(7)); - item.BasePermissions = (uint)reader.GetInt32(8); - item.EveryOnePermissions = (uint)reader.GetInt32(9); - item.SalePrice = reader.GetInt32(10); - item.SaleType = reader.GetByte(11); - item.CreationDate = reader.GetInt32(12); - item.GroupID = UUID.Parse(reader.GetString(13)); - item.GroupOwned = reader.GetBoolean(14); - item.Flags = (uint)reader.GetInt32(15); - item.ID = UUID.Parse(reader.GetString(16)); - item.Folder = UUID.Parse(reader.GetString(17)); - item.GroupPermissions = (uint)reader.GetInt32(18); - - inventory.Items.Add(item.ID, item); - } - - ret = BackendResponse.Success; - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); - ret = BackendResponse.Failure; - } - } - } - else - { - ret = BackendResponse.NotFound; - } - } - - server.MetricsProvider.LogInventoryFetchInventory(EXTENSION_NAME, ret, owner, DateTime.Now); - return ret; - } - - public BackendResponse TryFetchActiveGestures(Uri owner, out List gestures) - { - gestures = null; - BackendResponse ret; - UUID ownerID; - - if (Utils.TryGetOpenSimUUID(owner, out ownerID)) - { - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - IDataReader reader; - - try - { - dbConnection.Open(); - - MySqlCommand command = new MySqlCommand("SELECT assetID,inventoryName,inventoryDescription,inventoryNextPermissions," + - "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," + - "creationDate,groupID,groupOwned,inventoryID,parentFolderID,inventoryGroupPermissions FROM inventoryitems WHERE " + - "avatarId=?uuid AND assetType=?type AND flags=1", dbConnection); - command.Parameters.AddWithValue("?uuid", ownerID.ToString()); - command.Parameters.AddWithValue("?type", (int)AssetType.Gesture); - reader = command.ExecuteReader(); - - while (reader.Read()) - { - InventoryItem item = new InventoryItem(); - item.Owner = ownerID; - item.AssetType = (int)AssetType.Gesture; - item.Flags = (uint)1; - item.AssetID = UUID.Parse(reader.GetString(0)); - item.Name = reader.GetString(1); - item.Description = reader.GetString(2); - item.NextPermissions = (uint)reader.GetInt32(3); - item.CurrentPermissions = (uint)reader.GetInt32(4); - item.InvType = reader.GetInt32(5); - item.Creator = UUID.Parse(reader.GetString(6)); - item.BasePermissions = (uint)reader.GetInt32(7); - item.EveryOnePermissions = (uint)reader.GetInt32(8); - item.SalePrice = reader.GetInt32(9); - item.SaleType = reader.GetByte(10); - item.CreationDate = reader.GetInt32(11); - item.GroupID = UUID.Parse(reader.GetString(12)); - item.GroupOwned = reader.GetBoolean(13); - item.ID = UUID.Parse(reader.GetString(14)); - item.Folder = UUID.Parse(reader.GetString(15)); - item.GroupPermissions = (uint)reader.GetInt32(16); - - gestures.Add(item); - } - - ret = BackendResponse.Success; - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); - ret = BackendResponse.Failure; - } - } - } - else - { - ret = BackendResponse.NotFound; - } - - server.MetricsProvider.LogInventoryFetchActiveGestures(EXTENSION_NAME, ret, owner, DateTime.Now); - return ret; - } - - public BackendResponse TryCreateItem(Uri owner, InventoryItem item) - { - BackendResponse ret; - - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - try - { - dbConnection.Open(); - - MySqlCommand command = new MySqlCommand( - "REPLACE INTO inventoryitems (assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," + - "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," + - "creationDate,groupID,groupOwned,flags,inventoryID,avatarID,parentFolderID,inventoryGroupPermissions) VALUES " + - - "(?assetID,?assetType,?inventoryName,?inventoryDescription,?inventoryNextPermissions,?inventoryCurrentPermissions,?invType," + - "?creatorID,?inventoryBasePermissions,?inventoryEveryOnePermissions,?salePrice,?saleType,?creationDate,?groupID,?groupOwned," + - "?flags,?inventoryID,?avatarID,?parentFolderID,?inventoryGroupPermissions)", dbConnection); - - command.Parameters.AddWithValue("?assetID", item.AssetID.ToString()); - command.Parameters.AddWithValue("?assetType", item.AssetType); - command.Parameters.AddWithValue("?inventoryName", item.Name); - command.Parameters.AddWithValue("?inventoryDescription", item.Description); - command.Parameters.AddWithValue("?inventoryNextPermissions", item.NextPermissions); - command.Parameters.AddWithValue("?inventoryCurrentPermissions", item.CurrentPermissions); - command.Parameters.AddWithValue("?invType", item.InvType); - command.Parameters.AddWithValue("?creatorID", item.Creator.ToString()); - command.Parameters.AddWithValue("?inventoryBasePermissions", item.BasePermissions); - command.Parameters.AddWithValue("?inventoryEveryOnePermissions", item.EveryOnePermissions); - command.Parameters.AddWithValue("?salePrice", item.SalePrice); - command.Parameters.AddWithValue("?saleType", item.SaleType); - command.Parameters.AddWithValue("?creationDate", item.CreationDate); - command.Parameters.AddWithValue("?groupID", item.GroupID.ToString()); - command.Parameters.AddWithValue("?groupOwned", item.GroupOwned); - command.Parameters.AddWithValue("?flags", item.Flags); - command.Parameters.AddWithValue("?inventoryID", item.ID); - command.Parameters.AddWithValue("?avatarID", item.Owner); - command.Parameters.AddWithValue("?parentFolderID", item.Folder); - command.Parameters.AddWithValue("?inventoryGroupPermissions", item.GroupPermissions); - - int rowsAffected = command.ExecuteNonQuery(); - if (rowsAffected == 1) - { - ret = BackendResponse.Success; - } - else if (rowsAffected == 2) - { - Logger.Log.Info("Replaced inventory item " + item.ID.ToString()); - ret = BackendResponse.Success; - } - else - { - Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected); - ret = BackendResponse.Failure; - } - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); - ret = BackendResponse.Failure; - } - } - - server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, false, DateTime.Now); - return ret; - } - - public BackendResponse TryCreateFolder(Uri owner, InventoryFolder folder) - { - BackendResponse ret; - - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - try - { - dbConnection.Open(); - - MySqlCommand command = new MySqlCommand( - "REPLACE INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) VALUES " + - "(?folderName,?type,?version,?folderID,?agentID,?parentFolderID)", dbConnection); - - command.Parameters.AddWithValue("?folderName", folder.Name); - command.Parameters.AddWithValue("?type", folder.Type); - command.Parameters.AddWithValue("?version", folder.Version); - command.Parameters.AddWithValue("?folderID", folder.ID); - command.Parameters.AddWithValue("?agentID", folder.Owner); - command.Parameters.AddWithValue("?parentFolderID", folder.ParentID); - - int rowsAffected = command.ExecuteNonQuery(); - if (rowsAffected == 1) - { - ret = BackendResponse.Success; - } - else if (rowsAffected == 2) - { - Logger.Log.Info("Replaced inventory folder " + folder.ID.ToString()); - ret = BackendResponse.Success; - } - else - { - Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected); - ret = BackendResponse.Failure; - } - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); - ret = BackendResponse.Failure; - } - } - - server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, true, DateTime.Now); - return ret; - } - - public BackendResponse TryCreateInventory(Uri owner, InventoryFolder rootFolder) - { - return TryCreateFolder(owner, rootFolder); - } - - public BackendResponse TryDeleteItem(Uri owner, UUID itemID) - { - BackendResponse ret; - UUID ownerID; - - if (Utils.TryGetOpenSimUUID(owner, out ownerID)) - { - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - try - { - dbConnection.Open(); - - MySqlCommand command = new MySqlCommand( - "DELETE FROM inventoryitems WHERE inventoryID=?inventoryID AND avatarID=?avatarID", dbConnection); - - command.Parameters.AddWithValue("?inventoryID", itemID.ToString()); - command.Parameters.AddWithValue("?avatarID", ownerID.ToString()); - - int rowsAffected = command.ExecuteNonQuery(); - if (rowsAffected == 1) - { - ret = BackendResponse.Success; - } - else - { - Logger.Log.ErrorFormat("MySQL DELETE query affected {0} rows", rowsAffected); - ret = BackendResponse.NotFound; - } - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); - ret = BackendResponse.Failure; - } - } - } - else - { - ret = BackendResponse.NotFound; - } - - server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now); - return ret; - } - - public BackendResponse TryDeleteFolder(Uri owner, UUID folderID) - { - BackendResponse ret; - UUID ownerID; - - if (Utils.TryGetOpenSimUUID(owner, out ownerID)) - { - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - try - { - dbConnection.Open(); - - MySqlCommand command = new MySqlCommand( - "DELETE FROM inventoryfolders WHERE folderID=?folderID AND agentID=?agentID", dbConnection); - - command.Parameters.AddWithValue("?folderID", folderID.ToString()); - command.Parameters.AddWithValue("?agentID", ownerID.ToString()); - - int rowsAffected = command.ExecuteNonQuery(); - if (rowsAffected == 1) - { - ret = BackendResponse.Success; - } - else - { - Logger.Log.ErrorFormat("MySQL DELETE query affected {0} rows", rowsAffected); - ret = BackendResponse.NotFound; - } - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); - ret = BackendResponse.Failure; - } - } - } - else - { - ret = BackendResponse.NotFound; - } - - server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now); - return ret; - } - - public BackendResponse TryPurgeFolder(Uri owner, UUID folderID) - { - BackendResponse ret; - UUID ownerID; - - if (Utils.TryGetOpenSimUUID(owner, out ownerID)) - { - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - try - { - dbConnection.Open(); - - #region Delete items - - MySqlCommand command = new MySqlCommand( - "DELETE FROM inventoryitems WHERE parentFolderID=?parentFolderID AND avatarID=?avatarID", dbConnection); - - command.Parameters.AddWithValue("?parentFolderID", folderID.ToString()); - command.Parameters.AddWithValue("?avatarID", ownerID.ToString()); - - int rowsAffected = command.ExecuteNonQuery(); - - #endregion Delete items - - #region Delete folders - - command = new MySqlCommand( - "DELETE FROM inventoryfolders WHERE parentFolderID=?parentFolderID AND agentID=?agentID", dbConnection); - - command.Parameters.AddWithValue("?parentFolderID", folderID.ToString()); - command.Parameters.AddWithValue("?agentID", ownerID.ToString()); - - rowsAffected += command.ExecuteNonQuery(); - - #endregion Delete folders - - Logger.Log.DebugFormat("Deleted {0} inventory objects from MySQL in a folder purge", rowsAffected); - - ret = BackendResponse.Success; - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); - ret = BackendResponse.Failure; - } - } - } - else - { - ret = BackendResponse.NotFound; - } - - server.MetricsProvider.LogInventoryPurgeFolder(EXTENSION_NAME, ret, owner, folderID, DateTime.Now); - return ret; - } - - public int ForEach(Action action, int start, int count) - { - int rowCount = 0; - - using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) - { - MySqlDataReader reader; - - try - { - dbConnection.Open(); - - MySqlCommand command = dbConnection.CreateCommand(); - command.CommandText = String.Format("SELECT name,description,assetType,temporary,data,id FROM assets LIMIT {0}, {1}", - start, count); - reader = command.ExecuteReader(); - } - catch (MySqlException ex) - { - Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); - return 0; - } - - while (reader.Read()) - { - Metadata metadata = new Metadata(); - metadata.CreationDate = OpenMetaverse.Utils.Epoch; - metadata.Description = reader.GetString(1); - metadata.ID = UUID.Parse(reader.GetString(5)); - metadata.Name = reader.GetString(0); - metadata.SHA1 = OpenMetaverse.Utils.SHA1((byte[])reader.GetValue(4)); - metadata.Temporary = reader.GetBoolean(3); - metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2)); - - action(metadata); - ++rowCount; - } - - reader.Close(); - } - - return rowCount; - } - - #endregion Required Interfaces - } -} diff --git a/OpenSim/Grid/AssetInventoryServer/Extensions/SimpleInventory.cs b/OpenSim/Grid/AssetInventoryServer/Extensions/SimpleInventory.cs deleted file mode 100644 index c140965..0000000 --- a/OpenSim/Grid/AssetInventoryServer/Extensions/SimpleInventory.cs +++ /dev/null @@ -1,602 +0,0 @@ -/* - * Copyright (c) 2008 Intel Corporation - * All rights reserved. - * 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 Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``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 INTEL OR ITS - * 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.Net; -using System.IO; -using System.Text; -using ExtensionLoader; -using OpenMetaverse; -using OpenMetaverse.StructuredData; - -namespace OpenSim.Grid.AssetInventoryServer.Extensions -{ - public class SimpleInventory : IExtension, IInventoryProvider - { - const string EXTENSION_NAME = "SimpleInventory"; // Used for metrics reporting - const string DEFAULT_INVENTORY_DIR = "SimpleInventory"; - - AssetInventoryServer server; - Dictionary inventories = new Dictionary(); - Dictionary> activeGestures = new Dictionary>(); - Utils.InventoryItemSerializer itemSerializer = new Utils.InventoryItemSerializer(); - Utils.InventoryFolderSerializer folderSerializer = new Utils.InventoryFolderSerializer(); - - public SimpleInventory() - { - } - - #region Required Interfaces - - public void Start(AssetInventoryServer server) - { - this.server = server; - - LoadFiles(DEFAULT_INVENTORY_DIR); - - Logger.Log.InfoFormat("Initialized the inventory index with data for {0} avatars", - inventories.Count); - } - - public void Stop() - { - } - - public BackendResponse TryFetchItem(Uri owner, UUID itemID, out InventoryItem item) - { - item = null; - BackendResponse ret; - - InventoryCollection collection; - if (inventories.TryGetValue(owner, out collection) && collection.Items.TryGetValue(itemID, out item)) - ret = BackendResponse.Success; - else - ret = BackendResponse.NotFound; - - server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now); - return ret; - } - - public BackendResponse TryFetchFolder(Uri owner, UUID folderID, out InventoryFolder folder) - { - folder = null; - BackendResponse ret; - - InventoryCollection collection; - if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder)) - ret = BackendResponse.Success; - else - ret = BackendResponse.NotFound; - - server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now); - return ret; - } - - public BackendResponse TryFetchFolderContents(Uri owner, UUID folderID, out InventoryCollection contents) - { - contents = null; - BackendResponse ret; - - InventoryCollection collection; - InventoryFolder folder; - - if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder)) - { - contents = new InventoryCollection(); - contents.UserID = collection.UserID; - contents.Folders = new Dictionary(); - contents.Items = new Dictionary(); - - foreach (InventoryBase invBase in folder.Children.Values) - { - if (invBase is InventoryItem) - { - InventoryItem invItem = invBase as InventoryItem; - contents.Items.Add(invItem.ID, invItem); - } - else - { - InventoryFolder invFolder = invBase as InventoryFolder; - contents.Folders.Add(invFolder.ID, invFolder); - } - } - - ret = BackendResponse.Success; - } - else - { - ret = BackendResponse.NotFound; - } - - server.MetricsProvider.LogInventoryFetchFolderContents(EXTENSION_NAME, ret, owner, folderID, DateTime.Now); - return ret; - } - - public BackendResponse TryFetchFolderList(Uri owner, out List folders) - { - folders = null; - BackendResponse ret; - - InventoryCollection collection; - if (inventories.TryGetValue(owner, out collection)) - { - folders = new List(collection.Folders.Values); - return BackendResponse.Success; - } - else - { - ret = BackendResponse.NotFound; - } - - server.MetricsProvider.LogInventoryFetchFolderList(EXTENSION_NAME, ret, owner, DateTime.Now); - return ret; - } - - public BackendResponse TryFetchInventory(Uri owner, out InventoryCollection inventory) - { - inventory = null; - BackendResponse ret; - - if (inventories.TryGetValue(owner, out inventory)) - ret = BackendResponse.Success; - else - ret = BackendResponse.NotFound; - - server.MetricsProvider.LogInventoryFetchInventory(EXTENSION_NAME, ret, owner, DateTime.Now); - return ret; - } - - public BackendResponse TryFetchActiveGestures(Uri owner, out List gestures) - { - gestures = null; - BackendResponse ret; - - if (activeGestures.TryGetValue(owner, out gestures)) - ret = BackendResponse.Success; - else - ret = BackendResponse.NotFound; - - server.MetricsProvider.LogInventoryFetchActiveGestures(EXTENSION_NAME, ret, owner, DateTime.Now); - return ret; - } - - public BackendResponse TryCreateItem(Uri owner, InventoryItem item) - { - BackendResponse ret; - - InventoryCollection collection; - if (inventories.TryGetValue(owner, out collection)) - { - // Delete this item first if it already exists - InventoryItem oldItem; - if (collection.Items.TryGetValue(item.ID, out oldItem)) - TryDeleteItem(owner, item.ID); - - try - { - // Create the file - SaveItem(item); - - // Add the item to the collection - lock (collection) collection.Items[item.ID] = item; - - // Add the item to its parent folder - InventoryFolder parent; - if (collection.Folders.TryGetValue(item.Folder, out parent)) - lock (parent.Children) parent.Children.Add(item.ID, item); - - // Add active gestures to our list - if (item.InvType == (int)InventoryType.Gesture && item.Flags == 1) - { - lock (activeGestures) - activeGestures[owner].Add(item); - } - - ret = BackendResponse.Success; - } - catch (Exception ex) - { - Logger.Log.Error(ex.Message); - ret = BackendResponse.Failure; - } - } - else - { - return BackendResponse.NotFound; - } - - server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, false, DateTime.Now); - return ret; - } - - public BackendResponse TryCreateFolder(Uri owner, InventoryFolder folder) - { - BackendResponse ret; - - InventoryCollection collection; - if (inventories.TryGetValue(owner, out collection)) - { - // Delete this folder first if it already exists - InventoryFolder oldFolder; - if (collection.Folders.TryGetValue(folder.ID, out oldFolder)) - TryDeleteFolder(owner, folder.ID); - - try - { - // Create the file - SaveFolder(folder); - - // Add the folder to the collection - lock (collection) collection.Folders[folder.ID] = folder; - - // Add the folder to its parent folder - InventoryFolder parent; - if (collection.Folders.TryGetValue(folder.ParentID, out parent)) - lock (parent.Children) parent.Children.Add(folder.ID, folder); - - ret = BackendResponse.Success; - } - catch (Exception ex) - { - Logger.Log.Error(ex.Message); - ret = BackendResponse.Failure; - } - } - else - { - ret = BackendResponse.NotFound; - } - - server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, true, DateTime.Now); - return ret; - } - - public BackendResponse TryCreateInventory(Uri owner, InventoryFolder rootFolder) - { - BackendResponse ret; - - lock (inventories) - { - if (!inventories.ContainsKey(owner)) - { - InventoryCollection collection = new InventoryCollection(); - collection.UserID = rootFolder.Owner; - collection.Folders = new Dictionary(); - collection.Folders.Add(rootFolder.ID, rootFolder); - collection.Items = new Dictionary(); - - inventories.Add(owner, collection); - - ret = BackendResponse.Success; - } - else - { - ret = BackendResponse.Failure; - } - } - - if (ret == BackendResponse.Success) - { - string path = Path.Combine(DEFAULT_INVENTORY_DIR, rootFolder.Owner.ToString()); - try - { - // Create the directory for this agent - Directory.CreateDirectory(path); - - // Create an index.txt containing the UUID and URI for this agent - string[] index = new string[] { rootFolder.Owner.ToString(), owner.ToString() }; - File.WriteAllLines(Path.Combine(path, "index.txt"), index); - - // Create the root folder file - SaveFolder(rootFolder); - } - catch (Exception ex) - { - Logger.Log.Error(ex.Message); - ret = BackendResponse.Failure; - } - } - - server.MetricsProvider.LogInventoryCreateInventory(EXTENSION_NAME, ret, DateTime.Now); - return ret; - } - - public BackendResponse TryDeleteItem(Uri owner, UUID itemID) - { - BackendResponse ret; - - InventoryCollection collection; - InventoryItem item; - if (inventories.TryGetValue(owner, out collection) && collection.Items.TryGetValue(itemID, out item)) - { - // Remove the item from its parent folder - InventoryFolder parent; - if (collection.Folders.TryGetValue(item.Folder, out parent)) - lock (parent.Children) parent.Children.Remove(itemID); - - // Remove the item from the collection - lock (collection) collection.Items.Remove(itemID); - - // Remove from the active gestures list if applicable - if (item.InvType == (int)InventoryType.Gesture) - { - lock (activeGestures) - { - for (int i = 0; i < activeGestures[owner].Count; i++) - { - if (activeGestures[owner][i].ID == itemID) - { - activeGestures[owner].RemoveAt(i); - break; - } - } - } - } - - // Delete the file. We don't know exactly what the file name is, - // so search for it - string path = PathFromURI(owner); - string[] matches = Directory.GetFiles(path, String.Format("*{0}.item", itemID), SearchOption.TopDirectoryOnly); - foreach (string match in matches) - { - try { File.Delete(match); } - catch (Exception ex) { Logger.Log.ErrorFormat("Failed to delete file {0}: {1}", match, ex.Message); } - } - - ret = BackendResponse.Success; - } - else - { - ret = BackendResponse.NotFound; - } - - server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now); - return ret; - } - - public BackendResponse TryDeleteFolder(Uri owner, UUID folderID) - { - BackendResponse ret; - - InventoryCollection collection; - InventoryFolder folder; - if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder)) - { - // Remove the folder from its parent folder - InventoryFolder parent; - if (collection.Folders.TryGetValue(folder.ParentID, out parent)) - lock (parent.Children) parent.Children.Remove(folderID); - - // Remove the folder from the collection - lock (collection) collection.Items.Remove(folderID); - - // Delete the folder file. We don't know exactly what the file name is, - // so search for it - string path = PathFromURI(owner); - string[] matches = Directory.GetFiles(path, String.Format("*{0}.folder", folderID), SearchOption.TopDirectoryOnly); - foreach (string match in matches) - { - try { File.Delete(match); } - catch (Exception ex) { Logger.Log.ErrorFormat("Failed to delete folder file {0}: {1}", match, ex.Message); } - } - - ret = BackendResponse.Success; - } - else - { - ret = BackendResponse.NotFound; - } - - server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now); - return ret; - } - - public BackendResponse TryPurgeFolder(Uri owner, UUID folderID) - { - BackendResponse ret; - - InventoryCollection collection; - InventoryFolder folder; - if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder)) - { - // Delete all of the folder children - foreach (InventoryBase obj in new List(folder.Children.Values)) - { - if (obj is InventoryItem) - { - TryDeleteItem(owner, (obj as InventoryItem).ID); - } - else - { - InventoryFolder childFolder = obj as InventoryFolder; - TryPurgeFolder(owner, childFolder.ID); - TryDeleteFolder(owner, childFolder.ID); - } - } - - ret = BackendResponse.Success; - } - else - { - ret = BackendResponse.NotFound; - } - - server.MetricsProvider.LogInventoryPurgeFolder(EXTENSION_NAME, ret, owner, folderID, DateTime.Now); - return ret; - } - - #endregion Required Interfaces - - void SaveItem(InventoryItem item) - { - string filename = String.Format("{0}-{1}.item", SanitizeFilename(item.Name), item.ID); - - string path = Path.Combine(DEFAULT_INVENTORY_DIR, item.Owner.ToString()); - path = Path.Combine(path, filename); - - using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write)) - { - itemSerializer.Serialize(stream, item); - stream.Flush(); - } - } - - void SaveFolder(InventoryFolder folder) - { - string filename = String.Format("{0}-{1}.folder", SanitizeFilename(folder.Name), folder.ID); - - string path = Path.Combine(DEFAULT_INVENTORY_DIR, folder.Owner.ToString()); - path = Path.Combine(path, filename); - - using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write)) - { - folderSerializer.Serialize(stream, folder); - stream.Flush(); - } - } - - string SanitizeFilename(string filename) - { - string output = filename; - - if (output.Length > 64) - output = output.Substring(0, 64); - - foreach (char i in Path.GetInvalidFileNameChars()) - output = output.Replace(i, '_'); - - return output; - } - - static string PathFromURI(Uri uri) - { - byte[] hash = OpenMetaverse.Utils.SHA1(Encoding.UTF8.GetBytes(uri.ToString())); - StringBuilder digest = new StringBuilder(40); - - // Convert the hash to a hex string - foreach (byte b in hash) - digest.AppendFormat(OpenMetaverse.Utils.EnUsCulture, "{0:x2}", b); - - return Path.Combine(DEFAULT_INVENTORY_DIR, digest.ToString()); - } - - void LoadFiles(string folder) - { - // Try to create the directory if it doesn't already exist - if (!Directory.Exists(folder)) - { - try { Directory.CreateDirectory(folder); } - catch (Exception ex) - { - Logger.Log.Warn(ex.Message); - return; - } - } - - try - { - string[] agentFolders = Directory.GetDirectories(DEFAULT_INVENTORY_DIR); - - for (int i = 0; i < agentFolders.Length; i++) - { - string foldername = agentFolders[i]; - string indexPath = Path.Combine(foldername, "index.txt"); - UUID ownerID = UUID.Zero; - Uri owner = null; - - try - { - string[] index = File.ReadAllLines(indexPath); - ownerID = UUID.Parse(index[0]); - owner = new Uri(index[1]); - } - catch (Exception ex) - { - Logger.Log.WarnFormat("Failed loading the index file {0}: {1}", indexPath, ex.Message); - } - - if (ownerID != UUID.Zero && owner != null) - { - // Initialize the active gestures list for this agent - activeGestures.Add(owner, new List()); - - InventoryCollection collection = new InventoryCollection(); - collection.UserID = ownerID; - - // Load all of the folders for this agent - string[] folders = Directory.GetFiles(foldername, "*.folder", SearchOption.TopDirectoryOnly); - collection.Folders = new Dictionary(folders.Length); - - for (int j = 0; j < folders.Length; j++) - { - InventoryFolder invFolder = (InventoryFolder)folderSerializer.Deserialize( - new FileStream(folders[j], FileMode.Open, FileAccess.Read)); - collection.Folders[invFolder.ID] = invFolder; - } - - // Iterate over the folders collection, adding children to their parents - foreach (InventoryFolder invFolder in collection.Folders.Values) - { - InventoryFolder parent; - if (collection.Folders.TryGetValue(invFolder.ParentID, out parent)) - parent.Children[invFolder.ID] = invFolder; - } - - // Load all of the items for this agent - string[] files = Directory.GetFiles(foldername, "*.item", SearchOption.TopDirectoryOnly); - collection.Items = new Dictionary(files.Length); - - for (int j = 0; j < files.Length; j++) - { - InventoryItem invItem = (InventoryItem)itemSerializer.Deserialize( - new FileStream(files[j], FileMode.Open, FileAccess.Read)); - collection.Items[invItem.ID] = invItem; - - // Add items to their parent folders - InventoryFolder parent; - if (collection.Folders.TryGetValue(invItem.Folder, out parent)) - parent.Children[invItem.ID] = invItem; - - // Add active gestures to our list - if (invItem.InvType == (int)InventoryType.Gesture && invItem.Flags != 0) - activeGestures[owner].Add(invItem); - } - - inventories.Add(owner, collection); - } - } - } - catch (Exception ex) - { - Logger.Log.ErrorFormat("Failed loading inventory from {0}: {1}", folder, ex.Message); - } - } - } -} diff --git a/OpenSim/Grid/AssetInventoryServer/Interfaces.cs b/OpenSim/Grid/AssetInventoryServer/Interfaces.cs index 870cf89..c4aa7ac 100644 --- a/OpenSim/Grid/AssetInventoryServer/Interfaces.cs +++ b/OpenSim/Grid/AssetInventoryServer/Interfaces.cs @@ -83,7 +83,7 @@ namespace OpenSim.Grid.AssetInventoryServer int ForEach(Action action, int start, int count); } - public interface IInventoryProvider + public interface IInventoryStorageProvider : IAssetInventoryServerPlugin { BackendResponse TryFetchItem(Uri owner, UUID itemID, out InventoryItem item); BackendResponse TryFetchFolder(Uri owner, UUID folderID, out InventoryFolder folder); diff --git a/OpenSim/Grid/AssetInventoryServer/Plugins/NullMetrics.cs b/OpenSim/Grid/AssetInventoryServer/Plugins/NullMetrics.cs deleted file mode 100644 index 86ae5cd..0000000 --- a/OpenSim/Grid/AssetInventoryServer/Plugins/NullMetrics.cs +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2008 Intel Corporation - * All rights reserved. - * 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 Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``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 INTEL OR ITS - * 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 OpenMetaverse; - -namespace OpenSim.Grid.AssetInventoryServer.Plugins -{ - public class NullMetrics : IMetricsProvider - { - AssetInventoryServer server; - - public NullMetrics() - { - } - - #region IMetricsProvider implementation - - public void LogAssetMetadataFetch(string extension, BackendResponse response, UUID assetID, DateTime time) - { - Logger.Log.DebugFormat("[{0}] AssetMetadataFetch(): AssetID: {1}, Response: {2}", extension, assetID, response); - } - - public void LogAssetDataFetch(string extension, BackendResponse response, UUID assetID, int dataSize, DateTime time) - { - Logger.Log.DebugFormat("[{0}] AssetDataFetch(): AssetID: {1}, DataSize: {2}, Response: {3}", extension, assetID, - dataSize, response); - } - - public void LogAssetCreate(string extension, BackendResponse response, UUID assetID, int dataSize, DateTime time) - { - Logger.Log.DebugFormat("[{0}] AssetCreate(): AssetID: {1}, DataSize: {2}, Response: {3}", extension, assetID, - dataSize, response); - } - - public void LogInventoryFetch(string extension, BackendResponse response, Uri owner, UUID objID, bool folder, DateTime time) - { - Logger.Log.DebugFormat("[{0}] InventoryFetch(): ObjID: {1}, Folder: {2}, OwnerID: {3}, Response: {4}", extension, - objID, folder, owner, response); - } - - public void LogInventoryFetchFolderContents(string extension, BackendResponse response, Uri owner, UUID folderID, DateTime time) - { - Logger.Log.DebugFormat("[{0}] InventoryFetchFolderContents(): FolderID: {1}, OwnerID: {2}, Response: {3}", extension, - folderID, owner, response); - } - - public void LogInventoryFetchFolderList(string extension, BackendResponse response, Uri owner, DateTime time) - { - Logger.Log.DebugFormat("[{0}] InventoryFetchFolderList(): OwnerID: {1}, Response: {2}", extension, - owner, response); - } - - public void LogInventoryFetchInventory(string extension, BackendResponse response, Uri owner, DateTime time) - { - Logger.Log.DebugFormat("[{0}] InventoryFetchInventory(): OwnerID: {1}, Response: {2}", extension, - owner, response); - } - - public void LogInventoryFetchActiveGestures(string extension, BackendResponse response, Uri owner, DateTime time) - { - Logger.Log.DebugFormat("[{0}] InventoryFetchActiveGestures(): OwnerID: {1}, Response: {2}", extension, - owner, response); - } - - public void LogInventoryCreate(string extension, BackendResponse response, Uri owner, bool folder, DateTime time) - { - Logger.Log.DebugFormat("[{0}] InventoryCreate(): OwnerID: {1}, Response: {2}", extension, - owner, response); - } - - public void LogInventoryCreateInventory(string extension, BackendResponse response, DateTime time) - { - Logger.Log.DebugFormat("[{0}] InventoryCreateInventory(): Response: {1}", extension, - response); - } - - public void LogInventoryDelete(string extension, BackendResponse response, Uri owner, UUID objID, bool folder, DateTime time) - { - Logger.Log.DebugFormat("[{0}] InventoryDelete(): OwnerID: {1}, Folder: {2}, Response: {3}", extension, - owner, folder, response); - } - - public void LogInventoryPurgeFolder(string extension, BackendResponse response, Uri owner, UUID folderID, DateTime time) - { - Logger.Log.DebugFormat("[{0}] InventoryPurgeFolder(): OwnerID: {1}, FolderID: {2}, Response: {3}", extension, - owner, response); - } - - #endregion IMetricsProvider implementation - - #region IPlugin implementation - - public void Initialise(AssetInventoryServer server) - { - this.server = server; - } - - /// - /// Initialises metrics interface - /// - public void Initialise() - { - this.server = null; - } - - public void Dispose() - { - } - - public string Version - { - // TODO: this should be something meaningful and not hardcoded? - get { return "0.1"; } - } - - public string Name - { - get { return "AssetInventoryServer Null Metrics"; } - } - - #endregion IPlugin implementation - } -} diff --git a/OpenSim/Grid/AssetInventoryServer/Plugins/NullMetricsPlugin.cs b/OpenSim/Grid/AssetInventoryServer/Plugins/NullMetricsPlugin.cs new file mode 100644 index 0000000..caa4efd --- /dev/null +++ b/OpenSim/Grid/AssetInventoryServer/Plugins/NullMetricsPlugin.cs @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2008 Intel Corporation + * All rights reserved. + * 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 Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``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 INTEL OR ITS + * 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 OpenMetaverse; + +namespace OpenSim.Grid.AssetInventoryServer.Plugins +{ + public class NullMetricsPlugin : IMetricsProvider + { + AssetInventoryServer server; + + public NullMetricsPlugin() + { + } + + #region IMetricsProvider implementation + + public void LogAssetMetadataFetch(string extension, BackendResponse response, UUID assetID, DateTime time) + { + Logger.Log.DebugFormat("[{0}] AssetMetadataFetch(): AssetID: {1}, Response: {2}", extension, assetID, response); + } + + public void LogAssetDataFetch(string extension, BackendResponse response, UUID assetID, int dataSize, DateTime time) + { + Logger.Log.DebugFormat("[{0}] AssetDataFetch(): AssetID: {1}, DataSize: {2}, Response: {3}", extension, assetID, + dataSize, response); + } + + public void LogAssetCreate(string extension, BackendResponse response, UUID assetID, int dataSize, DateTime time) + { + Logger.Log.DebugFormat("[{0}] AssetCreate(): AssetID: {1}, DataSize: {2}, Response: {3}", extension, assetID, + dataSize, response); + } + + public void LogInventoryFetch(string extension, BackendResponse response, Uri owner, UUID objID, bool folder, DateTime time) + { + Logger.Log.DebugFormat("[{0}] InventoryFetch(): ObjID: {1}, Folder: {2}, OwnerID: {3}, Response: {4}", extension, + objID, folder, owner, response); + } + + public void LogInventoryFetchFolderContents(string extension, BackendResponse response, Uri owner, UUID folderID, DateTime time) + { + Logger.Log.DebugFormat("[{0}] InventoryFetchFolderContents(): FolderID: {1}, OwnerID: {2}, Response: {3}", extension, + folderID, owner, response); + } + + public void LogInventoryFetchFolderList(string extension, BackendResponse response, Uri owner, DateTime time) + { + Logger.Log.DebugFormat("[{0}] InventoryFetchFolderList(): OwnerID: {1}, Response: {2}", extension, + owner, response); + } + + public void LogInventoryFetchInventory(string extension, BackendResponse response, Uri owner, DateTime time) + { + Logger.Log.DebugFormat("[{0}] InventoryFetchInventory(): OwnerID: {1}, Response: {2}", extension, + owner, response); + } + + public void LogInventoryFetchActiveGestures(string extension, BackendResponse response, Uri owner, DateTime time) + { + Logger.Log.DebugFormat("[{0}] InventoryFetchActiveGestures(): OwnerID: {1}, Response: {2}", extension, + owner, response); + } + + public void LogInventoryCreate(string extension, BackendResponse response, Uri owner, bool folder, DateTime time) + { + Logger.Log.DebugFormat("[{0}] InventoryCreate(): OwnerID: {1}, Response: {2}", extension, + owner, response); + } + + public void LogInventoryCreateInventory(string extension, BackendResponse response, DateTime time) + { + Logger.Log.DebugFormat("[{0}] InventoryCreateInventory(): Response: {1}", extension, + response); + } + + public void LogInventoryDelete(string extension, BackendResponse response, Uri owner, UUID objID, bool folder, DateTime time) + { + Logger.Log.DebugFormat("[{0}] InventoryDelete(): OwnerID: {1}, Folder: {2}, Response: {3}", extension, + owner, folder, response); + } + + public void LogInventoryPurgeFolder(string extension, BackendResponse response, Uri owner, UUID folderID, DateTime time) + { + Logger.Log.DebugFormat("[{0}] InventoryPurgeFolder(): OwnerID: {1}, FolderID: {2}, Response: {3}", extension, + owner, response); + } + + #endregion IMetricsProvider implementation + + #region IPlugin implementation + + public void Initialise(AssetInventoryServer server) + { + this.server = server; + } + + /// + /// Initialises metrics interface + /// + public void Initialise() + { + this.server = null; + } + + public void Dispose() + { + } + + public string Version + { + // TODO: this should be something meaningful and not hardcoded? + get { return "0.1"; } + } + + public string Name + { + get { return "AssetInventoryServer Null Metrics"; } + } + + #endregion IPlugin implementation + } +} diff --git a/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimInventoryStoragePlugin.cs b/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimInventoryStoragePlugin.cs new file mode 100644 index 0000000..3fd06c0 --- /dev/null +++ b/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimInventoryStoragePlugin.cs @@ -0,0 +1,835 @@ +/* + * Copyright (c) 2008 Intel Corporation + * All rights reserved. + * 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 Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``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 INTEL OR ITS + * 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.Net; +using System.Data; +using MySql.Data.MySqlClient; +using ExtensionLoader; +using ExtensionLoader.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Grid.AssetInventoryServer.Extensions; +using OpenSim.Data; + +namespace OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim +{ + public class OpenSimInventoryStoragePlugin : IInventoryStorageProvider + { + const string EXTENSION_NAME = "OpenSimInventoryStorage"; // Used in metrics reporting + + private AssetInventoryServer server; + private IInventoryDataPlugin m_inventoryProvider; + + public OpenSimInventoryStoragePlugin() + { + } + + #region Required Interfaces + + public BackendResponse TryFetchItem(Uri owner, UUID itemID, out InventoryItem item) + { + item = null; + BackendResponse ret; + + using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) + { + IDataReader reader; + + try + { + dbConnection.Open(); + + IDbCommand command = dbConnection.CreateCommand(); + command.CommandText = String.Format("SELECT assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," + + "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," + + "creationDate,groupID,groupOwned,flags,avatarID,parentFolderID,inventoryGroupPermissions FROM inventoryitems WHERE inventoryID='{0}'", + itemID.ToString()); + reader = command.ExecuteReader(); + + if (reader.Read()) + { + item = new InventoryItem(); + item.ID = itemID; + item.AssetID = UUID.Parse(reader.GetString(0)); + item.AssetType = reader.GetInt32(1); + item.Name = reader.GetString(2); + item.Description = reader.GetString(3); + item.NextPermissions = (uint)reader.GetInt32(4); + item.CurrentPermissions = (uint)reader.GetInt32(5); + item.InvType = reader.GetInt32(6); + item.Creator = UUID.Parse(reader.GetString(7)); + item.BasePermissions = (uint)reader.GetInt32(8); + item.EveryOnePermissions = (uint)reader.GetInt32(9); + item.SalePrice = reader.GetInt32(10); + item.SaleType = reader.GetByte(11); + item.CreationDate = reader.GetInt32(12); + item.GroupID = UUID.Parse(reader.GetString(13)); + item.GroupOwned = reader.GetBoolean(14); + item.Flags = (uint)reader.GetInt32(15); + item.Owner = UUID.Parse(reader.GetString(16)); + item.Folder = UUID.Parse(reader.GetString(17)); + item.GroupPermissions = (uint)reader.GetInt32(18); + + ret = BackendResponse.Success; + } + else + { + ret = BackendResponse.NotFound; + } + } + catch (MySqlException ex) + { + Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); + ret = BackendResponse.Failure; + } + } + + server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now); + return ret; + } + + public BackendResponse TryFetchFolder(Uri owner, UUID folderID, out InventoryFolder folder) + { + folder = null; + BackendResponse ret; + + using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) + { + IDataReader reader; + + try + { + dbConnection.Open(); + + IDbCommand command = dbConnection.CreateCommand(); + command.CommandText = String.Format("SELECT folderName,type,version,agentID,parentFolderID FROM inventoryfolders WHERE folderID='{0}'", + folderID.ToString()); + reader = command.ExecuteReader(); + + if (reader.Read()) + { + folder = new InventoryFolder(); + folder.Children = null; // This call only returns data for the folder itself, no children data + folder.ID = folderID; + folder.Name = reader.GetString(0); + folder.Type = reader.GetInt16(1); + folder.Version = (ushort)reader.GetInt16(2); + folder.Owner = UUID.Parse(reader.GetString(3)); + folder.ParentID = UUID.Parse(reader.GetString(4)); + + ret = BackendResponse.Success; + } + else + { + ret = BackendResponse.NotFound; + } + } + catch (MySqlException ex) + { + Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); + ret = BackendResponse.Failure; + } + } + + server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now); + return ret; + } + + public BackendResponse TryFetchFolderContents(Uri owner, UUID folderID, out InventoryCollection contents) + { + contents = null; + BackendResponse ret; + + using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) + { + IDataReader reader; + + try + { + dbConnection.Open(); + + contents = new InventoryCollection(); + + #region Folder retrieval + + IDbCommand command = dbConnection.CreateCommand(); + command.CommandText = String.Format("SELECT folderName,type,version,agentID,folderID FROM inventoryfolders WHERE parentFolderID='{0}'", + folderID.ToString()); + reader = command.ExecuteReader(); + + contents.Folders = new Dictionary(); + + while (reader.Read()) + { + InventoryFolder folder = new InventoryFolder(); + folder.ParentID = folderID; + folder.Children = null; // This call doesn't do recursion + folder.Name = reader.GetString(0); + folder.Type = reader.GetInt16(1); + folder.Version = (ushort)reader.GetInt16(2); + folder.Owner = UUID.Parse(reader.GetString(3)); + folder.ID = UUID.Parse(reader.GetString(4)); + + contents.Folders.Add(folder.ID, folder); + contents.UserID = folder.Owner; + } + + reader.Close(); + + #endregion Folder retrieval + + #region Item retrieval + + command = dbConnection.CreateCommand(); + command.CommandText = String.Format("SELECT assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," + + "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," + + "creationDate,groupID,groupOwned,flags,avatarID,inventoryID,inventoryGroupPermissions FROM inventoryitems WHERE parentFolderID='{0}'", + folderID.ToString()); + reader = command.ExecuteReader(); + + contents.Items = new Dictionary(); + + while (reader.Read()) + { + InventoryItem item = new InventoryItem(); + item.Folder = folderID; + item.AssetID = UUID.Parse(reader.GetString(0)); + item.AssetType = reader.GetInt32(1); + item.Name = reader.GetString(2); + item.Description = reader.GetString(3); + item.NextPermissions = (uint)reader.GetInt32(4); + item.CurrentPermissions = (uint)reader.GetInt32(5); + item.InvType = reader.GetInt32(6); + item.Creator = UUID.Parse(reader.GetString(7)); + item.BasePermissions = (uint)reader.GetInt32(8); + item.EveryOnePermissions = (uint)reader.GetInt32(9); + item.SalePrice = reader.GetInt32(10); + item.SaleType = reader.GetByte(11); + item.CreationDate = reader.GetInt32(12); + item.GroupID = UUID.Parse(reader.GetString(13)); + item.GroupOwned = reader.GetBoolean(14); + item.Flags = (uint)reader.GetInt32(15); + item.Owner = UUID.Parse(reader.GetString(16)); + item.ID = UUID.Parse(reader.GetString(17)); + item.GroupPermissions = (uint)reader.GetInt32(18); + + contents.Items.Add(item.ID, item); + contents.UserID = item.Owner; + } + + #endregion Item retrieval + + ret = BackendResponse.Success; + } + catch (MySqlException ex) + { + Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); + ret = BackendResponse.Failure; + } + } + + server.MetricsProvider.LogInventoryFetchFolderContents(EXTENSION_NAME, ret, owner, folderID, DateTime.Now); + return ret; + } + + public BackendResponse TryFetchFolderList(Uri owner, out List folders) + { + folders = null; + BackendResponse ret; + UUID ownerID; + + if (Utils.TryGetOpenSimUUID(owner, out ownerID)) + { + using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) + { + IDataReader reader; + + try + { + dbConnection.Open(); + folders = new List(); + + IDbCommand command = dbConnection.CreateCommand(); + command.CommandText = String.Format("SELECT folderName,type,version,folderID,parentFolderID FROM inventoryfolders WHERE agentID='{0}'", + ownerID.ToString()); + reader = command.ExecuteReader(); + + while (reader.Read()) + { + InventoryFolder folder = new InventoryFolder(); + folder.Owner = ownerID; + folder.Children = null; // This call does not create a folder hierarchy + folder.Name = reader.GetString(0); + folder.Type = reader.GetInt16(1); + folder.Version = (ushort)reader.GetInt16(2); + folder.ID = UUID.Parse(reader.GetString(3)); + folder.ParentID = UUID.Parse(reader.GetString(4)); + + folders.Add(folder); + } + + ret = BackendResponse.Success; + } + catch (MySqlException ex) + { + Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); + ret = BackendResponse.Failure; + } + } + } + else + { + ret = BackendResponse.NotFound; + } + + server.MetricsProvider.LogInventoryFetchFolderList(EXTENSION_NAME, ret, owner, DateTime.Now); + return ret; + } + + public BackendResponse TryFetchInventory(Uri owner, out InventoryCollection inventory) + { + inventory = null; + BackendResponse ret; + List folders; + UUID ownerID; + + ret = TryFetchFolderList(owner, out folders); + + if (ret == BackendResponse.Success) + { + // Add the retrieved folders to the inventory collection + inventory = new InventoryCollection(); + inventory.Folders = new Dictionary(folders.Count); + foreach (InventoryFolder folder in folders) + inventory.Folders[folder.ID] = folder; + + // Fetch inventory items + if (Utils.TryGetOpenSimUUID(owner, out ownerID)) + { + using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) + { + IDataReader reader; + + try + { + dbConnection.Open(); + + IDbCommand command = dbConnection.CreateCommand(); + command.CommandText = String.Format("SELECT assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," + + "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," + + "creationDate,groupID,groupOwned,flags,inventoryID,parentFolderID,inventoryGroupPermissions FROM inventoryitems WHERE " + + "avatarID='{0}'", ownerID.ToString()); + reader = command.ExecuteReader(); + + inventory.UserID = ownerID; + inventory.Items = new Dictionary(); + + while (reader.Read()) + { + InventoryItem item = new InventoryItem(); + item.Owner = ownerID; + item.AssetID = UUID.Parse(reader.GetString(0)); + item.AssetType = reader.GetInt32(1); + item.Name = reader.GetString(2); + item.Description = reader.GetString(3); + item.NextPermissions = (uint)reader.GetInt32(4); + item.CurrentPermissions = (uint)reader.GetInt32(5); + item.InvType = reader.GetInt32(6); + item.Creator = UUID.Parse(reader.GetString(7)); + item.BasePermissions = (uint)reader.GetInt32(8); + item.EveryOnePermissions = (uint)reader.GetInt32(9); + item.SalePrice = reader.GetInt32(10); + item.SaleType = reader.GetByte(11); + item.CreationDate = reader.GetInt32(12); + item.GroupID = UUID.Parse(reader.GetString(13)); + item.GroupOwned = reader.GetBoolean(14); + item.Flags = (uint)reader.GetInt32(15); + item.ID = UUID.Parse(reader.GetString(16)); + item.Folder = UUID.Parse(reader.GetString(17)); + item.GroupPermissions = (uint)reader.GetInt32(18); + + inventory.Items.Add(item.ID, item); + } + + ret = BackendResponse.Success; + } + catch (MySqlException ex) + { + Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); + ret = BackendResponse.Failure; + } + } + } + else + { + ret = BackendResponse.NotFound; + } + } + + server.MetricsProvider.LogInventoryFetchInventory(EXTENSION_NAME, ret, owner, DateTime.Now); + return ret; + } + + public BackendResponse TryFetchActiveGestures(Uri owner, out List gestures) + { + gestures = null; + BackendResponse ret; + UUID ownerID; + + if (Utils.TryGetOpenSimUUID(owner, out ownerID)) + { + using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) + { + IDataReader reader; + + try + { + dbConnection.Open(); + + MySqlCommand command = new MySqlCommand("SELECT assetID,inventoryName,inventoryDescription,inventoryNextPermissions," + + "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," + + "creationDate,groupID,groupOwned,inventoryID,parentFolderID,inventoryGroupPermissions FROM inventoryitems WHERE " + + "avatarId=?uuid AND assetType=?type AND flags=1", dbConnection); + command.Parameters.AddWithValue("?uuid", ownerID.ToString()); + command.Parameters.AddWithValue("?type", (int)AssetType.Gesture); + reader = command.ExecuteReader(); + + while (reader.Read()) + { + InventoryItem item = new InventoryItem(); + item.Owner = ownerID; + item.AssetType = (int)AssetType.Gesture; + item.Flags = (uint)1; + item.AssetID = UUID.Parse(reader.GetString(0)); + item.Name = reader.GetString(1); + item.Description = reader.GetString(2); + item.NextPermissions = (uint)reader.GetInt32(3); + item.CurrentPermissions = (uint)reader.GetInt32(4); + item.InvType = reader.GetInt32(5); + item.Creator = UUID.Parse(reader.GetString(6)); + item.BasePermissions = (uint)reader.GetInt32(7); + item.EveryOnePermissions = (uint)reader.GetInt32(8); + item.SalePrice = reader.GetInt32(9); + item.SaleType = reader.GetByte(10); + item.CreationDate = reader.GetInt32(11); + item.GroupID = UUID.Parse(reader.GetString(12)); + item.GroupOwned = reader.GetBoolean(13); + item.ID = UUID.Parse(reader.GetString(14)); + item.Folder = UUID.Parse(reader.GetString(15)); + item.GroupPermissions = (uint)reader.GetInt32(16); + + gestures.Add(item); + } + + ret = BackendResponse.Success; + } + catch (MySqlException ex) + { + Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); + ret = BackendResponse.Failure; + } + } + } + else + { + ret = BackendResponse.NotFound; + } + + server.MetricsProvider.LogInventoryFetchActiveGestures(EXTENSION_NAME, ret, owner, DateTime.Now); + return ret; + } + + public BackendResponse TryCreateItem(Uri owner, InventoryItem item) + { + BackendResponse ret; + + using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) + { + try + { + dbConnection.Open(); + + MySqlCommand command = new MySqlCommand( + "REPLACE INTO inventoryitems (assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," + + "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," + + "creationDate,groupID,groupOwned,flags,inventoryID,avatarID,parentFolderID,inventoryGroupPermissions) VALUES " + + + "(?assetID,?assetType,?inventoryName,?inventoryDescription,?inventoryNextPermissions,?inventoryCurrentPermissions,?invType," + + "?creatorID,?inventoryBasePermissions,?inventoryEveryOnePermissions,?salePrice,?saleType,?creationDate,?groupID,?groupOwned," + + "?flags,?inventoryID,?avatarID,?parentFolderID,?inventoryGroupPermissions)", dbConnection); + + command.Parameters.AddWithValue("?assetID", item.AssetID.ToString()); + command.Parameters.AddWithValue("?assetType", item.AssetType); + command.Parameters.AddWithValue("?inventoryName", item.Name); + command.Parameters.AddWithValue("?inventoryDescription", item.Description); + command.Parameters.AddWithValue("?inventoryNextPermissions", item.NextPermissions); + command.Parameters.AddWithValue("?inventoryCurrentPermissions", item.CurrentPermissions); + command.Parameters.AddWithValue("?invType", item.InvType); + command.Parameters.AddWithValue("?creatorID", item.Creator.ToString()); + command.Parameters.AddWithValue("?inventoryBasePermissions", item.BasePermissions); + command.Parameters.AddWithValue("?inventoryEveryOnePermissions", item.EveryOnePermissions); + command.Parameters.AddWithValue("?salePrice", item.SalePrice); + command.Parameters.AddWithValue("?saleType", item.SaleType); + command.Parameters.AddWithValue("?creationDate", item.CreationDate); + command.Parameters.AddWithValue("?groupID", item.GroupID.ToString()); + command.Parameters.AddWithValue("?groupOwned", item.GroupOwned); + command.Parameters.AddWithValue("?flags", item.Flags); + command.Parameters.AddWithValue("?inventoryID", item.ID); + command.Parameters.AddWithValue("?avatarID", item.Owner); + command.Parameters.AddWithValue("?parentFolderID", item.Folder); + command.Parameters.AddWithValue("?inventoryGroupPermissions", item.GroupPermissions); + + int rowsAffected = command.ExecuteNonQuery(); + if (rowsAffected == 1) + { + ret = BackendResponse.Success; + } + else if (rowsAffected == 2) + { + Logger.Log.Info("Replaced inventory item " + item.ID.ToString()); + ret = BackendResponse.Success; + } + else + { + Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected); + ret = BackendResponse.Failure; + } + } + catch (MySqlException ex) + { + Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); + ret = BackendResponse.Failure; + } + } + + server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, false, DateTime.Now); + return ret; + } + + public BackendResponse TryCreateFolder(Uri owner, InventoryFolder folder) + { + BackendResponse ret; + + using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) + { + try + { + dbConnection.Open(); + + MySqlCommand command = new MySqlCommand( + "REPLACE INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) VALUES " + + "(?folderName,?type,?version,?folderID,?agentID,?parentFolderID)", dbConnection); + + command.Parameters.AddWithValue("?folderName", folder.Name); + command.Parameters.AddWithValue("?type", folder.Type); + command.Parameters.AddWithValue("?version", folder.Version); + command.Parameters.AddWithValue("?folderID", folder.ID); + command.Parameters.AddWithValue("?agentID", folder.Owner); + command.Parameters.AddWithValue("?parentFolderID", folder.ParentID); + + int rowsAffected = command.ExecuteNonQuery(); + if (rowsAffected == 1) + { + ret = BackendResponse.Success; + } + else if (rowsAffected == 2) + { + Logger.Log.Info("Replaced inventory folder " + folder.ID.ToString()); + ret = BackendResponse.Success; + } + else + { + Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected); + ret = BackendResponse.Failure; + } + } + catch (MySqlException ex) + { + Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); + ret = BackendResponse.Failure; + } + } + + server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, true, DateTime.Now); + return ret; + } + + public BackendResponse TryCreateInventory(Uri owner, InventoryFolder rootFolder) + { + return TryCreateFolder(owner, rootFolder); + } + + public BackendResponse TryDeleteItem(Uri owner, UUID itemID) + { + BackendResponse ret; + UUID ownerID; + + if (Utils.TryGetOpenSimUUID(owner, out ownerID)) + { + using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) + { + try + { + dbConnection.Open(); + + MySqlCommand command = new MySqlCommand( + "DELETE FROM inventoryitems WHERE inventoryID=?inventoryID AND avatarID=?avatarID", dbConnection); + + command.Parameters.AddWithValue("?inventoryID", itemID.ToString()); + command.Parameters.AddWithValue("?avatarID", ownerID.ToString()); + + int rowsAffected = command.ExecuteNonQuery(); + if (rowsAffected == 1) + { + ret = BackendResponse.Success; + } + else + { + Logger.Log.ErrorFormat("MySQL DELETE query affected {0} rows", rowsAffected); + ret = BackendResponse.NotFound; + } + } + catch (MySqlException ex) + { + Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); + ret = BackendResponse.Failure; + } + } + } + else + { + ret = BackendResponse.NotFound; + } + + server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now); + return ret; + } + + public BackendResponse TryDeleteFolder(Uri owner, UUID folderID) + { + BackendResponse ret; + UUID ownerID; + + if (Utils.TryGetOpenSimUUID(owner, out ownerID)) + { + using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) + { + try + { + dbConnection.Open(); + + MySqlCommand command = new MySqlCommand( + "DELETE FROM inventoryfolders WHERE folderID=?folderID AND agentID=?agentID", dbConnection); + + command.Parameters.AddWithValue("?folderID", folderID.ToString()); + command.Parameters.AddWithValue("?agentID", ownerID.ToString()); + + int rowsAffected = command.ExecuteNonQuery(); + if (rowsAffected == 1) + { + ret = BackendResponse.Success; + } + else + { + Logger.Log.ErrorFormat("MySQL DELETE query affected {0} rows", rowsAffected); + ret = BackendResponse.NotFound; + } + } + catch (MySqlException ex) + { + Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); + ret = BackendResponse.Failure; + } + } + } + else + { + ret = BackendResponse.NotFound; + } + + server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now); + return ret; + } + + public BackendResponse TryPurgeFolder(Uri owner, UUID folderID) + { + BackendResponse ret; + UUID ownerID; + + if (Utils.TryGetOpenSimUUID(owner, out ownerID)) + { + using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) + { + try + { + dbConnection.Open(); + + #region Delete items + + MySqlCommand command = new MySqlCommand( + "DELETE FROM inventoryitems WHERE parentFolderID=?parentFolderID AND avatarID=?avatarID", dbConnection); + + command.Parameters.AddWithValue("?parentFolderID", folderID.ToString()); + command.Parameters.AddWithValue("?avatarID", ownerID.ToString()); + + int rowsAffected = command.ExecuteNonQuery(); + + #endregion Delete items + + #region Delete folders + + command = new MySqlCommand( + "DELETE FROM inventoryfolders WHERE parentFolderID=?parentFolderID AND agentID=?agentID", dbConnection); + + command.Parameters.AddWithValue("?parentFolderID", folderID.ToString()); + command.Parameters.AddWithValue("?agentID", ownerID.ToString()); + + rowsAffected += command.ExecuteNonQuery(); + + #endregion Delete folders + + Logger.Log.DebugFormat("Deleted {0} inventory objects from MySQL in a folder purge", rowsAffected); + + ret = BackendResponse.Success; + } + catch (MySqlException ex) + { + Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); + ret = BackendResponse.Failure; + } + } + } + else + { + ret = BackendResponse.NotFound; + } + + server.MetricsProvider.LogInventoryPurgeFolder(EXTENSION_NAME, ret, owner, folderID, DateTime.Now); + return ret; + } + + public int ForEach(Action action, int start, int count) + { + int rowCount = 0; + + using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile))) + { + MySqlDataReader reader; + + try + { + dbConnection.Open(); + + MySqlCommand command = dbConnection.CreateCommand(); + command.CommandText = String.Format("SELECT name,description,assetType,temporary,data,id FROM assets LIMIT {0}, {1}", + start, count); + reader = command.ExecuteReader(); + } + catch (MySqlException ex) + { + Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message); + return 0; + } + + while (reader.Read()) + { + Metadata metadata = new Metadata(); + metadata.CreationDate = OpenMetaverse.Utils.Epoch; + metadata.Description = reader.GetString(1); + metadata.ID = UUID.Parse(reader.GetString(5)); + metadata.Name = reader.GetString(0); + metadata.SHA1 = OpenMetaverse.Utils.SHA1((byte[])reader.GetValue(4)); + metadata.Temporary = reader.GetBoolean(3); + metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2)); + + action(metadata); + ++rowCount; + } + + reader.Close(); + } + + return rowCount; + } + + #endregion Required Interfaces + + #region IPlugin implementation + + public void Initialise(AssetInventoryServer server) + { + this.server = server; + + try + { + m_inventoryProvider = DataPluginFactory.LoadInventoryDataPlugin("OpenSim.Data.MySQL.dll", server.ConfigFile.Configs["MySQL"].GetString("database_connect", null)); + if (m_inventoryProvider == null) + { + Logger.Log.Error("[INVENTORY]: Failed to load a database plugin, server halting."); + Environment.Exit(-1); + } + else + Logger.Log.InfoFormat("[INVENTORY]: Loaded storage backend: {0}", Version); + } + catch (Exception e) + { + Logger.Log.WarnFormat("[INVENTORY]: Failure loading data plugin: {0}", e.ToString()); + } + } + + public void Stop() + { + } + + public void Initialise() + { + Logger.Log.InfoFormat("[INVENTORY]: {0} cannot be default-initialized!", Name); + throw new PluginNotInitialisedException(Name); + } + + public void Dispose() + { + } + + public string Version + { + get { return m_inventoryProvider.Version; } + } + + public string Name + { + get { return "AssetInventoryServer OpenSim inventory storage provider"; } + } + + #endregion IPlugin implementation + } +} diff --git a/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/Resources/AssetInventoryServerOpenSimPlugins.addin.xml b/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/Resources/AssetInventoryServerOpenSimPlugins.addin.xml index f458909..6d21327 100644 --- a/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/Resources/AssetInventoryServerOpenSimPlugins.addin.xml +++ b/OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/Resources/AssetInventoryServerOpenSimPlugins.addin.xml @@ -15,6 +15,9 @@ + + + diff --git a/OpenSim/Grid/AssetInventoryServer/Plugins/Resources/AssetInventoryServerPlugins.addin.xml b/OpenSim/Grid/AssetInventoryServer/Plugins/Resources/AssetInventoryServerPlugins.addin.xml index bca7ee1..089c6a2 100644 --- a/OpenSim/Grid/AssetInventoryServer/Plugins/Resources/AssetInventoryServerPlugins.addin.xml +++ b/OpenSim/Grid/AssetInventoryServer/Plugins/Resources/AssetInventoryServerPlugins.addin.xml @@ -8,6 +8,6 @@ - + diff --git a/OpenSim/Grid/AssetInventoryServer/Plugins/Simple/Resources/AssetInventoryServerSimplePlugins.addin.xml b/OpenSim/Grid/AssetInventoryServer/Plugins/Simple/Resources/AssetInventoryServerSimplePlugins.addin.xml index 53534c4..f898145 100644 --- a/OpenSim/Grid/AssetInventoryServer/Plugins/Simple/Resources/AssetInventoryServerSimplePlugins.addin.xml +++ b/OpenSim/Grid/AssetInventoryServer/Plugins/Simple/Resources/AssetInventoryServerSimplePlugins.addin.xml @@ -10,4 +10,7 @@ + + + diff --git a/OpenSim/Grid/AssetInventoryServer/Plugins/Simple/SimpleInventoryStoragePlugin.cs b/OpenSim/Grid/AssetInventoryServer/Plugins/Simple/SimpleInventoryStoragePlugin.cs new file mode 100644 index 0000000..78dae35 --- /dev/null +++ b/OpenSim/Grid/AssetInventoryServer/Plugins/Simple/SimpleInventoryStoragePlugin.cs @@ -0,0 +1,627 @@ +/* + * Copyright (c) 2008 Intel Corporation + * All rights reserved. + * 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 Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``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 INTEL OR ITS + * 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.Net; +using System.IO; +using System.Text; +using ExtensionLoader; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; + +namespace OpenSim.Grid.AssetInventoryServer.Plugins.Simple +{ + public class SimpleInventoryStoragePlugin : IInventoryStorageProvider + { + const string EXTENSION_NAME = "SimpleInventoryStorage"; // Used for metrics reporting + const string DEFAULT_INVENTORY_DIR = "SimpleInventory"; + + AssetInventoryServer server; + Dictionary inventories = new Dictionary(); + Dictionary> activeGestures = new Dictionary>(); + Utils.InventoryItemSerializer itemSerializer = new Utils.InventoryItemSerializer(); + Utils.InventoryFolderSerializer folderSerializer = new Utils.InventoryFolderSerializer(); + + public SimpleInventoryStoragePlugin() + { + } + + #region Required Interfaces + + public BackendResponse TryFetchItem(Uri owner, UUID itemID, out InventoryItem item) + { + item = null; + BackendResponse ret; + + InventoryCollection collection; + if (inventories.TryGetValue(owner, out collection) && collection.Items.TryGetValue(itemID, out item)) + ret = BackendResponse.Success; + else + ret = BackendResponse.NotFound; + + server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now); + return ret; + } + + public BackendResponse TryFetchFolder(Uri owner, UUID folderID, out InventoryFolder folder) + { + folder = null; + BackendResponse ret; + + InventoryCollection collection; + if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder)) + ret = BackendResponse.Success; + else + ret = BackendResponse.NotFound; + + server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now); + return ret; + } + + public BackendResponse TryFetchFolderContents(Uri owner, UUID folderID, out InventoryCollection contents) + { + contents = null; + BackendResponse ret; + + InventoryCollection collection; + InventoryFolder folder; + + if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder)) + { + contents = new InventoryCollection(); + contents.UserID = collection.UserID; + contents.Folders = new Dictionary(); + contents.Items = new Dictionary(); + + foreach (InventoryBase invBase in folder.Children.Values) + { + if (invBase is InventoryItem) + { + InventoryItem invItem = invBase as InventoryItem; + contents.Items.Add(invItem.ID, invItem); + } + else + { + InventoryFolder invFolder = invBase as InventoryFolder; + contents.Folders.Add(invFolder.ID, invFolder); + } + } + + ret = BackendResponse.Success; + } + else + { + ret = BackendResponse.NotFound; + } + + server.MetricsProvider.LogInventoryFetchFolderContents(EXTENSION_NAME, ret, owner, folderID, DateTime.Now); + return ret; + } + + public BackendResponse TryFetchFolderList(Uri owner, out List folders) + { + folders = null; + BackendResponse ret; + + InventoryCollection collection; + if (inventories.TryGetValue(owner, out collection)) + { + folders = new List(collection.Folders.Values); + return BackendResponse.Success; + } + else + { + ret = BackendResponse.NotFound; + } + + server.MetricsProvider.LogInventoryFetchFolderList(EXTENSION_NAME, ret, owner, DateTime.Now); + return ret; + } + + public BackendResponse TryFetchInventory(Uri owner, out InventoryCollection inventory) + { + inventory = null; + BackendResponse ret; + + if (inventories.TryGetValue(owner, out inventory)) + ret = BackendResponse.Success; + else + ret = BackendResponse.NotFound; + + server.MetricsProvider.LogInventoryFetchInventory(EXTENSION_NAME, ret, owner, DateTime.Now); + return ret; + } + + public BackendResponse TryFetchActiveGestures(Uri owner, out List gestures) + { + gestures = null; + BackendResponse ret; + + if (activeGestures.TryGetValue(owner, out gestures)) + ret = BackendResponse.Success; + else + ret = BackendResponse.NotFound; + + server.MetricsProvider.LogInventoryFetchActiveGestures(EXTENSION_NAME, ret, owner, DateTime.Now); + return ret; + } + + public BackendResponse TryCreateItem(Uri owner, InventoryItem item) + { + BackendResponse ret; + + InventoryCollection collection; + if (inventories.TryGetValue(owner, out collection)) + { + // Delete this item first if it already exists + InventoryItem oldItem; + if (collection.Items.TryGetValue(item.ID, out oldItem)) + TryDeleteItem(owner, item.ID); + + try + { + // Create the file + SaveItem(item); + + // Add the item to the collection + lock (collection) collection.Items[item.ID] = item; + + // Add the item to its parent folder + InventoryFolder parent; + if (collection.Folders.TryGetValue(item.Folder, out parent)) + lock (parent.Children) parent.Children.Add(item.ID, item); + + // Add active gestures to our list + if (item.InvType == (int)InventoryType.Gesture && item.Flags == 1) + { + lock (activeGestures) + activeGestures[owner].Add(item); + } + + ret = BackendResponse.Success; + } + catch (Exception ex) + { + Logger.Log.Error(ex.Message); + ret = BackendResponse.Failure; + } + } + else + { + return BackendResponse.NotFound; + } + + server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, false, DateTime.Now); + return ret; + } + + public BackendResponse TryCreateFolder(Uri owner, InventoryFolder folder) + { + BackendResponse ret; + + InventoryCollection collection; + if (inventories.TryGetValue(owner, out collection)) + { + // Delete this folder first if it already exists + InventoryFolder oldFolder; + if (collection.Folders.TryGetValue(folder.ID, out oldFolder)) + TryDeleteFolder(owner, folder.ID); + + try + { + // Create the file + SaveFolder(folder); + + // Add the folder to the collection + lock (collection) collection.Folders[folder.ID] = folder; + + // Add the folder to its parent folder + InventoryFolder parent; + if (collection.Folders.TryGetValue(folder.ParentID, out parent)) + lock (parent.Children) parent.Children.Add(folder.ID, folder); + + ret = BackendResponse.Success; + } + catch (Exception ex) + { + Logger.Log.Error(ex.Message); + ret = BackendResponse.Failure; + } + } + else + { + ret = BackendResponse.NotFound; + } + + server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, true, DateTime.Now); + return ret; + } + + public BackendResponse TryCreateInventory(Uri owner, InventoryFolder rootFolder) + { + BackendResponse ret; + + lock (inventories) + { + if (!inventories.ContainsKey(owner)) + { + InventoryCollection collection = new InventoryCollection(); + collection.UserID = rootFolder.Owner; + collection.Folders = new Dictionary(); + collection.Folders.Add(rootFolder.ID, rootFolder); + collection.Items = new Dictionary(); + + inventories.Add(owner, collection); + + ret = BackendResponse.Success; + } + else + { + ret = BackendResponse.Failure; + } + } + + if (ret == BackendResponse.Success) + { + string path = Path.Combine(DEFAULT_INVENTORY_DIR, rootFolder.Owner.ToString()); + try + { + // Create the directory for this agent + Directory.CreateDirectory(path); + + // Create an index.txt containing the UUID and URI for this agent + string[] index = new string[] { rootFolder.Owner.ToString(), owner.ToString() }; + File.WriteAllLines(Path.Combine(path, "index.txt"), index); + + // Create the root folder file + SaveFolder(rootFolder); + } + catch (Exception ex) + { + Logger.Log.Error(ex.Message); + ret = BackendResponse.Failure; + } + } + + server.MetricsProvider.LogInventoryCreateInventory(EXTENSION_NAME, ret, DateTime.Now); + return ret; + } + + public BackendResponse TryDeleteItem(Uri owner, UUID itemID) + { + BackendResponse ret; + + InventoryCollection collection; + InventoryItem item; + if (inventories.TryGetValue(owner, out collection) && collection.Items.TryGetValue(itemID, out item)) + { + // Remove the item from its parent folder + InventoryFolder parent; + if (collection.Folders.TryGetValue(item.Folder, out parent)) + lock (parent.Children) parent.Children.Remove(itemID); + + // Remove the item from the collection + lock (collection) collection.Items.Remove(itemID); + + // Remove from the active gestures list if applicable + if (item.InvType == (int)InventoryType.Gesture) + { + lock (activeGestures) + { + for (int i = 0; i < activeGestures[owner].Count; i++) + { + if (activeGestures[owner][i].ID == itemID) + { + activeGestures[owner].RemoveAt(i); + break; + } + } + } + } + + // Delete the file. We don't know exactly what the file name is, + // so search for it + string path = PathFromURI(owner); + string[] matches = Directory.GetFiles(path, String.Format("*{0}.item", itemID), SearchOption.TopDirectoryOnly); + foreach (string match in matches) + { + try { File.Delete(match); } + catch (Exception ex) { Logger.Log.ErrorFormat("Failed to delete file {0}: {1}", match, ex.Message); } + } + + ret = BackendResponse.Success; + } + else + { + ret = BackendResponse.NotFound; + } + + server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now); + return ret; + } + + public BackendResponse TryDeleteFolder(Uri owner, UUID folderID) + { + BackendResponse ret; + + InventoryCollection collection; + InventoryFolder folder; + if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder)) + { + // Remove the folder from its parent folder + InventoryFolder parent; + if (collection.Folders.TryGetValue(folder.ParentID, out parent)) + lock (parent.Children) parent.Children.Remove(folderID); + + // Remove the folder from the collection + lock (collection) collection.Items.Remove(folderID); + + // Delete the folder file. We don't know exactly what the file name is, + // so search for it + string path = PathFromURI(owner); + string[] matches = Directory.GetFiles(path, String.Format("*{0}.folder", folderID), SearchOption.TopDirectoryOnly); + foreach (string match in matches) + { + try { File.Delete(match); } + catch (Exception ex) { Logger.Log.ErrorFormat("Failed to delete folder file {0}: {1}", match, ex.Message); } + } + + ret = BackendResponse.Success; + } + else + { + ret = BackendResponse.NotFound; + } + + server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now); + return ret; + } + + public BackendResponse TryPurgeFolder(Uri owner, UUID folderID) + { + BackendResponse ret; + + InventoryCollection collection; + InventoryFolder folder; + if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder)) + { + // Delete all of the folder children + foreach (InventoryBase obj in new List(folder.Children.Values)) + { + if (obj is InventoryItem) + { + TryDeleteItem(owner, (obj as InventoryItem).ID); + } + else + { + InventoryFolder childFolder = obj as InventoryFolder; + TryPurgeFolder(owner, childFolder.ID); + TryDeleteFolder(owner, childFolder.ID); + } + } + + ret = BackendResponse.Success; + } + else + { + ret = BackendResponse.NotFound; + } + + server.MetricsProvider.LogInventoryPurgeFolder(EXTENSION_NAME, ret, owner, folderID, DateTime.Now); + return ret; + } + + #endregion Required Interfaces + + void SaveItem(InventoryItem item) + { + string filename = String.Format("{0}-{1}.item", SanitizeFilename(item.Name), item.ID); + + string path = Path.Combine(DEFAULT_INVENTORY_DIR, item.Owner.ToString()); + path = Path.Combine(path, filename); + + using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write)) + { + itemSerializer.Serialize(stream, item); + stream.Flush(); + } + } + + void SaveFolder(InventoryFolder folder) + { + string filename = String.Format("{0}-{1}.folder", SanitizeFilename(folder.Name), folder.ID); + + string path = Path.Combine(DEFAULT_INVENTORY_DIR, folder.Owner.ToString()); + path = Path.Combine(path, filename); + + using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write)) + { + folderSerializer.Serialize(stream, folder); + stream.Flush(); + } + } + + string SanitizeFilename(string filename) + { + string output = filename; + + if (output.Length > 64) + output = output.Substring(0, 64); + + foreach (char i in Path.GetInvalidFileNameChars()) + output = output.Replace(i, '_'); + + return output; + } + + static string PathFromURI(Uri uri) + { + byte[] hash = OpenMetaverse.Utils.SHA1(Encoding.UTF8.GetBytes(uri.ToString())); + StringBuilder digest = new StringBuilder(40); + + // Convert the hash to a hex string + foreach (byte b in hash) + digest.AppendFormat(OpenMetaverse.Utils.EnUsCulture, "{0:x2}", b); + + return Path.Combine(DEFAULT_INVENTORY_DIR, digest.ToString()); + } + + void LoadFiles(string folder) + { + // Try to create the directory if it doesn't already exist + if (!Directory.Exists(folder)) + { + try { Directory.CreateDirectory(folder); } + catch (Exception ex) + { + Logger.Log.Warn(ex.Message); + return; + } + } + + try + { + string[] agentFolders = Directory.GetDirectories(DEFAULT_INVENTORY_DIR); + + for (int i = 0; i < agentFolders.Length; i++) + { + string foldername = agentFolders[i]; + string indexPath = Path.Combine(foldername, "index.txt"); + UUID ownerID = UUID.Zero; + Uri owner = null; + + try + { + string[] index = File.ReadAllLines(indexPath); + ownerID = UUID.Parse(index[0]); + owner = new Uri(index[1]); + } + catch (Exception ex) + { + Logger.Log.WarnFormat("Failed loading the index file {0}: {1}", indexPath, ex.Message); + } + + if (ownerID != UUID.Zero && owner != null) + { + // Initialize the active gestures list for this agent + activeGestures.Add(owner, new List()); + + InventoryCollection collection = new InventoryCollection(); + collection.UserID = ownerID; + + // Load all of the folders for this agent + string[] folders = Directory.GetFiles(foldername, "*.folder", SearchOption.TopDirectoryOnly); + collection.Folders = new Dictionary(folders.Length); + + for (int j = 0; j < folders.Length; j++) + { + InventoryFolder invFolder = (InventoryFolder)folderSerializer.Deserialize( + new FileStream(folders[j], FileMode.Open, FileAccess.Read)); + collection.Folders[invFolder.ID] = invFolder; + } + + // Iterate over the folders collection, adding children to their parents + foreach (InventoryFolder invFolder in collection.Folders.Values) + { + InventoryFolder parent; + if (collection.Folders.TryGetValue(invFolder.ParentID, out parent)) + parent.Children[invFolder.ID] = invFolder; + } + + // Load all of the items for this agent + string[] files = Directory.GetFiles(foldername, "*.item", SearchOption.TopDirectoryOnly); + collection.Items = new Dictionary(files.Length); + + for (int j = 0; j < files.Length; j++) + { + InventoryItem invItem = (InventoryItem)itemSerializer.Deserialize( + new FileStream(files[j], FileMode.Open, FileAccess.Read)); + collection.Items[invItem.ID] = invItem; + + // Add items to their parent folders + InventoryFolder parent; + if (collection.Folders.TryGetValue(invItem.Folder, out parent)) + parent.Children[invItem.ID] = invItem; + + // Add active gestures to our list + if (invItem.InvType == (int)InventoryType.Gesture && invItem.Flags != 0) + activeGestures[owner].Add(invItem); + } + + inventories.Add(owner, collection); + } + } + } + catch (Exception ex) + { + Logger.Log.ErrorFormat("Failed loading inventory from {0}: {1}", folder, ex.Message); + } + } + + #region IPlugin implementation + + public void Initialise(AssetInventoryServer server) + { + this.server = server; + + LoadFiles(DEFAULT_INVENTORY_DIR); + + Logger.Log.InfoFormat("Initialized the inventory index with data for {0} avatars", + inventories.Count); + } + + /// + /// Initialises asset interface + /// + public void Initialise() + { + Logger.Log.InfoFormat("[ASSET]: {0} cannot be default-initialized!", Name); + throw new PluginNotInitialisedException(Name); + } + + public void Dispose() + { + } + + public string Version + { + // TODO: this should be something meaningful and not hardcoded? + get { return "0.1"; } + } + + public string Name + { + get { return "AssetInventoryServer Simple inventory storage provider"; } + } + + #endregion IPlugin implementation + } +} diff --git a/bin/OpenSim.Grid.AssetInventoryServer.addin.xml b/bin/OpenSim.Grid.AssetInventoryServer.addin.xml index 603ba85..1ba5c8d 100644 --- a/bin/OpenSim.Grid.AssetInventoryServer.addin.xml +++ b/bin/OpenSim.Grid.AssetInventoryServer.addin.xml @@ -10,7 +10,7 @@ - + diff --git a/prebuild.xml b/prebuild.xml index 715e8d5..cfa2b92 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -824,6 +824,7 @@ + -- cgit v1.1