ArchiveWriteRequestPreparation.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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 OpenSim 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. using OpenSim.Framework;
  28. using OpenSim.Framework.Communications.Cache;
  29. using OpenSim.Region.Environment.Interfaces;
  30. using OpenSim.Region.Environment.Modules.World.Serialiser;
  31. using OpenSim.Region.Environment.Modules.World.Terrain;
  32. using OpenSim.Region.Environment.Scenes;
  33. using System;
  34. using System.Collections.Generic;
  35. using System.Reflection;
  36. //using System.Text;
  37. using System.Text.RegularExpressions;
  38. using System.Threading;
  39. using OpenMetaverse;
  40. using log4net;
  41. using Nini.Config;
  42. namespace OpenSim.Region.Environment.Modules.World.Archiver
  43. {
  44. /// <summary>
  45. /// Prepare to write out an archive.
  46. /// </summary>
  47. public class ArchiveWriteRequestPreparation
  48. {
  49. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  50. protected Scene m_scene;
  51. protected string m_savePath;
  52. /// <summary>
  53. /// Used as a temporary store of an asset which represents an object. This can be a null if no appropriate
  54. /// asset was found by the asset service.
  55. /// </summary>
  56. protected AssetBase m_requestedObjectAsset;
  57. /// <summary>
  58. /// Signal whether we are currently waiting for the asset service to deliver an asset.
  59. /// </summary>
  60. protected bool m_waitingForObjectAsset;
  61. /// <summary>
  62. /// Constructor
  63. /// </summary>
  64. public ArchiveWriteRequestPreparation(Scene scene, string savePath)
  65. {
  66. m_scene = scene;
  67. m_savePath = savePath;
  68. }
  69. /// <summary>
  70. /// The callback made when we request the asset for an object from the asset service.
  71. /// </summary>
  72. public void AssetRequestCallback(UUID assetID, AssetBase asset)
  73. {
  74. lock (this)
  75. {
  76. m_requestedObjectAsset = asset;
  77. m_waitingForObjectAsset = false;
  78. Monitor.Pulse(this);
  79. }
  80. }
  81. /// <summary>
  82. /// Get an asset synchronously, potentially using an asynchronous callback. If the
  83. /// asynchronous callback is used, we will wait for it to complete.
  84. /// </summary>
  85. /// <param name="uuid"></param>
  86. /// <returns></returns>
  87. protected AssetBase GetAsset(UUID uuid)
  88. {
  89. m_waitingForObjectAsset = true;
  90. m_scene.AssetCache.GetAsset(uuid, AssetRequestCallback, true);
  91. // The asset cache callback can either
  92. //
  93. // 1. Complete on the same thread (if the asset is already in the cache) or
  94. // 2. Come in via a different thread (if we need to go fetch it).
  95. //
  96. // The code below handles both these alternatives.
  97. lock (this)
  98. {
  99. if (m_waitingForObjectAsset)
  100. {
  101. Monitor.Wait(this);
  102. m_waitingForObjectAsset = false;
  103. }
  104. }
  105. return m_requestedObjectAsset;
  106. }
  107. /// <summary>
  108. /// Record the asset uuids embedded within the given script.
  109. /// </summary>
  110. /// <param name="scriptUuid"></param>
  111. /// <param name="assetUuids">Dictionary in which to record the references</param>
  112. protected void GetScriptAssetUuids(UUID scriptUuid, IDictionary<UUID, int> assetUuids)
  113. {
  114. AssetBase scriptAsset = GetAsset(scriptUuid);
  115. if (null != scriptAsset)
  116. {
  117. string script = Utils.BytesToString(scriptAsset.Data);
  118. //m_log.DebugFormat("[ARCHIVER]: Script {0}", script);
  119. MatchCollection uuidMatches = Util.UUIDPattern.Matches(script);
  120. //m_log.DebugFormat("[ARCHIVER]: Found {0} matches in script", uuidMatches.Count);
  121. foreach (Match uuidMatch in uuidMatches)
  122. {
  123. UUID uuid = new UUID(uuidMatch.Value);
  124. //m_log.DebugFormat("[ARCHIVER]: Recording {0} in script", uuid);
  125. assetUuids[uuid] = 1;
  126. }
  127. }
  128. }
  129. /// <summary>
  130. /// Record the uuids referenced by the given wearable asset
  131. /// </summary>
  132. /// <param name="wearableAssetUuid"></param>
  133. /// <param name="assetUuids">Dictionary in which to record the references</param>
  134. protected void GetWearableAssetUuids(UUID wearableAssetUuid, IDictionary<UUID, int> assetUuids)
  135. {
  136. AssetBase assetBase = GetAsset(wearableAssetUuid);
  137. //m_log.Debug(new System.Text.ASCIIEncoding().GetString(bodypartAsset.Data));
  138. AssetWearable wearableAsset = new AssetBodypart(wearableAssetUuid, assetBase.Data);
  139. wearableAsset.Decode();
  140. //m_log.DebugFormat(
  141. // "[ARCHIVER]: Wearable asset {0} references {1} assets", wearableAssetUuid, wearableAsset.Textures.Count);
  142. foreach (UUID uuid in wearableAsset.Textures.Values)
  143. {
  144. //m_log.DebugFormat("[ARCHIVER]: Got bodypart uuid {0}", uuid);
  145. assetUuids[uuid] = 1;
  146. }
  147. }
  148. /// <summary>
  149. /// Get all the asset uuids associated with a given object. This includes both those directly associated with
  150. /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
  151. /// within this object).
  152. /// </summary>
  153. /// <param name="sceneObject"></param>
  154. /// <param name="assetUuids"></param>
  155. protected void GetSceneObjectAssetUuids(UUID sceneObjectUuid, IDictionary<UUID, int> assetUuids)
  156. {
  157. AssetBase objectAsset = GetAsset(sceneObjectUuid);
  158. if (null != objectAsset)
  159. {
  160. string xml = Utils.BytesToString(objectAsset.Data);
  161. SceneObjectGroup sog = new SceneObjectGroup(xml, true);
  162. GetSceneObjectAssetUuids(sog, assetUuids);
  163. }
  164. }
  165. /// <summary>
  166. /// Get all the asset uuids associated with a given object. This includes both those directly associated with
  167. /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
  168. /// within this object).
  169. /// </summary>
  170. /// <param name="sceneObject"></param>
  171. /// <param name="assetUuids"></param>
  172. protected void GetSceneObjectAssetUuids(SceneObjectGroup sceneObject, IDictionary<UUID, int> assetUuids)
  173. {
  174. m_log.DebugFormat(
  175. "[ARCHIVER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID);
  176. foreach (SceneObjectPart part in sceneObject.GetParts())
  177. {
  178. //m_log.DebugFormat(
  179. // "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID);
  180. try
  181. {
  182. Primitive.TextureEntry textureEntry = part.Shape.Textures;
  183. // Get the prim's default texture. This will be used for faces which don't have their own texture
  184. assetUuids[textureEntry.DefaultTexture.TextureID] = 1;
  185. if (part.Shape.SculptTexture != UUID.Zero)
  186. assetUuids[part.Shape.SculptTexture] = 1;
  187. // XXX: Not a great way to iterate through face textures, but there's no
  188. // other method available to tell how many faces there actually are
  189. //int i = 0;
  190. foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures)
  191. {
  192. if (texture != null)
  193. {
  194. //m_log.DebugFormat("[ARCHIVER]: Got face {0}", i++);
  195. assetUuids[texture.TextureID] = 1;
  196. }
  197. }
  198. foreach (TaskInventoryItem tii in part.TaskInventory.Values)
  199. {
  200. //m_log.DebugFormat("[ARCHIVER]: Analysing item asset type {0}", tii.Type);
  201. if (!assetUuids.ContainsKey(tii.AssetID))
  202. {
  203. assetUuids[tii.AssetID] = 1;
  204. if ((int)AssetType.Bodypart == tii.Type || ((int)AssetType.Clothing == tii.Type))
  205. {
  206. GetWearableAssetUuids(tii.AssetID, assetUuids);
  207. }
  208. else if ((int)AssetType.LSLText == tii.Type)
  209. {
  210. GetScriptAssetUuids(tii.AssetID, assetUuids);
  211. }
  212. else if ((int)AssetType.Object == tii.Type)
  213. {
  214. GetSceneObjectAssetUuids(tii.AssetID, assetUuids);
  215. }
  216. else
  217. {
  218. //m_log.DebugFormat("[ARCHIVER]: Recording asset {0} in object {1}", tii.AssetID, part.UUID);
  219. }
  220. }
  221. }
  222. }
  223. catch (Exception e)
  224. {
  225. m_log.ErrorFormat("[ARCHIVER]: Failed to get part - {0}", e);
  226. m_log.DebugFormat("[ARCHIVER]: Texture entry length for prim was {0} (min is 46)", part.Shape.TextureEntry.Length);
  227. }
  228. }
  229. }
  230. public void ArchiveRegion()
  231. {
  232. Dictionary<UUID, int> assetUuids = new Dictionary<UUID, int>();
  233. List<EntityBase> entities = m_scene.GetEntities();
  234. List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
  235. // Filter entities so that we only have scene objects.
  236. // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods
  237. // end up having to do this
  238. foreach (EntityBase entity in entities)
  239. {
  240. if (entity is SceneObjectGroup)
  241. {
  242. SceneObjectGroup sceneObject = (SceneObjectGroup)entity;
  243. if (!sceneObject.IsDeleted && !sceneObject.IsAttachment)
  244. sceneObjects.Add((SceneObjectGroup)entity);
  245. }
  246. }
  247. foreach (SceneObjectGroup sceneObject in sceneObjects)
  248. {
  249. GetSceneObjectAssetUuids(sceneObject, assetUuids);
  250. }
  251. m_log.DebugFormat(
  252. "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets",
  253. sceneObjects.Count, assetUuids.Count);
  254. // Asynchronously request all the assets required to perform this archive operation
  255. ArchiveWriteRequestExecution awre
  256. = new ArchiveWriteRequestExecution(
  257. sceneObjects,
  258. m_scene.RequestModuleInterface<ITerrainModule>(),
  259. m_scene.RequestModuleInterface<IRegionSerialiserModule>(),
  260. m_scene.RegionInfo.RegionName,
  261. m_savePath);
  262. new AssetsRequest(assetUuids.Keys, m_scene.AssetCache, awre.ReceivedAllAssets).Execute();
  263. }
  264. }
  265. }