aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs')
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs407
1 files changed, 407 insertions, 0 deletions
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs
new file mode 100644
index 0000000..9fb7723
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs
@@ -0,0 +1,407 @@
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
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Reflection;
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
40using OpenMetaverse;
41using OpenMetaverse.StructuredData;
42
43namespace OpenSim.Services.Connectors.SimianGrid
44{
45 /// <summary>
46 /// Connects to the SimianGrid asset service
47 /// </summary>
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
49 public class SimianAssetServiceConnector : IAssetService, ISharedRegionModule
50 {
51 private static readonly ILog m_log =
52 LogManager.GetLogger(
53 MethodBase.GetCurrentMethod().DeclaringType);
54 private static string ZeroID = UUID.Zero.ToString();
55
56 private string m_serverUrl = String.Empty;
57 private IImprovedAssetCache m_cache;
58
59 #region ISharedRegionModule
60
61 public Type ReplaceableInterface { get { return null; } }
62 public void RegionLoaded(Scene scene)
63 {
64 if (m_cache == null)
65 {
66 IImprovedAssetCache cache = scene.RequestModuleInterface<IImprovedAssetCache>();
67 if (cache is ISharedRegionModule)
68 m_cache = cache;
69 }
70 }
71 public void PostInitialise() { }
72 public void Close() { }
73
74 public SimianAssetServiceConnector() { }
75 public string Name { get { return "SimianAssetServiceConnector"; } }
76 public void AddRegion(Scene scene) { scene.RegisterModuleInterface<IAssetService>(this); }
77 public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface<IAssetService>(this); }
78
79 #endregion ISharedRegionModule
80
81 public SimianAssetServiceConnector(IConfigSource source)
82 {
83 Initialise(source);
84 }
85
86 public void Initialise(IConfigSource source)
87 {
88 IConfig gridConfig = source.Configs["AssetService"];
89 if (gridConfig == null)
90 {
91 m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini");
92 throw new Exception("Asset connector init error");
93 }
94
95 string serviceUrl = gridConfig.GetString("AssetServerURI");
96 if (String.IsNullOrEmpty(serviceUrl))
97 {
98 m_log.Error("[ASSET CONNECTOR]: No AssetServerURI in section AssetService");
99 throw new Exception("Asset connector init error");
100 }
101
102 if (!serviceUrl.EndsWith("/"))
103 serviceUrl = serviceUrl + '/';
104
105 m_serverUrl = serviceUrl;
106 }
107
108 #region IAssetService
109
110 public AssetBase Get(string id)
111 {
112 AssetBase asset = null;
113
114 // Cache fetch
115 if (m_cache != null)
116 {
117 asset = m_cache.Get(id);
118 if (asset != null)
119 return asset;
120 }
121
122 Uri url;
123
124 // Determine if id is an absolute URL or a grid-relative UUID
125 if (!Uri.TryCreate(id, UriKind.Absolute, out url))
126 url = new Uri(m_serverUrl + id);
127
128 try
129 {
130 HttpWebRequest request = UntrustedHttpWebRequest.Create(url);
131
132 using (WebResponse response = request.GetResponse())
133 {
134 using (Stream responseStream = response.GetResponseStream())
135 {
136 string creatorID = response.Headers.GetOne("X-Asset-Creator-Id") ?? String.Empty;
137
138 // Create the asset object
139 asset = new AssetBase(id, String.Empty, SLUtil.ContentTypeToSLAssetType(response.ContentType), creatorID);
140
141 UUID assetID;
142 if (UUID.TryParse(id, out assetID))
143 asset.FullID = assetID;
144
145 // Grab the asset data from the response stream
146 using (MemoryStream stream = new MemoryStream())
147 {
148 responseStream.CopyTo(stream, Int32.MaxValue);
149 asset.Data = stream.ToArray();
150 }
151 }
152 }
153
154 // Cache store
155 if (m_cache != null && asset != null)
156 m_cache.Cache(asset);
157
158 return asset;
159 }
160 catch (Exception ex)
161 {
162 m_log.Warn("[ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message);
163 return null;
164 }
165 }
166
167 /// <summary>
168 /// Get an asset's metadata
169 /// </summary>
170 /// <param name="id"></param>
171 /// <returns></returns>
172 public AssetMetadata GetMetadata(string id)
173 {
174 AssetMetadata metadata = null;
175
176 // Cache fetch
177 if (m_cache != null)
178 {
179 AssetBase asset = m_cache.Get(id);
180 if (asset != null)
181 return asset.Metadata;
182 }
183
184 Uri url;
185
186 // Determine if id is an absolute URL or a grid-relative UUID
187 if (!Uri.TryCreate(id, UriKind.Absolute, out url))
188 url = new Uri(m_serverUrl + id);
189
190 try
191 {
192 HttpWebRequest request = UntrustedHttpWebRequest.Create(url);
193 request.Method = "HEAD";
194
195 using (WebResponse response = request.GetResponse())
196 {
197 using (Stream responseStream = response.GetResponseStream())
198 {
199 // Create the metadata object
200 metadata = new AssetMetadata();
201 metadata.ContentType = response.ContentType;
202 metadata.ID = id;
203
204 UUID uuid;
205 if (UUID.TryParse(id, out uuid))
206 metadata.FullID = uuid;
207
208 string lastModifiedStr = response.Headers.Get("Last-Modified");
209 if (!String.IsNullOrEmpty(lastModifiedStr))
210 {
211 DateTime lastModified;
212 if (DateTime.TryParse(lastModifiedStr, out lastModified))
213 metadata.CreationDate = lastModified;
214 }
215 }
216 }
217 }
218 catch (Exception ex)
219 {
220 m_log.Warn("[ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message);
221 }
222
223 return metadata;
224 }
225
226 public byte[] GetData(string id)
227 {
228 AssetBase asset = Get(id);
229
230 if (asset != null)
231 return asset.Data;
232
233 return null;
234 }
235
236 /// <summary>
237 /// Get an asset asynchronously
238 /// </summary>
239 /// <param name="id">The asset id</param>
240 /// <param name="sender">Represents the requester. Passed back via the handler</param>
241 /// <param name="handler">The handler to call back once the asset has been retrieved</param>
242 /// <returns>True if the id was parseable, false otherwise</returns>
243 public bool Get(string id, Object sender, AssetRetrieved handler)
244 {
245 Util.FireAndForget(
246 delegate(object o)
247 {
248 AssetBase asset = Get(id);
249 handler(id, sender, asset);
250 }
251 );
252
253 return true;
254 }
255
256 /// <summary>
257 /// Creates a new asset
258 /// </summary>
259 /// Returns a random ID if none is passed into it
260 /// <param name="asset"></param>
261 /// <returns></returns>
262 public string Store(AssetBase asset)
263 {
264 bool storedInCache = false;
265 string errorMessage = null;
266
267 // AssetID handling
268 if (String.IsNullOrEmpty(asset.ID) || asset.ID == ZeroID)
269 {
270 asset.FullID = UUID.Random();
271 asset.ID = asset.FullID.ToString();
272 }
273
274 // Cache handling
275 if (m_cache != null)
276 {
277 m_cache.Cache(asset);
278 storedInCache = true;
279 }
280
281 // Local asset handling
282 if (asset.Local)
283 {
284 if (!storedInCache)
285 {
286 m_log.Error("Cannot store local " + asset.Metadata.ContentType + " asset without an asset cache");
287 asset.ID = null;
288 asset.FullID = UUID.Zero;
289 }
290
291 return asset.ID;
292 }
293
294 // Distinguish public and private assets
295 bool isPublic = true;
296 switch ((AssetType)asset.Type)
297 {
298 case AssetType.CallingCard:
299 case AssetType.Gesture:
300 case AssetType.LSLBytecode:
301 case AssetType.LSLText:
302 isPublic = false;
303 break;
304 }
305
306 // Make sure ContentType is set
307 if (String.IsNullOrEmpty(asset.Metadata.ContentType))
308 asset.Metadata.ContentType = SLUtil.SLAssetTypeToContentType(asset.Type);
309
310 // Build the remote storage request
311 List<MultipartForm.Element> postParameters = new List<MultipartForm.Element>()
312 {
313 new MultipartForm.Parameter("AssetID", asset.FullID.ToString()),
314 new MultipartForm.Parameter("CreatorID", asset.Metadata.CreatorID),
315 new MultipartForm.Parameter("Temporary", asset.Temporary ? "1" : "0"),
316 new MultipartForm.Parameter("Public", isPublic ? "1" : "0"),
317 new MultipartForm.File("Asset", asset.Name, asset.Metadata.ContentType, asset.Data)
318 };
319
320 // Make the remote storage request
321 try
322 {
323 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl);
324
325 HttpWebResponse response = MultipartForm.Post(request, postParameters);
326 using (Stream responseStream = response.GetResponseStream())
327 {
328 try
329 {
330 string responseStr = responseStream.GetStreamString();
331 OSD responseOSD = OSDParser.Deserialize(responseStr);
332 if (responseOSD.Type == OSDType.Map)
333 {
334 OSDMap responseMap = (OSDMap)responseOSD;
335 if (responseMap["Success"].AsBoolean())
336 return asset.ID;
337 else
338 errorMessage = "Upload failed: " + responseMap["Message"].AsString();
339 }
340 else
341 {
342 errorMessage = "Response format was invalid.";
343 }
344 }
345 catch
346 {
347 errorMessage = "Failed to parse the response.";
348 }
349 }
350 }
351 catch (WebException ex)
352 {
353 errorMessage = ex.Message;
354 }
355
356 m_log.WarnFormat("[ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}",
357 asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage);
358 return null;
359 }
360
361 /// <summary>
362 /// Update an asset's content
363 /// </summary>
364 /// Attachments and bare scripts need this!!
365 /// <param name="id"> </param>
366 /// <param name="data"></param>
367 /// <returns></returns>
368 public bool UpdateContent(string id, byte[] data)
369 {
370 AssetBase asset = Get(id);
371
372 if (asset == null)
373 {
374 m_log.Warn("[ASSET CONNECTOR]: Failed to fetch asset " + id + " for updating");
375 return false;
376 }
377
378 asset.Data = data;
379
380 string result = Store(asset);
381 return !String.IsNullOrEmpty(result);
382 }
383
384 /// <summary>
385 /// Delete an asset
386 /// </summary>
387 /// <param name="id"></param>
388 /// <returns></returns>
389 public bool Delete(string id)
390 {
391 if (m_cache != null)
392 m_cache.Expire(id);
393
394 string url = m_serverUrl + id;
395
396 OSDMap response = WebUtil.ServiceRequest(url, "DELETE");
397 if (response["Success"].AsBoolean())
398 return true;
399 else
400 m_log.Warn("[ASSET CONNECTOR]: Failed to delete asset " + id + " from the asset service");
401
402 return false;
403 }
404
405 #endregion IAssetService
406 }
407}