HGAssetMapper.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /**
  2. * Copyright (c) 2008, Contributors. All rights reserved.
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without modification,
  6. * are permitted provided that the following conditions are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright notice,
  9. * this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright notice,
  11. * this list of conditions and the following disclaimer in the documentation
  12. * and/or other materials provided with the distribution.
  13. * * Neither the name of the Organizations nor the names of Individual
  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 "AS IS" AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  20. * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  21. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  22. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  23. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  24. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  25. * OF THE POSSIBILITY OF SUCH DAMAGE.
  26. *
  27. */
  28. using System;
  29. using System.Collections;
  30. using System.Collections.Generic;
  31. using System.Reflection;
  32. using System.Threading;
  33. using log4net;
  34. using Nini.Config;
  35. using OpenMetaverse;
  36. using OpenSim.Framework;
  37. using OpenSim.Framework.Communications;
  38. using OpenSim.Framework.Communications.Cache;
  39. using OpenSim.Framework.Servers;
  40. using OpenSim.Region.Environment;
  41. using OpenSim.Region.Environment.Scenes;
  42. //using HyperGrid.Framework;
  43. //using OpenSim.Region.Communications.Hypergrid;
  44. namespace OpenSim.Region.Environment.Scenes.Hypergrid
  45. {
  46. public class HGAssetMapper
  47. {
  48. #region Fields
  49. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  50. // This maps between asset server URLs and asset server clients
  51. private Dictionary<string, GridAssetClient> m_assetServers = new Dictionary<string, GridAssetClient>();
  52. // This maps between asset UUIDs and asset servers
  53. private Dictionary<UUID, GridAssetClient> m_assetMap = new Dictionary<UUID, GridAssetClient>();
  54. private Scene m_scene;
  55. #endregion
  56. #region Constructor
  57. public HGAssetMapper(Scene scene)
  58. {
  59. m_scene = scene;
  60. }
  61. #endregion
  62. #region Internal functions
  63. private string UserAssetURL(UUID userID)
  64. {
  65. CachedUserInfo uinfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(userID);
  66. if (uinfo != null)
  67. return (uinfo.UserProfile.UserAssetURI == "") ? null : uinfo.UserProfile.UserAssetURI;
  68. return null;
  69. }
  70. private bool IsLocalUser(UUID userID)
  71. {
  72. CachedUserInfo uinfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(userID);
  73. if (uinfo != null)
  74. {
  75. if (HGNetworkServersInfo.Singleton.IsLocalUser(uinfo.UserProfile))
  76. {
  77. m_log.Debug("[HGScene]: Home user " + uinfo.UserProfile.FirstName + " " + uinfo.UserProfile.SurName);
  78. return true;
  79. }
  80. }
  81. m_log.Debug("[HGScene]: Foreign user " + uinfo.UserProfile.FirstName + " " + uinfo.UserProfile.SurName);
  82. return false;
  83. }
  84. private bool IsInAssetMap(UUID uuid)
  85. {
  86. return m_assetMap.ContainsKey(uuid);
  87. }
  88. private bool FetchAsset(GridAssetClient asscli, UUID assetID, bool isTexture)
  89. {
  90. // I'm not going over 3 seconds since this will be blocking processing of all the other inbound
  91. // packets from the client.
  92. int pollPeriod = 200;
  93. int maxPolls = 15;
  94. AssetBase asset;
  95. // Maybe it came late, and it's already here. Check first.
  96. if (m_scene.CommsManager.AssetCache.TryGetCachedAsset(assetID, out asset))
  97. {
  98. m_log.Debug("[HGScene]: Asset already in asset cache. " + assetID);
  99. return true;
  100. }
  101. asscli.RequestAsset(assetID, isTexture);
  102. do
  103. {
  104. Thread.Sleep(pollPeriod);
  105. if (m_scene.CommsManager.AssetCache.TryGetCachedAsset(assetID, out asset) && (asset != null))
  106. {
  107. m_log.Debug("[HGScene]: Asset made it to asset cache. " + asset.Name + " " + assetID);
  108. // I think I need to store it in the asset DB too.
  109. // For now, let me just do it for textures and scripts
  110. if (((AssetType)asset.Type == AssetType.Texture) ||
  111. ((AssetType)asset.Type == AssetType.LSLBytecode) ||
  112. ((AssetType)asset.Type == AssetType.LSLText))
  113. {
  114. AssetBase asset1 = new AssetBase();
  115. Copy(asset, asset1);
  116. m_scene.AssetCache.AssetServer.StoreAsset(asset1);
  117. }
  118. return true;
  119. }
  120. } while (--maxPolls > 0);
  121. m_log.WarnFormat("[HGScene]: {0} {1} was not received before the retrieval timeout was reached",
  122. isTexture ? "texture" : "asset", assetID.ToString());
  123. return false;
  124. }
  125. private bool PostAsset(GridAssetClient asscli, UUID assetID)
  126. {
  127. AssetBase asset1;
  128. m_scene.CommsManager.AssetCache.TryGetCachedAsset(assetID, out asset1);
  129. if (asset1 != null)
  130. {
  131. // See long comment in AssetCache.AddAsset
  132. if (!asset1.Temporary || asset1.Local)
  133. {
  134. // The asset cache returns instances of subclasses of AssetBase:
  135. // TextureImage or AssetInfo. So in passing them to the remote
  136. // server we first need to convert this to instances of AssetBase,
  137. // which is the serializable class for assets.
  138. AssetBase asset = new AssetBase();
  139. Copy(asset1, asset);
  140. asscli.StoreAsset(asset);
  141. }
  142. return true;
  143. }
  144. else
  145. m_log.Warn("[HGScene]: Tried to post asset to remote server, but asset not in local cache.");
  146. return false;
  147. }
  148. private void Copy(AssetBase from, AssetBase to)
  149. {
  150. to.Data = from.Data;
  151. to.Description = from.Description;
  152. to.FullID = from.FullID;
  153. to.ID = from.ID;
  154. to.Local = from.Local;
  155. to.Name = from.Name;
  156. to.Temporary = from.Temporary;
  157. to.Type = from.Type;
  158. }
  159. private void _guardedAdd(Dictionary<UUID, bool> lst, UUID obj, bool val)
  160. {
  161. if (!lst.ContainsKey(obj))
  162. lst.Add(obj, val);
  163. }
  164. private void SniffTextureUUIDs(Dictionary<UUID, bool> uuids, SceneObjectGroup sog)
  165. {
  166. try
  167. {
  168. _guardedAdd(uuids, sog.RootPart.Shape.Textures.DefaultTexture.TextureID, true);
  169. }
  170. catch (Exception) { }
  171. foreach (Primitive.TextureEntryFace tface in sog.RootPart.Shape.Textures.FaceTextures)
  172. {
  173. try
  174. {
  175. _guardedAdd(uuids, tface.TextureID, true);
  176. }
  177. catch (Exception) { }
  178. }
  179. foreach (SceneObjectPart sop in sog.Children.Values)
  180. {
  181. try
  182. {
  183. _guardedAdd(uuids, sop.Shape.Textures.DefaultTexture.TextureID, true);
  184. }
  185. catch (Exception) { }
  186. foreach (Primitive.TextureEntryFace tface in sop.Shape.Textures.FaceTextures)
  187. {
  188. try
  189. {
  190. _guardedAdd(uuids, tface.TextureID, true);
  191. }
  192. catch (Exception) { }
  193. }
  194. }
  195. }
  196. private void SniffTaskInventoryUUIDs(Dictionary<UUID, bool> uuids, SceneObjectGroup sog)
  197. {
  198. TaskInventoryDictionary tinv = sog.RootPart.TaskInventory;
  199. foreach (TaskInventoryItem titem in tinv.Values)
  200. {
  201. uuids.Add(titem.AssetID, (InventoryType)titem.Type == InventoryType.Texture);
  202. }
  203. }
  204. private Dictionary<UUID, bool> SniffUUIDs(AssetBase asset)
  205. {
  206. Dictionary<UUID, bool> uuids = new Dictionary<UUID, bool>();
  207. if ((asset != null) && ((AssetType)asset.Type == AssetType.Object))
  208. {
  209. string ass_str = Utils.BytesToString(asset.Data);
  210. SceneObjectGroup sog = new SceneObjectGroup(ass_str, true);
  211. SniffTextureUUIDs(uuids, sog);
  212. // We need to sniff further...
  213. SniffTaskInventoryUUIDs(uuids, sog);
  214. }
  215. return uuids;
  216. }
  217. private Dictionary<UUID, bool> SniffUUIDs(UUID assetID)
  218. {
  219. //Dictionary<UUID, bool> uuids = new Dictionary<UUID, bool>();
  220. AssetBase asset;
  221. m_scene.CommsManager.AssetCache.TryGetCachedAsset(assetID, out asset);
  222. return SniffUUIDs(asset);
  223. }
  224. private void Dump(Dictionary<UUID, bool> lst)
  225. {
  226. m_log.Debug("XXX -------- UUID DUMP ------- XXX");
  227. foreach (KeyValuePair<UUID, bool> kvp in lst)
  228. m_log.Debug(" >> " + kvp.Key + " (texture? " + kvp.Value + ")");
  229. m_log.Debug("XXX -------- UUID DUMP ------- XXX");
  230. }
  231. #endregion
  232. #region Public interface
  233. public void Get(UUID itemID, UUID ownerID)
  234. {
  235. if (!IsInAssetMap(itemID) && !IsLocalUser(ownerID))
  236. {
  237. // Get the item from the remote asset server onto the local AssetCache
  238. // and place an entry in m_assetMap
  239. GridAssetClient asscli = null;
  240. string userAssetURL = UserAssetURL(ownerID);
  241. if (userAssetURL != null)
  242. {
  243. m_assetServers.TryGetValue(userAssetURL, out asscli);
  244. if (asscli == null)
  245. {
  246. m_log.Debug("[HGScene]: Starting new GridAssetClient for " + userAssetURL);
  247. asscli = new GridAssetClient(userAssetURL);
  248. asscli.SetReceiver(m_scene.CommsManager.AssetCache); // Straight to the asset cache!
  249. m_assetServers.Add(userAssetURL, asscli);
  250. }
  251. m_log.Debug("[HGScene]: Fetching object " + itemID + " to asset server " + userAssetURL);
  252. bool success = FetchAsset(asscli, itemID, false); // asscli.RequestAsset(item.ItemID, false);
  253. // OK, now fetch the inside.
  254. Dictionary<UUID, bool> ids = SniffUUIDs(itemID);
  255. Dump(ids);
  256. foreach (KeyValuePair<UUID, bool> kvp in ids)
  257. FetchAsset(asscli, kvp.Key, kvp.Value);
  258. if (success)
  259. {
  260. m_log.Debug("[HGScene]: Successfully fetched item from remote asset server " + userAssetURL);
  261. m_assetMap.Add(itemID, asscli);
  262. }
  263. else
  264. m_log.Warn("[HGScene]: Could not fetch asset from remote asset server " + userAssetURL);
  265. }
  266. else
  267. m_log.Warn("[HGScene]: Unable to locate foreign user's asset server");
  268. }
  269. }
  270. public void Post(UUID itemID, UUID ownerID)
  271. {
  272. if (!IsLocalUser(ownerID))
  273. {
  274. // Post the item from the local AssetCache ontp the remote asset server
  275. // and place an entry in m_assetMap
  276. GridAssetClient asscli = null;
  277. string userAssetURL = UserAssetURL(ownerID);
  278. if (userAssetURL != null)
  279. {
  280. m_assetServers.TryGetValue(userAssetURL, out asscli);
  281. if (asscli == null)
  282. {
  283. m_log.Debug("[HGScene]: Starting new GridAssetClient for " + userAssetURL);
  284. asscli = new GridAssetClient(userAssetURL);
  285. asscli.SetReceiver(m_scene.CommsManager.AssetCache); // Straight to the asset cache!
  286. m_assetServers.Add(userAssetURL, asscli);
  287. }
  288. m_log.Debug("[HGScene]: Posting object " + itemID + " to asset server " + userAssetURL);
  289. bool success = PostAsset(asscli, itemID);
  290. // Now the inside
  291. Dictionary<UUID, bool> ids = SniffUUIDs(itemID);
  292. Dump(ids);
  293. foreach (KeyValuePair<UUID, bool> kvp in ids)
  294. PostAsset(asscli, kvp.Key);
  295. if (success)
  296. {
  297. m_log.Debug("[HGScene]: Successfully posted item to remote asset server " + userAssetURL);
  298. m_assetMap.Add(itemID, asscli);
  299. }
  300. else
  301. m_log.Warn("[HGScene]: Could not post asset to remote asset server " + userAssetURL);
  302. //if (!m_assetMap.ContainsKey(itemID))
  303. // m_assetMap.Add(itemID, asscli);
  304. }
  305. else
  306. m_log.Warn("[HGScene]: Unable to locate foreign user's asset server");
  307. }
  308. }
  309. #endregion
  310. }
  311. }