aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Services/Connectors/SimianGrid
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Services/Connectors/SimianGrid')
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs100
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs685
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs307
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs344
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs180
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs236
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs147
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs266
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs484
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs941
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs459
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs478
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs337
13 files changed, 4964 insertions, 0 deletions
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs
new file mode 100644
index 0000000..cd4781d
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs
@@ -0,0 +1,100 @@
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.Reflection;
30using OpenSim.Framework;
31using OpenSim.Region.Framework.Scenes;
32using OpenSim.Services.Interfaces;
33using OpenMetaverse;
34using log4net;
35
36namespace OpenSim.Services.Connectors.SimianGrid
37{
38 public class SimianActivityDetector
39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41
42 private IGridUserService m_GridUserService;
43
44 public SimianActivityDetector(IGridUserService guService)
45 {
46 m_GridUserService = guService;
47 m_log.DebugFormat("[SIMIAN ACTIVITY DETECTOR]: Started");
48 }
49
50 public void AddRegion(Scene scene)
51 {
52 // For now the only events we listen to are these
53 // But we could trigger the position update more often
54 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
55 scene.EventManager.OnNewClient += OnNewClient;
56 scene.EventManager.OnAvatarEnteringNewParcel += OnEnteringNewParcel;
57 }
58
59 public void RemoveRegion(Scene scene)
60 {
61 scene.EventManager.OnMakeRootAgent -= OnMakeRootAgent;
62 scene.EventManager.OnNewClient -= OnNewClient;
63 scene.EventManager.OnAvatarEnteringNewParcel -= OnEnteringNewParcel;
64 }
65
66 public void OnMakeRootAgent(ScenePresence sp)
67 {
68 m_log.DebugFormat("[SIMIAN ACTIVITY DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName);
69 Util.FireAndForget(delegate(object o)
70 {
71 m_GridUserService.SetLastPosition(sp.UUID.ToString(), sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
72 }, null, "SimianActivityDetector.SetLastPositionOnMakeRootAgent");
73 }
74
75 public void OnNewClient(IClientAPI client)
76 {
77 client.OnConnectionClosed += OnConnectionClose;
78 }
79
80 public void OnConnectionClose(IClientAPI client)
81 {
82 if (client.SceneAgent.IsChildAgent)
83 return;
84
85// m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName);
86 m_GridUserService.LoggedOut(
87 client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID,
88 client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat);
89 }
90
91 void OnEnteringNewParcel(ScenePresence sp, int localLandID, UUID regionID)
92 {
93 // Asynchronously update the position stored in the session table for this agent
94 Util.FireAndForget(delegate(object o)
95 {
96 m_GridUserService.SetLastPosition(sp.UUID.ToString(), sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
97 }, null, "SimianActivityDetector.SetLastPositionOnEnteringNewParcel");
98 }
99 }
100} \ No newline at end of file
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs
new file mode 100644
index 0000000..9ad4a7a
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs
@@ -0,0 +1,685 @@
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.Collections.Specialized;
31using System.IO;
32using System.Net;
33using System.Reflection;
34using log4net;
35using Mono.Addins;
36using Nini.Config;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenMetaverse;
42using OpenMetaverse.StructuredData;
43
44namespace OpenSim.Services.Connectors.SimianGrid
45{
46 /// <summary>
47 /// Connects to the SimianGrid asset service
48 /// </summary>
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianAssetServiceConnector")]
50 public class SimianAssetServiceConnector : IAssetService, ISharedRegionModule
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(
54 MethodBase.GetCurrentMethod().DeclaringType);
55 private static string ZeroID = UUID.Zero.ToString();
56
57 private string m_serverUrl = String.Empty;
58 private IImprovedAssetCache m_cache;
59 private bool m_Enabled = false;
60
61 #region ISharedRegionModule
62
63 public Type ReplaceableInterface { get { return null; } }
64 public void RegionLoaded(Scene scene)
65 {
66 if (m_cache == null)
67 {
68 IImprovedAssetCache cache = scene.RequestModuleInterface<IImprovedAssetCache>();
69 if (cache is ISharedRegionModule)
70 m_cache = cache;
71 }
72 }
73 public void PostInitialise() { }
74 public void Close() { }
75
76 public SimianAssetServiceConnector() { }
77 public string Name { get { return "SimianAssetServiceConnector"; } }
78 public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IAssetService>(this); } }
79 public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IAssetService>(this); } }
80
81 #endregion ISharedRegionModule
82
83 public SimianAssetServiceConnector(IConfigSource source)
84 {
85 CommonInit(source);
86 }
87
88 public SimianAssetServiceConnector(string url)
89 {
90 if (!url.EndsWith("/") && !url.EndsWith("="))
91 url = url + '/';
92 m_serverUrl = url;
93 }
94
95 public void Initialise(IConfigSource source)
96 {
97 IConfig moduleConfig = source.Configs["Modules"];
98 if (moduleConfig != null)
99 {
100 string name = moduleConfig.GetString("AssetServices", "");
101 if (name == Name)
102 CommonInit(source);
103 }
104 }
105
106 private void CommonInit(IConfigSource source)
107 {
108 IConfig gridConfig = source.Configs["AssetService"];
109 if (gridConfig != null)
110 {
111 string serviceUrl = gridConfig.GetString("AssetServerURI");
112 if (!String.IsNullOrEmpty(serviceUrl))
113 {
114 if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
115 serviceUrl = serviceUrl + '/';
116 m_serverUrl = serviceUrl;
117 }
118 }
119
120 if (String.IsNullOrEmpty(m_serverUrl))
121 m_log.Info("[SIMIAN ASSET CONNECTOR]: No AssetServerURI specified, disabling connector");
122 else
123 m_Enabled = true;
124 }
125
126#region IAssetService
127
128 public AssetBase Get(string id)
129 {
130 if (String.IsNullOrEmpty(m_serverUrl))
131 {
132 m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
133 throw new InvalidOperationException();
134 }
135
136 // Cache fetch
137 if (m_cache != null)
138 {
139 AssetBase asset = m_cache.Get(id);
140 if (asset != null)
141 return asset;
142 }
143
144 return SimianGetOperation(id);
145 }
146
147
148 public AssetBase GetCached(string id)
149 {
150 if (m_cache != null)
151 return m_cache.Get(id);
152
153 return null;
154 }
155
156 /// <summary>
157 /// Get an asset's metadata
158 /// </summary>
159 /// <param name="id"></param>
160 /// <returns></returns>
161 public AssetMetadata GetMetadata(string id)
162 {
163 if (String.IsNullOrEmpty(m_serverUrl))
164 {
165 m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
166 throw new InvalidOperationException();
167 }
168
169 // Cache fetch
170 if (m_cache != null)
171 {
172 AssetBase asset = m_cache.Get(id);
173 if (asset != null)
174 return asset.Metadata;
175 }
176
177 // return GetRemoteMetadata(id);
178 return SimianGetMetadataOperation(id);
179 }
180
181 public byte[] GetData(string id)
182 {
183 if (String.IsNullOrEmpty(m_serverUrl))
184 {
185 m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
186 throw new InvalidOperationException();
187 }
188
189 AssetBase asset = Get(id);
190
191 if (asset != null)
192 return asset.Data;
193
194 return null;
195 }
196
197 /// <summary>
198 /// Get an asset asynchronously
199 /// </summary>
200 /// <param name="id">The asset id</param>
201 /// <param name="sender">Represents the requester. Passed back via the handler</param>
202 /// <param name="handler">The handler to call back once the asset has been retrieved</param>
203 /// <returns>True if the id was parseable, false otherwise</returns>
204 public bool Get(string id, Object sender, AssetRetrieved handler)
205 {
206 if (String.IsNullOrEmpty(m_serverUrl))
207 {
208 m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
209 throw new InvalidOperationException();
210 }
211
212 // Cache fetch
213 if (m_cache != null)
214 {
215 AssetBase asset = m_cache.Get(id);
216 if (asset != null)
217 {
218 handler(id, sender, asset);
219 return true;
220 }
221 }
222
223 Util.FireAndForget(
224 delegate(object o)
225 {
226 AssetBase asset = SimianGetOperation(id);
227 handler(id, sender, asset);
228 }, null, "SimianAssetServiceConnector.GetFromService"
229 );
230
231 return true;
232 }
233
234 public bool[] AssetsExist(string[] ids)
235 {
236 if (String.IsNullOrEmpty(m_serverUrl))
237 {
238 m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
239 throw new InvalidOperationException();
240 }
241
242 bool[] exist = new bool[ids.Length];
243
244 for (int i = 0; i < ids.Length; i++)
245 {
246 AssetMetadata metadata = GetMetadata(ids[i]);
247 if (metadata != null)
248 exist[i] = true;
249 }
250
251 return exist;
252 }
253
254 /// <summary>
255 /// Creates a new asset
256 /// </summary>
257 /// Returns a random ID if none is passed into it
258 /// <param name="asset"></param>
259 /// <returns></returns>
260 public string Store(AssetBase asset)
261 {
262 if (String.IsNullOrEmpty(m_serverUrl))
263 {
264 m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
265 throw new InvalidOperationException();
266 }
267
268 bool storedInCache = false;
269
270 // AssetID handling
271 if (String.IsNullOrEmpty(asset.ID) || asset.ID == ZeroID)
272 {
273 asset.FullID = UUID.Random();
274 asset.ID = asset.FullID.ToString();
275 }
276
277 // Cache handling
278 if (m_cache != null)
279 {
280 m_cache.Cache(asset);
281 storedInCache = true;
282 }
283
284 // Local asset handling
285 if (asset.Local)
286 {
287 if (!storedInCache)
288 {
289 m_log.Error("Cannot store local " + asset.Metadata.ContentType + " asset without an asset cache");
290 asset.ID = null;
291 asset.FullID = UUID.Zero;
292 }
293
294 return asset.ID;
295 }
296
297 return SimianStoreOperation(asset);
298 }
299
300 /// <summary>
301 /// Update an asset's content
302 /// </summary>
303 /// Attachments and bare scripts need this!!
304 /// <param name="id"> </param>
305 /// <param name="data"></param>
306 /// <returns></returns>
307 public bool UpdateContent(string id, byte[] data)
308 {
309 if (String.IsNullOrEmpty(m_serverUrl))
310 {
311 m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
312 throw new InvalidOperationException();
313 }
314
315 AssetBase asset = Get(id);
316
317 if (asset == null)
318 {
319 m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to fetch asset {0} for updating", id);
320 return false;
321 }
322
323 asset.Data = data;
324
325 string result = Store(asset);
326 return !String.IsNullOrEmpty(result);
327 }
328
329 /// <summary>
330 /// Delete an asset
331 /// </summary>
332 /// <param name="id"></param>
333 /// <returns></returns>
334 public bool Delete(string id)
335 {
336 if (String.IsNullOrEmpty(m_serverUrl))
337 {
338 m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
339 throw new InvalidOperationException();
340 }
341
342 if (m_cache != null)
343 m_cache.Expire(id);
344
345 return SimianDeleteOperation(id);
346 }
347
348#endregion IAssetService
349
350#region SimianOperations
351 /// <summary>
352 /// Invokes the xRemoveAsset operation on the simian server to delete an asset
353 /// </summary>
354 /// <param name="id"></param>
355 /// <returns></returns>
356 private bool SimianDeleteOperation(string id)
357 {
358 try
359 {
360 NameValueCollection requestArgs = new NameValueCollection
361 {
362 { "RequestMethod", "xRemoveAsset" },
363 { "AssetID", id }
364 };
365
366 OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
367 if (! response["Success"].AsBoolean())
368 {
369 m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to delete asset; {0}",response["Message"].AsString());
370 return false;
371 }
372
373 return true;
374
375 }
376 catch (Exception ex)
377 {
378 m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to delete asset {0}; {1}", id, ex.Message);
379 }
380
381 return false;
382 }
383
384 /// <summary>
385 /// Invokes the xAddAsset operation on the simian server to create or update an asset
386 /// </summary>
387 /// <param name="id"></param>
388 /// <returns></returns>
389 private string SimianStoreOperation(AssetBase asset)
390 {
391 try
392 {
393 NameValueCollection requestArgs = new NameValueCollection
394 {
395 { "RequestMethod", "xAddAsset" },
396 { "ContentType", asset.Metadata.ContentType },
397 { "EncodedData", Convert.ToBase64String(asset.Data) },
398 { "AssetID", asset.FullID.ToString() },
399 { "CreatorID", asset.Metadata.CreatorID },
400 { "Temporary", asset.Temporary ? "1" : "0" },
401 { "Name", asset.Name }
402 };
403
404 OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
405 if (! response["Success"].AsBoolean())
406 {
407 m_log.WarnFormat("[SIMIAN ASSET CONNECTOR] failed to store asset; {0}",response["Message"].AsString());
408 return null;
409 }
410
411 // asset.ID is always set before calling this function
412 return asset.ID;
413
414 }
415 catch (Exception ex)
416 {
417 m_log.ErrorFormat("[SIMIAN ASSET CONNECTOR] failed to store asset; {0}",ex.Message);
418 }
419
420 return null;
421 }
422
423 /// <summary>
424 /// Invokes the xGetAsset operation on the simian server to get data associated with an asset
425 /// </summary>
426 /// <param name="id"></param>
427 /// <returns></returns>
428 private AssetBase SimianGetOperation(string id)
429 {
430 try
431 {
432 NameValueCollection requestArgs = new NameValueCollection
433 {
434 { "RequestMethod", "xGetAsset" },
435 { "ID", id }
436 };
437
438 OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
439 if (! response["Success"].AsBoolean())
440 {
441 m_log.WarnFormat("[SIMIAN ASSET CONNECTOR] Failed to get asset; {0}",response["Message"].AsString());
442 return null;
443 }
444
445 AssetBase asset = new AssetBase();
446
447 asset.ID = id;
448 asset.Name = String.Empty;
449 asset.Metadata.ContentType = response["ContentType"].AsString(); // this will also set the asset Type property
450 asset.CreatorID = response["CreatorID"].AsString();
451 asset.Data = System.Convert.FromBase64String(response["EncodedData"].AsString());
452 asset.Local = false;
453 asset.Temporary = response["Temporary"];
454
455 return asset;
456 }
457 catch (Exception ex)
458 {
459 m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to retrieve asset {0}; {1}", id, ex.Message);
460 }
461
462 return null;
463 }
464
465 /// <summary>
466 /// Invokes the xGetAssetMetadata operation on the simian server to retrieve metadata for an asset
467 /// This operation is generally used to determine if an asset exists in the database
468 /// </summary>
469 /// <param name="id"></param>
470 /// <returns></returns>
471 private AssetMetadata SimianGetMetadataOperation(string id)
472 {
473 try
474 {
475 NameValueCollection requestArgs = new NameValueCollection
476 {
477 { "RequestMethod", "xGetAssetMetadata" },
478 { "ID", id }
479 };
480
481 OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
482 if (! response["Success"].AsBoolean())
483 {
484 // this is not really an error, this call is used to test existence
485 // m_log.DebugFormat("[SIMIAN ASSET CONNECTOR] Failed to get asset metadata; {0}",response["Message"].AsString());
486 return null;
487 }
488
489 AssetMetadata metadata = new AssetMetadata();
490 metadata.ID = id;
491 metadata.ContentType = response["ContentType"].AsString();
492 metadata.CreatorID = response["CreatorID"].AsString();
493 metadata.Local = false;
494 metadata.Temporary = response["Temporary"];
495
496 string lastModifiedStr = response["Last-Modified"].AsString();
497 if (! String.IsNullOrEmpty(lastModifiedStr))
498 {
499 DateTime lastModified;
500 if (DateTime.TryParse(lastModifiedStr, out lastModified))
501 metadata.CreationDate = lastModified;
502 }
503
504 return metadata;
505 }
506 catch (Exception ex)
507 {
508 m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to get asset metadata; {0}", ex.Message);
509 }
510
511 return null;
512 }
513#endregion
514
515 // private AssetMetadata GetRemoteMetadata(string id)
516 // {
517 // Uri url;
518 // AssetMetadata metadata = null;
519
520 // // Determine if id is an absolute URL or a grid-relative UUID
521 // if (!Uri.TryCreate(id, UriKind.Absolute, out url))
522 // url = new Uri(m_serverUrl + id);
523
524 // try
525 // {
526 // HttpWebRequest request = UntrustedHttpWebRequest.Create(url);
527 // request.Method = "HEAD";
528
529 // using (WebResponse response = request.GetResponse())
530 // {
531 // using (Stream responseStream = response.GetResponseStream())
532 // {
533 // // Create the metadata object
534 // metadata = new AssetMetadata();
535 // metadata.ContentType = response.ContentType;
536 // metadata.ID = id;
537
538 // UUID uuid;
539 // if (UUID.TryParse(id, out uuid))
540 // metadata.FullID = uuid;
541
542 // string lastModifiedStr = response.Headers.Get("Last-Modified");
543 // if (!String.IsNullOrEmpty(lastModifiedStr))
544 // {
545 // DateTime lastModified;
546 // if (DateTime.TryParse(lastModifiedStr, out lastModified))
547 // metadata.CreationDate = lastModified;
548 // }
549 // }
550 // }
551 // }
552 // catch (Exception ex)
553 // {
554 // m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset HEAD from " + url + " failed: " + ex.Message);
555 // }
556
557 // return metadata;
558 // }
559
560 // private AssetBase GetRemote(string id)
561 // {
562 // AssetBase asset = null;
563 // Uri url;
564
565 // // Determine if id is an absolute URL or a grid-relative UUID
566 // if (!Uri.TryCreate(id, UriKind.Absolute, out url))
567 // url = new Uri(m_serverUrl + id);
568
569 // try
570 // {
571 // HttpWebRequest request = UntrustedHttpWebRequest.Create(url);
572
573 // using (WebResponse response = request.GetResponse())
574 // {
575 // using (Stream responseStream = response.GetResponseStream())
576 // {
577 // string creatorID = response.Headers.GetOne("X-Asset-Creator-Id") ?? String.Empty;
578
579 // // Create the asset object
580 // asset = new AssetBase(id, String.Empty, SLUtil.ContentTypeToSLAssetType(response.ContentType), creatorID);
581
582 // UUID assetID;
583 // if (UUID.TryParse(id, out assetID))
584 // asset.FullID = assetID;
585
586 // // Grab the asset data from the response stream
587 // using (MemoryStream stream = new MemoryStream())
588 // {
589 // responseStream.CopyStream(stream, Int32.MaxValue);
590 // asset.Data = stream.ToArray();
591 // }
592 // }
593 // }
594
595 // // Cache store
596 // if (m_cache != null && asset != null)
597 // m_cache.Cache(asset);
598
599 // return asset;
600 // }
601 // catch (Exception ex)
602 // {
603 // m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message);
604 // return null;
605 // }
606 // }
607
608 // private string StoreRemote(AssetBase asset)
609 // {
610 // // Distinguish public and private assets
611 // bool isPublic = true;
612 // switch ((AssetType)asset.Type)
613 // {
614 // case AssetType.CallingCard:
615 // case AssetType.Gesture:
616 // case AssetType.LSLBytecode:
617 // case AssetType.LSLText:
618 // isPublic = false;
619 // break;
620 // }
621
622 // string errorMessage = null;
623
624 // // Build the remote storage request
625 // List<MultipartForm.Element> postParameters = new List<MultipartForm.Element>()
626 // {
627 // new MultipartForm.Parameter("AssetID", asset.FullID.ToString()),
628 // new MultipartForm.Parameter("CreatorID", asset.Metadata.CreatorID),
629 // new MultipartForm.Parameter("Temporary", asset.Temporary ? "1" : "0"),
630 // new MultipartForm.Parameter("Public", isPublic ? "1" : "0"),
631 // new MultipartForm.File("Asset", asset.Name, asset.Metadata.ContentType, asset.Data)
632 // };
633
634 // // Make the remote storage request
635 // try
636 // {
637 // // Simian does not require the asset ID to be in the URL because it's in the post data.
638 // // By appending it to the URL also, we allow caching proxies (squid) to invalidate asset URLs
639 // HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl + asset.FullID.ToString());
640
641 // using (HttpWebResponse response = MultipartForm.Post(request, postParameters))
642 // {
643 // using (Stream responseStream = response.GetResponseStream())
644 // {
645 // string responseStr = null;
646
647 // try
648 // {
649 // responseStr = responseStream.GetStreamString();
650 // OSD responseOSD = OSDParser.Deserialize(responseStr);
651 // if (responseOSD.Type == OSDType.Map)
652 // {
653 // OSDMap responseMap = (OSDMap)responseOSD;
654 // if (responseMap["Success"].AsBoolean())
655 // return asset.ID;
656 // else
657 // errorMessage = "Upload failed: " + responseMap["Message"].AsString();
658 // }
659 // else
660 // {
661 // errorMessage = "Response format was invalid:\n" + responseStr;
662 // }
663 // }
664 // catch (Exception ex)
665 // {
666 // if (!String.IsNullOrEmpty(responseStr))
667 // errorMessage = "Failed to parse the response:\n" + responseStr;
668 // else
669 // errorMessage = "Failed to retrieve the response: " + ex.Message;
670 // }
671 // }
672 // }
673 // }
674 // catch (WebException ex)
675 // {
676 // errorMessage = ex.Message;
677 // }
678
679 // m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}",
680 // asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage);
681
682 // return null;
683 // }
684 }
685}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs
new file mode 100644
index 0000000..3bd11d9
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs
@@ -0,0 +1,307 @@
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.Specialized;
30using System.Reflection;
31using log4net;
32using Mono.Addins;
33using Nini.Config;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
40
41namespace OpenSim.Services.Connectors.SimianGrid
42{
43 /// <summary>
44 /// Connects authentication/authorization to the SimianGrid backend
45 /// </summary>
46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianAuthenticationServiceConnector")]
47 public class SimianAuthenticationServiceConnector : IAuthenticationService, ISharedRegionModule
48 {
49 private static readonly ILog m_log =
50 LogManager.GetLogger(
51 MethodBase.GetCurrentMethod().DeclaringType);
52
53 private string m_serverUrl = String.Empty;
54 private bool m_Enabled = false;
55
56 #region ISharedRegionModule
57
58 public Type ReplaceableInterface { get { return null; } }
59 public void RegionLoaded(Scene scene) { }
60 public void PostInitialise() { }
61 public void Close() { }
62
63 public SimianAuthenticationServiceConnector() { }
64 public string Name { get { return "SimianAuthenticationServiceConnector"; } }
65 public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IAuthenticationService>(this); } }
66 public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IAuthenticationService>(this); } }
67
68 #endregion ISharedRegionModule
69
70 public SimianAuthenticationServiceConnector(IConfigSource source)
71 {
72 CommonInit(source);
73 }
74
75 public void Initialise(IConfigSource source)
76 {
77 IConfig moduleConfig = source.Configs["Modules"];
78 if (moduleConfig != null)
79 {
80 string name = moduleConfig.GetString("AuthenticationServices", "");
81 if (name == Name)
82 CommonInit(source);
83 }
84 }
85
86 private void CommonInit(IConfigSource source)
87 {
88 IConfig gridConfig = source.Configs["AuthenticationService"];
89 if (gridConfig != null)
90 {
91 string serviceUrl = gridConfig.GetString("AuthenticationServerURI");
92 if (!String.IsNullOrEmpty(serviceUrl))
93 {
94 if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
95 serviceUrl = serviceUrl + '/';
96 m_serverUrl = serviceUrl;
97 m_Enabled = true;
98 }
99 }
100
101 if (String.IsNullOrEmpty(m_serverUrl))
102 m_log.Info("[SIMIAN AUTH CONNECTOR]: No AuthenticationServerURI specified, disabling connector");
103 }
104
105 public string Authenticate(UUID principalID, string password, int lifetime)
106 {
107 NameValueCollection requestArgs = new NameValueCollection
108 {
109 { "RequestMethod", "GetIdentities" },
110 { "UserID", principalID.ToString() }
111 };
112
113 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
114 if (response["Success"].AsBoolean() && response["Identities"] is OSDArray)
115 {
116 bool md5hashFound = false;
117
118 OSDArray identities = (OSDArray)response["Identities"];
119 for (int i = 0; i < identities.Count; i++)
120 {
121 OSDMap identity = identities[i] as OSDMap;
122 if (identity != null)
123 {
124 if (identity["Type"].AsString() == "md5hash")
125 {
126 string authorizeResult;
127 if (CheckPassword(principalID, password, identity["Credential"].AsString(), out authorizeResult))
128 return authorizeResult;
129
130 md5hashFound = true;
131 break;
132 }
133 }
134 }
135
136 if (!md5hashFound)
137 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Authentication failed for " + principalID + ", no md5hash identity found");
138 }
139 else
140 {
141 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Failed to retrieve identities for " + principalID + ": " +
142 response["Message"].AsString());
143 }
144
145 return String.Empty;
146 }
147
148 public bool Verify(UUID principalID, string token, int lifetime)
149 {
150 NameValueCollection requestArgs = new NameValueCollection
151 {
152 { "RequestMethod", "GetSession" },
153 { "SessionID", token }
154 };
155
156 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
157 if (response["Success"].AsBoolean())
158 {
159 return true;
160 }
161 else
162 {
163 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Could not verify session for " + principalID + ": " +
164 response["Message"].AsString());
165 }
166
167 return false;
168 }
169
170 public bool Release(UUID principalID, string token)
171 {
172 NameValueCollection requestArgs = new NameValueCollection
173 {
174 { "RequestMethod", "RemoveSession" },
175 { "UserID", principalID.ToString() }
176 };
177
178 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
179 if (response["Success"].AsBoolean())
180 {
181 return true;
182 }
183 else
184 {
185 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Failed to remove session for " + principalID + ": " +
186 response["Message"].AsString());
187 }
188
189 return false;
190 }
191
192 public bool SetPassword(UUID principalID, string passwd)
193 {
194 // Fetch the user name first
195 NameValueCollection requestArgs = new NameValueCollection
196 {
197 { "RequestMethod", "GetUser" },
198 { "UserID", principalID.ToString() }
199 };
200
201 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
202 if (response["Success"].AsBoolean() && response["User"] is OSDMap)
203 {
204 OSDMap userMap = (OSDMap)response["User"];
205 string identifier = userMap["Name"].AsString();
206
207 if (!String.IsNullOrEmpty(identifier))
208 {
209 // Add/update the md5hash identity
210 // TODO: Support salts when AddIdentity does
211 // TODO: Create an a1hash too for WebDAV logins
212 requestArgs = new NameValueCollection
213 {
214 { "RequestMethod", "AddIdentity" },
215 { "Identifier", identifier },
216 { "Credential", "$1$" + Utils.MD5String(passwd) },
217 { "Type", "md5hash" },
218 { "UserID", principalID.ToString() }
219 };
220
221 response = SimianGrid.PostToService(m_serverUrl, requestArgs);
222 bool success = response["Success"].AsBoolean();
223
224 if (!success)
225 m_log.WarnFormat("[SIMIAN AUTH CONNECTOR]: Failed to set password for {0} ({1})", identifier, principalID);
226
227 return success;
228 }
229 }
230 else
231 {
232 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Failed to retrieve identities for " + principalID + ": " +
233 response["Message"].AsString());
234 }
235
236 return false;
237 }
238
239 public AuthInfo GetAuthInfo(UUID principalID)
240 {
241 throw new NotImplementedException();
242 }
243
244 public bool SetAuthInfo(AuthInfo info)
245 {
246 throw new NotImplementedException();
247 }
248
249 private bool CheckPassword(UUID userID, string password, string simianGridCredential, out string authorizeResult)
250 {
251 if (simianGridCredential.Contains(":"))
252 {
253 // Salted version
254 int idx = simianGridCredential.IndexOf(':');
255 string finalhash = simianGridCredential.Substring(0, idx);
256 string salt = simianGridCredential.Substring(idx + 1);
257
258 if (finalhash == Utils.MD5String(password + ":" + salt))
259 {
260 authorizeResult = Authorize(userID);
261 return true;
262 }
263 else
264 {
265 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Authentication failed for " + userID +
266 " using md5hash " + Utils.MD5String(password) + ":" + salt);
267 }
268 }
269 else
270 {
271 // Unsalted version
272 if (password == simianGridCredential ||
273 "$1$" + password == simianGridCredential ||
274 "$1$" + Utils.MD5String(password) == simianGridCredential ||
275 Utils.MD5String(password) == simianGridCredential ||
276 "$1$" + Utils.MD5String(password + ":") == simianGridCredential)
277 {
278 authorizeResult = Authorize(userID);
279 return true;
280 }
281 else
282 {
283 m_log.Warn("[SIMIAN AUTH CONNECTOR]: Authentication failed for " + userID +
284 " using md5hash $1$" + Utils.MD5String(password));
285 }
286 }
287
288 authorizeResult = null;
289 return false;
290 }
291
292 private string Authorize(UUID userID)
293 {
294 NameValueCollection requestArgs = new NameValueCollection
295 {
296 { "RequestMethod", "AddSession" },
297 { "UserID", userID.ToString() }
298 };
299
300 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
301 if (response["Success"].AsBoolean())
302 return response["SessionID"].AsUUID().ToString();
303 else
304 return String.Empty;
305 }
306 }
307}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs
new file mode 100644
index 0000000..a397740
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs
@@ -0,0 +1,344 @@
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.Collections.Specialized;
31// DEBUG ON
32using System.Diagnostics;
33// DEBUG OFF
34using System.Reflection;
35using log4net;
36using Mono.Addins;
37using Nini.Config;
38using OpenSim.Framework;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Services.Interfaces;
42using OpenMetaverse;
43using OpenMetaverse.StructuredData;
44
45namespace OpenSim.Services.Connectors.SimianGrid
46{
47 /// <summary>
48 /// Connects avatar appearance data to the SimianGrid backend
49 /// </summary>
50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianAvatarServiceConnector")]
51 public class SimianAvatarServiceConnector : IAvatarService, ISharedRegionModule
52 {
53 private static readonly ILog m_log =
54 LogManager.GetLogger(
55 MethodBase.GetCurrentMethod().DeclaringType);
56// private static string ZeroID = UUID.Zero.ToString();
57
58 private string m_serverUrl = String.Empty;
59 private bool m_Enabled = false;
60
61 #region ISharedRegionModule
62
63 public Type ReplaceableInterface { get { return null; } }
64 public void RegionLoaded(Scene scene) { }
65 public void PostInitialise() { }
66 public void Close() { }
67
68 public SimianAvatarServiceConnector() { }
69 public string Name { get { return "SimianAvatarServiceConnector"; } }
70 public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IAvatarService>(this); } }
71 public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IAvatarService>(this); } }
72
73 #endregion ISharedRegionModule
74
75 public SimianAvatarServiceConnector(IConfigSource source)
76 {
77 CommonInit(source);
78 }
79
80 public void Initialise(IConfigSource source)
81 {
82 IConfig moduleConfig = source.Configs["Modules"];
83 if (moduleConfig != null)
84 {
85 string name = moduleConfig.GetString("AvatarServices", "");
86 if (name == Name)
87 CommonInit(source);
88 }
89 }
90
91 private void CommonInit(IConfigSource source)
92 {
93 IConfig gridConfig = source.Configs["AvatarService"];
94 if (gridConfig != null)
95 {
96 string serviceUrl = gridConfig.GetString("AvatarServerURI");
97 if (!String.IsNullOrEmpty(serviceUrl))
98 {
99 if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
100 serviceUrl = serviceUrl + '/';
101 m_serverUrl = serviceUrl;
102 m_Enabled = true;
103 }
104 }
105
106 if (String.IsNullOrEmpty(m_serverUrl))
107 m_log.Info("[SIMIAN AVATAR CONNECTOR]: No AvatarServerURI specified, disabling connector");
108 }
109
110 #region IAvatarService
111
112 // <summary>
113 // Retrieves the LLPackedAppearance field from user data and unpacks
114 // it into an AvatarAppearance structure
115 // </summary>
116 // <param name="userID"></param>
117 public AvatarAppearance GetAppearance(UUID userID)
118 {
119 NameValueCollection requestArgs = new NameValueCollection
120 {
121 { "RequestMethod", "GetUser" },
122 { "UserID", userID.ToString() }
123 };
124
125 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
126 if (response["Success"].AsBoolean())
127 {
128 OSDMap map = null;
129 try { map = OSDParser.DeserializeJson(response["LLPackedAppearance"].AsString()) as OSDMap; }
130 catch { }
131
132 if (map != null)
133 {
134 AvatarAppearance appearance = new AvatarAppearance(map);
135// DEBUG ON
136 m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR] retrieved appearance for {0}:\n{1}",userID,appearance.ToString());
137// DEBUG OFF
138 return appearance;
139 }
140
141 m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR]: Failed to decode appearance for {0}",userID);
142 return null;
143 }
144
145 m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR]: Failed to get appearance for {0}: {1}",
146 userID,response["Message"].AsString());
147 return null;
148 }
149
150 // <summary>
151 // </summary>
152 // <param name=""></param>
153 public bool SetAppearance(UUID userID, AvatarAppearance appearance)
154 {
155 OSDMap map = appearance.Pack();
156 if (map == null)
157 {
158 m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR]: Failed to encode appearance for {0}",userID);
159 return false;
160 }
161
162 // m_log.DebugFormat("[SIMIAN AVATAR CONNECTOR] save appearance for {0}",userID);
163
164 NameValueCollection requestArgs = new NameValueCollection
165 {
166 { "RequestMethod", "AddUserData" },
167 { "UserID", userID.ToString() },
168 { "LLPackedAppearance", OSDParser.SerializeJsonString(map) }
169 };
170
171 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
172 bool success = response["Success"].AsBoolean();
173
174 if (! success)
175 m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR]: Failed to save appearance for {0}: {1}",
176 userID,response["Message"].AsString());
177
178 return success;
179 }
180
181 // <summary>
182 // </summary>
183 // <param name=""></param>
184 public AvatarData GetAvatar(UUID userID)
185 {
186 NameValueCollection requestArgs = new NameValueCollection
187 {
188 { "RequestMethod", "GetUser" },
189 { "UserID", userID.ToString() }
190 };
191
192 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
193 if (response["Success"].AsBoolean())
194 {
195 OSDMap map = null;
196 try { map = OSDParser.DeserializeJson(response["LLAppearance"].AsString()) as OSDMap; }
197 catch { }
198
199 if (map != null)
200 {
201 AvatarWearable[] wearables = new AvatarWearable[13];
202 wearables[0] = new AvatarWearable(map["ShapeItem"].AsUUID(), map["ShapeAsset"].AsUUID());
203 wearables[1] = new AvatarWearable(map["SkinItem"].AsUUID(), map["SkinAsset"].AsUUID());
204 wearables[2] = new AvatarWearable(map["HairItem"].AsUUID(), map["HairAsset"].AsUUID());
205 wearables[3] = new AvatarWearable(map["EyesItem"].AsUUID(), map["EyesAsset"].AsUUID());
206 wearables[4] = new AvatarWearable(map["ShirtItem"].AsUUID(), map["ShirtAsset"].AsUUID());
207 wearables[5] = new AvatarWearable(map["PantsItem"].AsUUID(), map["PantsAsset"].AsUUID());
208 wearables[6] = new AvatarWearable(map["ShoesItem"].AsUUID(), map["ShoesAsset"].AsUUID());
209 wearables[7] = new AvatarWearable(map["SocksItem"].AsUUID(), map["SocksAsset"].AsUUID());
210 wearables[8] = new AvatarWearable(map["JacketItem"].AsUUID(), map["JacketAsset"].AsUUID());
211 wearables[9] = new AvatarWearable(map["GlovesItem"].AsUUID(), map["GlovesAsset"].AsUUID());
212 wearables[10] = new AvatarWearable(map["UndershirtItem"].AsUUID(), map["UndershirtAsset"].AsUUID());
213 wearables[11] = new AvatarWearable(map["UnderpantsItem"].AsUUID(), map["UnderpantsAsset"].AsUUID());
214 wearables[12] = new AvatarWearable(map["SkirtItem"].AsUUID(), map["SkirtAsset"].AsUUID());
215
216 AvatarAppearance appearance = new AvatarAppearance();
217 appearance.Wearables = wearables;
218 appearance.AvatarHeight = (float)map["Height"].AsReal();
219
220 AvatarData avatar = new AvatarData(appearance);
221
222 // Get attachments
223 map = null;
224 try { map = OSDParser.DeserializeJson(response["LLAttachments"].AsString()) as OSDMap; }
225 catch { }
226
227 if (map != null)
228 {
229 foreach (KeyValuePair<string, OSD> kvp in map)
230 avatar.Data[kvp.Key] = kvp.Value.AsString();
231 }
232
233 return avatar;
234 }
235 else
236 {
237 m_log.Warn("[SIMIAN AVATAR CONNECTOR]: Failed to get user appearance for " + userID +
238 ", LLAppearance is missing or invalid");
239 return null;
240 }
241 }
242 else
243 {
244 m_log.Warn("[SIMIAN AVATAR CONNECTOR]: Failed to get user appearance for " + userID + ": " +
245 response["Message"].AsString());
246 }
247
248 return null;
249 }
250
251 // <summary>
252 // </summary>
253 // <param name=""></param>
254 public bool SetAvatar(UUID userID, AvatarData avatar)
255 {
256 m_log.Debug("[SIMIAN AVATAR CONNECTOR]: SetAvatar called for " + userID);
257
258 if (avatar.AvatarType == 1) // LLAvatar
259 {
260 AvatarAppearance appearance = avatar.ToAvatarAppearance();
261
262 OSDMap map = new OSDMap();
263
264 map["Height"] = OSD.FromReal(appearance.AvatarHeight);
265
266 map["BodyItem"] = appearance.Wearables[AvatarWearable.BODY][0].ItemID.ToString();
267 map["EyesItem"] = appearance.Wearables[AvatarWearable.EYES][0].ItemID.ToString();
268 map["GlovesItem"] = appearance.Wearables[AvatarWearable.GLOVES][0].ItemID.ToString();
269 map["HairItem"] = appearance.Wearables[AvatarWearable.HAIR][0].ItemID.ToString();
270 map["JacketItem"] = appearance.Wearables[AvatarWearable.JACKET][0].ItemID.ToString();
271 map["PantsItem"] = appearance.Wearables[AvatarWearable.PANTS][0].ItemID.ToString();
272 map["ShirtItem"] = appearance.Wearables[AvatarWearable.SHIRT][0].ItemID.ToString();
273 map["ShoesItem"] = appearance.Wearables[AvatarWearable.SHOES][0].ItemID.ToString();
274 map["SkinItem"] = appearance.Wearables[AvatarWearable.SKIN][0].ItemID.ToString();
275 map["SkirtItem"] = appearance.Wearables[AvatarWearable.SKIRT][0].ItemID.ToString();
276 map["SocksItem"] = appearance.Wearables[AvatarWearable.SOCKS][0].ItemID.ToString();
277 map["UnderPantsItem"] = appearance.Wearables[AvatarWearable.UNDERPANTS][0].ItemID.ToString();
278 map["UnderShirtItem"] = appearance.Wearables[AvatarWearable.UNDERSHIRT][0].ItemID.ToString();
279 map["BodyAsset"] = appearance.Wearables[AvatarWearable.BODY][0].AssetID.ToString();
280 map["EyesAsset"] = appearance.Wearables[AvatarWearable.EYES][0].AssetID.ToString();
281 map["GlovesAsset"] = appearance.Wearables[AvatarWearable.GLOVES][0].AssetID.ToString();
282 map["HairAsset"] = appearance.Wearables[AvatarWearable.HAIR][0].AssetID.ToString();
283 map["JacketAsset"] = appearance.Wearables[AvatarWearable.JACKET][0].AssetID.ToString();
284 map["PantsAsset"] = appearance.Wearables[AvatarWearable.PANTS][0].AssetID.ToString();
285 map["ShirtAsset"] = appearance.Wearables[AvatarWearable.SHIRT][0].AssetID.ToString();
286 map["ShoesAsset"] = appearance.Wearables[AvatarWearable.SHOES][0].AssetID.ToString();
287 map["SkinAsset"] = appearance.Wearables[AvatarWearable.SKIN][0].AssetID.ToString();
288 map["SkirtAsset"] = appearance.Wearables[AvatarWearable.SKIRT][0].AssetID.ToString();
289 map["SocksAsset"] = appearance.Wearables[AvatarWearable.SOCKS][0].AssetID.ToString();
290 map["UnderPantsAsset"] = appearance.Wearables[AvatarWearable.UNDERPANTS][0].AssetID.ToString();
291 map["UnderShirtAsset"] = appearance.Wearables[AvatarWearable.UNDERSHIRT][0].AssetID.ToString();
292
293
294 OSDMap items = new OSDMap();
295 foreach (KeyValuePair<string, string> kvp in avatar.Data)
296 {
297 if (kvp.Key.StartsWith("_ap_"))
298 items.Add(kvp.Key, OSD.FromString(kvp.Value));
299 }
300
301 NameValueCollection requestArgs = new NameValueCollection
302 {
303 { "RequestMethod", "AddUserData" },
304 { "UserID", userID.ToString() },
305 { "LLAppearance", OSDParser.SerializeJsonString(map) },
306 { "LLAttachments", OSDParser.SerializeJsonString(items) }
307 };
308
309 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
310 bool success = response["Success"].AsBoolean();
311
312 if (!success)
313 m_log.Warn("[SIMIAN AVATAR CONNECTOR]: Failed saving appearance for " + userID + ": " + response["Message"].AsString());
314
315 return success;
316 }
317 else
318 {
319 m_log.Error("[SIMIAN AVATAR CONNECTOR]: Can't save appearance for " + userID + ". Unhandled avatar type " + avatar.AvatarType);
320 return false;
321 }
322 }
323
324 public bool ResetAvatar(UUID userID)
325 {
326 m_log.Error("[SIMIAN AVATAR CONNECTOR]: ResetAvatar called for " + userID + ", implement this");
327 return false;
328 }
329
330 public bool SetItems(UUID userID, string[] names, string[] values)
331 {
332 m_log.Error("[SIMIAN AVATAR CONNECTOR]: SetItems called for " + userID + " with " + names.Length + " names and " + values.Length + " values, implement this");
333 return false;
334 }
335
336 public bool RemoveItems(UUID userID, string[] names)
337 {
338 m_log.Error("[SIMIAN AVATAR CONNECTOR]: RemoveItems called for " + userID + " with " + names.Length + " names, implement this");
339 return false;
340 }
341
342 #endregion IAvatarService
343 }
344}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs b/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs
new file mode 100644
index 0000000..764e71f
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs
@@ -0,0 +1,180 @@
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;
30using System.Collections.Generic;
31using System.Reflection;
32using System.IO;
33using System.Web;
34
35using log4net;
36using Nini.Config;
37using Mono.Addins;
38
39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41
42using OpenSim.Framework;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45using OpenSim.Services.Interfaces;
46using Caps = OpenSim.Framework.Capabilities.Caps;
47
48namespace OpenSim.Services.Connectors.SimianGrid
49{
50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianExternalCapsModule")]
51 public class SimianExternalCapsModule : INonSharedRegionModule, IExternalCapsModule
52 {
53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54
55 private bool m_enabled = true;
56 private Scene m_scene;
57 private String m_simianURL;
58
59#region IRegionModule Members
60
61 public string Name
62 {
63 get { return this.GetType().Name; }
64 }
65
66 public void Initialise(IConfigSource config)
67 {
68 try
69 {
70 IConfig m_config;
71
72 if ((m_config = config.Configs["SimianExternalCaps"]) != null)
73 {
74 m_enabled = m_config.GetBoolean("Enabled", m_enabled);
75 if ((m_config = config.Configs["SimianGrid"]) != null)
76 {
77 m_simianURL = m_config.GetString("SimianServiceURL");
78 if (String.IsNullOrEmpty(m_simianURL))
79 {
80 //m_log.DebugFormat("[SimianGrid] service URL is not defined");
81 m_enabled = false;
82 return;
83 }
84 }
85 }
86 else
87 m_enabled = false;
88 }
89 catch (Exception e)
90 {
91 m_log.ErrorFormat("[SimianExternalCaps] initialization error: {0}",e.Message);
92 return;
93 }
94 }
95
96 public void PostInitialise() { }
97 public void Close() { }
98
99 public void AddRegion(Scene scene)
100 {
101 if (! m_enabled)
102 return;
103
104 m_scene = scene;
105 m_scene.RegisterModuleInterface<IExternalCapsModule>(this);
106 }
107
108 public void RemoveRegion(Scene scene)
109 {
110 if (! m_enabled)
111 return;
112
113 m_scene.EventManager.OnRegisterCaps -= RegisterCapsEventHandler;
114 m_scene.EventManager.OnDeregisterCaps -= DeregisterCapsEventHandler;
115 }
116
117 public void RegionLoaded(Scene scene)
118 {
119 if (! m_enabled)
120 return;
121
122 m_scene.EventManager.OnRegisterCaps += RegisterCapsEventHandler;
123 m_scene.EventManager.OnDeregisterCaps += DeregisterCapsEventHandler;
124 }
125
126 public Type ReplaceableInterface
127 {
128 get { return null; }
129 }
130
131#endregion
132
133#region IExternalCapsModule
134 // Eg http://grid.sciencesim.com/GridPublic/%CAP%/%OP%/"
135 public bool RegisterExternalUserCapsHandler(UUID agentID, Caps caps, String capName, String urlSkel)
136 {
137 UUID cap = UUID.Random();
138
139 // Call to simian to register the cap we generated
140 // NameValueCollection requestArgs = new NameValueCollection
141 // {
142 // { "RequestMethod", "AddCapability" },
143 // { "Resource", "user" },
144 // { "Expiration", 0 },
145 // { "OwnerID", agentID.ToString() },
146 // { "CapabilityID", cap.ToString() }
147 // };
148
149 // OSDMap response = SimianGrid.PostToService(m_simianURL, requestArgs);
150
151 Dictionary<String,String> subs = new Dictionary<String,String>();
152 subs["%OP%"] = capName;
153 subs["%USR%"] = agentID.ToString();
154 subs["%CAP%"] = cap.ToString();
155 subs["%SIM%"] = m_scene.RegionInfo.RegionID.ToString();
156
157 caps.RegisterHandler(capName,ExpandSkeletonURL(urlSkel,subs));
158 return true;
159 }
160
161#endregion
162
163#region EventHandlers
164 public void RegisterCapsEventHandler(UUID agentID, Caps caps) { }
165 public void DeregisterCapsEventHandler(UUID agentID, Caps caps) { }
166#endregion
167
168 private String ExpandSkeletonURL(String urlSkel, Dictionary<String,String> subs)
169 {
170 String result = urlSkel;
171
172 foreach (KeyValuePair<String,String> kvp in subs)
173 {
174 result = result.Replace(kvp.Key,kvp.Value);
175 }
176
177 return result;
178 }
179 }
180} \ No newline at end of file
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs
new file mode 100644
index 0000000..9a8164c
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs
@@ -0,0 +1,236 @@
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.Collections.Specialized;
31using System.Reflection;
32using log4net;
33using Nini.Config;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Framework;
37using OpenSim.Services.Interfaces;
38
39using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
40
41namespace OpenSim.Services.Connectors.SimianGrid
42{
43 /// <summary>
44 /// Stores and retrieves friend lists from the SimianGrid backend
45 /// </summary>
46 public class SimianFriendsServiceConnector : IFriendsService
47 {
48 private static readonly ILog m_log =
49 LogManager.GetLogger(
50 MethodBase.GetCurrentMethod().DeclaringType);
51
52 private string m_serverUrl = String.Empty;
53
54 public SimianFriendsServiceConnector(IConfigSource source)
55 {
56 Initialise(source);
57 }
58
59 public void Initialise(IConfigSource source)
60 {
61 IConfig gridConfig = source.Configs["FriendsService"];
62 if (gridConfig != null)
63 {
64 string serviceUrl = gridConfig.GetString("FriendsServerURI");
65 if (!String.IsNullOrEmpty(serviceUrl))
66 {
67 if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
68 serviceUrl = serviceUrl + '/';
69 m_serverUrl = serviceUrl;
70 }
71 }
72
73 if (String.IsNullOrEmpty(m_serverUrl))
74 m_log.Info("[SIMIAN FRIENDS CONNECTOR]: No FriendsServerURI specified, disabling connector");
75 }
76
77 #region IFriendsService
78
79 public FriendInfo[] GetFriends(UUID principalID)
80 {
81 return GetFriends(principalID.ToString());
82 }
83
84 public FriendInfo[] GetFriends(string principalID)
85 {
86 if (String.IsNullOrEmpty(m_serverUrl))
87 return new FriendInfo[0];
88
89 Dictionary<UUID, FriendInfo> friends = new Dictionary<UUID, FriendInfo>();
90
91 OSDArray friendsArray = GetFriended(principalID);
92 OSDArray friendedMeArray = GetFriendedBy(principalID);
93
94 // Load the list of friends and their granted permissions
95 for (int i = 0; i < friendsArray.Count; i++)
96 {
97 OSDMap friendEntry = friendsArray[i] as OSDMap;
98 if (friendEntry != null)
99 {
100 UUID friendID = friendEntry["Key"].AsUUID();
101
102 FriendInfo friend = new FriendInfo();
103 if (!UUID.TryParse(principalID, out friend.PrincipalID))
104 {
105 string tmp = string.Empty;
106 if (!Util.ParseUniversalUserIdentifier(principalID, out friend.PrincipalID, out tmp, out tmp, out tmp, out tmp))
107 // bad record. ignore this entry
108 continue;
109 }
110
111 friend.Friend = friendID.ToString();
112 friend.MyFlags = friendEntry["Value"].AsInteger();
113 friend.TheirFlags = -1;
114
115 friends[friendID] = friend;
116 }
117 }
118
119 // Load the permissions those friends have granted to this user
120 for (int i = 0; i < friendedMeArray.Count; i++)
121 {
122 OSDMap friendedMeEntry = friendedMeArray[i] as OSDMap;
123 if (friendedMeEntry != null)
124 {
125 UUID friendID = friendedMeEntry["OwnerID"].AsUUID();
126
127 FriendInfo friend;
128 if (friends.TryGetValue(friendID, out friend))
129 friend.TheirFlags = friendedMeEntry["Value"].AsInteger();
130 }
131 }
132
133 // Convert the dictionary of friends to an array and return it
134 FriendInfo[] array = new FriendInfo[friends.Count];
135 int j = 0;
136 foreach (FriendInfo friend in friends.Values)
137 array[j++] = friend;
138
139 return array;
140 }
141
142 public bool StoreFriend(string principalID, string friend, int flags)
143 {
144 if (String.IsNullOrEmpty(m_serverUrl))
145 return true;
146
147 NameValueCollection requestArgs = new NameValueCollection
148 {
149 { "RequestMethod", "AddGeneric" },
150 { "OwnerID", principalID.ToString() },
151 { "Type", "Friend" },
152 { "Key", friend },
153 { "Value", flags.ToString() }
154 };
155
156 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
157 bool success = response["Success"].AsBoolean();
158
159 if (!success)
160 m_log.Error("[SIMIAN FRIENDS CONNECTOR]: Failed to store friend " + friend + " for user " + principalID + ": " + response["Message"].AsString());
161
162 return success;
163 }
164
165 public bool Delete(UUID principalID, string friend)
166 {
167 return Delete(principalID.ToString(), friend);
168 }
169
170 public bool Delete(string principalID, string friend)
171 {
172 if (String.IsNullOrEmpty(m_serverUrl))
173 return true;
174
175 NameValueCollection requestArgs = new NameValueCollection
176 {
177 { "RequestMethod", "RemoveGeneric" },
178 { "OwnerID", principalID.ToString() },
179 { "Type", "Friend" },
180 { "Key", friend }
181 };
182
183 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
184 bool success = response["Success"].AsBoolean();
185
186 if (!success)
187 m_log.Error("[SIMIAN FRIENDS CONNECTOR]: Failed to remove friend " + friend + " for user " + principalID + ": " + response["Message"].AsString());
188
189 return success;
190 }
191
192 #endregion IFriendsService
193
194 private OSDArray GetFriended(string ownerID)
195 {
196 NameValueCollection requestArgs = new NameValueCollection
197 {
198 { "RequestMethod", "GetGenerics" },
199 { "OwnerID", ownerID.ToString() },
200 { "Type", "Friend" }
201 };
202
203 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
204 if (response["Success"].AsBoolean() && response["Entries"] is OSDArray)
205 {
206 return (OSDArray)response["Entries"];
207 }
208 else
209 {
210 m_log.Warn("[SIMIAN FRIENDS CONNECTOR]: Failed to retrieve friends for user " + ownerID + ": " + response["Message"].AsString());
211 return new OSDArray(0);
212 }
213 }
214
215 private OSDArray GetFriendedBy(string ownerID)
216 {
217 NameValueCollection requestArgs = new NameValueCollection
218 {
219 { "RequestMethod", "GetGenerics" },
220 { "Key", ownerID.ToString() },
221 { "Type", "Friend" }
222 };
223
224 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
225 if (response["Success"].AsBoolean() && response["Entries"] is OSDArray)
226 {
227 return (OSDArray)response["Entries"];
228 }
229 else
230 {
231 m_log.Warn("[SIMIAN FRIENDS CONNECTOR]: Failed to retrieve reverse friends for user " + ownerID + ": " + response["Message"].AsString());
232 return new OSDArray(0);
233 }
234 }
235 }
236}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs
new file mode 100644
index 0000000..a35d749
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs
@@ -0,0 +1,147 @@
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.Collections.Specialized;
31using System.Reflection;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Services.Interfaces;
39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41
42[assembly: Addin("SimianGrid", OpenSim.VersionInfo.VersionNumber)]
43[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
44
45namespace OpenSim.Services.Connectors.SimianGrid
46{
47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianExternalCapsModule")]
48 public class SimianGrid : ISharedRegionModule
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 private IConfig m_config = null;
53
54 private String m_simianURL;
55
56#region IRegionModule Members
57
58 public string Name
59 {
60 get { return this.GetType().Name; }
61 }
62
63 public void Initialise(IConfigSource config)
64 {
65 try
66 {
67 m_config = config.Configs["SimianGrid"];
68
69 if (m_config != null)
70 {
71 m_simianURL = m_config.GetString("SimianServiceURL");
72 if (String.IsNullOrEmpty(m_simianURL))
73 {
74 // m_log.DebugFormat("[SimianGrid] service URL is not defined");
75 return;
76 }
77
78 InitialiseSimCap();
79 SimulatorCapability = SimulatorCapability.Trim();
80 m_log.InfoFormat("[SimianExternalCaps] using {0} as simulator capability",SimulatorCapability);
81 }
82 }
83 catch (Exception e)
84 {
85 m_log.ErrorFormat("[SimianExternalCaps] initialization error: {0}",e.Message);
86 return;
87 }
88 }
89
90 public void PostInitialise() { }
91 public void Close() { }
92 public void AddRegion(Scene scene) { }
93 public void RemoveRegion(Scene scene) { }
94 public void RegionLoaded(Scene scene) { }
95
96 public Type ReplaceableInterface
97 {
98 get { return null; }
99 }
100
101 ///<summary>
102 /// Try a variety of methods for finding the simian simulator capability; first check the
103 /// configuration itself, then look for a file that contains the cap, then finally look
104 /// for an environment variable that contains it.
105 ///</summary>
106 private void InitialiseSimCap()
107 {
108 if (m_config.Contains("SimulatorCapability"))
109 {
110 SimulatorCapability = m_config.GetString("SimulatorCapability");
111 return;
112 }
113
114 if (m_config.Contains("SimulatorCapabilityFile"))
115 {
116 String filename = m_config.GetString("SimulatorCapabilityFile");
117 if (System.IO.File.Exists(filename))
118 {
119 SimulatorCapability = System.IO.File.ReadAllText(filename);
120 return;
121 }
122 }
123
124 if (m_config.Contains("SimulatorCapabilityVariable"))
125 {
126 String envname = m_config.GetString("SimulatorCapabilityVariable");
127 String envvalue = System.Environment.GetEnvironmentVariable(envname);
128 if (envvalue != null)
129 {
130 SimulatorCapability = envvalue;
131 return;
132 }
133 }
134
135 m_log.WarnFormat("[SimianExternalCaps] no method specified for simulator capability");
136 }
137
138#endregion
139
140 public static String SimulatorCapability = UUID.Zero.ToString();
141 public static OSDMap PostToService(string url, NameValueCollection data)
142 {
143 data["cap"] = SimulatorCapability;
144 return WebUtil.PostToService(url, data);
145 }
146 }
147} \ No newline at end of file
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs
new file mode 100644
index 0000000..8375c95
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs
@@ -0,0 +1,266 @@
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.Collections.Specialized;
31using System.Reflection;
32using System.Net;
33using System.IO;
34using System.Timers;
35using System.Drawing;
36using System.Drawing.Imaging;
37
38using log4net;
39using Mono.Addins;
40using Nini.Config;
41using OpenSim.Framework;
42using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes;
44using OpenMetaverse;
45using OpenMetaverse.StructuredData;
46
47//namespace OpenSim.Region.OptionalModules.Simian
48namespace OpenSim.Services.Connectors.SimianGrid
49{
50 /// <summary>
51 /// </summary>
52 /// <remarks>
53 /// </remarks>
54
55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianGridMaptile")]
56 public class SimianGridMaptile : ISharedRegionModule
57 {
58 private static readonly ILog m_log =
59 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60
61 private bool m_enabled = false;
62 private string m_serverUrl = String.Empty;
63 private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
64
65 private int m_refreshtime = 0;
66 private int m_lastrefresh = 0;
67 private System.Timers.Timer m_refreshTimer = new System.Timers.Timer();
68
69 #region ISharedRegionModule
70
71 public Type ReplaceableInterface { get { return null; } }
72 public string Name { get { return "SimianGridMaptile"; } }
73 public void RegionLoaded(Scene scene) { }
74 public void Close() { }
75
76 ///<summary>
77 ///
78 ///</summary>
79 public void Initialise(IConfigSource source)
80 {
81 IConfig config = source.Configs["SimianGridMaptiles"];
82 if (config == null)
83 return;
84
85 if (! config.GetBoolean("Enabled", false))
86 return;
87
88 m_serverUrl = config.GetString("MaptileURL");
89 if (String.IsNullOrEmpty(m_serverUrl))
90 return;
91
92 int refreshseconds = Convert.ToInt32(config.GetString("RefreshTime"));
93 if (refreshseconds <= 0)
94 return;
95
96 m_refreshtime = refreshseconds * 1000; // convert from seconds to ms
97 m_log.InfoFormat("[SIMIAN MAPTILE] enabled with refresh timeout {0} and URL {1}",
98 m_refreshtime,m_serverUrl);
99
100 m_enabled = true;
101 }
102
103 ///<summary>
104 ///
105 ///</summary>
106 public void PostInitialise()
107 {
108 if (m_enabled)
109 {
110 m_refreshTimer.Enabled = true;
111 m_refreshTimer.AutoReset = true;
112 m_refreshTimer.Interval = 5 * 60 * 1000; // every 5 minutes
113 m_refreshTimer.Elapsed += new ElapsedEventHandler(HandleMaptileRefresh);
114 }
115 }
116
117
118 ///<summary>
119 ///
120 ///</summary>
121 public void AddRegion(Scene scene)
122 {
123 if (! m_enabled)
124 return;
125
126 // Every shared region module has to maintain an indepedent list of
127 // currently running regions
128 lock (m_scenes)
129 m_scenes[scene.RegionInfo.RegionID] = scene;
130 }
131
132 ///<summary>
133 ///
134 ///</summary>
135 public void RemoveRegion(Scene scene)
136 {
137 if (! m_enabled)
138 return;
139
140 lock (m_scenes)
141 m_scenes.Remove(scene.RegionInfo.RegionID);
142 }
143
144 #endregion ISharedRegionModule
145
146 ///<summary>
147 ///
148 ///</summary>
149 private void HandleMaptileRefresh(object sender, EventArgs ea)
150 {
151 // this approach is a bit convoluted becase we want to wait for the
152 // first upload to happen on startup but after all the objects are
153 // loaded and initialized
154 if (m_lastrefresh > 0 && Util.EnvironmentTickCountSubtract(m_lastrefresh) < m_refreshtime)
155 return;
156
157 m_log.DebugFormat("[SIMIAN MAPTILE] map refresh fired");
158 lock (m_scenes)
159 {
160 foreach (IScene scene in m_scenes.Values)
161 {
162 try
163 {
164 UploadMapTile(scene);
165 }
166 catch (Exception ex)
167 {
168 m_log.WarnFormat("[SIMIAN MAPTILE] something bad happened {0}",ex.Message);
169 }
170 }
171 }
172
173 m_lastrefresh = Util.EnvironmentTickCount();
174 }
175
176 ///<summary>
177 ///
178 ///</summary>
179 private void UploadMapTile(IScene scene)
180 {
181 m_log.DebugFormat("[SIMIAN MAPTILE]: upload maptile for {0}",scene.RegionInfo.RegionName);
182
183 // Create a PNG map tile and upload it to the AddMapTile API
184 IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>();
185 if (tileGenerator == null)
186 {
187 m_log.Warn("[SIMIAN MAPTILE]: Cannot upload PNG map tile without an ImageGenerator");
188 return;
189 }
190
191 using (Bitmap mapTile = tileGenerator.CreateMapTile())
192 {
193 if (mapTile != null)
194 {
195 // If the region/maptile is legacy sized, just upload the one tile like it has always been done
196 if (mapTile.Width == Constants.RegionSize && mapTile.Height == Constants.RegionSize)
197 {
198 ConvertAndUploadMaptile(mapTile, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY);
199 }
200 else
201 {
202 // For larger regions (varregion) we must cut the region image into legacy sized
203 // pieces since that is how the maptile system works.
204 // Note the assumption that varregions are always a multiple of legacy size.
205 for (uint xx = 0; xx < mapTile.Width; xx += Constants.RegionSize)
206 {
207 for (uint yy = 0; yy < mapTile.Height; yy += Constants.RegionSize)
208 {
209 // Images are addressed from the upper left corner so have to do funny
210 // math to pick out the sub-tile since regions are numbered from
211 // the lower left.
212 Rectangle rect = new Rectangle(
213 (int)xx,
214 mapTile.Height - (int)yy - (int)Constants.RegionSize,
215 (int)Constants.RegionSize, (int)Constants.RegionSize);
216
217 using (Bitmap subMapTile = mapTile.Clone(rect, mapTile.PixelFormat))
218 {
219 uint locX = scene.RegionInfo.RegionLocX + (xx / Constants.RegionSize);
220 uint locY = scene.RegionInfo.RegionLocY + (yy / Constants.RegionSize);
221
222 ConvertAndUploadMaptile(subMapTile, locX, locY);
223 }
224 }
225 }
226 }
227 }
228 else
229 {
230 m_log.WarnFormat("[SIMIAN MAPTILE] Tile image generation failed");
231 }
232 }
233
234 }
235
236 ///<summary>
237 ///
238 ///</summary>
239 private void ConvertAndUploadMaptile(Image mapTile, uint locX, uint locY)
240 {
241 //m_log.DebugFormat("[SIMIAN MAPTILE]: upload maptile for location {0}, {1}", locX, locY);
242
243 byte[] pngData = Utils.EmptyBytes;
244 using (MemoryStream stream = new MemoryStream())
245 {
246 mapTile.Save(stream, ImageFormat.Png);
247 pngData = stream.ToArray();
248 }
249
250 NameValueCollection requestArgs = new NameValueCollection
251 {
252 { "RequestMethod", "xAddMapTile" },
253 { "X", locX.ToString() },
254 { "Y", locY.ToString() },
255 { "ContentType", "image/png" },
256 { "EncodedData", System.Convert.ToBase64String(pngData) }
257 };
258
259 OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
260 if (! response["Success"].AsBoolean())
261 {
262 m_log.WarnFormat("[SIMIAN MAPTILE] failed to store map tile; {0}",response["Message"].AsString());
263 }
264 }
265 }
266} \ No newline at end of file
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
new file mode 100644
index 0000000..b031f21
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
@@ -0,0 +1,484 @@
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.Collections.Specialized;
31using System.IO;
32using System.Net;
33using System.Reflection;
34using log4net;
35using Mono.Addins;
36using Nini.Config;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenMetaverse;
42using OpenMetaverse.StructuredData;
43
44using GridRegion = OpenSim.Services.Interfaces.GridRegion;
45
46namespace OpenSim.Services.Connectors.SimianGrid
47{
48 /// <summary>
49 /// Connects region registration and neighbor lookups to the SimianGrid
50 /// backend
51 /// </summary>
52 public class SimianGridServiceConnector : IGridService
53 {
54 private static readonly ILog m_log =
55 LogManager.GetLogger(
56 MethodBase.GetCurrentMethod().DeclaringType);
57
58 private string m_ServerURI = String.Empty;
59// private bool m_Enabled = false;
60
61 public SimianGridServiceConnector() { }
62 public SimianGridServiceConnector(string serverURI)
63 {
64 m_ServerURI = serverURI.TrimEnd('/');
65 }
66
67 public SimianGridServiceConnector(IConfigSource source)
68 {
69 CommonInit(source);
70 }
71
72 public void Initialise(IConfigSource source)
73 {
74 CommonInit(source);
75 }
76
77 private void CommonInit(IConfigSource source)
78 {
79 IConfig gridConfig = source.Configs["GridService"];
80 if (gridConfig == null)
81 {
82 m_log.Error("[SIMIAN GRID CONNECTOR]: GridService missing from OpenSim.ini");
83 throw new Exception("Grid connector init error");
84 }
85
86 string serviceUrl = gridConfig.GetString("GridServerURI");
87 if (String.IsNullOrEmpty(serviceUrl))
88 {
89 m_log.Error("[SIMIAN GRID CONNECTOR]: No Server URI named in section GridService");
90 throw new Exception("Grid connector init error");
91 }
92
93 if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
94 serviceUrl = serviceUrl + '/';
95 m_ServerURI = serviceUrl;
96// m_Enabled = true;
97 }
98
99 #region IGridService
100
101 public string RegisterRegion(UUID scopeID, GridRegion regionInfo)
102 {
103 Vector3d minPosition = new Vector3d(regionInfo.RegionLocX, regionInfo.RegionLocY, 0.0);
104 Vector3d maxPosition = minPosition + new Vector3d(regionInfo.RegionSizeX, regionInfo.RegionSizeY, Constants.RegionHeight);
105
106 OSDMap extraData = new OSDMap
107 {
108 { "ServerURI", OSD.FromString(regionInfo.ServerURI) },
109 { "InternalAddress", OSD.FromString(regionInfo.InternalEndPoint.Address.ToString()) },
110 { "InternalPort", OSD.FromInteger(regionInfo.InternalEndPoint.Port) },
111 { "ExternalAddress", OSD.FromString(regionInfo.ExternalEndPoint.Address.ToString()) },
112 { "ExternalPort", OSD.FromInteger(regionInfo.ExternalEndPoint.Port) },
113 { "MapTexture", OSD.FromUUID(regionInfo.TerrainImage) },
114 { "Access", OSD.FromInteger(regionInfo.Access) },
115 { "RegionSecret", OSD.FromString(regionInfo.RegionSecret) },
116 { "EstateOwner", OSD.FromUUID(regionInfo.EstateOwner) },
117 { "Token", OSD.FromString(regionInfo.Token) }
118 };
119
120 NameValueCollection requestArgs = new NameValueCollection
121 {
122 { "RequestMethod", "AddScene" },
123 { "SceneID", regionInfo.RegionID.ToString() },
124 { "Name", regionInfo.RegionName },
125 { "MinPosition", minPosition.ToString() },
126 { "MaxPosition", maxPosition.ToString() },
127 { "Address", regionInfo.ServerURI },
128 { "Enabled", "1" },
129 { "ExtraData", OSDParser.SerializeJsonString(extraData) }
130 };
131
132 OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs);
133 if (response["Success"].AsBoolean())
134 return String.Empty;
135 else
136 return "Region registration for " + regionInfo.RegionName + " failed: " + response["Message"].AsString();
137 }
138
139 public bool DeregisterRegion(UUID regionID)
140 {
141 NameValueCollection requestArgs = new NameValueCollection
142 {
143 { "RequestMethod", "AddScene" },
144 { "SceneID", regionID.ToString() },
145 { "Enabled", "0" }
146 };
147
148 OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs);
149 bool success = response["Success"].AsBoolean();
150
151 if (!success)
152 m_log.Warn("[SIMIAN GRID CONNECTOR]: Region deregistration for " + regionID + " failed: " + response["Message"].AsString());
153
154 return success;
155 }
156
157 public List<GridRegion> GetNeighbours(UUID scopeID, UUID regionID)
158 {
159 GridRegion region = GetRegionByUUID(scopeID, regionID);
160
161 int NEIGHBOR_RADIUS = Math.Max(region.RegionSizeX, region.RegionSizeY) / 2;
162
163 if (region != null)
164 {
165 List<GridRegion> regions = GetRegionRange(scopeID,
166 region.RegionLocX - NEIGHBOR_RADIUS, region.RegionLocX + region.RegionSizeX + NEIGHBOR_RADIUS,
167 region.RegionLocY - NEIGHBOR_RADIUS, region.RegionLocY + region.RegionSizeY + NEIGHBOR_RADIUS);
168
169 for (int i = 0; i < regions.Count; i++)
170 {
171 if (regions[i].RegionID == regionID)
172 {
173 regions.RemoveAt(i);
174 break;
175 }
176 }
177
178// m_log.Debug("[SIMIAN GRID CONNECTOR]: Found " + regions.Count + " neighbors for region " + regionID);
179 return regions;
180 }
181
182 return new List<GridRegion>(0);
183 }
184
185 public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID)
186 {
187 NameValueCollection requestArgs = new NameValueCollection
188 {
189 { "RequestMethod", "GetScene" },
190 { "SceneID", regionID.ToString() }
191 };
192
193 // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request region with uuid {0}",regionID.ToString());
194
195 OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs);
196 if (response["Success"].AsBoolean())
197 {
198 // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] uuid request successful {0}",response["Name"].AsString());
199 return ResponseToGridRegion(response);
200 }
201 else
202 {
203 m_log.Warn("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region " + regionID);
204 return null;
205 }
206 }
207
208 public GridRegion GetRegionByPosition(UUID scopeID, int x, int y)
209 {
210 // Go one meter in from the requested x/y coords to avoid requesting a position
211 // that falls on the border of two sims
212 Vector3d position = new Vector3d(x + 1, y + 1, 0.0);
213
214 NameValueCollection requestArgs = new NameValueCollection
215 {
216 { "RequestMethod", "GetScene" },
217 { "Position", position.ToString() },
218 { "Enabled", "1" }
219 };
220
221 // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request grid at {0}",position.ToString());
222
223 OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs);
224 if (response["Success"].AsBoolean())
225 {
226 // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] position request successful {0}",response["Name"].AsString());
227 return ResponseToGridRegion(response);
228 }
229 else
230 {
231 // m_log.InfoFormat("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region at {0},{1}",
232 // Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y));
233 return null;
234 }
235 }
236
237 public GridRegion GetRegionByName(UUID scopeID, string regionName)
238 {
239 List<GridRegion> regions = GetRegionsByName(scopeID, regionName, 1);
240
241 m_log.Debug("[SIMIAN GRID CONNECTOR]: Got " + regions.Count + " matches for region name " + regionName);
242
243 if (regions.Count > 0)
244 return regions[0];
245
246 return null;
247 }
248
249 public List<GridRegion> GetRegionsByName(UUID scopeID, string name, int maxNumber)
250 {
251 List<GridRegion> foundRegions = new List<GridRegion>();
252
253 NameValueCollection requestArgs = new NameValueCollection
254 {
255 { "RequestMethod", "GetScenes" },
256 { "NameQuery", name },
257 { "Enabled", "1" }
258 };
259 if (maxNumber > 0)
260 requestArgs["MaxNumber"] = maxNumber.ToString();
261
262 // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request regions with name {0}",name);
263
264 OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs);
265 if (response["Success"].AsBoolean())
266 {
267 // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] found regions with name {0}",name);
268
269 OSDArray array = response["Scenes"] as OSDArray;
270 if (array != null)
271 {
272 for (int i = 0; i < array.Count; i++)
273 {
274 GridRegion region = ResponseToGridRegion(array[i] as OSDMap);
275 if (region != null)
276 foundRegions.Add(region);
277 }
278 }
279 }
280
281 return foundRegions;
282 }
283
284 public List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax)
285 {
286 List<GridRegion> foundRegions = new List<GridRegion>();
287
288 Vector3d minPosition = new Vector3d(xmin, ymin, 0.0);
289 Vector3d maxPosition = new Vector3d(xmax, ymax, Constants.RegionHeight);
290
291 NameValueCollection requestArgs = new NameValueCollection
292 {
293 { "RequestMethod", "GetScenes" },
294 { "MinPosition", minPosition.ToString() },
295 { "MaxPosition", maxPosition.ToString() },
296 { "Enabled", "1" }
297 };
298
299 //m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request regions by range {0} to {1}",minPosition.ToString(),maxPosition.ToString());
300
301
302 OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs);
303 if (response["Success"].AsBoolean())
304 {
305 OSDArray array = response["Scenes"] as OSDArray;
306 if (array != null)
307 {
308 for (int i = 0; i < array.Count; i++)
309 {
310 GridRegion region = ResponseToGridRegion(array[i] as OSDMap);
311 if (region != null)
312 foundRegions.Add(region);
313 }
314 }
315 }
316
317 return foundRegions;
318 }
319
320 public List<GridRegion> GetDefaultRegions(UUID scopeID)
321 {
322 // TODO: Allow specifying the default grid location
323 const int DEFAULT_X = 1000 * 256;
324 const int DEFAULT_Y = 1000 * 256;
325
326 GridRegion defRegion = GetNearestRegion(new Vector3d(DEFAULT_X, DEFAULT_Y, 0.0), true);
327 if (defRegion != null)
328 return new List<GridRegion>(1) { defRegion };
329 else
330 return new List<GridRegion>(0);
331 }
332
333 public List<GridRegion> GetDefaultHypergridRegions(UUID scopeID)
334 {
335 // TODO: Allow specifying the default grid location
336 return GetDefaultRegions(scopeID);
337 }
338
339 public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y)
340 {
341 GridRegion defRegion = GetNearestRegion(new Vector3d(x, y, 0.0), true);
342 if (defRegion != null)
343 return new List<GridRegion>(1) { defRegion };
344 else
345 return new List<GridRegion>(0);
346 }
347
348 public List<GridRegion> GetHyperlinks(UUID scopeID)
349 {
350 List<GridRegion> foundRegions = new List<GridRegion>();
351
352 NameValueCollection requestArgs = new NameValueCollection
353 {
354 { "RequestMethod", "GetScenes" },
355 { "HyperGrid", "true" },
356 { "Enabled", "1" }
357 };
358
359 OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs);
360 if (response["Success"].AsBoolean())
361 {
362 // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] found regions with name {0}",name);
363
364 OSDArray array = response["Scenes"] as OSDArray;
365 if (array != null)
366 {
367 for (int i = 0; i < array.Count; i++)
368 {
369 GridRegion region = ResponseToGridRegion(array[i] as OSDMap);
370 if (region != null)
371 foundRegions.Add(region);
372 }
373 }
374 }
375
376 return foundRegions;
377 }
378
379 public int GetRegionFlags(UUID scopeID, UUID regionID)
380 {
381 NameValueCollection requestArgs = new NameValueCollection
382 {
383 { "RequestMethod", "GetScene" },
384 { "SceneID", regionID.ToString() }
385 };
386
387 m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request region flags for {0}",regionID.ToString());
388
389 OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs);
390 if (response["Success"].AsBoolean())
391 {
392 OSDMap extraData = response["ExtraData"] as OSDMap;
393 int enabled = response["Enabled"].AsBoolean() ? (int)OpenSim.Framework.RegionFlags.RegionOnline : 0;
394 int hypergrid = extraData["HyperGrid"].AsBoolean() ? (int)OpenSim.Framework.RegionFlags.Hyperlink : 0;
395 int flags = enabled | hypergrid;
396 m_log.DebugFormat("[SGGC] enabled - {0} hg - {1} flags - {2}", enabled, hypergrid, flags);
397 return flags;
398 }
399 else
400 {
401 m_log.Warn("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region " + regionID + " during region flags check");
402 return -1;
403 }
404 }
405
406 public Dictionary<string, object> GetExtraFeatures()
407 {
408 /// See SimulatorFeaturesModule - Need to get map, search and destination guide
409 Dictionary<string, object> extraFeatures = new Dictionary<string, object>();
410 return extraFeatures;
411 }
412
413 #endregion IGridService
414
415 private GridRegion GetNearestRegion(Vector3d position, bool onlyEnabled)
416 {
417 NameValueCollection requestArgs = new NameValueCollection
418 {
419 { "RequestMethod", "GetScene" },
420 { "Position", position.ToString() },
421 { "FindClosest", "1" }
422 };
423 if (onlyEnabled)
424 requestArgs["Enabled"] = "1";
425
426 OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs);
427 if (response["Success"].AsBoolean())
428 {
429 return ResponseToGridRegion(response);
430 }
431 else
432 {
433 m_log.Warn("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region at " + position);
434 return null;
435 }
436 }
437
438 private GridRegion ResponseToGridRegion(OSDMap response)
439 {
440 if (response == null)
441 return null;
442
443 OSDMap extraData = response["ExtraData"] as OSDMap;
444 if (extraData == null)
445 return null;
446
447 GridRegion region = new GridRegion();
448
449 region.RegionID = response["SceneID"].AsUUID();
450 region.RegionName = response["Name"].AsString();
451
452 Vector3d minPosition = response["MinPosition"].AsVector3d();
453 Vector3d maxPosition = response["MaxPosition"].AsVector3d();
454 region.RegionLocX = (int)minPosition.X;
455 region.RegionLocY = (int)minPosition.Y;
456
457 region.RegionSizeX = (int)maxPosition.X - (int)minPosition.X;
458 region.RegionSizeY = (int)maxPosition.Y - (int)minPosition.Y;
459
460 if ( ! extraData["HyperGrid"] ) {
461 Uri httpAddress = response["Address"].AsUri();
462 region.ExternalHostName = httpAddress.Host;
463 region.HttpPort = (uint)httpAddress.Port;
464
465 IPAddress internalAddress;
466 IPAddress.TryParse(extraData["InternalAddress"].AsString(), out internalAddress);
467 if (internalAddress == null)
468 internalAddress = IPAddress.Any;
469
470 region.InternalEndPoint = new IPEndPoint(internalAddress, extraData["InternalPort"].AsInteger());
471 region.TerrainImage = extraData["MapTexture"].AsUUID();
472 region.Access = (byte)extraData["Access"].AsInteger();
473 region.RegionSecret = extraData["RegionSecret"].AsString();
474 region.EstateOwner = extraData["EstateOwner"].AsUUID();
475 region.Token = extraData["Token"].AsString();
476 region.ServerURI = extraData["ServerURI"].AsString();
477 } else {
478 region.ServerURI = response["Address"];
479 }
480
481 return region;
482 }
483 }
484}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs
new file mode 100644
index 0000000..e793420
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs
@@ -0,0 +1,941 @@
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.Collections.Specialized;
31using System.Reflection;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using PermissionMask = OpenSim.Framework.PermissionMask;
42
43namespace OpenSim.Services.Connectors.SimianGrid
44{
45 /// <summary>
46 /// Permissions bitflags
47 /// </summary>
48 /*
49 [Flags]
50 public enum PermissionMask : uint
51 {
52 None = 0,
53 Transfer = 1 << 13,
54 Modify = 1 << 14,
55 Copy = 1 << 15,
56 Move = 1 << 19,
57 Damage = 1 << 20,
58 All = 0x7FFFFFFF
59 }
60 */
61
62 /// <summary>
63 /// Connects avatar inventories to the SimianGrid backend
64 /// </summary>
65 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianInventoryServiceConnector")]
66 public class SimianInventoryServiceConnector : IInventoryService, ISharedRegionModule
67 {
68 private static readonly ILog m_log =
69 LogManager.GetLogger(
70 MethodBase.GetCurrentMethod().DeclaringType);
71
72 private string m_serverUrl = String.Empty;
73 private string m_userServerUrl = String.Empty;
74// private object m_gestureSyncRoot = new object();
75 private bool m_Enabled = false;
76
77 private const double CACHE_EXPIRATION_SECONDS = 20.0;
78 private static ExpiringCache<UUID, InventoryItemBase> m_ItemCache;
79
80 #region ISharedRegionModule
81
82 public Type ReplaceableInterface { get { return null; } }
83 public void RegionLoaded(Scene scene) { }
84 public void PostInitialise() { }
85 public void Close() { }
86
87 public SimianInventoryServiceConnector() { }
88 public string Name { get { return "SimianInventoryServiceConnector"; } }
89 public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IInventoryService>(this); } }
90 public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IInventoryService>(this); } }
91
92 #endregion ISharedRegionModule
93
94 public SimianInventoryServiceConnector(IConfigSource source)
95 {
96 CommonInit(source);
97 }
98
99 public SimianInventoryServiceConnector(string url)
100 {
101 if (!url.EndsWith("/") && !url.EndsWith("="))
102 url = url + '/';
103 m_serverUrl = url;
104
105 if (m_ItemCache == null)
106 m_ItemCache = new ExpiringCache<UUID, InventoryItemBase>();
107
108 }
109
110 public void Initialise(IConfigSource source)
111 {
112 IConfig moduleConfig = source.Configs["Modules"];
113 if (moduleConfig != null)
114 {
115 string name = moduleConfig.GetString("InventoryServices", "");
116 if (name == Name)
117 CommonInit(source);
118 }
119 }
120
121 private void CommonInit(IConfigSource source)
122 {
123 IConfig gridConfig = source.Configs["InventoryService"];
124 if (gridConfig != null)
125 {
126 string serviceUrl = gridConfig.GetString("InventoryServerURI");
127 if (!String.IsNullOrEmpty(serviceUrl))
128 {
129 if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
130 serviceUrl = serviceUrl + '/';
131 m_serverUrl = serviceUrl;
132
133 gridConfig = source.Configs["UserAccountService"];
134 if (gridConfig != null)
135 {
136 serviceUrl = gridConfig.GetString("UserAccountServerURI");
137 if (!String.IsNullOrEmpty(serviceUrl))
138 {
139 m_userServerUrl = serviceUrl;
140 m_Enabled = true;
141 if (m_ItemCache == null)
142 m_ItemCache = new ExpiringCache<UUID, InventoryItemBase>();
143 }
144 }
145 }
146 }
147
148 if (String.IsNullOrEmpty(m_serverUrl))
149 m_log.Info("[SIMIAN INVENTORY CONNECTOR]: No InventoryServerURI specified, disabling connector");
150 else if (String.IsNullOrEmpty(m_userServerUrl))
151 m_log.Info("[SIMIAN INVENTORY CONNECTOR]: No UserAccountServerURI specified, disabling connector");
152 }
153
154 /// <summary>
155 /// Create the entire inventory for a given user
156 /// </summary>
157 /// <param name="user"></param>
158 /// <returns></returns>
159 public bool CreateUserInventory(UUID userID)
160 {
161 NameValueCollection requestArgs = new NameValueCollection
162 {
163 { "RequestMethod", "AddInventory" },
164 { "OwnerID", userID.ToString() }
165 };
166
167 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
168 bool success = response["Success"].AsBoolean();
169
170 if (!success)
171 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Inventory creation for " + userID + " failed: " + response["Message"].AsString());
172
173 return success;
174 }
175
176 /// <summary>
177 /// Gets the skeleton of the inventory -- folders only
178 /// </summary>
179 /// <param name="userID"></param>
180 /// <returns></returns>
181 public List<InventoryFolderBase> GetInventorySkeleton(UUID userID)
182 {
183 NameValueCollection requestArgs = new NameValueCollection
184 {
185 { "RequestMethod", "GetInventoryNode" },
186 { "ItemID", userID.ToString() },
187 { "OwnerID", userID.ToString() },
188 { "IncludeFolders", "1" },
189 { "IncludeItems", "0" },
190 { "ChildrenOnly", "0" }
191 };
192
193 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
194 if (response["Success"].AsBoolean() && response["Items"] is OSDArray)
195 {
196 OSDArray items = (OSDArray)response["Items"];
197 return GetFoldersFromResponse(items, userID, true);
198 }
199 else
200 {
201 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Failed to retrieve inventory skeleton for " + userID + ": " +
202 response["Message"].AsString());
203 return new List<InventoryFolderBase>(0);
204 }
205 }
206
207 /// <summary>
208 /// Retrieve the root inventory folder for the given user.
209 /// </summary>
210 /// <param name="userID"></param>
211 /// <returns>null if no root folder was found</returns>
212 public InventoryFolderBase GetRootFolder(UUID userID)
213 {
214 NameValueCollection requestArgs = new NameValueCollection
215 {
216 { "RequestMethod", "GetInventoryNode" },
217 { "ItemID", userID.ToString() },
218 { "OwnerID", userID.ToString() },
219 { "IncludeFolders", "1" },
220 { "IncludeItems", "0" },
221 { "ChildrenOnly", "1" }
222 };
223
224 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
225 if (response["Success"].AsBoolean() && response["Items"] is OSDArray)
226 {
227 OSDArray items = (OSDArray)response["Items"];
228 List<InventoryFolderBase> folders = GetFoldersFromResponse(items, userID, true);
229
230 if (folders.Count > 0)
231 return folders[0];
232 }
233
234 return null;
235 }
236
237 /// <summary>
238 /// Gets the user folder for the given folder-type
239 /// </summary>
240 /// <param name="userID"></param>
241 /// <param name="type"></param>
242 /// <returns></returns>
243 public InventoryFolderBase GetFolderForType(UUID userID, FolderType type)
244 {
245 string contentType = SLUtil.SLAssetTypeToContentType((int)type);
246
247 NameValueCollection requestArgs = new NameValueCollection
248 {
249 { "RequestMethod", "GetFolderForType" },
250 { "ContentType", contentType },
251 { "OwnerID", userID.ToString() }
252 };
253
254 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
255 if (response["Success"].AsBoolean() && response["Folder"] is OSDMap)
256 {
257 OSDMap folder = (OSDMap)response["Folder"];
258
259 return new InventoryFolderBase(
260 folder["ID"].AsUUID(),
261 folder["Name"].AsString(),
262 folder["OwnerID"].AsUUID(),
263 (short)SLUtil.ContentTypeToSLAssetType(folder["ContentType"].AsString()),
264 folder["ParentID"].AsUUID(),
265 (ushort)folder["Version"].AsInteger()
266 );
267 }
268 else
269 {
270 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Default folder not found for content type " + contentType + ": " + response["Message"].AsString());
271 return GetRootFolder(userID);
272 }
273 }
274
275 /// <summary>
276 /// Get an item, given by its UUID
277 /// </summary>
278 /// <param name="item"></param>
279 /// <returns></returns>
280 public InventoryItemBase GetItem(InventoryItemBase item)
281 {
282 InventoryItemBase retrieved = null;
283 if (m_ItemCache.TryGetValue(item.ID, out retrieved))
284 return retrieved;
285
286 NameValueCollection requestArgs = new NameValueCollection
287 {
288 { "RequestMethod", "GetInventoryNode" },
289 { "ItemID", item.ID.ToString() },
290 { "OwnerID", item.Owner.ToString() },
291 { "IncludeFolders", "1" },
292 { "IncludeItems", "1" },
293 { "ChildrenOnly", "1" }
294 };
295
296 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
297 if (response["Success"].AsBoolean() && response["Items"] is OSDArray)
298 {
299 List<InventoryItemBase> items = GetItemsFromResponse((OSDArray)response["Items"]);
300 if (items.Count > 0)
301 {
302 // The requested item should be the first in this list, but loop through
303 // and sanity check just in case
304 for (int i = 0; i < items.Count; i++)
305 {
306 if (items[i].ID == item.ID)
307 {
308 retrieved = items[i];
309 m_ItemCache.AddOrUpdate(item.ID, retrieved, CACHE_EXPIRATION_SECONDS);
310 return retrieved;
311 }
312 }
313 }
314 }
315
316 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Item " + item.ID + " owned by " + item.Owner + " not found");
317 return null;
318 }
319
320 public InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs)
321 {
322 InventoryItemBase[] result = new InventoryItemBase[itemIDs.Length];
323 int i = 0;
324 InventoryItemBase item = new InventoryItemBase();
325 item.Owner = principalID;
326 foreach (UUID id in itemIDs)
327 {
328 item.ID = id;
329 result[i++] = GetItem(item);
330 }
331
332 return result;
333 }
334
335 /// <summary>
336 /// Get a folder, given by its UUID
337 /// </summary>
338 /// <param name="folder"></param>
339 /// <returns></returns>
340 public InventoryFolderBase GetFolder(InventoryFolderBase folder)
341 {
342 NameValueCollection requestArgs = new NameValueCollection
343 {
344 { "RequestMethod", "GetInventoryNode" },
345 { "ItemID", folder.ID.ToString() },
346 { "OwnerID", folder.Owner.ToString() },
347 { "IncludeFolders", "1" },
348 { "IncludeItems", "0" },
349 { "ChildrenOnly", "1" }
350 };
351
352 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
353 if (response["Success"].AsBoolean() && response["Items"] is OSDArray)
354 {
355 OSDArray items = (OSDArray)response["Items"];
356 List<InventoryFolderBase> folders = GetFoldersFromResponse(items, folder.ID, true);
357
358 if (folders.Count > 0)
359 return folders[0];
360 }
361
362 return null;
363 }
364
365 /// <summary>
366 /// Gets everything (folders and items) inside a folder
367 /// </summary>
368 /// <param name="userID"></param>
369 /// <param name="folderID"></param>
370 /// <returns></returns>
371 public InventoryCollection GetFolderContent(UUID userID, UUID folderID)
372 {
373 InventoryCollection inventory = new InventoryCollection();
374 inventory.OwnerID = userID;
375
376 NameValueCollection requestArgs = new NameValueCollection
377 {
378 { "RequestMethod", "GetInventoryNode" },
379 { "ItemID", folderID.ToString() },
380 { "OwnerID", userID.ToString() },
381 { "IncludeFolders", "1" },
382 { "IncludeItems", "1" },
383 { "ChildrenOnly", "1" }
384 };
385
386 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
387 if (response["Success"].AsBoolean() && response["Items"] is OSDArray)
388 {
389 OSDArray items = (OSDArray)response["Items"];
390
391 inventory.Folders = GetFoldersFromResponse(items, folderID, false);
392 inventory.Items = GetItemsFromResponse(items);
393 }
394 else
395 {
396 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Error fetching folder " + folderID + " content for " + userID + ": " +
397 response["Message"].AsString());
398 inventory.Folders = new List<InventoryFolderBase>(0);
399 inventory.Items = new List<InventoryItemBase>(0);
400 }
401
402 return inventory;
403 }
404
405 public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs)
406 {
407 InventoryCollection[] invColl = new InventoryCollection[folderIDs.Length];
408 int i = 0;
409 foreach (UUID fid in folderIDs)
410 {
411 invColl[i++] = GetFolderContent(principalID, fid);
412 }
413
414 return invColl;
415 }
416
417 /// <summary>
418 /// Gets the items inside a folder
419 /// </summary>
420 /// <param name="userID"></param>
421 /// <param name="folderID"></param>
422 /// <returns></returns>
423 public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
424 {
425 InventoryCollection inventory = new InventoryCollection();
426 inventory.OwnerID = userID;
427
428 NameValueCollection requestArgs = new NameValueCollection
429 {
430 { "RequestMethod", "GetInventoryNode" },
431 { "ItemID", folderID.ToString() },
432 { "OwnerID", userID.ToString() },
433 { "IncludeFolders", "0" },
434 { "IncludeItems", "1" },
435 { "ChildrenOnly", "1" }
436 };
437
438 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
439 if (response["Success"].AsBoolean() && response["Items"] is OSDArray)
440 {
441 OSDArray items = (OSDArray)response["Items"];
442 return GetItemsFromResponse(items);
443 }
444 else
445 {
446 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Error fetching folder " + folderID + " for " + userID + ": " +
447 response["Message"].AsString());
448 return new List<InventoryItemBase>(0);
449 }
450 }
451
452 /// <summary>
453 /// Add a new folder to the user's inventory
454 /// </summary>
455 /// <param name="folder"></param>
456 /// <returns>true if the folder was successfully added</returns>
457 public bool AddFolder(InventoryFolderBase folder)
458 {
459 NameValueCollection requestArgs = new NameValueCollection
460 {
461 { "RequestMethod", "AddInventoryFolder" },
462 { "FolderID", folder.ID.ToString() },
463 { "ParentID", folder.ParentID.ToString() },
464 { "OwnerID", folder.Owner.ToString() },
465 { "Name", folder.Name },
466 { "ContentType", SLUtil.SLAssetTypeToContentType(folder.Type) }
467 };
468
469 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
470 bool success = response["Success"].AsBoolean();
471
472 if (!success)
473 {
474 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Error creating folder " + folder.Name + " for " + folder.Owner + ": " +
475 response["Message"].AsString());
476 }
477
478 return success;
479 }
480
481 /// <summary>
482 /// Update a folder in the user's inventory
483 /// </summary>
484 /// <param name="folder"></param>
485 /// <returns>true if the folder was successfully updated</returns>
486 public bool UpdateFolder(InventoryFolderBase folder)
487 {
488 return AddFolder(folder);
489 }
490
491 /// <summary>
492 /// Move an inventory folder to a new location
493 /// </summary>
494 /// <param name="folder">A folder containing the details of the new location</param>
495 /// <returns>true if the folder was successfully moved</returns>
496 public bool MoveFolder(InventoryFolderBase folder)
497 {
498 return AddFolder(folder);
499 }
500
501 /// <summary>
502 /// Delete an item from the user's inventory
503 /// </summary>
504 /// <param name="item"></param>
505 /// <returns>true if the item was successfully deleted</returns>
506 //bool DeleteItem(InventoryItemBase item);
507 public bool DeleteFolders(UUID userID, List<UUID> folderIDs)
508 {
509 return DeleteItems(userID, folderIDs);
510 }
511
512 /// <summary>
513 /// Delete an item from the user's inventory
514 /// </summary>
515 /// <param name="item"></param>
516 /// <returns>true if the item was successfully deleted</returns>
517 public bool DeleteItems(UUID userID, List<UUID> itemIDs)
518 {
519 // TODO: RemoveInventoryNode should be replaced with RemoveInventoryNodes
520 bool allSuccess = true;
521
522 for (int i = 0; i < itemIDs.Count; i++)
523 {
524 UUID itemID = itemIDs[i];
525
526 NameValueCollection requestArgs = new NameValueCollection
527 {
528 { "RequestMethod", "RemoveInventoryNode" },
529 { "OwnerID", userID.ToString() },
530 { "ItemID", itemID.ToString() }
531 };
532
533 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
534 bool success = response["Success"].AsBoolean();
535
536 if (!success)
537 {
538 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Error removing item " + itemID + " for " + userID + ": " +
539 response["Message"].AsString());
540 allSuccess = false;
541 }
542 }
543
544 return allSuccess;
545 }
546
547 /// <summary>
548 /// Purge an inventory folder of all its items and subfolders.
549 /// </summary>
550 /// <param name="folder"></param>
551 /// <returns>true if the folder was successfully purged</returns>
552 public bool PurgeFolder(InventoryFolderBase folder)
553 {
554 NameValueCollection requestArgs = new NameValueCollection
555 {
556 { "RequestMethod", "PurgeInventoryFolder" },
557 { "OwnerID", folder.Owner.ToString() },
558 { "FolderID", folder.ID.ToString() }
559 };
560
561 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
562 bool success = response["Success"].AsBoolean();
563
564 if (!success)
565 {
566 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Error purging folder " + folder.ID + " for " + folder.Owner + ": " +
567 response["Message"].AsString());
568 }
569
570 return success;
571 }
572
573 /// <summary>
574 /// Add a new item to the user's inventory
575 /// </summary>
576 /// <param name="item"></param>
577 /// <returns>true if the item was successfully added</returns>
578 public bool AddItem(InventoryItemBase item)
579 {
580 // A folder of UUID.Zero means we need to find the most appropriate home for this item
581 if (item.Folder == UUID.Zero)
582 {
583 InventoryFolderBase folder = null;
584 if (Enum.IsDefined(typeof(FolderType), (sbyte)item.AssetType))
585 folder = GetFolderForType(item.Owner, (FolderType)item.AssetType);
586 if (folder != null && folder.ID != UUID.Zero)
587 item.Folder = folder.ID;
588 else
589 item.Folder = item.Owner; // Root folder
590 }
591
592 if ((AssetType)item.AssetType == AssetType.Gesture)
593 UpdateGesture(item.Owner, item.ID, item.Flags == 1);
594
595 if (item.BasePermissions == 0)
596 m_log.WarnFormat("[SIMIAN INVENTORY CONNECTOR]: Adding inventory item {0} ({1}) with no base permissions", item.Name, item.ID);
597
598 OSDMap permissions = new OSDMap
599 {
600 { "BaseMask", OSD.FromInteger(item.BasePermissions) },
601 { "EveryoneMask", OSD.FromInteger(item.EveryOnePermissions) },
602 { "GroupMask", OSD.FromInteger(item.GroupPermissions) },
603 { "NextOwnerMask", OSD.FromInteger(item.NextPermissions) },
604 { "OwnerMask", OSD.FromInteger(item.CurrentPermissions) }
605 };
606
607 OSDMap extraData = new OSDMap()
608 {
609 { "Flags", OSD.FromInteger(item.Flags) },
610 { "GroupID", OSD.FromUUID(item.GroupID) },
611 { "GroupOwned", OSD.FromBoolean(item.GroupOwned) },
612 { "SalePrice", OSD.FromInteger(item.SalePrice) },
613 { "SaleType", OSD.FromInteger(item.SaleType) },
614 { "Permissions", permissions }
615 };
616
617 // Add different asset type only if it differs from inventory type
618 // (needed for links)
619 string invContentType = SLUtil.SLInvTypeToContentType(item.InvType);
620 string assetContentType = SLUtil.SLAssetTypeToContentType(item.AssetType);
621
622 if (invContentType != assetContentType)
623 extraData["LinkedItemType"] = OSD.FromString(assetContentType);
624
625 NameValueCollection requestArgs = new NameValueCollection
626 {
627 { "RequestMethod", "AddInventoryItem" },
628 { "ItemID", item.ID.ToString() },
629 { "AssetID", item.AssetID.ToString() },
630 { "ParentID", item.Folder.ToString() },
631 { "OwnerID", item.Owner.ToString() },
632 { "Name", item.Name },
633 { "Description", item.Description },
634 { "CreatorID", item.CreatorId },
635 { "CreatorData", item.CreatorData },
636 { "ContentType", invContentType },
637 { "ExtraData", OSDParser.SerializeJsonString(extraData) }
638 };
639
640 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
641 bool success = response["Success"].AsBoolean();
642
643 if (!success)
644 {
645 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Error creating item " + item.Name + " for " + item.Owner + ": " +
646 response["Message"].AsString());
647 }
648
649 return success;
650 }
651
652 /// <summary>
653 /// Update an item in the user's inventory
654 /// </summary>
655 /// <param name="item"></param>
656 /// <returns>true if the item was successfully updated</returns>
657 public bool UpdateItem(InventoryItemBase item)
658 {
659 if (item.AssetID != UUID.Zero)
660 {
661 return AddItem(item);
662 }
663 else
664 {
665 // This is actually a folder update
666 InventoryFolderBase folder = new InventoryFolderBase(item.ID, item.Name, item.Owner, (short)item.AssetType, item.Folder, 0);
667 return UpdateFolder(folder);
668 }
669 }
670
671 public bool MoveItems(UUID ownerID, List<InventoryItemBase> items)
672 {
673 bool success = true;
674
675 while (items.Count > 0)
676 {
677 List<InventoryItemBase> currentItems = new List<InventoryItemBase>();
678 UUID destFolderID = items[0].Folder;
679
680 // Find all of the items being moved to the current destination folder
681 for (int i = 0; i < items.Count; i++)
682 {
683 InventoryItemBase item = items[i];
684 if (item.Folder == destFolderID)
685 currentItems.Add(item);
686 }
687
688 // Do the inventory move for the current items
689 success &= MoveItems(ownerID, items, destFolderID);
690
691 // Remove the processed items from the list
692 for (int i = 0; i < currentItems.Count; i++)
693 items.Remove(currentItems[i]);
694 }
695
696 return success;
697 }
698
699 /// <summary>
700 /// Does the given user have an inventory structure?
701 /// </summary>
702 /// <param name="userID"></param>
703 /// <returns></returns>
704 public bool HasInventoryForUser(UUID userID)
705 {
706 return GetRootFolder(userID) != null;
707 }
708
709 /// <summary>
710 /// Get the active gestures of the agent.
711 /// </summary>
712 /// <param name="userID"></param>
713 /// <returns></returns>
714 public List<InventoryItemBase> GetActiveGestures(UUID userID)
715 {
716 OSDArray items = FetchGestures(userID);
717
718 string[] itemIDs = new string[items.Count];
719 for (int i = 0; i < items.Count; i++)
720 itemIDs[i] = items[i].AsUUID().ToString();
721
722// NameValueCollection requestArgs = new NameValueCollection
723// {
724// { "RequestMethod", "GetInventoryNodes" },
725// { "OwnerID", userID.ToString() },
726// { "Items", String.Join(",", itemIDs) }
727// };
728
729 // FIXME: Implement this in SimianGrid
730 return new List<InventoryItemBase>(0);
731 }
732
733 /// <summary>
734 /// Get the union of permissions of all inventory items
735 /// that hold the given assetID.
736 /// </summary>
737 /// <param name="userID"></param>
738 /// <param name="assetID"></param>
739 /// <returns>The permissions or 0 if no such asset is found in
740 /// the user's inventory</returns>
741 public int GetAssetPermissions(UUID userID, UUID assetID)
742 {
743// NameValueCollection requestArgs = new NameValueCollection
744// {
745// { "RequestMethod", "GetInventoryNodes" },
746// { "OwnerID", userID.ToString() },
747// { "AssetID", assetID.ToString() }
748// };
749
750 // FIXME: Implement this in SimianGrid
751 return (int)PermissionMask.All;
752 }
753
754 private List<InventoryFolderBase> GetFoldersFromResponse(OSDArray items, UUID baseFolder, bool includeBaseFolder)
755 {
756 List<InventoryFolderBase> invFolders = new List<InventoryFolderBase>(items.Count);
757
758 for (int i = 0; i < items.Count; i++)
759 {
760 OSDMap item = items[i] as OSDMap;
761
762 if (item != null && item["Type"].AsString() == "Folder")
763 {
764 UUID folderID = item["ID"].AsUUID();
765
766 if (folderID == baseFolder && !includeBaseFolder)
767 continue;
768
769 invFolders.Add(new InventoryFolderBase(
770 folderID,
771 item["Name"].AsString(),
772 item["OwnerID"].AsUUID(),
773 (short)SLUtil.ContentTypeToSLAssetType(item["ContentType"].AsString()),
774 item["ParentID"].AsUUID(),
775 (ushort)item["Version"].AsInteger()
776 ));
777 }
778 }
779
780// m_log.Debug("[SIMIAN INVENTORY CONNECTOR]: Parsed " + invFolders.Count + " folders from SimianGrid response");
781 return invFolders;
782 }
783
784 private List<InventoryItemBase> GetItemsFromResponse(OSDArray items)
785 {
786 List<InventoryItemBase> invItems = new List<InventoryItemBase>(items.Count);
787
788 for (int i = 0; i < items.Count; i++)
789 {
790 OSDMap item = items[i] as OSDMap;
791
792 if (item != null && item["Type"].AsString() == "Item")
793 {
794 InventoryItemBase invItem = new InventoryItemBase();
795
796 invItem.AssetID = item["AssetID"].AsUUID();
797 invItem.AssetType = SLUtil.ContentTypeToSLAssetType(item["ContentType"].AsString());
798 invItem.CreationDate = item["CreationDate"].AsInteger();
799 invItem.CreatorId = item["CreatorID"].AsString();
800 invItem.CreatorData = item["CreatorData"].AsString();
801 invItem.Description = item["Description"].AsString();
802 invItem.Folder = item["ParentID"].AsUUID();
803 invItem.ID = item["ID"].AsUUID();
804 invItem.InvType = SLUtil.ContentTypeToSLInvType(item["ContentType"].AsString());
805 invItem.Name = item["Name"].AsString();
806 invItem.Owner = item["OwnerID"].AsUUID();
807
808 OSDMap extraData = item["ExtraData"] as OSDMap;
809 if (extraData != null && extraData.Count > 0)
810 {
811 invItem.Flags = extraData["Flags"].AsUInteger();
812 invItem.GroupID = extraData["GroupID"].AsUUID();
813 invItem.GroupOwned = extraData["GroupOwned"].AsBoolean();
814 invItem.SalePrice = extraData["SalePrice"].AsInteger();
815 invItem.SaleType = (byte)extraData["SaleType"].AsInteger();
816
817 OSDMap perms = extraData["Permissions"] as OSDMap;
818 if (perms != null)
819 {
820 invItem.BasePermissions = perms["BaseMask"].AsUInteger();
821 invItem.CurrentPermissions = perms["OwnerMask"].AsUInteger();
822 invItem.EveryOnePermissions = perms["EveryoneMask"].AsUInteger();
823 invItem.GroupPermissions = perms["GroupMask"].AsUInteger();
824 invItem.NextPermissions = perms["NextOwnerMask"].AsUInteger();
825 }
826
827 if (extraData.ContainsKey("LinkedItemType"))
828 invItem.AssetType = SLUtil.ContentTypeToSLAssetType(extraData["LinkedItemType"].AsString());
829 }
830
831 if (invItem.BasePermissions == 0)
832 {
833 m_log.InfoFormat("[SIMIAN INVENTORY CONNECTOR]: Forcing item permissions to full for item {0} ({1})",
834 invItem.Name, invItem.ID);
835 invItem.BasePermissions = (uint)PermissionMask.All;
836 invItem.CurrentPermissions = (uint)PermissionMask.All;
837 invItem.EveryOnePermissions = (uint)PermissionMask.All;
838 invItem.GroupPermissions = (uint)PermissionMask.All;
839 invItem.NextPermissions = (uint)PermissionMask.All;
840 }
841
842 invItems.Add(invItem);
843 }
844 }
845
846// m_log.Debug("[SIMIAN INVENTORY CONNECTOR]: Parsed " + invItems.Count + " items from SimianGrid response");
847 return invItems;
848 }
849
850 private bool MoveItems(UUID ownerID, List<InventoryItemBase> items, UUID destFolderID)
851 {
852 string[] itemIDs = new string[items.Count];
853 for (int i = 0; i < items.Count; i++)
854 itemIDs[i] = items[i].ID.ToString();
855
856 NameValueCollection requestArgs = new NameValueCollection
857 {
858 { "RequestMethod", "MoveInventoryNodes" },
859 { "OwnerID", ownerID.ToString() },
860 { "FolderID", destFolderID.ToString() },
861 { "Items", String.Join(",", itemIDs) }
862 };
863
864 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
865 bool success = response["Success"].AsBoolean();
866
867 if (!success)
868 {
869 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Failed to move " + items.Count + " items to " +
870 destFolderID + ": " + response["Message"].AsString());
871 }
872
873 return success;
874 }
875
876 private void UpdateGesture(UUID userID, UUID itemID, bool enabled)
877 {
878 OSDArray gestures = FetchGestures(userID);
879 OSDArray newGestures = new OSDArray();
880
881 for (int i = 0; i < gestures.Count; i++)
882 {
883 UUID gesture = gestures[i].AsUUID();
884 if (gesture != itemID)
885 newGestures.Add(OSD.FromUUID(gesture));
886 }
887
888 if (enabled)
889 newGestures.Add(OSD.FromUUID(itemID));
890
891 SaveGestures(userID, newGestures);
892 }
893
894 private OSDArray FetchGestures(UUID userID)
895 {
896 NameValueCollection requestArgs = new NameValueCollection
897 {
898 { "RequestMethod", "GetUser" },
899 { "UserID", userID.ToString() }
900 };
901
902 OSDMap response = SimianGrid.PostToService(m_userServerUrl, requestArgs);
903 if (response["Success"].AsBoolean())
904 {
905 OSDMap user = response["User"] as OSDMap;
906 if (user != null && response.ContainsKey("Gestures"))
907 {
908 OSD gestures = OSDParser.DeserializeJson(response["Gestures"].AsString());
909 if (gestures != null && gestures is OSDArray)
910 return (OSDArray)gestures;
911 else
912 m_log.Error("[SIMIAN INVENTORY CONNECTOR]: Unrecognized active gestures data for " + userID);
913 }
914 }
915 else
916 {
917 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Failed to fetch active gestures for " + userID + ": " +
918 response["Message"].AsString());
919 }
920
921 return new OSDArray();
922 }
923
924 private void SaveGestures(UUID userID, OSDArray gestures)
925 {
926 NameValueCollection requestArgs = new NameValueCollection
927 {
928 { "RequestMethod", "AddUserData" },
929 { "UserID", userID.ToString() },
930 { "Gestures", OSDParser.SerializeJsonString(gestures) }
931 };
932
933 OSDMap response = SimianGrid.PostToService(m_userServerUrl, requestArgs);
934 if (!response["Success"].AsBoolean())
935 {
936 m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Failed to save active gestures for " + userID + ": " +
937 response["Message"].AsString());
938 }
939 }
940 }
941}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs
new file mode 100644
index 0000000..211b775
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs
@@ -0,0 +1,459 @@
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.Collections.Specialized;
31using System.Reflection;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Services.Interfaces;
39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41
42using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
43
44namespace OpenSim.Services.Connectors.SimianGrid
45{
46 /// <summary>
47 /// Connects avatar presence information (for tracking current location and
48 /// message routing) to the SimianGrid backend
49 /// </summary>
50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianPresenceServiceConnector")]
51 public class SimianPresenceServiceConnector : IPresenceService, IGridUserService, ISharedRegionModule
52 {
53 private static readonly ILog m_log =
54 LogManager.GetLogger(
55 MethodBase.GetCurrentMethod().DeclaringType);
56
57 private string m_serverUrl = String.Empty;
58 private SimianActivityDetector m_activityDetector;
59 private bool m_Enabled = false;
60
61 #region ISharedRegionModule
62
63 public Type ReplaceableInterface { get { return null; } }
64 public void RegionLoaded(Scene scene) { }
65 public void PostInitialise() { }
66 public void Close() { }
67
68 public SimianPresenceServiceConnector() { }
69 public string Name { get { return "SimianPresenceServiceConnector"; } }
70 public void AddRegion(Scene scene)
71 {
72 if (m_Enabled)
73 {
74 scene.RegisterModuleInterface<IPresenceService>(this);
75 scene.RegisterModuleInterface<IGridUserService>(this);
76
77 m_activityDetector.AddRegion(scene);
78
79 LogoutRegionAgents(scene.RegionInfo.RegionID);
80 }
81 }
82 public void RemoveRegion(Scene scene)
83 {
84 if (m_Enabled)
85 {
86 scene.UnregisterModuleInterface<IPresenceService>(this);
87 scene.UnregisterModuleInterface<IGridUserService>(this);
88
89 m_activityDetector.RemoveRegion(scene);
90
91 LogoutRegionAgents(scene.RegionInfo.RegionID);
92 }
93 }
94
95 #endregion ISharedRegionModule
96
97 public SimianPresenceServiceConnector(IConfigSource source)
98 {
99 CommonInit(source);
100 }
101
102 public void Initialise(IConfigSource source)
103 {
104 IConfig moduleConfig = source.Configs["Modules"];
105 if (moduleConfig != null)
106 {
107 string name = moduleConfig.GetString("PresenceServices", "");
108 if (name == Name)
109 CommonInit(source);
110 }
111 }
112
113 private void CommonInit(IConfigSource source)
114 {
115 IConfig gridConfig = source.Configs["PresenceService"];
116 if (gridConfig != null)
117 {
118 string serviceUrl = gridConfig.GetString("PresenceServerURI");
119 if (!String.IsNullOrEmpty(serviceUrl))
120 {
121 if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
122 serviceUrl = serviceUrl + '/';
123 m_serverUrl = serviceUrl;
124 m_activityDetector = new SimianActivityDetector(this);
125 m_Enabled = true;
126 }
127 }
128
129 if (String.IsNullOrEmpty(m_serverUrl))
130 m_log.Info("[SIMIAN PRESENCE CONNECTOR]: No PresenceServerURI specified, disabling connector");
131 }
132
133 #region IPresenceService
134
135 public bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID)
136 {
137 m_log.ErrorFormat("[SIMIAN PRESENCE CONNECTOR]: Login requested, UserID={0}, SessionID={1}, SecureSessionID={2}",
138 userID, sessionID, secureSessionID);
139
140 NameValueCollection requestArgs = new NameValueCollection
141 {
142 { "RequestMethod", "AddSession" },
143 { "UserID", userID.ToString() }
144 };
145
146 if (sessionID != UUID.Zero)
147 {
148 requestArgs["SessionID"] = sessionID.ToString();
149 requestArgs["SecureSessionID"] = secureSessionID.ToString();
150 }
151
152 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
153 bool success = response["Success"].AsBoolean();
154
155 if (!success)
156 m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to login agent " + userID + ": " + response["Message"].AsString());
157
158 return success;
159 }
160
161 public bool LogoutAgent(UUID sessionID)
162 {
163 // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID);
164
165 NameValueCollection requestArgs = new NameValueCollection
166 {
167 { "RequestMethod", "RemoveSession" },
168 { "SessionID", sessionID.ToString() }
169 };
170
171 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
172 bool success = response["Success"].AsBoolean();
173
174 if (!success)
175 m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to logout agent with sessionID " + sessionID + ": " + response["Message"].AsString());
176
177 return success;
178 }
179
180 public bool LogoutRegionAgents(UUID regionID)
181 {
182 // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID);
183
184 NameValueCollection requestArgs = new NameValueCollection
185 {
186 { "RequestMethod", "RemoveSessions" },
187 { "SceneID", regionID.ToString() }
188 };
189
190 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
191 bool success = response["Success"].AsBoolean();
192
193 if (!success)
194 m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to logout agents from region " + regionID + ": " + response["Message"].AsString());
195
196 return success;
197 }
198
199 public bool ReportAgent(UUID sessionID, UUID regionID)
200 {
201 // Not needed for SimianGrid
202 return true;
203 }
204
205 public PresenceInfo GetAgent(UUID sessionID)
206 {
207 OSDMap sessionResponse = GetSessionDataFromSessionID(sessionID);
208 if (sessionResponse == null)
209 {
210 m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session {0}: {1}",sessionID.ToString(),sessionResponse["Message"].AsString());
211 return null;
212 }
213
214 UUID userID = sessionResponse["UserID"].AsUUID();
215 OSDMap userResponse = GetUserData(userID);
216 if (userResponse == null)
217 {
218 m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID.ToString(),userResponse["Message"].AsString());
219 return null;
220 }
221
222 return ResponseToPresenceInfo(sessionResponse);
223 }
224
225 public PresenceInfo[] GetAgents(string[] userIDs)
226 {
227 List<PresenceInfo> presences = new List<PresenceInfo>();
228
229 NameValueCollection requestArgs = new NameValueCollection
230 {
231 { "RequestMethod", "GetSessions" },
232 { "UserIDList", String.Join(",",userIDs) }
233 };
234
235 OSDMap sessionListResponse = SimianGrid.PostToService(m_serverUrl, requestArgs);
236 if (! sessionListResponse["Success"].AsBoolean())
237 {
238 m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve sessions: {0}",sessionListResponse["Message"].AsString());
239 return null;
240 }
241
242 OSDArray sessionList = sessionListResponse["Sessions"] as OSDArray;
243 for (int i = 0; i < sessionList.Count; i++)
244 {
245 OSDMap sessionInfo = sessionList[i] as OSDMap;
246 presences.Add(ResponseToPresenceInfo(sessionInfo));
247 }
248
249 return presences.ToArray();
250 }
251
252 #endregion IPresenceService
253
254 #region IGridUserService
255
256 public GridUserInfo LoggedIn(string userID)
257 {
258 // Never implemented at the sim
259 return null;
260 }
261
262 public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
263 {
264 // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID);
265
266 // Remove the session to mark this user offline
267 if (!LogoutAgent(sessionID))
268 return false;
269
270 // Save our last position as user data
271 NameValueCollection requestArgs = new NameValueCollection
272 {
273 { "RequestMethod", "AddUserData" },
274 { "UserID", userID.ToString() },
275 { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) }
276 };
277
278 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
279 bool success = response["Success"].AsBoolean();
280
281 if (!success)
282 m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to set last location for " + userID + ": " + response["Message"].AsString());
283
284 return success;
285 }
286
287 public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
288 {
289 // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID);
290
291 NameValueCollection requestArgs = new NameValueCollection
292 {
293 { "RequestMethod", "AddUserData" },
294 { "UserID", userID.ToString() },
295 { "HomeLocation", SerializeLocation(regionID, position, lookAt) }
296 };
297
298 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
299 bool success = response["Success"].AsBoolean();
300
301 if (!success)
302 m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to set home location for " + userID + ": " + response["Message"].AsString());
303
304 return success;
305 }
306
307 public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
308 {
309 return UpdateSession(sessionID, regionID, lastPosition, lastLookAt);
310 }
311
312 public GridUserInfo GetGridUserInfo(string user)
313 {
314 // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user);
315
316 UUID userID = new UUID(user);
317 OSDMap userResponse = GetUserData(userID);
318
319 if (userResponse == null)
320 {
321 m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}", userID);
322 }
323
324 // Note that ResponseToGridUserInfo properly checks for and returns a null if passed a null.
325 return ResponseToGridUserInfo(userResponse);
326
327 }
328
329 #endregion
330
331 #region Helpers
332
333 private OSDMap GetUserData(UUID userID)
334 {
335 // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID);
336
337 NameValueCollection requestArgs = new NameValueCollection
338 {
339 { "RequestMethod", "GetUser" },
340 { "UserID", userID.ToString() }
341 };
342
343 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
344 if (response["Success"].AsBoolean() && response["User"] is OSDMap)
345 return response;
346
347 m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}; {1}",userID.ToString(),response["Message"].AsString());
348 return null;
349 }
350
351 private OSDMap GetSessionDataFromSessionID(UUID sessionID)
352 {
353 NameValueCollection requestArgs = new NameValueCollection
354 {
355 { "RequestMethod", "GetSession" },
356 { "SessionID", sessionID.ToString() }
357 };
358
359 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
360 if (response["Success"].AsBoolean())
361 return response;
362
363 m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session data for {0}; {1}",sessionID.ToString(),response["Message"].AsString());
364 return null;
365 }
366
367 private bool UpdateSession(UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
368 {
369 // Save our current location as session data
370 NameValueCollection requestArgs = new NameValueCollection
371 {
372 { "RequestMethod", "UpdateSession" },
373 { "SessionID", sessionID.ToString() },
374 { "SceneID", regionID.ToString() },
375 { "ScenePosition", lastPosition.ToString() },
376 { "SceneLookAt", lastLookAt.ToString() }
377 };
378
379 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
380 bool success = response["Success"].AsBoolean();
381
382 if (!success)
383 m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to update agent session " + sessionID + ": " + response["Message"].AsString());
384
385 return success;
386 }
387
388 private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse)
389 {
390 if (sessionResponse == null)
391 return null;
392
393 PresenceInfo info = new PresenceInfo();
394
395 info.UserID = sessionResponse["UserID"].AsUUID().ToString();
396 info.RegionID = sessionResponse["SceneID"].AsUUID();
397
398 return info;
399 }
400
401 private GridUserInfo ResponseToGridUserInfo(OSDMap userResponse)
402 {
403 if (userResponse != null && userResponse["User"] is OSDMap)
404 {
405 GridUserInfo info = new GridUserInfo();
406
407 info.Online = true;
408 info.UserID = userResponse["UserID"].AsUUID().ToString();
409 info.LastRegionID = userResponse["SceneID"].AsUUID();
410 info.LastPosition = userResponse["ScenePosition"].AsVector3();
411 info.LastLookAt = userResponse["SceneLookAt"].AsVector3();
412
413 OSDMap user = (OSDMap)userResponse["User"];
414
415 info.Login = user["LastLoginDate"].AsDate();
416 info.Logout = user["LastLogoutDate"].AsDate();
417 DeserializeLocation(user["HomeLocation"].AsString(), out info.HomeRegionID, out info.HomePosition, out info.HomeLookAt);
418
419 return info;
420 }
421
422 return null;
423 }
424
425 private string SerializeLocation(UUID regionID, Vector3 position, Vector3 lookAt)
426 {
427 return "{" + String.Format("\"SceneID\":\"{0}\",\"Position\":\"{1}\",\"LookAt\":\"{2}\"", regionID, position, lookAt) + "}";
428 }
429
430 private bool DeserializeLocation(string location, out UUID regionID, out Vector3 position, out Vector3 lookAt)
431 {
432 OSDMap map = null;
433
434 try { map = OSDParser.DeserializeJson(location) as OSDMap; }
435 catch { }
436
437 if (map != null)
438 {
439 regionID = map["SceneID"].AsUUID();
440 if (Vector3.TryParse(map["Position"].AsString(), out position) &&
441 Vector3.TryParse(map["LookAt"].AsString(), out lookAt))
442 {
443 return true;
444 }
445 }
446
447 regionID = UUID.Zero;
448 position = Vector3.Zero;
449 lookAt = Vector3.Zero;
450 return false;
451 }
452
453 public GridUserInfo[] GetGridUserInfo(string[] userIDs)
454 {
455 return new GridUserInfo[0];
456 }
457 #endregion Helpers
458 }
459}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs
new file mode 100644
index 0000000..8fc766d
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs
@@ -0,0 +1,478 @@
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.Collections.Specialized;
31using System.Reflection;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Framework.Client;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Services.Interfaces;
42
43namespace OpenSim.Services.Connectors.SimianGrid
44{
45 /// <summary>
46 /// Avatar profile flags
47 /// </summary>
48 [Flags]
49 public enum ProfileFlags : uint
50 {
51 AllowPublish = 1,
52 MaturePublish = 2,
53 Identified = 4,
54 Transacted = 8,
55 Online = 16
56 }
57
58 /// <summary>
59 /// Connects avatar profile and classified queries to the SimianGrid
60 /// backend
61 /// </summary>
62 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianProfiles")]
63 public class SimianProfiles : INonSharedRegionModule
64 {
65 private static readonly ILog m_log =
66 LogManager.GetLogger(
67 MethodBase.GetCurrentMethod().DeclaringType);
68
69 private string m_serverUrl = String.Empty;
70 private bool m_Enabled = false;
71
72 #region INonSharedRegionModule
73
74 public Type ReplaceableInterface { get { return null; } }
75 public void RegionLoaded(Scene scene) { }
76 public void Close() { }
77
78 public SimianProfiles() { }
79 public string Name { get { return "SimianProfiles"; } }
80
81 public void AddRegion(Scene scene)
82 {
83 if (m_Enabled)
84 {
85 CheckEstateManager(scene);
86 scene.EventManager.OnClientConnect += ClientConnectHandler;
87 }
88 }
89
90 public void RemoveRegion(Scene scene)
91 {
92 if (m_Enabled)
93 {
94 scene.EventManager.OnClientConnect -= ClientConnectHandler;
95 }
96 }
97
98 #endregion INonSharedRegionModule
99
100 public SimianProfiles(IConfigSource source)
101 {
102 Initialise(source);
103 }
104
105 public void Initialise(IConfigSource source)
106 {
107 IConfig profileConfig = source.Configs["Profiles"];
108 if (profileConfig == null)
109 return;
110
111 if (profileConfig.GetString("Module", String.Empty) != Name)
112 return;
113
114 m_log.DebugFormat("[SIMIAN PROFILES] module enabled");
115 m_Enabled = true;
116
117 IConfig gridConfig = source.Configs["UserAccountService"];
118 if (gridConfig != null)
119 {
120 string serviceUrl = gridConfig.GetString("UserAccountServerURI");
121 if (!String.IsNullOrEmpty(serviceUrl))
122 {
123 if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
124 serviceUrl = serviceUrl + '/';
125 m_serverUrl = serviceUrl;
126 }
127 }
128
129 if (String.IsNullOrEmpty(m_serverUrl))
130 m_log.Info("[SIMIAN PROFILES]: No UserAccountServerURI specified, disabling connector");
131 }
132
133 private void ClientConnectHandler(IClientCore clientCore)
134 {
135 if (clientCore is IClientAPI)
136 {
137 IClientAPI client = (IClientAPI)clientCore;
138
139 // Classifieds
140 client.AddGenericPacketHandler("avatarclassifiedsrequest", AvatarClassifiedsRequestHandler);
141 client.OnClassifiedInfoRequest += ClassifiedInfoRequestHandler;
142 client.OnClassifiedInfoUpdate += ClassifiedInfoUpdateHandler;
143 client.OnClassifiedDelete += ClassifiedDeleteHandler;
144
145 // Picks
146 client.AddGenericPacketHandler("avatarpicksrequest", HandleAvatarPicksRequest);
147 client.AddGenericPacketHandler("pickinforequest", HandlePickInfoRequest);
148 client.OnPickInfoUpdate += PickInfoUpdateHandler;
149 client.OnPickDelete += PickDeleteHandler;
150
151 // Notes
152 client.AddGenericPacketHandler("avatarnotesrequest", HandleAvatarNotesRequest);
153 client.OnAvatarNotesUpdate += AvatarNotesUpdateHandler;
154
155 // Profiles
156 client.OnRequestAvatarProperties += RequestAvatarPropertiesHandler;
157
158 client.OnUpdateAvatarProperties += UpdateAvatarPropertiesHandler;
159 client.OnAvatarInterestUpdate += AvatarInterestUpdateHandler;
160 client.OnUserInfoRequest += UserInfoRequestHandler;
161 client.OnUpdateUserInfo += UpdateUserInfoHandler;
162 }
163 }
164
165 #region Classifieds
166
167 private void AvatarClassifiedsRequestHandler(Object sender, string method, List<String> args)
168 {
169 if (!(sender is IClientAPI))
170 return;
171 IClientAPI client = (IClientAPI)sender;
172
173 UUID targetAvatarID;
174 if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID))
175 {
176 m_log.Error("[SIMIAN PROFILES]: Unrecognized arguments for " + method);
177 return;
178 }
179
180 // FIXME: Query the generic key/value store for classifieds
181 client.SendAvatarClassifiedReply(targetAvatarID, new Dictionary<UUID, string>(0));
182 }
183
184 private void ClassifiedInfoRequestHandler(UUID classifiedID, IClientAPI client)
185 {
186 // FIXME: Fetch this info
187 client.SendClassifiedInfoReply(classifiedID, UUID.Zero, 0, Utils.DateTimeToUnixTime(DateTime.UtcNow + TimeSpan.FromDays(1)),
188 0, String.Empty, String.Empty, UUID.Zero, 0, UUID.Zero, String.Empty, Vector3.Zero, String.Empty, 0, 0);
189 }
190
191 private void ClassifiedInfoUpdateHandler(UUID classifiedID, uint category, string name, string description,
192 UUID parcelID, uint parentEstate, UUID snapshotID, Vector3 globalPos, byte classifiedFlags, int price,
193 IClientAPI client)
194 {
195 // FIXME: Save this info
196 }
197
198 private void ClassifiedDeleteHandler(UUID classifiedID, IClientAPI client)
199 {
200 // FIXME: Delete the specified classified ad
201 }
202
203 #endregion Classifieds
204
205 #region Picks
206
207 private void HandleAvatarPicksRequest(Object sender, string method, List<String> args)
208 {
209 if (!(sender is IClientAPI))
210 return;
211 IClientAPI client = (IClientAPI)sender;
212
213 UUID targetAvatarID;
214 if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID))
215 {
216 m_log.Error("[SIMIAN PROFILES]: Unrecognized arguments for " + method);
217 return;
218 }
219
220 // FIXME: Fetch these
221 client.SendAvatarPicksReply(targetAvatarID, new Dictionary<UUID, string>(0));
222 }
223
224 private void HandlePickInfoRequest(Object sender, string method, List<String> args)
225 {
226 if (!(sender is IClientAPI))
227 return;
228 IClientAPI client = (IClientAPI)sender;
229
230 UUID avatarID;
231 UUID pickID;
232 if (args.Count < 2 || !UUID.TryParse(args[0], out avatarID) || !UUID.TryParse(args[1], out pickID))
233 {
234 m_log.Error("[SIMIAN PROFILES]: Unrecognized arguments for " + method);
235 return;
236 }
237
238 // FIXME: Fetch this
239 client.SendPickInfoReply(pickID, avatarID, false, UUID.Zero, String.Empty, String.Empty, UUID.Zero, String.Empty,
240 String.Empty, String.Empty, Vector3.Zero, 0, false);
241 }
242
243 private void PickInfoUpdateHandler(IClientAPI client, UUID pickID, UUID creatorID, bool topPick, string name,
244 string desc, UUID snapshotID, int sortOrder, bool enabled)
245 {
246 // FIXME: Save this
247 }
248
249 private void PickDeleteHandler(IClientAPI client, UUID pickID)
250 {
251 // FIXME: Delete
252 }
253
254 #endregion Picks
255
256 #region Notes
257
258 private void HandleAvatarNotesRequest(Object sender, string method, List<String> args)
259 {
260 if (!(sender is IClientAPI))
261 return;
262 IClientAPI client = (IClientAPI)sender;
263
264 UUID targetAvatarID;
265 if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID))
266 {
267 m_log.Error("[SIMIAN PROFILES]: Unrecognized arguments for " + method);
268 return;
269 }
270
271 // FIXME: Fetch this
272 client.SendAvatarNotesReply(targetAvatarID, String.Empty);
273 }
274
275 private void AvatarNotesUpdateHandler(IClientAPI client, UUID targetID, string notes)
276 {
277 // FIXME: Save this
278 }
279
280 #endregion Notes
281
282 #region Profiles
283
284 private void RequestAvatarPropertiesHandler(IClientAPI client, UUID avatarID)
285 {
286 m_log.DebugFormat("[SIMIAN PROFILES]: Request avatar properties for {0}",avatarID);
287
288 OSDMap user = FetchUserData(avatarID);
289
290 ProfileFlags flags = ProfileFlags.AllowPublish | ProfileFlags.MaturePublish;
291
292 if (user != null)
293 {
294 OSDMap about = null;
295 if (user.ContainsKey("LLAbout"))
296 {
297 try
298 {
299 about = OSDParser.DeserializeJson(user["LLAbout"].AsString()) as OSDMap;
300 }
301 catch
302 {
303 m_log.WarnFormat("[SIMIAN PROFILES]: Unable to decode LLAbout");
304 }
305 }
306
307 if (about == null)
308 about = new OSDMap(0);
309
310 // Check if this user is a grid operator
311 byte[] charterMember;
312 if (user["AccessLevel"].AsInteger() >= 200)
313 charterMember = Utils.StringToBytes("Operator");
314 else
315 charterMember = Utils.EmptyBytes;
316
317 // Check if the user is online
318 if (client.Scene is Scene)
319 {
320 OpenSim.Services.Interfaces.PresenceInfo[] presences = ((Scene)client.Scene).PresenceService.GetAgents(new string[] { avatarID.ToString() });
321 if (presences != null && presences.Length > 0)
322 flags |= ProfileFlags.Online;
323 }
324
325 // Check if the user is identified
326 if (user["Identified"].AsBoolean())
327 flags |= ProfileFlags.Identified;
328
329 client.SendAvatarProperties(avatarID, about["About"].AsString(), user["CreationDate"].AsDate().ToString("M/d/yyyy",
330 System.Globalization.CultureInfo.InvariantCulture), charterMember, about["FLAbout"].AsString(), (uint)flags,
331 about["FLImage"].AsUUID(), about["Image"].AsUUID(), about["URL"].AsString(), user["Partner"].AsUUID());
332
333 OSDMap interests = null;
334 if (user.ContainsKey("LLInterests"))
335 {
336 try
337 {
338 interests = OSDParser.DeserializeJson(user["LLInterests"].AsString()) as OSDMap;
339 client.SendAvatarInterestsReply(avatarID, interests["WantMask"].AsUInteger(), interests["WantText"].AsString(), interests["SkillsMask"].AsUInteger(), interests["SkillsText"].AsString(), interests["Languages"].AsString());
340 }
341 catch { }
342 }
343
344 if (about == null)
345 about = new OSDMap(0);
346 }
347 else
348 {
349 m_log.Warn("[SIMIAN PROFILES]: Failed to fetch profile information for " + client.Name + ", returning default values");
350 client.SendAvatarProperties(avatarID, String.Empty, "1/1/1970", Utils.EmptyBytes,
351 String.Empty, (uint)flags, UUID.Zero, UUID.Zero, String.Empty, UUID.Zero);
352 }
353 }
354
355 private void UpdateAvatarPropertiesHandler(IClientAPI client, UserProfileData profileData)
356 {
357 OSDMap map = new OSDMap
358 {
359 { "About", OSD.FromString(profileData.AboutText) },
360 { "Image", OSD.FromUUID(profileData.Image) },
361 { "FLAbout", OSD.FromString(profileData.FirstLifeAboutText) },
362 { "FLImage", OSD.FromUUID(profileData.FirstLifeImage) },
363 { "URL", OSD.FromString(profileData.ProfileUrl) }
364 };
365
366 AddUserData(client.AgentId, "LLAbout", map);
367 }
368
369 private void AvatarInterestUpdateHandler(IClientAPI client, uint wantmask, string wanttext, uint skillsmask,
370 string skillstext, string languages)
371 {
372 OSDMap map = new OSDMap
373 {
374 { "WantMask", OSD.FromInteger(wantmask) },
375 { "WantText", OSD.FromString(wanttext) },
376 { "SkillsMask", OSD.FromInteger(skillsmask) },
377 { "SkillsText", OSD.FromString(skillstext) },
378 { "Languages", OSD.FromString(languages) }
379 };
380
381 AddUserData(client.AgentId, "LLInterests", map);
382 }
383
384 private void UserInfoRequestHandler(IClientAPI client)
385 {
386 m_log.Error("[SIMIAN PROFILES]: UserInfoRequestHandler");
387
388 // Fetch this user's e-mail address
389 NameValueCollection requestArgs = new NameValueCollection
390 {
391 { "RequestMethod", "GetUser" },
392 { "UserID", client.AgentId.ToString() }
393 };
394
395 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
396 string email = response["Email"].AsString();
397
398 if (!response["Success"].AsBoolean())
399 m_log.Warn("[SIMIAN PROFILES]: GetUser failed during a user info request for " + client.Name);
400
401 client.SendUserInfoReply(false, true, email);
402 }
403
404 private void UpdateUserInfoHandler(bool imViaEmail, bool visible, IClientAPI client)
405 {
406 m_log.Info("[SIMIAN PROFILES]: Ignoring user info update from " + client.Name);
407 }
408
409 #endregion Profiles
410
411 /// <summary>
412 /// Sanity checks regions for a valid estate owner at startup
413 /// </summary>
414 private void CheckEstateManager(Scene scene)
415 {
416 EstateSettings estate = scene.RegionInfo.EstateSettings;
417
418 if (estate.EstateOwner == UUID.Zero)
419 {
420 // Attempt to lookup the grid admin
421 UserAccount admin = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, UUID.Zero);
422 if (admin != null)
423 {
424 m_log.InfoFormat("[SIMIAN PROFILES]: Setting estate {0} (ID: {1}) owner to {2}", estate.EstateName,
425 estate.EstateID, admin.Name);
426
427 estate.EstateOwner = admin.PrincipalID;
428 scene.EstateDataService.StoreEstateSettings(estate);
429 }
430 else
431 {
432 m_log.WarnFormat("[SIMIAN PROFILES]: Estate {0} (ID: {1}) does not have an owner", estate.EstateName, estate.EstateID);
433 }
434 }
435 }
436
437 private bool AddUserData(UUID userID, string key, OSDMap value)
438 {
439 NameValueCollection requestArgs = new NameValueCollection
440 {
441 { "RequestMethod", "AddUserData" },
442 { "UserID", userID.ToString() },
443 { key, OSDParser.SerializeJsonString(value) }
444 };
445
446 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
447 bool success = response["Success"].AsBoolean();
448
449 if (!success)
450 m_log.WarnFormat("[SIMIAN PROFILES]: Failed to add user data with key {0} for {1}: {2}", key, userID, response["Message"].AsString());
451
452 return success;
453 }
454
455 private OSDMap FetchUserData(UUID userID)
456 {
457 m_log.DebugFormat("[SIMIAN PROFILES]: Fetch information about {0}",userID);
458
459 NameValueCollection requestArgs = new NameValueCollection
460 {
461 { "RequestMethod", "GetUser" },
462 { "UserID", userID.ToString() }
463 };
464
465 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
466 if (response["Success"].AsBoolean() && response["User"] is OSDMap)
467 {
468 return (OSDMap)response["User"];
469 }
470 else
471 {
472 m_log.Error("[SIMIAN PROFILES]: Failed to fetch user data for " + userID + ": " + response["Message"].AsString());
473 }
474
475 return null;
476 }
477 }
478}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs
new file mode 100644
index 0000000..698c4c0
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs
@@ -0,0 +1,337 @@
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.Collections.Specialized;
31using System.Reflection;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Services.Interfaces;
36using log4net;
37using Mono.Addins;
38using Nini.Config;
39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41
42namespace OpenSim.Services.Connectors.SimianGrid
43{
44 /// <summary>
45 /// Connects user account data (creating new users, looking up existing
46 /// users) to the SimianGrid backend
47 /// </summary>
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianUserAccountServiceConnector")]
49 public class SimianUserAccountServiceConnector : IUserAccountService, ISharedRegionModule
50 {
51 private const double CACHE_EXPIRATION_SECONDS = 120.0;
52
53 private static readonly ILog m_log =
54 LogManager.GetLogger(
55 MethodBase.GetCurrentMethod().DeclaringType);
56
57 private string m_serverUrl = String.Empty;
58 private ExpiringCache<UUID, UserAccount> m_accountCache = new ExpiringCache<UUID,UserAccount>();
59 private bool m_Enabled;
60
61 #region ISharedRegionModule
62
63 public Type ReplaceableInterface { get { return null; } }
64 public void RegionLoaded(Scene scene) { }
65 public void PostInitialise() { }
66 public void Close() { }
67
68 public SimianUserAccountServiceConnector() { }
69 public string Name { get { return "SimianUserAccountServiceConnector"; } }
70 public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IUserAccountService>(this); } }
71 public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IUserAccountService>(this); } }
72
73 #endregion ISharedRegionModule
74
75 public SimianUserAccountServiceConnector(IConfigSource source)
76 {
77 CommonInit(source);
78 }
79
80 public void Initialise(IConfigSource source)
81 {
82 IConfig moduleConfig = source.Configs["Modules"];
83 if (moduleConfig != null)
84 {
85 string name = moduleConfig.GetString("UserAccountServices", "");
86 if (name == Name)
87 CommonInit(source);
88 }
89 }
90
91 private void CommonInit(IConfigSource source)
92 {
93 IConfig gridConfig = source.Configs["UserAccountService"];
94 if (gridConfig != null)
95 {
96 string serviceUrl = gridConfig.GetString("UserAccountServerURI");
97 if (!String.IsNullOrEmpty(serviceUrl))
98 {
99 if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
100 serviceUrl = serviceUrl + '/';
101 m_serverUrl = serviceUrl;
102 m_Enabled = true;
103 }
104 }
105
106 if (String.IsNullOrEmpty(m_serverUrl))
107 m_log.Info("[SIMIAN ACCOUNT CONNECTOR]: No UserAccountServerURI specified, disabling connector");
108 }
109
110 public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName)
111 {
112 NameValueCollection requestArgs = new NameValueCollection
113 {
114 { "RequestMethod", "GetUser" },
115 { "Name", firstName + ' ' + lastName }
116 };
117
118 return GetUser(requestArgs);
119 }
120
121 public UserAccount GetUserAccount(UUID scopeID, string email)
122 {
123 NameValueCollection requestArgs = new NameValueCollection
124 {
125 { "RequestMethod", "GetUser" },
126 { "Email", email }
127 };
128
129 return GetUser(requestArgs);
130 }
131
132 public UserAccount GetUserAccount(UUID scopeID, UUID userID)
133 {
134 // Cache check
135 UserAccount account;
136 if (m_accountCache.TryGetValue(userID, out account))
137 return account;
138
139 NameValueCollection requestArgs = new NameValueCollection
140 {
141 { "RequestMethod", "GetUser" },
142 { "UserID", userID.ToString() }
143 };
144
145 account = GetUser(requestArgs);
146
147 if (account == null)
148 {
149 // Store null responses too, to avoid repeated lookups for missing accounts
150 m_accountCache.AddOrUpdate(userID, null, CACHE_EXPIRATION_SECONDS);
151 }
152
153 return account;
154 }
155
156 public List<UserAccount> GetUserAccounts(UUID scopeID, string query)
157 {
158 List<UserAccount> accounts = new List<UserAccount>();
159
160// m_log.DebugFormat("[SIMIAN ACCOUNT CONNECTOR]: Searching for user accounts with name query " + query);
161
162 NameValueCollection requestArgs = new NameValueCollection
163 {
164 { "RequestMethod", "GetUsers" },
165 { "NameQuery", query }
166 };
167
168 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
169 if (response["Success"].AsBoolean())
170 {
171 OSDArray array = response["Users"] as OSDArray;
172 if (array != null && array.Count > 0)
173 {
174 for (int i = 0; i < array.Count; i++)
175 {
176 UserAccount account = ResponseToUserAccount(array[i] as OSDMap);
177 if (account != null)
178 accounts.Add(account);
179 }
180 }
181 else
182 {
183 m_log.Warn("[SIMIAN ACCOUNT CONNECTOR]: Account search failed, response data was in an invalid format");
184 }
185 }
186 else
187 {
188 m_log.Warn("[SIMIAN ACCOUNT CONNECTOR]: Failed to search for account data by name " + query);
189 }
190
191 return accounts;
192 }
193
194 public void InvalidateCache(UUID userID)
195 {
196 m_accountCache.Remove(userID);
197 }
198
199 public bool StoreUserAccount(UserAccount data)
200 {
201// m_log.InfoFormat("[SIMIAN ACCOUNT CONNECTOR]: Storing user account for " + data.Name);
202
203 NameValueCollection requestArgs = new NameValueCollection
204 {
205 { "RequestMethod", "AddUser" },
206 { "UserID", data.PrincipalID.ToString() },
207 { "Name", data.Name },
208 { "Email", data.Email },
209 { "AccessLevel", data.UserLevel.ToString() }
210 };
211
212 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
213
214 if (response["Success"].AsBoolean())
215 {
216 m_log.InfoFormat("[SIMIAN ACCOUNT CONNECTOR]: Storing user account data for " + data.Name);
217
218 requestArgs = new NameValueCollection
219 {
220 { "RequestMethod", "AddUserData" },
221 { "UserID", data.PrincipalID.ToString() },
222 { "CreationDate", data.Created.ToString() },
223 { "UserFlags", data.UserFlags.ToString() },
224 { "UserTitle", data.UserTitle }
225 };
226
227 response = SimianGrid.PostToService(m_serverUrl, requestArgs);
228 bool success = response["Success"].AsBoolean();
229
230 if (success)
231 {
232 // Cache the user account info
233 m_accountCache.AddOrUpdate(data.PrincipalID, data, CACHE_EXPIRATION_SECONDS);
234 }
235 else
236 {
237 m_log.Warn("[SIMIAN ACCOUNT CONNECTOR]: Failed to store user account data for " + data.Name + ": " + response["Message"].AsString());
238 }
239
240 return success;
241 }
242 else
243 {
244 m_log.Warn("[SIMIAN ACCOUNT CONNECTOR]: Failed to store user account for " + data.Name + ": " + response["Message"].AsString());
245 }
246
247 return false;
248 }
249
250 /// <summary>
251 /// Helper method for the various ways of retrieving a user account
252 /// </summary>
253 /// <param name="requestArgs">Service query parameters</param>
254 /// <returns>A UserAccount object on success, null on failure</returns>
255 private UserAccount GetUser(NameValueCollection requestArgs)
256 {
257 string lookupValue = (requestArgs.Count > 1) ? requestArgs[1] : "(Unknown)";
258// m_log.DebugFormat("[SIMIAN ACCOUNT CONNECTOR]: Looking up user account with query: " + lookupValue);
259
260 OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
261 if (response["Success"].AsBoolean())
262 {
263 OSDMap user = response["User"] as OSDMap;
264 if (user != null)
265 return ResponseToUserAccount(user);
266 else
267 m_log.Warn("[SIMIAN ACCOUNT CONNECTOR]: Account search failed, response data was in an invalid format");
268 }
269 else
270 {
271 m_log.Warn("[SIMIAN ACCOUNT CONNECTOR]: Failed to lookup user account with query: " + lookupValue);
272 }
273
274 return null;
275 }
276
277 /// <summary>
278 /// Convert a User object in LLSD format to a UserAccount
279 /// </summary>
280 /// <param name="response">LLSD containing user account data</param>
281 /// <returns>A UserAccount object on success, null on failure</returns>
282 private UserAccount ResponseToUserAccount(OSDMap response)
283 {
284 if (response == null)
285 return null;
286
287 UserAccount account = new UserAccount();
288 account.PrincipalID = response["UserID"].AsUUID();
289 account.Created = response["CreationDate"].AsInteger();
290 account.Email = response["Email"].AsString();
291 account.ServiceURLs = new Dictionary<string, object>(0);
292 account.UserFlags = response["UserFlags"].AsInteger();
293 account.UserLevel = response["AccessLevel"].AsInteger();
294 account.UserTitle = response["UserTitle"].AsString();
295 account.LocalToGrid = true;
296 if (response.ContainsKey("LocalToGrid"))
297 account.LocalToGrid = (response["LocalToGrid"].AsString() == "true" ? true : false);
298
299 GetFirstLastName(response["Name"].AsString(), out account.FirstName, out account.LastName);
300
301 // Cache the user account info
302 m_accountCache.AddOrUpdate(account.PrincipalID, account, CACHE_EXPIRATION_SECONDS);
303
304 return account;
305 }
306
307 /// <summary>
308 /// Convert a name with a single space in it to a first and last name
309 /// </summary>
310 /// <param name="name">A full name such as "John Doe"</param>
311 /// <param name="firstName">First name</param>
312 /// <param name="lastName">Last name (surname)</param>
313 private static void GetFirstLastName(string name, out string firstName, out string lastName)
314 {
315 if (String.IsNullOrEmpty(name))
316 {
317 firstName = String.Empty;
318 lastName = String.Empty;
319 }
320 else
321 {
322 string[] names = name.Split(' ');
323
324 if (names.Length == 2)
325 {
326 firstName = names[0];
327 lastName = names[1];
328 }
329 else
330 {
331 firstName = String.Empty;
332 lastName = name;
333 }
334 }
335 }
336 }
337} \ No newline at end of file