PageRenderTime 64ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs

https://github.com/UbitUmarov/Ubit-opensim
C# | 332 lines | 236 code | 61 blank | 35 comment | 53 complexity | e280f279ddced3e72f0295d0f017e9c9 MD5 | raw file
  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 log4net;
  28. using System;
  29. using System.Collections.Generic;
  30. using System.IO;
  31. using System.Reflection;
  32. using Nini.Config;
  33. using OpenSim.Framework;
  34. using OpenSim.Framework.Console;
  35. using OpenSim.Framework.Communications;
  36. using OpenSim.Services.Interfaces;
  37. using OpenMetaverse;
  38. namespace OpenSim.Services.Connectors
  39. {
  40. public class AssetServicesConnector : IAssetService
  41. {
  42. private static readonly ILog m_log =
  43. LogManager.GetLogger(
  44. MethodBase.GetCurrentMethod().DeclaringType);
  45. private string m_ServerURI = String.Empty;
  46. private IImprovedAssetCache m_Cache = null;
  47. private delegate void AssetRetrievedEx(AssetBase asset);
  48. private List<AssetRetrievedEx> AssetRetrievedExList;
  49. // Keeps track of concurrent requests for the same asset, so that it's only loaded once.
  50. // Maps: Asset ID -> Handlers which will be called when the asset has been loaded
  51. private Dictionary<string, List<AssetRetrievedEx>> m_AssetHandlers = new Dictionary<string, List<AssetRetrievedEx>>();
  52. public AssetServicesConnector()
  53. {
  54. }
  55. public AssetServicesConnector(string serverURI)
  56. {
  57. m_ServerURI = serverURI.TrimEnd('/');
  58. }
  59. public AssetServicesConnector(IConfigSource source)
  60. {
  61. Initialise(source);
  62. }
  63. public virtual void Initialise(IConfigSource source)
  64. {
  65. IConfig assetConfig = source.Configs["AssetService"];
  66. if (assetConfig == null)
  67. {
  68. m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini");
  69. throw new Exception("Asset connector init error");
  70. }
  71. string serviceURI = assetConfig.GetString("AssetServerURI",
  72. String.Empty);
  73. if (serviceURI == String.Empty)
  74. {
  75. m_log.Error("[ASSET CONNECTOR]: No Server URI named in section AssetService");
  76. throw new Exception("Asset connector init error");
  77. }
  78. m_ServerURI = serviceURI;
  79. }
  80. protected void SetCache(IImprovedAssetCache cache)
  81. {
  82. m_Cache = cache;
  83. }
  84. public AssetBase Get(string id)
  85. {
  86. // m_log.DebugFormat("[ASSET SERVICE CONNECTOR]: Synchronous get request for {0}", id);
  87. string uri = m_ServerURI + "/assets/" + id;
  88. AssetBase asset = null;
  89. if (m_Cache != null)
  90. asset = m_Cache.Get(id);
  91. if (asset == null)
  92. {
  93. asset = SynchronousRestObjectRequester.
  94. MakeRequest<int, AssetBase>("GET", uri, 0);
  95. if (m_Cache != null)
  96. m_Cache.Cache(asset);
  97. }
  98. return asset;
  99. }
  100. public AssetBase GetCached(string id)
  101. {
  102. // m_log.DebugFormat("[ASSET SERVICE CONNECTOR]: Cache request for {0}", id);
  103. if (m_Cache != null)
  104. return m_Cache.Get(id);
  105. return null;
  106. }
  107. public AssetMetadata GetMetadata(string id)
  108. {
  109. if (m_Cache != null)
  110. {
  111. AssetBase fullAsset = m_Cache.Get(id);
  112. if (fullAsset != null)
  113. return fullAsset.Metadata;
  114. }
  115. string uri = m_ServerURI + "/assets/" + id + "/metadata";
  116. AssetMetadata asset = SynchronousRestObjectRequester.
  117. MakeRequest<int, AssetMetadata>("GET", uri, 0);
  118. return asset;
  119. }
  120. public byte[] GetData(string id)
  121. {
  122. if (m_Cache != null)
  123. {
  124. AssetBase fullAsset = m_Cache.Get(id);
  125. if (fullAsset != null)
  126. return fullAsset.Data;
  127. }
  128. RestClient rc = new RestClient(m_ServerURI);
  129. rc.AddResourcePath("assets");
  130. rc.AddResourcePath(id);
  131. rc.AddResourcePath("data");
  132. rc.RequestMethod = "GET";
  133. Stream s = rc.Request();
  134. if (s == null)
  135. return null;
  136. if (s.Length > 0)
  137. {
  138. byte[] ret = new byte[s.Length];
  139. s.Read(ret, 0, (int)s.Length);
  140. return ret;
  141. }
  142. return null;
  143. }
  144. public bool Get(string id, Object sender, AssetRetrieved handler)
  145. {
  146. // m_log.DebugFormat("[ASSET SERVICE CONNECTOR]: Potentially asynchronous get request for {0}", id);
  147. string uri = m_ServerURI + "/assets/" + id;
  148. AssetBase asset = null;
  149. if (m_Cache != null)
  150. asset = m_Cache.Get(id);
  151. if (asset == null)
  152. {
  153. lock (m_AssetHandlers)
  154. {
  155. AssetRetrievedEx handlerEx = new AssetRetrievedEx(delegate(AssetBase _asset) { handler(id, sender, _asset); });
  156. List<AssetRetrievedEx> handlers;
  157. if (m_AssetHandlers.TryGetValue(id, out handlers))
  158. {
  159. // Someone else is already loading this asset. It will notify our handler when done.
  160. handlers.Add(handlerEx);
  161. return true;
  162. }
  163. // Load the asset ourselves
  164. handlers = new List<AssetRetrievedEx>();
  165. handlers.Add(handlerEx);
  166. m_AssetHandlers.Add(id, handlers);
  167. }
  168. bool success = false;
  169. try
  170. {
  171. AsynchronousRestObjectRequester.MakeRequest<int, AssetBase>("GET", uri, 0,
  172. delegate(AssetBase a)
  173. {
  174. if (m_Cache != null)
  175. m_Cache.Cache(a);
  176. List<AssetRetrievedEx> handlers;
  177. lock (m_AssetHandlers)
  178. {
  179. handlers = m_AssetHandlers[id];
  180. m_AssetHandlers.Remove(id);
  181. }
  182. foreach(AssetRetrievedEx h in handlers)
  183. h.Invoke(a);
  184. });
  185. success = true;
  186. }
  187. finally
  188. {
  189. if (!success)
  190. {
  191. lock (m_AssetHandlers)
  192. {
  193. m_AssetHandlers.Remove(id);
  194. }
  195. }
  196. }
  197. }
  198. else
  199. {
  200. handler(id, sender, asset);
  201. }
  202. return true;
  203. }
  204. public string Store(AssetBase asset)
  205. {
  206. if (asset.Temporary || asset.Local)
  207. {
  208. if (m_Cache != null)
  209. m_Cache.Cache(asset);
  210. return asset.ID;
  211. }
  212. string uri = m_ServerURI + "/assets/";
  213. string newID = string.Empty;
  214. try
  215. {
  216. newID = SynchronousRestObjectRequester.
  217. MakeRequest<AssetBase, string>("POST", uri, asset);
  218. }
  219. catch (Exception e)
  220. {
  221. m_log.WarnFormat("[ASSET CONNECTOR]: Unable to send asset {0} to asset server. Reason: {1}", asset.ID, e.Message);
  222. }
  223. if (newID != String.Empty)
  224. {
  225. // Placing this here, so that this work with old asset servers that don't send any reply back
  226. // SynchronousRestObjectRequester returns somethins that is not an empty string
  227. if (newID != null)
  228. asset.ID = newID;
  229. if (m_Cache != null)
  230. m_Cache.Cache(asset);
  231. }
  232. return newID;
  233. }
  234. public bool UpdateContent(string id, byte[] data)
  235. {
  236. AssetBase asset = null;
  237. if (m_Cache != null)
  238. asset = m_Cache.Get(id);
  239. if (asset == null)
  240. {
  241. AssetMetadata metadata = GetMetadata(id);
  242. if (metadata == null)
  243. return false;
  244. asset = new AssetBase(metadata.FullID, metadata.Name, metadata.Type, UUID.Zero.ToString());
  245. asset.Metadata = metadata;
  246. }
  247. asset.Data = data;
  248. string uri = m_ServerURI + "/assets/" + id;
  249. if (SynchronousRestObjectRequester.
  250. MakeRequest<AssetBase, bool>("POST", uri, asset))
  251. {
  252. if (m_Cache != null)
  253. m_Cache.Cache(asset);
  254. return true;
  255. }
  256. return false;
  257. }
  258. public bool Delete(string id)
  259. {
  260. string uri = m_ServerURI + "/assets/" + id;
  261. if (SynchronousRestObjectRequester.
  262. MakeRequest<int, bool>("DELETE", uri, 0))
  263. {
  264. if (m_Cache != null)
  265. m_Cache.Expire(id);
  266. return true;
  267. }
  268. return false;
  269. }
  270. }
  271. }