opensim-development – Blame information for rev 1

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