aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Grid/AssetInventoryServer/Plugins
diff options
context:
space:
mode:
authorMike Mazur2009-02-16 02:26:27 +0000
committerMike Mazur2009-02-16 02:26:27 +0000
commit74a2bd237aed26b49d88045fe6afa526ed19c00d (patch)
treec72262c4343a6b95b8aa20616094e1b0fbc640a4 /OpenSim/Grid/AssetInventoryServer/Plugins
parent- added Simple AssetInventoryServer plugin (asset storage only) (diff)
downloadopensim-SC_OLD-74a2bd237aed26b49d88045fe6afa526ed19c00d.zip
opensim-SC_OLD-74a2bd237aed26b49d88045fe6afa526ed19c00d.tar.gz
opensim-SC_OLD-74a2bd237aed26b49d88045fe6afa526ed19c00d.tar.bz2
opensim-SC_OLD-74a2bd237aed26b49d88045fe6afa526ed19c00d.tar.xz
Add OpenSim & Simple inventory storage plugins and Null metrics plugin.
Diffstat (limited to 'OpenSim/Grid/AssetInventoryServer/Plugins')
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Plugins/NullMetricsPlugin.cs (renamed from OpenSim/Grid/AssetInventoryServer/Plugins/NullMetrics.cs)4
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/OpenSimInventoryStoragePlugin.cs835
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Plugins/OpenSim/Resources/AssetInventoryServerOpenSimPlugins.addin.xml3
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Plugins/Resources/AssetInventoryServerPlugins.addin.xml2
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Plugins/Simple/Resources/AssetInventoryServerSimplePlugins.addin.xml3
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Plugins/Simple/SimpleInventoryStoragePlugin.cs627
6 files changed, 1471 insertions, 3 deletions
diff --git a/OpenSim/Grid/AssetInventoryServer/Plugins/NullMetrics.cs b/OpenSim/Grid/AssetInventoryServer/Plugins/NullMetricsPlugin.cs
index 86ae5cd..caa4efd 100644
--- a/OpenSim/Grid/AssetInventoryServer/Plugins/NullMetrics.cs
+++ b/OpenSim/Grid/AssetInventoryServer/Plugins/NullMetricsPlugin.cs
@@ -32,11 +32,11 @@ using OpenMetaverse;
32 32
33namespace OpenSim.Grid.AssetInventoryServer.Plugins 33namespace OpenSim.Grid.AssetInventoryServer.Plugins
34{ 34{
35 public class NullMetrics : IMetricsProvider 35 public class NullMetricsPlugin : IMetricsProvider
36 { 36 {
37 AssetInventoryServer server; 37 AssetInventoryServer server;
38 38
39 public NullMetrics() 39 public NullMetricsPlugin()
40 { 40 {
41 } 41 }
42 42
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 @@
1/*
2 * Copyright (c) 2008 Intel Corporation
3 * All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * -- Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * -- Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * -- Neither the name of the Intel Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30using System;
31using System.Collections.Generic;
32using System.Net;
33using System.Data;
34using MySql.Data.MySqlClient;
35using ExtensionLoader;
36using ExtensionLoader.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Grid.AssetInventoryServer.Extensions;
41using OpenSim.Data;
42
43namespace OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim
44{
45 public class OpenSimInventoryStoragePlugin : IInventoryStorageProvider
46 {
47 const string EXTENSION_NAME = "OpenSimInventoryStorage"; // Used in metrics reporting
48
49 private AssetInventoryServer server;
50 private IInventoryDataPlugin m_inventoryProvider;
51
52 public OpenSimInventoryStoragePlugin()
53 {
54 }
55
56 #region Required Interfaces
57
58 public BackendResponse TryFetchItem(Uri owner, UUID itemID, out InventoryItem item)
59 {
60 item = null;
61 BackendResponse ret;
62
63 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
64 {
65 IDataReader reader;
66
67 try
68 {
69 dbConnection.Open();
70
71 IDbCommand command = dbConnection.CreateCommand();
72 command.CommandText = String.Format("SELECT assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," +
73 "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," +
74 "creationDate,groupID,groupOwned,flags,avatarID,parentFolderID,inventoryGroupPermissions FROM inventoryitems WHERE inventoryID='{0}'",
75 itemID.ToString());
76 reader = command.ExecuteReader();
77
78 if (reader.Read())
79 {
80 item = new InventoryItem();
81 item.ID = itemID;
82 item.AssetID = UUID.Parse(reader.GetString(0));
83 item.AssetType = reader.GetInt32(1);
84 item.Name = reader.GetString(2);
85 item.Description = reader.GetString(3);
86 item.NextPermissions = (uint)reader.GetInt32(4);
87 item.CurrentPermissions = (uint)reader.GetInt32(5);
88 item.InvType = reader.GetInt32(6);
89 item.Creator = UUID.Parse(reader.GetString(7));
90 item.BasePermissions = (uint)reader.GetInt32(8);
91 item.EveryOnePermissions = (uint)reader.GetInt32(9);
92 item.SalePrice = reader.GetInt32(10);
93 item.SaleType = reader.GetByte(11);
94 item.CreationDate = reader.GetInt32(12);
95 item.GroupID = UUID.Parse(reader.GetString(13));
96 item.GroupOwned = reader.GetBoolean(14);
97 item.Flags = (uint)reader.GetInt32(15);
98 item.Owner = UUID.Parse(reader.GetString(16));
99 item.Folder = UUID.Parse(reader.GetString(17));
100 item.GroupPermissions = (uint)reader.GetInt32(18);
101
102 ret = BackendResponse.Success;
103 }
104 else
105 {
106 ret = BackendResponse.NotFound;
107 }
108 }
109 catch (MySqlException ex)
110 {
111 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
112 ret = BackendResponse.Failure;
113 }
114 }
115
116 server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now);
117 return ret;
118 }
119
120 public BackendResponse TryFetchFolder(Uri owner, UUID folderID, out InventoryFolder folder)
121 {
122 folder = null;
123 BackendResponse ret;
124
125 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
126 {
127 IDataReader reader;
128
129 try
130 {
131 dbConnection.Open();
132
133 IDbCommand command = dbConnection.CreateCommand();
134 command.CommandText = String.Format("SELECT folderName,type,version,agentID,parentFolderID FROM inventoryfolders WHERE folderID='{0}'",
135 folderID.ToString());
136 reader = command.ExecuteReader();
137
138 if (reader.Read())
139 {
140 folder = new InventoryFolder();
141 folder.Children = null; // This call only returns data for the folder itself, no children data
142 folder.ID = folderID;
143 folder.Name = reader.GetString(0);
144 folder.Type = reader.GetInt16(1);
145 folder.Version = (ushort)reader.GetInt16(2);
146 folder.Owner = UUID.Parse(reader.GetString(3));
147 folder.ParentID = UUID.Parse(reader.GetString(4));
148
149 ret = BackendResponse.Success;
150 }
151 else
152 {
153 ret = BackendResponse.NotFound;
154 }
155 }
156 catch (MySqlException ex)
157 {
158 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
159 ret = BackendResponse.Failure;
160 }
161 }
162
163 server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now);
164 return ret;
165 }
166
167 public BackendResponse TryFetchFolderContents(Uri owner, UUID folderID, out InventoryCollection contents)
168 {
169 contents = null;
170 BackendResponse ret;
171
172 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
173 {
174 IDataReader reader;
175
176 try
177 {
178 dbConnection.Open();
179
180 contents = new InventoryCollection();
181
182 #region Folder retrieval
183
184 IDbCommand command = dbConnection.CreateCommand();
185 command.CommandText = String.Format("SELECT folderName,type,version,agentID,folderID FROM inventoryfolders WHERE parentFolderID='{0}'",
186 folderID.ToString());
187 reader = command.ExecuteReader();
188
189 contents.Folders = new Dictionary<UUID, InventoryFolder>();
190
191 while (reader.Read())
192 {
193 InventoryFolder folder = new InventoryFolder();
194 folder.ParentID = folderID;
195 folder.Children = null; // This call doesn't do recursion
196 folder.Name = reader.GetString(0);
197 folder.Type = reader.GetInt16(1);
198 folder.Version = (ushort)reader.GetInt16(2);
199 folder.Owner = UUID.Parse(reader.GetString(3));
200 folder.ID = UUID.Parse(reader.GetString(4));
201
202 contents.Folders.Add(folder.ID, folder);
203 contents.UserID = folder.Owner;
204 }
205
206 reader.Close();
207
208 #endregion Folder retrieval
209
210 #region Item retrieval
211
212 command = dbConnection.CreateCommand();
213 command.CommandText = String.Format("SELECT assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," +
214 "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," +
215 "creationDate,groupID,groupOwned,flags,avatarID,inventoryID,inventoryGroupPermissions FROM inventoryitems WHERE parentFolderID='{0}'",
216 folderID.ToString());
217 reader = command.ExecuteReader();
218
219 contents.Items = new Dictionary<UUID, InventoryItem>();
220
221 while (reader.Read())
222 {
223 InventoryItem item = new InventoryItem();
224 item.Folder = folderID;
225 item.AssetID = UUID.Parse(reader.GetString(0));
226 item.AssetType = reader.GetInt32(1);
227 item.Name = reader.GetString(2);
228 item.Description = reader.GetString(3);
229 item.NextPermissions = (uint)reader.GetInt32(4);
230 item.CurrentPermissions = (uint)reader.GetInt32(5);
231 item.InvType = reader.GetInt32(6);
232 item.Creator = UUID.Parse(reader.GetString(7));
233 item.BasePermissions = (uint)reader.GetInt32(8);
234 item.EveryOnePermissions = (uint)reader.GetInt32(9);
235 item.SalePrice = reader.GetInt32(10);
236 item.SaleType = reader.GetByte(11);
237 item.CreationDate = reader.GetInt32(12);
238 item.GroupID = UUID.Parse(reader.GetString(13));
239 item.GroupOwned = reader.GetBoolean(14);
240 item.Flags = (uint)reader.GetInt32(15);
241 item.Owner = UUID.Parse(reader.GetString(16));
242 item.ID = UUID.Parse(reader.GetString(17));
243 item.GroupPermissions = (uint)reader.GetInt32(18);
244
245 contents.Items.Add(item.ID, item);
246 contents.UserID = item.Owner;
247 }
248
249 #endregion Item retrieval
250
251 ret = BackendResponse.Success;
252 }
253 catch (MySqlException ex)
254 {
255 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
256 ret = BackendResponse.Failure;
257 }
258 }
259
260 server.MetricsProvider.LogInventoryFetchFolderContents(EXTENSION_NAME, ret, owner, folderID, DateTime.Now);
261 return ret;
262 }
263
264 public BackendResponse TryFetchFolderList(Uri owner, out List<InventoryFolder> folders)
265 {
266 folders = null;
267 BackendResponse ret;
268 UUID ownerID;
269
270 if (Utils.TryGetOpenSimUUID(owner, out ownerID))
271 {
272 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
273 {
274 IDataReader reader;
275
276 try
277 {
278 dbConnection.Open();
279 folders = new List<InventoryFolder>();
280
281 IDbCommand command = dbConnection.CreateCommand();
282 command.CommandText = String.Format("SELECT folderName,type,version,folderID,parentFolderID FROM inventoryfolders WHERE agentID='{0}'",
283 ownerID.ToString());
284 reader = command.ExecuteReader();
285
286 while (reader.Read())
287 {
288 InventoryFolder folder = new InventoryFolder();
289 folder.Owner = ownerID;
290 folder.Children = null; // This call does not create a folder hierarchy
291 folder.Name = reader.GetString(0);
292 folder.Type = reader.GetInt16(1);
293 folder.Version = (ushort)reader.GetInt16(2);
294 folder.ID = UUID.Parse(reader.GetString(3));
295 folder.ParentID = UUID.Parse(reader.GetString(4));
296
297 folders.Add(folder);
298 }
299
300 ret = BackendResponse.Success;
301 }
302 catch (MySqlException ex)
303 {
304 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
305 ret = BackendResponse.Failure;
306 }
307 }
308 }
309 else
310 {
311 ret = BackendResponse.NotFound;
312 }
313
314 server.MetricsProvider.LogInventoryFetchFolderList(EXTENSION_NAME, ret, owner, DateTime.Now);
315 return ret;
316 }
317
318 public BackendResponse TryFetchInventory(Uri owner, out InventoryCollection inventory)
319 {
320 inventory = null;
321 BackendResponse ret;
322 List<InventoryFolder> folders;
323 UUID ownerID;
324
325 ret = TryFetchFolderList(owner, out folders);
326
327 if (ret == BackendResponse.Success)
328 {
329 // Add the retrieved folders to the inventory collection
330 inventory = new InventoryCollection();
331 inventory.Folders = new Dictionary<UUID, InventoryFolder>(folders.Count);
332 foreach (InventoryFolder folder in folders)
333 inventory.Folders[folder.ID] = folder;
334
335 // Fetch inventory items
336 if (Utils.TryGetOpenSimUUID(owner, out ownerID))
337 {
338 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
339 {
340 IDataReader reader;
341
342 try
343 {
344 dbConnection.Open();
345
346 IDbCommand command = dbConnection.CreateCommand();
347 command.CommandText = String.Format("SELECT assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," +
348 "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," +
349 "creationDate,groupID,groupOwned,flags,inventoryID,parentFolderID,inventoryGroupPermissions FROM inventoryitems WHERE " +
350 "avatarID='{0}'", ownerID.ToString());
351 reader = command.ExecuteReader();
352
353 inventory.UserID = ownerID;
354 inventory.Items = new Dictionary<UUID, InventoryItem>();
355
356 while (reader.Read())
357 {
358 InventoryItem item = new InventoryItem();
359 item.Owner = ownerID;
360 item.AssetID = UUID.Parse(reader.GetString(0));
361 item.AssetType = reader.GetInt32(1);
362 item.Name = reader.GetString(2);
363 item.Description = reader.GetString(3);
364 item.NextPermissions = (uint)reader.GetInt32(4);
365 item.CurrentPermissions = (uint)reader.GetInt32(5);
366 item.InvType = reader.GetInt32(6);
367 item.Creator = UUID.Parse(reader.GetString(7));
368 item.BasePermissions = (uint)reader.GetInt32(8);
369 item.EveryOnePermissions = (uint)reader.GetInt32(9);
370 item.SalePrice = reader.GetInt32(10);
371 item.SaleType = reader.GetByte(11);
372 item.CreationDate = reader.GetInt32(12);
373 item.GroupID = UUID.Parse(reader.GetString(13));
374 item.GroupOwned = reader.GetBoolean(14);
375 item.Flags = (uint)reader.GetInt32(15);
376 item.ID = UUID.Parse(reader.GetString(16));
377 item.Folder = UUID.Parse(reader.GetString(17));
378 item.GroupPermissions = (uint)reader.GetInt32(18);
379
380 inventory.Items.Add(item.ID, item);
381 }
382
383 ret = BackendResponse.Success;
384 }
385 catch (MySqlException ex)
386 {
387 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
388 ret = BackendResponse.Failure;
389 }
390 }
391 }
392 else
393 {
394 ret = BackendResponse.NotFound;
395 }
396 }
397
398 server.MetricsProvider.LogInventoryFetchInventory(EXTENSION_NAME, ret, owner, DateTime.Now);
399 return ret;
400 }
401
402 public BackendResponse TryFetchActiveGestures(Uri owner, out List<InventoryItem> gestures)
403 {
404 gestures = null;
405 BackendResponse ret;
406 UUID ownerID;
407
408 if (Utils.TryGetOpenSimUUID(owner, out ownerID))
409 {
410 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
411 {
412 IDataReader reader;
413
414 try
415 {
416 dbConnection.Open();
417
418 MySqlCommand command = new MySqlCommand("SELECT assetID,inventoryName,inventoryDescription,inventoryNextPermissions," +
419 "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," +
420 "creationDate,groupID,groupOwned,inventoryID,parentFolderID,inventoryGroupPermissions FROM inventoryitems WHERE " +
421 "avatarId=?uuid AND assetType=?type AND flags=1", dbConnection);
422 command.Parameters.AddWithValue("?uuid", ownerID.ToString());
423 command.Parameters.AddWithValue("?type", (int)AssetType.Gesture);
424 reader = command.ExecuteReader();
425
426 while (reader.Read())
427 {
428 InventoryItem item = new InventoryItem();
429 item.Owner = ownerID;
430 item.AssetType = (int)AssetType.Gesture;
431 item.Flags = (uint)1;
432 item.AssetID = UUID.Parse(reader.GetString(0));
433 item.Name = reader.GetString(1);
434 item.Description = reader.GetString(2);
435 item.NextPermissions = (uint)reader.GetInt32(3);
436 item.CurrentPermissions = (uint)reader.GetInt32(4);
437 item.InvType = reader.GetInt32(5);
438 item.Creator = UUID.Parse(reader.GetString(6));
439 item.BasePermissions = (uint)reader.GetInt32(7);
440 item.EveryOnePermissions = (uint)reader.GetInt32(8);
441 item.SalePrice = reader.GetInt32(9);
442 item.SaleType = reader.GetByte(10);
443 item.CreationDate = reader.GetInt32(11);
444 item.GroupID = UUID.Parse(reader.GetString(12));
445 item.GroupOwned = reader.GetBoolean(13);
446 item.ID = UUID.Parse(reader.GetString(14));
447 item.Folder = UUID.Parse(reader.GetString(15));
448 item.GroupPermissions = (uint)reader.GetInt32(16);
449
450 gestures.Add(item);
451 }
452
453 ret = BackendResponse.Success;
454 }
455 catch (MySqlException ex)
456 {
457 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
458 ret = BackendResponse.Failure;
459 }
460 }
461 }
462 else
463 {
464 ret = BackendResponse.NotFound;
465 }
466
467 server.MetricsProvider.LogInventoryFetchActiveGestures(EXTENSION_NAME, ret, owner, DateTime.Now);
468 return ret;
469 }
470
471 public BackendResponse TryCreateItem(Uri owner, InventoryItem item)
472 {
473 BackendResponse ret;
474
475 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
476 {
477 try
478 {
479 dbConnection.Open();
480
481 MySqlCommand command = new MySqlCommand(
482 "REPLACE INTO inventoryitems (assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," +
483 "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," +
484 "creationDate,groupID,groupOwned,flags,inventoryID,avatarID,parentFolderID,inventoryGroupPermissions) VALUES " +
485
486 "(?assetID,?assetType,?inventoryName,?inventoryDescription,?inventoryNextPermissions,?inventoryCurrentPermissions,?invType," +
487 "?creatorID,?inventoryBasePermissions,?inventoryEveryOnePermissions,?salePrice,?saleType,?creationDate,?groupID,?groupOwned," +
488 "?flags,?inventoryID,?avatarID,?parentFolderID,?inventoryGroupPermissions)", dbConnection);
489
490 command.Parameters.AddWithValue("?assetID", item.AssetID.ToString());
491 command.Parameters.AddWithValue("?assetType", item.AssetType);
492 command.Parameters.AddWithValue("?inventoryName", item.Name);
493 command.Parameters.AddWithValue("?inventoryDescription", item.Description);
494 command.Parameters.AddWithValue("?inventoryNextPermissions", item.NextPermissions);
495 command.Parameters.AddWithValue("?inventoryCurrentPermissions", item.CurrentPermissions);
496 command.Parameters.AddWithValue("?invType", item.InvType);
497 command.Parameters.AddWithValue("?creatorID", item.Creator.ToString());
498 command.Parameters.AddWithValue("?inventoryBasePermissions", item.BasePermissions);
499 command.Parameters.AddWithValue("?inventoryEveryOnePermissions", item.EveryOnePermissions);
500 command.Parameters.AddWithValue("?salePrice", item.SalePrice);
501 command.Parameters.AddWithValue("?saleType", item.SaleType);
502 command.Parameters.AddWithValue("?creationDate", item.CreationDate);
503 command.Parameters.AddWithValue("?groupID", item.GroupID.ToString());
504 command.Parameters.AddWithValue("?groupOwned", item.GroupOwned);
505 command.Parameters.AddWithValue("?flags", item.Flags);
506 command.Parameters.AddWithValue("?inventoryID", item.ID);
507 command.Parameters.AddWithValue("?avatarID", item.Owner);
508 command.Parameters.AddWithValue("?parentFolderID", item.Folder);
509 command.Parameters.AddWithValue("?inventoryGroupPermissions", item.GroupPermissions);
510
511 int rowsAffected = command.ExecuteNonQuery();
512 if (rowsAffected == 1)
513 {
514 ret = BackendResponse.Success;
515 }
516 else if (rowsAffected == 2)
517 {
518 Logger.Log.Info("Replaced inventory item " + item.ID.ToString());
519 ret = BackendResponse.Success;
520 }
521 else
522 {
523 Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected);
524 ret = BackendResponse.Failure;
525 }
526 }
527 catch (MySqlException ex)
528 {
529 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
530 ret = BackendResponse.Failure;
531 }
532 }
533
534 server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, false, DateTime.Now);
535 return ret;
536 }
537
538 public BackendResponse TryCreateFolder(Uri owner, InventoryFolder folder)
539 {
540 BackendResponse ret;
541
542 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
543 {
544 try
545 {
546 dbConnection.Open();
547
548 MySqlCommand command = new MySqlCommand(
549 "REPLACE INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) VALUES " +
550 "(?folderName,?type,?version,?folderID,?agentID,?parentFolderID)", dbConnection);
551
552 command.Parameters.AddWithValue("?folderName", folder.Name);
553 command.Parameters.AddWithValue("?type", folder.Type);
554 command.Parameters.AddWithValue("?version", folder.Version);
555 command.Parameters.AddWithValue("?folderID", folder.ID);
556 command.Parameters.AddWithValue("?agentID", folder.Owner);
557 command.Parameters.AddWithValue("?parentFolderID", folder.ParentID);
558
559 int rowsAffected = command.ExecuteNonQuery();
560 if (rowsAffected == 1)
561 {
562 ret = BackendResponse.Success;
563 }
564 else if (rowsAffected == 2)
565 {
566 Logger.Log.Info("Replaced inventory folder " + folder.ID.ToString());
567 ret = BackendResponse.Success;
568 }
569 else
570 {
571 Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected);
572 ret = BackendResponse.Failure;
573 }
574 }
575 catch (MySqlException ex)
576 {
577 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
578 ret = BackendResponse.Failure;
579 }
580 }
581
582 server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, true, DateTime.Now);
583 return ret;
584 }
585
586 public BackendResponse TryCreateInventory(Uri owner, InventoryFolder rootFolder)
587 {
588 return TryCreateFolder(owner, rootFolder);
589 }
590
591 public BackendResponse TryDeleteItem(Uri owner, UUID itemID)
592 {
593 BackendResponse ret;
594 UUID ownerID;
595
596 if (Utils.TryGetOpenSimUUID(owner, out ownerID))
597 {
598 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
599 {
600 try
601 {
602 dbConnection.Open();
603
604 MySqlCommand command = new MySqlCommand(
605 "DELETE FROM inventoryitems WHERE inventoryID=?inventoryID AND avatarID=?avatarID", dbConnection);
606
607 command.Parameters.AddWithValue("?inventoryID", itemID.ToString());
608 command.Parameters.AddWithValue("?avatarID", ownerID.ToString());
609
610 int rowsAffected = command.ExecuteNonQuery();
611 if (rowsAffected == 1)
612 {
613 ret = BackendResponse.Success;
614 }
615 else
616 {
617 Logger.Log.ErrorFormat("MySQL DELETE query affected {0} rows", rowsAffected);
618 ret = BackendResponse.NotFound;
619 }
620 }
621 catch (MySqlException ex)
622 {
623 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
624 ret = BackendResponse.Failure;
625 }
626 }
627 }
628 else
629 {
630 ret = BackendResponse.NotFound;
631 }
632
633 server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now);
634 return ret;
635 }
636
637 public BackendResponse TryDeleteFolder(Uri owner, UUID folderID)
638 {
639 BackendResponse ret;
640 UUID ownerID;
641
642 if (Utils.TryGetOpenSimUUID(owner, out ownerID))
643 {
644 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
645 {
646 try
647 {
648 dbConnection.Open();
649
650 MySqlCommand command = new MySqlCommand(
651 "DELETE FROM inventoryfolders WHERE folderID=?folderID AND agentID=?agentID", dbConnection);
652
653 command.Parameters.AddWithValue("?folderID", folderID.ToString());
654 command.Parameters.AddWithValue("?agentID", ownerID.ToString());
655
656 int rowsAffected = command.ExecuteNonQuery();
657 if (rowsAffected == 1)
658 {
659 ret = BackendResponse.Success;
660 }
661 else
662 {
663 Logger.Log.ErrorFormat("MySQL DELETE query affected {0} rows", rowsAffected);
664 ret = BackendResponse.NotFound;
665 }
666 }
667 catch (MySqlException ex)
668 {
669 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
670 ret = BackendResponse.Failure;
671 }
672 }
673 }
674 else
675 {
676 ret = BackendResponse.NotFound;
677 }
678
679 server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now);
680 return ret;
681 }
682
683 public BackendResponse TryPurgeFolder(Uri owner, UUID folderID)
684 {
685 BackendResponse ret;
686 UUID ownerID;
687
688 if (Utils.TryGetOpenSimUUID(owner, out ownerID))
689 {
690 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
691 {
692 try
693 {
694 dbConnection.Open();
695
696 #region Delete items
697
698 MySqlCommand command = new MySqlCommand(
699 "DELETE FROM inventoryitems WHERE parentFolderID=?parentFolderID AND avatarID=?avatarID", dbConnection);
700
701 command.Parameters.AddWithValue("?parentFolderID", folderID.ToString());
702 command.Parameters.AddWithValue("?avatarID", ownerID.ToString());
703
704 int rowsAffected = command.ExecuteNonQuery();
705
706 #endregion Delete items
707
708 #region Delete folders
709
710 command = new MySqlCommand(
711 "DELETE FROM inventoryfolders WHERE parentFolderID=?parentFolderID AND agentID=?agentID", dbConnection);
712
713 command.Parameters.AddWithValue("?parentFolderID", folderID.ToString());
714 command.Parameters.AddWithValue("?agentID", ownerID.ToString());
715
716 rowsAffected += command.ExecuteNonQuery();
717
718 #endregion Delete folders
719
720 Logger.Log.DebugFormat("Deleted {0} inventory objects from MySQL in a folder purge", rowsAffected);
721
722 ret = BackendResponse.Success;
723 }
724 catch (MySqlException ex)
725 {
726 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
727 ret = BackendResponse.Failure;
728 }
729 }
730 }
731 else
732 {
733 ret = BackendResponse.NotFound;
734 }
735
736 server.MetricsProvider.LogInventoryPurgeFolder(EXTENSION_NAME, ret, owner, folderID, DateTime.Now);
737 return ret;
738 }
739
740 public int ForEach(Action<Metadata> action, int start, int count)
741 {
742 int rowCount = 0;
743
744 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
745 {
746 MySqlDataReader reader;
747
748 try
749 {
750 dbConnection.Open();
751
752 MySqlCommand command = dbConnection.CreateCommand();
753 command.CommandText = String.Format("SELECT name,description,assetType,temporary,data,id FROM assets LIMIT {0}, {1}",
754 start, count);
755 reader = command.ExecuteReader();
756 }
757 catch (MySqlException ex)
758 {
759 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
760 return 0;
761 }
762
763 while (reader.Read())
764 {
765 Metadata metadata = new Metadata();
766 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
767 metadata.Description = reader.GetString(1);
768 metadata.ID = UUID.Parse(reader.GetString(5));
769 metadata.Name = reader.GetString(0);
770 metadata.SHA1 = OpenMetaverse.Utils.SHA1((byte[])reader.GetValue(4));
771 metadata.Temporary = reader.GetBoolean(3);
772 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
773
774 action(metadata);
775 ++rowCount;
776 }
777
778 reader.Close();
779 }
780
781 return rowCount;
782 }
783
784 #endregion Required Interfaces
785
786 #region IPlugin implementation
787
788 public void Initialise(AssetInventoryServer server)
789 {
790 this.server = server;
791
792 try
793 {
794 m_inventoryProvider = DataPluginFactory.LoadInventoryDataPlugin("OpenSim.Data.MySQL.dll", server.ConfigFile.Configs["MySQL"].GetString("database_connect", null));
795 if (m_inventoryProvider == null)
796 {
797 Logger.Log.Error("[INVENTORY]: Failed to load a database plugin, server halting.");
798 Environment.Exit(-1);
799 }
800 else
801 Logger.Log.InfoFormat("[INVENTORY]: Loaded storage backend: {0}", Version);
802 }
803 catch (Exception e)
804 {
805 Logger.Log.WarnFormat("[INVENTORY]: Failure loading data plugin: {0}", e.ToString());
806 }
807 }
808
809 public void Stop()
810 {
811 }
812
813 public void Initialise()
814 {
815 Logger.Log.InfoFormat("[INVENTORY]: {0} cannot be default-initialized!", Name);
816 throw new PluginNotInitialisedException(Name);
817 }
818
819 public void Dispose()
820 {
821 }
822
823 public string Version
824 {
825 get { return m_inventoryProvider.Version; }
826 }
827
828 public string Name
829 {
830 get { return "AssetInventoryServer OpenSim inventory storage provider"; }
831 }
832
833 #endregion IPlugin implementation
834 }
835}
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 @@
15 <Extension path="/OpenSim/AssetInventoryServer/StorageProvider"> 15 <Extension path="/OpenSim/AssetInventoryServer/StorageProvider">
16 <Plugin id="OpenSimAssetStorage" provider="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll" type="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimAssetStoragePlugin" /> 16 <Plugin id="OpenSimAssetStorage" provider="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll" type="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimAssetStoragePlugin" />
17 </Extension> 17 </Extension>
18 <Extension path="/OpenSim/AssetInventoryServer/InventoryProvider">
19 <Plugin id="OpenSimInventoryStorage" provider="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll" type="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimInventoryStoragePlugin" />
20 </Extension>
18 <Extension path="/OpenSim/AssetInventoryServer/Frontend"> 21 <Extension path="/OpenSim/AssetInventoryServer/Frontend">
19 <Plugin id="OpenSimAssetFrontend" provider="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll" type="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimAssetFrontendPlugin" /> 22 <Plugin id="OpenSimAssetFrontend" provider="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.dll" type="OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim.OpenSimAssetFrontendPlugin" />
20 </Extension> 23 </Extension>
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 @@
8 </Dependencies> 8 </Dependencies>
9 9
10 <Extension path="/OpenSim/AssetInventoryServer/MetricsProvider"> 10 <Extension path="/OpenSim/AssetInventoryServer/MetricsProvider">
11 <Plugin id="OpenSimMetrics" provider="OpenSim.Grid.AssetInventoryServer.Plugins.dll" type="OpenSim.Grid.AssetInventoryServer.Plugins.NullMetrics" /> 11 <Plugin id="AssetInventoryMetrics" provider="OpenSim.Grid.AssetInventoryServer.Plugins.dll" type="OpenSim.Grid.AssetInventoryServer.Plugins.NullMetricsPlugin" />
12 </Extension> 12 </Extension>
13</Addin> 13</Addin>
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 @@
10 <Extension path="/OpenSim/AssetInventoryServer/StorageProvider"> 10 <Extension path="/OpenSim/AssetInventoryServer/StorageProvider">
11 <Plugin id="SimpleAssetStorage" provider="OpenSim.Grid.AssetInventoryServer.Plugins.Simple.dll" type="OpenSim.Grid.AssetInventoryServer.Plugins.Simple.SimpleAssetStoragePlugin" /> 11 <Plugin id="SimpleAssetStorage" provider="OpenSim.Grid.AssetInventoryServer.Plugins.Simple.dll" type="OpenSim.Grid.AssetInventoryServer.Plugins.Simple.SimpleAssetStoragePlugin" />
12 </Extension> 12 </Extension>
13 <Extension path="/OpenSim/AssetInventoryServer/InventoryProvider">
14 <Plugin id="SimpleInventoryStorage" provider="OpenSim.Grid.AssetInventoryServer.Plugins.Simple.dll" type="OpenSim.Grid.AssetInventoryServer.Plugins.Simple.SimpleInventoryStoragePlugin" />
15 </Extension>
13</Addin> 16</Addin>
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 @@
1/*
2 * Copyright (c) 2008 Intel Corporation
3 * All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * -- Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * -- Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * -- Neither the name of the Intel Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30using System;
31using System.Collections.Generic;
32using System.Net;
33using System.IO;
34using System.Text;
35using ExtensionLoader;
36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
38using OpenSim.Framework;
39
40namespace OpenSim.Grid.AssetInventoryServer.Plugins.Simple
41{
42 public class SimpleInventoryStoragePlugin : IInventoryStorageProvider
43 {
44 const string EXTENSION_NAME = "SimpleInventoryStorage"; // Used for metrics reporting
45 const string DEFAULT_INVENTORY_DIR = "SimpleInventory";
46
47 AssetInventoryServer server;
48 Dictionary<Uri, InventoryCollection> inventories = new Dictionary<Uri, InventoryCollection>();
49 Dictionary<Uri, List<InventoryItem>> activeGestures = new Dictionary<Uri, List<InventoryItem>>();
50 Utils.InventoryItemSerializer itemSerializer = new Utils.InventoryItemSerializer();
51 Utils.InventoryFolderSerializer folderSerializer = new Utils.InventoryFolderSerializer();
52
53 public SimpleInventoryStoragePlugin()
54 {
55 }
56
57 #region Required Interfaces
58
59 public BackendResponse TryFetchItem(Uri owner, UUID itemID, out InventoryItem item)
60 {
61 item = null;
62 BackendResponse ret;
63
64 InventoryCollection collection;
65 if (inventories.TryGetValue(owner, out collection) && collection.Items.TryGetValue(itemID, out item))
66 ret = BackendResponse.Success;
67 else
68 ret = BackendResponse.NotFound;
69
70 server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now);
71 return ret;
72 }
73
74 public BackendResponse TryFetchFolder(Uri owner, UUID folderID, out InventoryFolder folder)
75 {
76 folder = null;
77 BackendResponse ret;
78
79 InventoryCollection collection;
80 if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder))
81 ret = BackendResponse.Success;
82 else
83 ret = BackendResponse.NotFound;
84
85 server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now);
86 return ret;
87 }
88
89 public BackendResponse TryFetchFolderContents(Uri owner, UUID folderID, out InventoryCollection contents)
90 {
91 contents = null;
92 BackendResponse ret;
93
94 InventoryCollection collection;
95 InventoryFolder folder;
96
97 if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder))
98 {
99 contents = new InventoryCollection();
100 contents.UserID = collection.UserID;
101 contents.Folders = new Dictionary<UUID, InventoryFolder>();
102 contents.Items = new Dictionary<UUID, InventoryItem>();
103
104 foreach (InventoryBase invBase in folder.Children.Values)
105 {
106 if (invBase is InventoryItem)
107 {
108 InventoryItem invItem = invBase as InventoryItem;
109 contents.Items.Add(invItem.ID, invItem);
110 }
111 else
112 {
113 InventoryFolder invFolder = invBase as InventoryFolder;
114 contents.Folders.Add(invFolder.ID, invFolder);
115 }
116 }
117
118 ret = BackendResponse.Success;
119 }
120 else
121 {
122 ret = BackendResponse.NotFound;
123 }
124
125 server.MetricsProvider.LogInventoryFetchFolderContents(EXTENSION_NAME, ret, owner, folderID, DateTime.Now);
126 return ret;
127 }
128
129 public BackendResponse TryFetchFolderList(Uri owner, out List<InventoryFolder> folders)
130 {
131 folders = null;
132 BackendResponse ret;
133
134 InventoryCollection collection;
135 if (inventories.TryGetValue(owner, out collection))
136 {
137 folders = new List<InventoryFolder>(collection.Folders.Values);
138 return BackendResponse.Success;
139 }
140 else
141 {
142 ret = BackendResponse.NotFound;
143 }
144
145 server.MetricsProvider.LogInventoryFetchFolderList(EXTENSION_NAME, ret, owner, DateTime.Now);
146 return ret;
147 }
148
149 public BackendResponse TryFetchInventory(Uri owner, out InventoryCollection inventory)
150 {
151 inventory = null;
152 BackendResponse ret;
153
154 if (inventories.TryGetValue(owner, out inventory))
155 ret = BackendResponse.Success;
156 else
157 ret = BackendResponse.NotFound;
158
159 server.MetricsProvider.LogInventoryFetchInventory(EXTENSION_NAME, ret, owner, DateTime.Now);
160 return ret;
161 }
162
163 public BackendResponse TryFetchActiveGestures(Uri owner, out List<InventoryItem> gestures)
164 {
165 gestures = null;
166 BackendResponse ret;
167
168 if (activeGestures.TryGetValue(owner, out gestures))
169 ret = BackendResponse.Success;
170 else
171 ret = BackendResponse.NotFound;
172
173 server.MetricsProvider.LogInventoryFetchActiveGestures(EXTENSION_NAME, ret, owner, DateTime.Now);
174 return ret;
175 }
176
177 public BackendResponse TryCreateItem(Uri owner, InventoryItem item)
178 {
179 BackendResponse ret;
180
181 InventoryCollection collection;
182 if (inventories.TryGetValue(owner, out collection))
183 {
184 // Delete this item first if it already exists
185 InventoryItem oldItem;
186 if (collection.Items.TryGetValue(item.ID, out oldItem))
187 TryDeleteItem(owner, item.ID);
188
189 try
190 {
191 // Create the file
192 SaveItem(item);
193
194 // Add the item to the collection
195 lock (collection) collection.Items[item.ID] = item;
196
197 // Add the item to its parent folder
198 InventoryFolder parent;
199 if (collection.Folders.TryGetValue(item.Folder, out parent))
200 lock (parent.Children) parent.Children.Add(item.ID, item);
201
202 // Add active gestures to our list
203 if (item.InvType == (int)InventoryType.Gesture && item.Flags == 1)
204 {
205 lock (activeGestures)
206 activeGestures[owner].Add(item);
207 }
208
209 ret = BackendResponse.Success;
210 }
211 catch (Exception ex)
212 {
213 Logger.Log.Error(ex.Message);
214 ret = BackendResponse.Failure;
215 }
216 }
217 else
218 {
219 return BackendResponse.NotFound;
220 }
221
222 server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, false, DateTime.Now);
223 return ret;
224 }
225
226 public BackendResponse TryCreateFolder(Uri owner, InventoryFolder folder)
227 {
228 BackendResponse ret;
229
230 InventoryCollection collection;
231 if (inventories.TryGetValue(owner, out collection))
232 {
233 // Delete this folder first if it already exists
234 InventoryFolder oldFolder;
235 if (collection.Folders.TryGetValue(folder.ID, out oldFolder))
236 TryDeleteFolder(owner, folder.ID);
237
238 try
239 {
240 // Create the file
241 SaveFolder(folder);
242
243 // Add the folder to the collection
244 lock (collection) collection.Folders[folder.ID] = folder;
245
246 // Add the folder to its parent folder
247 InventoryFolder parent;
248 if (collection.Folders.TryGetValue(folder.ParentID, out parent))
249 lock (parent.Children) parent.Children.Add(folder.ID, folder);
250
251 ret = BackendResponse.Success;
252 }
253 catch (Exception ex)
254 {
255 Logger.Log.Error(ex.Message);
256 ret = BackendResponse.Failure;
257 }
258 }
259 else
260 {
261 ret = BackendResponse.NotFound;
262 }
263
264 server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, true, DateTime.Now);
265 return ret;
266 }
267
268 public BackendResponse TryCreateInventory(Uri owner, InventoryFolder rootFolder)
269 {
270 BackendResponse ret;
271
272 lock (inventories)
273 {
274 if (!inventories.ContainsKey(owner))
275 {
276 InventoryCollection collection = new InventoryCollection();
277 collection.UserID = rootFolder.Owner;
278 collection.Folders = new Dictionary<UUID, InventoryFolder>();
279 collection.Folders.Add(rootFolder.ID, rootFolder);
280 collection.Items = new Dictionary<UUID, InventoryItem>();
281
282 inventories.Add(owner, collection);
283
284 ret = BackendResponse.Success;
285 }
286 else
287 {
288 ret = BackendResponse.Failure;
289 }
290 }
291
292 if (ret == BackendResponse.Success)
293 {
294 string path = Path.Combine(DEFAULT_INVENTORY_DIR, rootFolder.Owner.ToString());
295 try
296 {
297 // Create the directory for this agent
298 Directory.CreateDirectory(path);
299
300 // Create an index.txt containing the UUID and URI for this agent
301 string[] index = new string[] { rootFolder.Owner.ToString(), owner.ToString() };
302 File.WriteAllLines(Path.Combine(path, "index.txt"), index);
303
304 // Create the root folder file
305 SaveFolder(rootFolder);
306 }
307 catch (Exception ex)
308 {
309 Logger.Log.Error(ex.Message);
310 ret = BackendResponse.Failure;
311 }
312 }
313
314 server.MetricsProvider.LogInventoryCreateInventory(EXTENSION_NAME, ret, DateTime.Now);
315 return ret;
316 }
317
318 public BackendResponse TryDeleteItem(Uri owner, UUID itemID)
319 {
320 BackendResponse ret;
321
322 InventoryCollection collection;
323 InventoryItem item;
324 if (inventories.TryGetValue(owner, out collection) && collection.Items.TryGetValue(itemID, out item))
325 {
326 // Remove the item from its parent folder
327 InventoryFolder parent;
328 if (collection.Folders.TryGetValue(item.Folder, out parent))
329 lock (parent.Children) parent.Children.Remove(itemID);
330
331 // Remove the item from the collection
332 lock (collection) collection.Items.Remove(itemID);
333
334 // Remove from the active gestures list if applicable
335 if (item.InvType == (int)InventoryType.Gesture)
336 {
337 lock (activeGestures)
338 {
339 for (int i = 0; i < activeGestures[owner].Count; i++)
340 {
341 if (activeGestures[owner][i].ID == itemID)
342 {
343 activeGestures[owner].RemoveAt(i);
344 break;
345 }
346 }
347 }
348 }
349
350 // Delete the file. We don't know exactly what the file name is,
351 // so search for it
352 string path = PathFromURI(owner);
353 string[] matches = Directory.GetFiles(path, String.Format("*{0}.item", itemID), SearchOption.TopDirectoryOnly);
354 foreach (string match in matches)
355 {
356 try { File.Delete(match); }
357 catch (Exception ex) { Logger.Log.ErrorFormat("Failed to delete file {0}: {1}", match, ex.Message); }
358 }
359
360 ret = BackendResponse.Success;
361 }
362 else
363 {
364 ret = BackendResponse.NotFound;
365 }
366
367 server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now);
368 return ret;
369 }
370
371 public BackendResponse TryDeleteFolder(Uri owner, UUID folderID)
372 {
373 BackendResponse ret;
374
375 InventoryCollection collection;
376 InventoryFolder folder;
377 if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder))
378 {
379 // Remove the folder from its parent folder
380 InventoryFolder parent;
381 if (collection.Folders.TryGetValue(folder.ParentID, out parent))
382 lock (parent.Children) parent.Children.Remove(folderID);
383
384 // Remove the folder from the collection
385 lock (collection) collection.Items.Remove(folderID);
386
387 // Delete the folder file. We don't know exactly what the file name is,
388 // so search for it
389 string path = PathFromURI(owner);
390 string[] matches = Directory.GetFiles(path, String.Format("*{0}.folder", folderID), SearchOption.TopDirectoryOnly);
391 foreach (string match in matches)
392 {
393 try { File.Delete(match); }
394 catch (Exception ex) { Logger.Log.ErrorFormat("Failed to delete folder file {0}: {1}", match, ex.Message); }
395 }
396
397 ret = BackendResponse.Success;
398 }
399 else
400 {
401 ret = BackendResponse.NotFound;
402 }
403
404 server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now);
405 return ret;
406 }
407
408 public BackendResponse TryPurgeFolder(Uri owner, UUID folderID)
409 {
410 BackendResponse ret;
411
412 InventoryCollection collection;
413 InventoryFolder folder;
414 if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder))
415 {
416 // Delete all of the folder children
417 foreach (InventoryBase obj in new List<InventoryBase>(folder.Children.Values))
418 {
419 if (obj is InventoryItem)
420 {
421 TryDeleteItem(owner, (obj as InventoryItem).ID);
422 }
423 else
424 {
425 InventoryFolder childFolder = obj as InventoryFolder;
426 TryPurgeFolder(owner, childFolder.ID);
427 TryDeleteFolder(owner, childFolder.ID);
428 }
429 }
430
431 ret = BackendResponse.Success;
432 }
433 else
434 {
435 ret = BackendResponse.NotFound;
436 }
437
438 server.MetricsProvider.LogInventoryPurgeFolder(EXTENSION_NAME, ret, owner, folderID, DateTime.Now);
439 return ret;
440 }
441
442 #endregion Required Interfaces
443
444 void SaveItem(InventoryItem item)
445 {
446 string filename = String.Format("{0}-{1}.item", SanitizeFilename(item.Name), item.ID);
447
448 string path = Path.Combine(DEFAULT_INVENTORY_DIR, item.Owner.ToString());
449 path = Path.Combine(path, filename);
450
451 using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write))
452 {
453 itemSerializer.Serialize(stream, item);
454 stream.Flush();
455 }
456 }
457
458 void SaveFolder(InventoryFolder folder)
459 {
460 string filename = String.Format("{0}-{1}.folder", SanitizeFilename(folder.Name), folder.ID);
461
462 string path = Path.Combine(DEFAULT_INVENTORY_DIR, folder.Owner.ToString());
463 path = Path.Combine(path, filename);
464
465 using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write))
466 {
467 folderSerializer.Serialize(stream, folder);
468 stream.Flush();
469 }
470 }
471
472 string SanitizeFilename(string filename)
473 {
474 string output = filename;
475
476 if (output.Length > 64)
477 output = output.Substring(0, 64);
478
479 foreach (char i in Path.GetInvalidFileNameChars())
480 output = output.Replace(i, '_');
481
482 return output;
483 }
484
485 static string PathFromURI(Uri uri)
486 {
487 byte[] hash = OpenMetaverse.Utils.SHA1(Encoding.UTF8.GetBytes(uri.ToString()));
488 StringBuilder digest = new StringBuilder(40);
489
490 // Convert the hash to a hex string
491 foreach (byte b in hash)
492 digest.AppendFormat(OpenMetaverse.Utils.EnUsCulture, "{0:x2}", b);
493
494 return Path.Combine(DEFAULT_INVENTORY_DIR, digest.ToString());
495 }
496
497 void LoadFiles(string folder)
498 {
499 // Try to create the directory if it doesn't already exist
500 if (!Directory.Exists(folder))
501 {
502 try { Directory.CreateDirectory(folder); }
503 catch (Exception ex)
504 {
505 Logger.Log.Warn(ex.Message);
506 return;
507 }
508 }
509
510 try
511 {
512 string[] agentFolders = Directory.GetDirectories(DEFAULT_INVENTORY_DIR);
513
514 for (int i = 0; i < agentFolders.Length; i++)
515 {
516 string foldername = agentFolders[i];
517 string indexPath = Path.Combine(foldername, "index.txt");
518 UUID ownerID = UUID.Zero;
519 Uri owner = null;
520
521 try
522 {
523 string[] index = File.ReadAllLines(indexPath);
524 ownerID = UUID.Parse(index[0]);
525 owner = new Uri(index[1]);
526 }
527 catch (Exception ex)
528 {
529 Logger.Log.WarnFormat("Failed loading the index file {0}: {1}", indexPath, ex.Message);
530 }
531
532 if (ownerID != UUID.Zero && owner != null)
533 {
534 // Initialize the active gestures list for this agent
535 activeGestures.Add(owner, new List<InventoryItem>());
536
537 InventoryCollection collection = new InventoryCollection();
538 collection.UserID = ownerID;
539
540 // Load all of the folders for this agent
541 string[] folders = Directory.GetFiles(foldername, "*.folder", SearchOption.TopDirectoryOnly);
542 collection.Folders = new Dictionary<UUID,InventoryFolder>(folders.Length);
543
544 for (int j = 0; j < folders.Length; j++)
545 {
546 InventoryFolder invFolder = (InventoryFolder)folderSerializer.Deserialize(
547 new FileStream(folders[j], FileMode.Open, FileAccess.Read));
548 collection.Folders[invFolder.ID] = invFolder;
549 }
550
551 // Iterate over the folders collection, adding children to their parents
552 foreach (InventoryFolder invFolder in collection.Folders.Values)
553 {
554 InventoryFolder parent;
555 if (collection.Folders.TryGetValue(invFolder.ParentID, out parent))
556 parent.Children[invFolder.ID] = invFolder;
557 }
558
559 // Load all of the items for this agent
560 string[] files = Directory.GetFiles(foldername, "*.item", SearchOption.TopDirectoryOnly);
561 collection.Items = new Dictionary<UUID, InventoryItem>(files.Length);
562
563 for (int j = 0; j < files.Length; j++)
564 {
565 InventoryItem invItem = (InventoryItem)itemSerializer.Deserialize(
566 new FileStream(files[j], FileMode.Open, FileAccess.Read));
567 collection.Items[invItem.ID] = invItem;
568
569 // Add items to their parent folders
570 InventoryFolder parent;
571 if (collection.Folders.TryGetValue(invItem.Folder, out parent))
572 parent.Children[invItem.ID] = invItem;
573
574 // Add active gestures to our list
575 if (invItem.InvType == (int)InventoryType.Gesture && invItem.Flags != 0)
576 activeGestures[owner].Add(invItem);
577 }
578
579 inventories.Add(owner, collection);
580 }
581 }
582 }
583 catch (Exception ex)
584 {
585 Logger.Log.ErrorFormat("Failed loading inventory from {0}: {1}", folder, ex.Message);
586 }
587 }
588
589 #region IPlugin implementation
590
591 public void Initialise(AssetInventoryServer server)
592 {
593 this.server = server;
594
595 LoadFiles(DEFAULT_INVENTORY_DIR);
596
597 Logger.Log.InfoFormat("Initialized the inventory index with data for {0} avatars",
598 inventories.Count);
599 }
600
601 /// <summary>
602 /// <para>Initialises asset interface</para>
603 /// </summary>
604 public void Initialise()
605 {
606 Logger.Log.InfoFormat("[ASSET]: {0} cannot be default-initialized!", Name);
607 throw new PluginNotInitialisedException(Name);
608 }
609
610 public void Dispose()
611 {
612 }
613
614 public string Version
615 {
616 // TODO: this should be something meaningful and not hardcoded?
617 get { return "0.1"; }
618 }
619
620 public string Name
621 {
622 get { return "AssetInventoryServer Simple inventory storage provider"; }
623 }
624
625 #endregion IPlugin implementation
626 }
627}