aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Grid/AssetInventoryServer/Plugins/Simple/SimpleInventoryStoragePlugin.cs
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/Simple/SimpleInventoryStoragePlugin.cs
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/Simple/SimpleInventoryStoragePlugin.cs')
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Plugins/Simple/SimpleInventoryStoragePlugin.cs627
1 files changed, 627 insertions, 0 deletions
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}