clockwerk-opensim-stable – Blame information for rev 3

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections.Generic;
30 using System.IO;
31 using System.Reflection;
32 using log4net;
33 using NDesk.Options;
34 using Nini.Config;
35 using OpenMetaverse;
36 using OpenSim.Framework;
37 using OpenSim.Framework.Communications;
38 using OpenSim.Framework.Console;
39 using OpenSim.Region.Framework.Interfaces;
40 using OpenSim.Region.Framework.Scenes;
41 using OpenSim.Services.Interfaces;
42 using Mono.Addins;
43  
44 namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
45 {
46 /// <summary>
47 /// This module loads and saves OpenSimulator inventory archives
48 /// </summary>
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "InventoryArchiverModule")]
50 public class InventoryArchiverModule : ISharedRegionModule, IInventoryArchiverModule
51 {
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53  
54 /// <value>
55 /// Enable or disable checking whether the iar user is actually logged in
56 /// </value>
57 // public bool DisablePresenceChecks { get; set; }
58  
59 public event InventoryArchiveSaved OnInventoryArchiveSaved;
60  
61 /// <summary>
62 /// The file to load and save inventory if no filename has been specified
63 /// </summary>
64 protected const string DEFAULT_INV_BACKUP_FILENAME = "user-inventory.iar";
65  
66 /// <value>
67 /// Pending save completions initiated from the console
68 /// </value>
69 protected List<Guid> m_pendingConsoleSaves = new List<Guid>();
70  
71 /// <value>
72 /// All scenes that this module knows about
73 /// </value>
74 private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
75 private Scene m_aScene;
76  
77 private IUserAccountService m_UserAccountService;
78 protected IUserAccountService UserAccountService
79 {
80 get
81 {
82 if (m_UserAccountService == null)
83 // What a strange thing to do...
84 foreach (Scene s in m_scenes.Values)
85 {
86 m_UserAccountService = s.RequestModuleInterface<IUserAccountService>();
87 break;
88 }
89  
90 return m_UserAccountService;
91 }
92 }
93  
94  
95 public InventoryArchiverModule() {}
96  
97 // public InventoryArchiverModule(bool disablePresenceChecks)
98 // {
99 // DisablePresenceChecks = disablePresenceChecks;
100 // }
101  
102 #region ISharedRegionModule
103  
104 public void Initialise(IConfigSource source)
105 {
106 }
107  
108 public void AddRegion(Scene scene)
109 {
110 if (m_scenes.Count == 0)
111 {
112 scene.RegisterModuleInterface<IInventoryArchiverModule>(this);
113 OnInventoryArchiveSaved += SaveInvConsoleCommandCompleted;
114  
115 scene.AddCommand(
116 "Archiving", this, "load iar",
3 vero 117 "load iar [-m|--merge] <first> <last> <inventory path> [<IAR path>]",
1 vero 118 "Load user inventory archive (IAR).",
119 "-m|--merge is an option which merges the loaded IAR with existing inventory folders where possible, rather than always creating new ones"
120 + "<first> is user's first name." + Environment.NewLine
121 + "<last> is user's last name." + Environment.NewLine
122 + "<inventory path> is the path inside the user's inventory where the IAR should be loaded." + Environment.NewLine
123 + "<IAR path> is the filesystem path or URI from which to load the IAR."
124 + string.Format(" If this is not given then the filename {0} in the current directory is used", DEFAULT_INV_BACKUP_FILENAME),
125 HandleLoadInvConsoleCommand);
126  
127 scene.AddCommand(
128 "Archiving", this, "save iar",
3 vero 129 "save iar [-h|--home=<url>] [--noassets] <first> <last> <inventory path> [<IAR path>] [-c|--creators] [-e|--exclude=<name/uuid>] [-f|--excludefolder=<foldername/uuid>] [-v|--verbose]",
1 vero 130 "Save user inventory archive (IAR).",
131 "<first> is the user's first name.\n"
132 + "<last> is the user's last name.\n"
133 + "<inventory path> is the path inside the user's inventory for the folder/item to be saved.\n"
134 + "<IAR path> is the filesystem path at which to save the IAR."
135 + string.Format(" If this is not given then the filename {0} in the current directory is used.\n", DEFAULT_INV_BACKUP_FILENAME)
136 + "-h|--home=<url> adds the url of the profile service to the saved user information.\n"
137 + "-c|--creators preserves information about foreign creators.\n"
138 + "-e|--exclude=<name/uuid> don't save the inventory item in archive" + Environment.NewLine
139 + "-f|--excludefolder=<folder/uuid> don't save contents of the folder in archive" + Environment.NewLine
140 + "-v|--verbose extra debug messages.\n"
141 + "--noassets stops assets being saved to the IAR.",
142 HandleSaveInvConsoleCommand);
143  
144 m_aScene = scene;
145 }
146  
147 m_scenes[scene.RegionInfo.RegionID] = scene;
148 }
149  
150 public void RemoveRegion(Scene scene)
151 {
152 }
153  
154 public void Close() {}
155  
156 public void RegionLoaded(Scene scene)
157 {
158 }
159  
160 public void PostInitialise()
161 {
162 }
163  
164 public Type ReplaceableInterface
165 {
166 get { return null; }
167 }
168  
169 public string Name { get { return "Inventory Archiver Module"; } }
170  
171 #endregion
172  
173 /// <summary>
174 /// Trigger the inventory archive saved event.
175 /// </summary>
176 protected internal void TriggerInventoryArchiveSaved(
177 Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream,
178 Exception reportedException)
179 {
180 InventoryArchiveSaved handlerInventoryArchiveSaved = OnInventoryArchiveSaved;
181 if (handlerInventoryArchiveSaved != null)
182 handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException);
183 }
184  
185 public bool ArchiveInventory(
3 vero 186 Guid id, string firstName, string lastName, string invPath, Stream saveStream)
1 vero 187 {
3 vero 188 return ArchiveInventory(id, firstName, lastName, invPath, saveStream, new Dictionary<string, object>());
1 vero 189 }
190  
191 public bool ArchiveInventory(
3 vero 192 Guid id, string firstName, string lastName, string invPath, Stream saveStream,
1 vero 193 Dictionary<string, object> options)
194 {
195 if (m_scenes.Count > 0)
196 {
3 vero 197 UserAccount userInfo = GetUserInfo(firstName, lastName);
1 vero 198  
199 if (userInfo != null)
200 {
201 // if (CheckPresence(userInfo.PrincipalID))
202 // {
203 try
204 {
205 new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, saveStream).Execute(options, UserAccountService);
206 }
207 catch (EntryPointNotFoundException e)
208 {
209 m_log.ErrorFormat(
210 "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
211 + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
212 m_log.Error(e);
213  
214 return false;
215 }
216  
217 return true;
218 // }
219 // else
220 // {
221 // m_log.ErrorFormat(
222 // "[INVENTORY ARCHIVER]: User {0} {1} {2} not logged in to this region simulator",
223 // userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID);
224 // }
225 }
226 }
227  
228 return false;
229 }
230  
231 public bool ArchiveInventory(
3 vero 232 Guid id, string firstName, string lastName, string invPath, string savePath,
1 vero 233 Dictionary<string, object> options)
234 {
235 // if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath))
236 // return false;
237  
238 if (m_scenes.Count > 0)
239 {
3 vero 240 UserAccount userInfo = GetUserInfo(firstName, lastName);
1 vero 241  
242 if (userInfo != null)
243 {
244 // if (CheckPresence(userInfo.PrincipalID))
245 // {
246 try
247 {
248 new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, savePath).Execute(options, UserAccountService);
249 }
250 catch (EntryPointNotFoundException e)
251 {
252 m_log.ErrorFormat(
253 "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
254 + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
255 m_log.Error(e);
256  
257 return false;
258 }
259  
260 return true;
261 // }
262 // else
263 // {
264 // m_log.ErrorFormat(
265 // "[INVENTORY ARCHIVER]: User {0} {1} {2} not logged in to this region simulator",
266 // userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID);
267 // }
268 }
269 }
270  
271 return false;
272 }
273  
3 vero 274 public bool DearchiveInventory(string firstName, string lastName, string invPath, Stream loadStream)
1 vero 275 {
3 vero 276 return DearchiveInventory(firstName, lastName, invPath, loadStream, new Dictionary<string, object>());
1 vero 277 }
278  
279 public bool DearchiveInventory(
3 vero 280 string firstName, string lastName, string invPath, Stream loadStream,
1 vero 281 Dictionary<string, object> options)
282 {
283 if (m_scenes.Count > 0)
284 {
3 vero 285 UserAccount userInfo = GetUserInfo(firstName, lastName);
1 vero 286  
287 if (userInfo != null)
288 {
289 // if (CheckPresence(userInfo.PrincipalID))
290 // {
291 InventoryArchiveReadRequest request;
292 bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false);
293  
294 try
295 {
296 request = new InventoryArchiveReadRequest(m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadStream, merge);
297 }
298 catch (EntryPointNotFoundException e)
299 {
300 m_log.ErrorFormat(
301 "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
302 + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
303 m_log.Error(e);
304  
305 return false;
306 }
307  
308 UpdateClientWithLoadedNodes(userInfo, request.Execute());
309  
310 return true;
311 // }
312 // else
313 // {
314 // m_log.ErrorFormat(
315 // "[INVENTORY ARCHIVER]: User {0} {1} {2} not logged in to this region simulator",
316 // userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID);
317 // }
318 }
319 else
320 m_log.ErrorFormat("[INVENTORY ARCHIVER]: User {0} {1} not found",
321 firstName, lastName);
322 }
323  
324 return false;
325 }
326  
327 public bool DearchiveInventory(
3 vero 328 string firstName, string lastName, string invPath, string loadPath,
1 vero 329 Dictionary<string, object> options)
330 {
331 if (m_scenes.Count > 0)
332 {
3 vero 333 UserAccount userInfo = GetUserInfo(firstName, lastName);
1 vero 334  
335 if (userInfo != null)
336 {
337 // if (CheckPresence(userInfo.PrincipalID))
338 // {
339 InventoryArchiveReadRequest request;
340 bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false);
341  
342 try
343 {
344 request = new InventoryArchiveReadRequest(m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadPath, merge);
345 }
346 catch (EntryPointNotFoundException e)
347 {
348 m_log.ErrorFormat(
349 "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
350 + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
351 m_log.Error(e);
352  
353 return false;
354 }
355  
356 UpdateClientWithLoadedNodes(userInfo, request.Execute());
357  
358 return true;
359 // }
360 // else
361 // {
362 // m_log.ErrorFormat(
363 // "[INVENTORY ARCHIVER]: User {0} {1} {2} not logged in to this region simulator",
364 // userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID);
365 // }
366 }
367 }
368  
369 return false;
370 }
371  
372 /// <summary>
373 /// Load inventory from an inventory file archive
374 /// </summary>
375 /// <param name="cmdparams"></param>
376 protected void HandleLoadInvConsoleCommand(string module, string[] cmdparams)
377 {
378 try
379 {
380 Dictionary<string, object> options = new Dictionary<string, object>();
381 OptionSet optionSet = new OptionSet().Add("m|merge", delegate (string v) { options["merge"] = v != null; });
382  
383 List<string> mainParams = optionSet.Parse(cmdparams);
384  
3 vero 385 if (mainParams.Count < 5)
1 vero 386 {
387 m_log.Error(
3 vero 388 "[INVENTORY ARCHIVER]: usage is load iar [-m|--merge] <first name> <last name> <inventory path> [<load file path>]");
1 vero 389 return;
390 }
391  
392 string firstName = mainParams[2];
393 string lastName = mainParams[3];
394 string invPath = mainParams[4];
3 vero 395 string loadPath = (mainParams.Count > 5 ? mainParams[5] : DEFAULT_INV_BACKUP_FILENAME);
1 vero 396  
397 m_log.InfoFormat(
398 "[INVENTORY ARCHIVER]: Loading archive {0} to inventory path {1} for {2} {3}",
399 loadPath, invPath, firstName, lastName);
400  
3 vero 401 if (DearchiveInventory(firstName, lastName, invPath, loadPath, options))
1 vero 402 m_log.InfoFormat(
403 "[INVENTORY ARCHIVER]: Loaded archive {0} for {1} {2}",
404 loadPath, firstName, lastName);
405 }
406 catch (InventoryArchiverException e)
407 {
408 m_log.ErrorFormat("[INVENTORY ARCHIVER]: {0}", e.Message);
409 }
410 }
411  
412 /// <summary>
413 /// Save inventory to a file archive
414 /// </summary>
415 /// <param name="cmdparams"></param>
416 protected void HandleSaveInvConsoleCommand(string module, string[] cmdparams)
417 {
418 Guid id = Guid.NewGuid();
419  
420 Dictionary<string, object> options = new Dictionary<string, object>();
421  
422 OptionSet ops = new OptionSet();
423 //ops.Add("v|version=", delegate(string v) { options["version"] = v; });
424 ops.Add("h|home=", delegate(string v) { options["home"] = v; });
425 ops.Add("v|verbose", delegate(string v) { options["verbose"] = v; });
426 ops.Add("c|creators", delegate(string v) { options["creators"] = v; });
427 ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; });
428 ops.Add("e|exclude=", delegate(string v)
429 {
430 if (!options.ContainsKey("exclude"))
431 options["exclude"] = new List<String>();
432 ((List<String>)options["exclude"]).Add(v);
433 });
434 ops.Add("f|excludefolder=", delegate(string v)
435 {
436 if (!options.ContainsKey("excludefolders"))
437 options["excludefolders"] = new List<String>();
438 ((List<String>)options["excludefolders"]).Add(v);
439 });
440  
441 List<string> mainParams = ops.Parse(cmdparams);
442  
443 try
444 {
3 vero 445 if (mainParams.Count < 5)
1 vero 446 {
447 m_log.Error(
3 vero 448 "[INVENTORY ARCHIVER]: save iar [-h|--home=<url>] [--noassets] <first> <last> <inventory path> [<IAR path>] [-c|--creators] [-e|--exclude=<name/uuid>] [-f|--excludefolder=<foldername/uuid>] [-v|--verbose]");
1 vero 449 return;
450 }
451  
452 if (options.ContainsKey("home"))
453 m_log.WarnFormat("[INVENTORY ARCHIVER]: Please be aware that inventory archives with creator information are not compatible with OpenSim 0.7.0.2 and earlier. Do not use the -home option if you want to produce a compatible IAR");
454  
455 string firstName = mainParams[2];
456 string lastName = mainParams[3];
457 string invPath = mainParams[4];
3 vero 458 string savePath = (mainParams.Count > 5 ? mainParams[5] : DEFAULT_INV_BACKUP_FILENAME);
1 vero 459  
460 m_log.InfoFormat(
461 "[INVENTORY ARCHIVER]: Saving archive {0} using inventory path {1} for {2} {3}",
462 savePath, invPath, firstName, lastName);
463  
464 lock (m_pendingConsoleSaves)
465 m_pendingConsoleSaves.Add(id);
466  
3 vero 467 ArchiveInventory(id, firstName, lastName, invPath, savePath, options);
1 vero 468 }
469 catch (InventoryArchiverException e)
470 {
471 m_log.ErrorFormat("[INVENTORY ARCHIVER]: {0}", e.Message);
472 }
473 }
474  
475 private void SaveInvConsoleCommandCompleted(
476 Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream,
477 Exception reportedException)
478 {
479 lock (m_pendingConsoleSaves)
480 {
481 if (m_pendingConsoleSaves.Contains(id))
482 m_pendingConsoleSaves.Remove(id);
483 else
484 return;
485 }
486  
487 if (succeeded)
488 {
489 m_log.InfoFormat("[INVENTORY ARCHIVER]: Saved archive for {0} {1}", userInfo.FirstName, userInfo.LastName);
490 }
491 else
492 {
493 m_log.ErrorFormat(
494 "[INVENTORY ARCHIVER]: Archive save for {0} {1} failed - {2}",
495 userInfo.FirstName, userInfo.LastName, reportedException.Message);
496 }
497 }
498  
499 /// <summary>
500 /// Get user information for the given name.
501 /// </summary>
502 /// <param name="firstName"></param>
503 /// <param name="lastName"></param>
504 /// <returns></returns>
3 vero 505 protected UserAccount GetUserInfo(string firstName, string lastName)
1 vero 506 {
507 UserAccount account
508 = m_aScene.UserAccountService.GetUserAccount(m_aScene.RegionInfo.ScopeID, firstName, lastName);
509  
510 if (null == account)
511 {
512 m_log.ErrorFormat(
513 "[INVENTORY ARCHIVER]: Failed to find user info for {0} {1}",
514 firstName, lastName);
515 return null;
516 }
3 vero 517 return account;
1 vero 518 }
519  
520 /// <summary>
521 /// Notify the client of loaded nodes if they are logged in
522 /// </summary>
523 /// <param name="loadedNodes">Can be empty. In which case, nothing happens</param>
524 private void UpdateClientWithLoadedNodes(UserAccount userInfo, HashSet<InventoryNodeBase> loadedNodes)
525 {
526 if (loadedNodes.Count == 0)
527 return;
528  
529 foreach (Scene scene in m_scenes.Values)
530 {
531 ScenePresence user = scene.GetScenePresence(userInfo.PrincipalID);
532  
533 if (user != null && !user.IsChildAgent)
534 {
535 foreach (InventoryNodeBase node in loadedNodes)
536 {
537 // m_log.DebugFormat(
538 // "[INVENTORY ARCHIVER]: Notifying {0} of loaded inventory node {1}",
539 // user.Name, node.Name);
540  
541 user.ControllingClient.SendBulkUpdateInventory(node);
542 }
543  
544 break;
545 }
546 }
547 }
548  
549 // /// <summary>
550 // /// Check if the given user is present in any of the scenes.
551 // /// </summary>
552 // /// <param name="userId">The user to check</param>
553 // /// <returns>true if the user is in any of the scenes, false otherwise</returns>
554 // protected bool CheckPresence(UUID userId)
555 // {
556 // if (DisablePresenceChecks)
557 // return true;
558 //
559 // foreach (Scene scene in m_scenes.Values)
560 // {
561 // ScenePresence p;
562 // if ((p = scene.GetScenePresence(userId)) != null)
563 // {
564 // p.ControllingClient.SendAgentAlertMessage("Inventory operation has been started", false);
565 // return true;
566 // }
567 // }
568 //
569 // return false;
570 // }
571 }
572 }