HGAssetMapper.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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. using System;
  28. using System.Collections.Generic;
  29. using System.IO;
  30. using System.Reflection;
  31. using System.Threading;
  32. using System.Xml;
  33. using log4net;
  34. using OpenMetaverse;
  35. using OpenSim.Framework;
  36. using OpenSim.Region.Framework.Scenes;
  37. using OpenSim.Region.Framework.Scenes.Serialization;
  38. using OpenSim.Region.Framework.Interfaces;
  39. using OpenSim.Services.Interfaces;
  40. //using HyperGrid.Framework;
  41. //using OpenSim.Region.Communications.Hypergrid;
  42. namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
  43. {
  44. public class HGAssetMapper
  45. {
  46. #region Fields
  47. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  48. // This maps between inventory server urls and inventory server clients
  49. // private Dictionary<string, InventoryClient> m_inventoryServers = new Dictionary<string, InventoryClient>();
  50. private Scene m_scene;
  51. private string m_HomeURI;
  52. #endregion
  53. #region Constructor
  54. public HGAssetMapper(Scene scene, string homeURL)
  55. {
  56. m_scene = scene;
  57. m_HomeURI = homeURL;
  58. }
  59. #endregion
  60. #region Internal functions
  61. private AssetMetadata FetchMetadata(string url, UUID assetID)
  62. {
  63. if (string.IsNullOrEmpty(url))
  64. return null;
  65. if (!url.EndsWith("/") && !url.EndsWith("="))
  66. url = url + "/";
  67. AssetMetadata meta = m_scene.AssetService.GetMetadata(url + assetID.ToString());
  68. if (meta != null)
  69. m_log.DebugFormat("[HG ASSET MAPPER]: Fetched metadata for asset {0} of type {1} from {2} ", assetID, meta.Type, url);
  70. else
  71. m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetched metadata for asset {0} from {1} ", assetID, url);
  72. return meta;
  73. }
  74. private AssetBase FetchAsset(string url, UUID assetID)
  75. {
  76. // Test if it's already here
  77. AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
  78. if (asset == null)
  79. {
  80. if (string.IsNullOrEmpty(url))
  81. return null;
  82. if (!url.EndsWith("/") && !url.EndsWith("="))
  83. url = url + "/";
  84. asset = m_scene.AssetService.Get(url + assetID.ToString());
  85. //if (asset != null)
  86. // m_log.DebugFormat("[HG ASSET MAPPER]: Fetched asset {0} of type {1} from {2} ", assetID, asset.Metadata.Type, url);
  87. //else
  88. // m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetch asset {0} from {1} ", assetID, url);
  89. }
  90. return asset;
  91. }
  92. public bool PostAsset(string url, AssetBase asset)
  93. {
  94. if (string.IsNullOrEmpty(url))
  95. return false;
  96. if (asset != null)
  97. {
  98. if (!url.EndsWith("/") && !url.EndsWith("="))
  99. url = url + "/";
  100. bool success = true;
  101. // See long comment in AssetCache.AddAsset
  102. if (!asset.Temporary || asset.Local)
  103. {
  104. // We need to copy the asset into a new asset, because
  105. // we need to set its ID to be URL+UUID, so that the
  106. // HGAssetService dispatches it to the remote grid.
  107. // It's not pretty, but the best that can be done while
  108. // not having a global naming infrastructure
  109. AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID);
  110. Copy(asset, asset1);
  111. asset1.ID = url + asset.ID;
  112. AdjustIdentifiers(asset1.Metadata);
  113. if (asset1.Metadata.Type == (sbyte)AssetType.Object)
  114. asset1.Data = AdjustIdentifiers(asset.Data);
  115. else
  116. asset1.Data = asset.Data;
  117. string id = m_scene.AssetService.Store(asset1);
  118. if (id == string.Empty)
  119. {
  120. m_log.DebugFormat("[HG ASSET MAPPER]: Asset server {0} did not accept {1}", url, asset.ID);
  121. success = false;
  122. }
  123. else
  124. m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
  125. }
  126. return success;
  127. }
  128. else
  129. m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache.");
  130. return false;
  131. }
  132. private void Copy(AssetBase from, AssetBase to)
  133. {
  134. //to.Data = from.Data; // don't copy this, it's copied elsewhere
  135. to.Description = from.Description;
  136. to.FullID = from.FullID;
  137. to.ID = from.ID;
  138. to.Local = from.Local;
  139. to.Name = from.Name;
  140. to.Temporary = from.Temporary;
  141. to.Type = from.Type;
  142. }
  143. private void AdjustIdentifiers(AssetMetadata meta)
  144. {
  145. if (meta.CreatorID != null && meta.CreatorID != string.Empty)
  146. {
  147. UUID uuid = UUID.Zero;
  148. UUID.TryParse(meta.CreatorID, out uuid);
  149. UserAccount creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid);
  150. if (creator != null)
  151. meta.CreatorID = m_HomeURI + ";" + creator.FirstName + " " + creator.LastName;
  152. }
  153. }
  154. protected byte[] AdjustIdentifiers(byte[] data)
  155. {
  156. string xml = Utils.BytesToString(data);
  157. return Utils.StringToBytes(RewriteSOP(xml));
  158. }
  159. protected string RewriteSOP(string xml)
  160. {
  161. XmlDocument doc = new XmlDocument();
  162. doc.LoadXml(xml);
  163. XmlNodeList sops = doc.GetElementsByTagName("SceneObjectPart");
  164. foreach (XmlNode sop in sops)
  165. {
  166. UserAccount creator = null;
  167. bool hasCreatorData = false;
  168. XmlNodeList nodes = sop.ChildNodes;
  169. foreach (XmlNode node in nodes)
  170. {
  171. if (node.Name == "CreatorID")
  172. {
  173. UUID uuid = UUID.Zero;
  174. UUID.TryParse(node.InnerText, out uuid);
  175. creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid);
  176. }
  177. if (node.Name == "CreatorData" && node.InnerText != null && node.InnerText != string.Empty)
  178. hasCreatorData = true;
  179. //if (node.Name == "OwnerID")
  180. //{
  181. // UserAccount owner = GetUser(node.InnerText);
  182. // if (owner != null)
  183. // node.InnerText = m_ProfileServiceURL + "/" + node.InnerText + "/" + owner.FirstName + " " + owner.LastName;
  184. //}
  185. }
  186. if (!hasCreatorData && creator != null)
  187. {
  188. XmlElement creatorData = doc.CreateElement("CreatorData");
  189. creatorData.InnerText = m_HomeURI + ";" + creator.FirstName + " " + creator.LastName;
  190. sop.AppendChild(creatorData);
  191. }
  192. }
  193. using (StringWriter wr = new StringWriter())
  194. {
  195. doc.Save(wr);
  196. return wr.ToString();
  197. }
  198. }
  199. // TODO: unused
  200. // private void Dump(Dictionary<UUID, bool> lst)
  201. // {
  202. // m_log.Debug("XXX -------- UUID DUMP ------- XXX");
  203. // foreach (KeyValuePair<UUID, bool> kvp in lst)
  204. // m_log.Debug(" >> " + kvp.Key + " (texture? " + kvp.Value + ")");
  205. // m_log.Debug("XXX -------- UUID DUMP ------- XXX");
  206. // }
  207. #endregion
  208. #region Public interface
  209. public void Get(UUID assetID, UUID ownerID, string userAssetURL)
  210. {
  211. // Get the item from the remote asset server onto the local AssetService
  212. AssetMetadata meta = FetchMetadata(userAssetURL, assetID);
  213. if (meta == null)
  214. return;
  215. // The act of gathering UUIDs downloads some assets from the remote server
  216. // but not all...
  217. Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
  218. HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL);
  219. uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids);
  220. m_log.DebugFormat("[HG ASSET MAPPER]: Preparing to get {0} assets", ids.Count);
  221. bool success = true;
  222. foreach (UUID uuid in ids.Keys)
  223. if (FetchAsset(userAssetURL, uuid) == null)
  224. success = false;
  225. // maybe all pieces got here...
  226. if (!success)
  227. m_log.DebugFormat("[HG ASSET MAPPER]: Problems getting item {0} from asset server {1}", assetID, userAssetURL);
  228. else
  229. m_log.DebugFormat("[HG ASSET MAPPER]: Successfully got item {0} from asset server {1}", assetID, userAssetURL);
  230. }
  231. public void Post(UUID assetID, UUID ownerID, string userAssetURL)
  232. {
  233. // Post the item from the local AssetCache onto the remote asset server
  234. // and place an entry in m_assetMap
  235. m_log.Debug("[HG ASSET MAPPER]: Posting object " + assetID + " to asset server " + userAssetURL);
  236. AssetBase asset = m_scene.AssetService.Get(assetID.ToString());
  237. if (asset != null)
  238. {
  239. Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
  240. HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty);
  241. uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
  242. bool success = false;
  243. foreach (UUID uuid in ids.Keys)
  244. {
  245. asset = m_scene.AssetService.Get(uuid.ToString());
  246. if (asset == null)
  247. m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid);
  248. else
  249. success = PostAsset(userAssetURL, asset);
  250. }
  251. // maybe all pieces got there...
  252. if (!success)
  253. m_log.DebugFormat("[HG ASSET MAPPER]: Problems posting item {0} to asset server {1}", assetID, userAssetURL);
  254. else
  255. m_log.DebugFormat("[HG ASSET MAPPER]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL);
  256. }
  257. else
  258. m_log.DebugFormat("[HG ASSET MAPPER]: Something wrong with asset {0}, it could not be found", assetID);
  259. }
  260. #endregion
  261. }
  262. }