aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Services
diff options
context:
space:
mode:
authorJohn Hurliman2010-03-11 10:05:03 -0800
committerJohn Hurliman2010-03-11 11:19:02 -0800
commit20406498711d1f26037ae32e1b7f8378b01ad848 (patch)
treee4a5a1c2f8eb9730d69a424aad59776f1359a9eb /OpenSim/Services
parentMerge branch 'master' of ssh://opensimulator.org/var/git/opensim (diff)
downloadopensim-SC-20406498711d1f26037ae32e1b7f8378b01ad848.zip
opensim-SC-20406498711d1f26037ae32e1b7f8378b01ad848.tar.gz
opensim-SC-20406498711d1f26037ae32e1b7f8378b01ad848.tar.bz2
opensim-SC-20406498711d1f26037ae32e1b7f8378b01ad848.tar.xz
Adding the SimianGrid connectors
Diffstat (limited to 'OpenSim/Services')
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs407
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs198
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs259
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs229
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs31
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs418
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs880
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs502
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs432
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs307
10 files changed, 3663 insertions, 0 deletions
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs
new file mode 100644
index 0000000..9fb7723
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs
@@ -0,0 +1,407 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Reflection;
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
40using OpenMetaverse;
41using OpenMetaverse.StructuredData;
42
43namespace OpenSim.Services.Connectors.SimianGrid
44{
45 /// <summary>
46 /// Connects to the SimianGrid asset service
47 /// </summary>
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
49 public class SimianAssetServiceConnector : IAssetService, ISharedRegionModule
50 {
51 private static readonly ILog m_log =
52 LogManager.GetLogger(
53 MethodBase.GetCurrentMethod().DeclaringType);
54 private static string ZeroID = UUID.Zero.ToString();
55
56 private string m_serverUrl = String.Empty;
57 private IImprovedAssetCache m_cache;
58
59 #region ISharedRegionModule
60
61 public Type ReplaceableInterface { get { return null; } }
62 public void RegionLoaded(Scene scene)
63 {
64 if (m_cache == null)
65 {
66 IImprovedAssetCache cache = scene.RequestModuleInterface<IImprovedAssetCache>();
67 if (cache is ISharedRegionModule)
68 m_cache = cache;
69 }
70 }
71 public void PostInitialise() { }
72 public void Close() { }
73
74 public SimianAssetServiceConnector() { }
75 public string Name { get { return "SimianAssetServiceConnector"; } }
76 public void AddRegion(Scene scene) { scene.RegisterModuleInterface<IAssetService>(this); }
77 public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface<IAssetService>(this); }
78
79 #endregion ISharedRegionModule
80
81 public SimianAssetServiceConnector(IConfigSource source)
82 {
83 Initialise(source);
84 }
85
86 public void Initialise(IConfigSource source)
87 {
88 IConfig gridConfig = source.Configs["AssetService"];
89 if (gridConfig == null)
90 {
91 m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini");
92 throw new Exception("Asset connector init error");
93 }
94
95 string serviceUrl = gridConfig.GetString("AssetServerURI");
96 if (String.IsNullOrEmpty(serviceUrl))
97 {
98 m_log.Error("[ASSET CONNECTOR]: No AssetServerURI in section AssetService");
99 throw new Exception("Asset connector init error");
100 }
101
102 if (!serviceUrl.EndsWith("/"))
103 serviceUrl = serviceUrl + '/';
104
105 m_serverUrl = serviceUrl;
106 }
107
108 #region IAssetService
109
110 public AssetBase Get(string id)
111 {
112 AssetBase asset = null;
113
114 // Cache fetch
115 if (m_cache != null)
116 {
117 asset = m_cache.Get(id);
118 if (asset != null)
119 return asset;
120 }
121
122 Uri url;
123
124 // Determine if id is an absolute URL or a grid-relative UUID
125 if (!Uri.TryCreate(id, UriKind.Absolute, out url))
126 url = new Uri(m_serverUrl + id);
127
128 try
129 {
130 HttpWebRequest request = UntrustedHttpWebRequest.Create(url);
131
132 using (WebResponse response = request.GetResponse())
133 {
134 using (Stream responseStream = response.GetResponseStream())
135 {
136 string creatorID = response.Headers.GetOne("X-Asset-Creator-Id") ?? String.Empty;
137
138 // Create the asset object
139 asset = new AssetBase(id, String.Empty, SLUtil.ContentTypeToSLAssetType(response.ContentType), creatorID);
140
141 UUID assetID;
142 if (UUID.TryParse(id, out assetID))
143 asset.FullID = assetID;
144
145 // Grab the asset data from the response stream
146 using (MemoryStream stream = new MemoryStream())
147 {
148 responseStream.CopyTo(stream, Int32.MaxValue);
149 asset.Data = stream.ToArray();
150 }
151 }
152 }
153
154 // Cache store
155 if (m_cache != null && asset != null)
156 m_cache.Cache(asset);
157
158 return asset;
159 }
160 catch (Exception ex)
161 {
162 m_log.Warn("[ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message);
163 return null;
164 }
165 }
166
167 /// <summary>
168 /// Get an asset's metadata
169 /// </summary>
170 /// <param name="id"></param>
171 /// <returns></returns>
172 public AssetMetadata GetMetadata(string id)
173 {
174 AssetMetadata metadata = null;
175
176 // Cache fetch
177 if (m_cache != null)
178 {
179 AssetBase asset = m_cache.Get(id);
180 if (asset != null)
181 return asset.Metadata;
182 }
183
184 Uri url;
185
186 // Determine if id is an absolute URL or a grid-relative UUID
187 if (!Uri.TryCreate(id, UriKind.Absolute, out url))
188 url = new Uri(m_serverUrl + id);
189
190 try
191 {
192 HttpWebRequest request = UntrustedHttpWebRequest.Create(url);
193 request.Method = "HEAD";
194
195 using (WebResponse response = request.GetResponse())
196 {
197 using (Stream responseStream = response.GetResponseStream())
198 {
199 // Create the metadata object
200 metadata = new AssetMetadata();
201 metadata.ContentType = response.ContentType;
202 metadata.ID = id;
203
204 UUID uuid;
205 if (UUID.TryParse(id, out uuid))
206 metadata.FullID = uuid;
207
208 string lastModifiedStr = response.Headers.Get("Last-Modified");
209 if (!String.IsNullOrEmpty(lastModifiedStr))
210 {
211 DateTime lastModified;
212 if (DateTime.TryParse(lastModifiedStr, out lastModified))
213 metadata.CreationDate = lastModified;
214 }
215 }
216 }
217 }
218 catch (Exception ex)
219 {
220 m_log.Warn("[ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message);
221 }
222
223 return metadata;
224 }
225
226 public byte[] GetData(string id)
227 {
228 AssetBase asset = Get(id);
229
230 if (asset != null)
231 return asset.Data;
232
233 return null;
234 }
235
236 /// <summary>
237 /// Get an asset asynchronously
238 /// </summary>
239 /// <param name="id">The asset id</param>
240 /// <param name="sender">Represents the requester. Passed back via the handler</param>
241 /// <param name="handler">The handler to call back once the asset has been retrieved</param>
242 /// <returns>True if the id was parseable, false otherwise</returns>
243 public bool Get(string id, Object sender, AssetRetrieved handler)
244 {
245 Util.FireAndForget(
246 delegate(object o)
247 {
248 AssetBase asset = Get(id);
249 handler(id, sender, asset);
250 }
251 );
252
253 return true;
254 }
255
256 /// <summary>
257 /// Creates a new asset
258 /// </summary>
259 /// Returns a random ID if none is passed into it
260 /// <param name="asset"></param>
261 /// <returns></returns>
262 public string Store(AssetBase asset)
263 {
264 bool storedInCache = false;
265 string errorMessage = null;
266
267 // AssetID handling
268 if (String.IsNullOrEmpty(asset.ID) || asset.ID == ZeroID)
269 {
270 asset.FullID = UUID.Random();
271 asset.ID = asset.FullID.ToString();
272 }
273
274 // Cache handling
275 if (m_cache != null)
276 {
277 m_cache.Cache(asset);
278 storedInCache = true;
279 }
280
281 // Local asset handling
282 if (asset.Local)
283 {
284 if (!storedInCache)
285 {
286 m_log.Error("Cannot store local " + asset.Metadata.ContentType + " asset without an asset cache");
287 asset.ID = null;
288 asset.FullID = UUID.Zero;
289 }
290
291 return asset.ID;
292 }
293
294 // Distinguish public and private assets
295 bool isPublic = true;
296 switch ((AssetType)asset.Type)
297 {
298 case AssetType.CallingCard:
299 case AssetType.Gesture:
300 case AssetType.LSLBytecode:
301 case AssetType.LSLText:
302 isPublic = false;
303 break;
304 }
305
306 // Make sure ContentType is set
307 if (String.IsNullOrEmpty(asset.Metadata.ContentType))
308 asset.Metadata.ContentType = SLUtil.SLAssetTypeToContentType(asset.Type);
309
310 // Build the remote storage request
311 List<MultipartForm.Element> postParameters = new List<MultipartForm.Element>()
312 {
313 new MultipartForm.Parameter("AssetID", asset.FullID.ToString()),
314 new MultipartForm.Parameter("CreatorID", asset.Metadata.CreatorID),
315 new MultipartForm.Parameter("Temporary", asset.Temporary ? "1" : "0"),
316 new MultipartForm.Parameter("Public", isPublic ? "1" : "0"),
317 new MultipartForm.File("Asset", asset.Name, asset.Metadata.ContentType, asset.Data)
318 };
319
320 // Make the remote storage request
321 try
322 {
323 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl);
324
325 HttpWebResponse response = MultipartForm.Post(request, postParameters);
326 using (Stream responseStream = response.GetResponseStream())
327 {
328 try
329 {
330 string responseStr = responseStream.GetStreamString();
331 OSD responseOSD = OSDParser.Deserialize(responseStr);
332 if (responseOSD.Type == OSDType.Map)
333 {
334 OSDMap responseMap = (OSDMap)responseOSD;
335 if (responseMap["Success"].AsBoolean())
336 return asset.ID;
337 else
338 errorMessage = "Upload failed: " + responseMap["Message"].AsString();
339 }
340 else
341 {
342 errorMessage = "Response format was invalid.";
343 }
344 }
345 catch
346 {
347 errorMessage = "Failed to parse the response.";
348 }
349 }
350 }
351 catch (WebException ex)
352 {
353 errorMessage = ex.Message;
354 }
355
356 m_log.WarnFormat("[ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}",
357 asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage);
358 return null;
359 }
360
361 /// <summary>
362 /// Update an asset's content
363 /// </summary>
364 /// Attachments and bare scripts need this!!
365 /// <param name="id"> </param>
366 /// <param name="data"></param>
367 /// <returns></returns>
368 public bool UpdateContent(string id, byte[] data)
369 {
370 AssetBase asset = Get(id);
371
372 if (asset == null)
373 {
374 m_log.Warn("[ASSET CONNECTOR]: Failed to fetch asset " + id + " for updating");
375 return false;
376 }
377
378 asset.Data = data;
379
380 string result = Store(asset);
381 return !String.IsNullOrEmpty(result);
382 }
383
384 /// <summary>
385 /// Delete an asset
386 /// </summary>
387 /// <param name="id"></param>
388 /// <returns></returns>
389 public bool Delete(string id)
390 {
391 if (m_cache != null)
392 m_cache.Expire(id);
393
394 string url = m_serverUrl + id;
395
396 OSDMap response = WebUtil.ServiceRequest(url, "DELETE");
397 if (response["Success"].AsBoolean())
398 return true;
399 else
400 m_log.Warn("[ASSET CONNECTOR]: Failed to delete asset " + id + " from the asset service");
401
402 return false;
403 }
404
405 #endregion IAssetService
406 }
407}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs
new file mode 100644
index 0000000..ec66341
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs
@@ -0,0 +1,198 @@
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")]
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
55 #region ISharedRegionModule
56
57 public Type ReplaceableInterface { get { return null; } }
58 public void RegionLoaded(Scene scene) { }
59 public void PostInitialise() { }
60 public void Close() { }
61
62 public SimianAuthenticationServiceConnector() { }
63 public string Name { get { return "SimianAuthenticationServiceConnector"; } }
64 public void AddRegion(Scene scene) { scene.RegisterModuleInterface<IAuthenticationService>(this); }
65 public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface<IAuthenticationService>(this); }
66
67 #endregion ISharedRegionModule
68
69 public SimianAuthenticationServiceConnector(IConfigSource source)
70 {
71 Initialise(source);
72 }
73
74 public void Initialise(IConfigSource source)
75 {
76 IConfig assetConfig = source.Configs["AuthenticationService"];
77 if (assetConfig == null)
78 {
79 m_log.Error("[AUTH CONNECTOR]: AuthenticationService missing from OpenSim.ini");
80 throw new Exception("Authentication connector init error");
81 }
82
83 string serviceURI = assetConfig.GetString("AuthenticationServerURI");
84 if (String.IsNullOrEmpty(serviceURI))
85 {
86 m_log.Error("[AUTH CONNECTOR]: No Server URI named in section AuthenticationService");
87 throw new Exception("Authentication connector init error");
88 }
89
90 m_serverUrl = serviceURI;
91 }
92
93 public string Authenticate(UUID principalID, string password, int lifetime)
94 {
95 NameValueCollection requestArgs = new NameValueCollection
96 {
97 { "RequestMethod", "GetIdentities" },
98 { "UserID", principalID.ToString() }
99 };
100
101 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
102 if (response["Success"].AsBoolean() && response["Identities"] is OSDArray)
103 {
104 OSDArray identities = (OSDArray)response["Identities"];
105 for (int i = 0; i < identities.Count; i++)
106 {
107 OSDMap identity = identities[i] as OSDMap;
108 if (identity != null)
109 {
110 if (identity["Type"].AsString() == "md5hash")
111 {
112 string credential = identity["Credential"].AsString();
113
114 if (password == credential || Utils.MD5String(password) == credential)
115 return Authorize(principalID);
116 }
117 }
118 }
119
120 m_log.Warn("[AUTH CONNECTOR]: Authentication failed for " + principalID);
121 }
122 else
123 {
124 m_log.Warn("[AUTH CONNECTOR]: Failed to retrieve identities for " + principalID + ": " +
125 response["Message"].AsString());
126 }
127
128 return String.Empty;
129 }
130
131 public bool Verify(UUID principalID, string token, int lifetime)
132 {
133 NameValueCollection requestArgs = new NameValueCollection
134 {
135 { "RequestMethod", "GetSession" },
136 { "SessionID", token }
137 };
138
139 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
140 if (response["Success"].AsBoolean())
141 {
142 return true;
143 }
144 else
145 {
146 m_log.Warn("[AUTH CONNECTOR]: Could not verify session for " + principalID + ": " +
147 response["Message"].AsString());
148 }
149
150 return false;
151 }
152
153 public bool Release(UUID principalID, string token)
154 {
155 NameValueCollection requestArgs = new NameValueCollection
156 {
157 { "RequestMethod", "RemoveSession" },
158 { "UserID", principalID.ToString() }
159 };
160
161 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
162 if (response["Success"].AsBoolean())
163 {
164 return true;
165 }
166 else
167 {
168 m_log.Warn("[AUTH CONNECTOR]: Failed to remove session for " + principalID + ": " +
169 response["Message"].AsString());
170 }
171
172 return false;
173 }
174
175 public bool SetPassword(UUID principalID, string passwd)
176 {
177 // TODO: Use GetIdentities to find the md5hash identity for principalID
178 // and then update it with AddIdentity
179 m_log.Error("[AUTH CONNECTOR]: Changing passwords is not implemented yet");
180 return false;
181 }
182
183 private string Authorize(UUID userID)
184 {
185 NameValueCollection requestArgs = new NameValueCollection
186 {
187 { "RequestMethod", "AddSession" },
188 { "UserID", userID.ToString() }
189 };
190
191 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
192 if (response["Success"].AsBoolean())
193 return response["SessionID"].AsUUID().ToString();
194 else
195 return String.Empty;
196 }
197 }
198}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs
new file mode 100644
index 0000000..220f143
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs
@@ -0,0 +1,259 @@
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.Server.Base;
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")]
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
60 #region ISharedRegionModule
61
62 public Type ReplaceableInterface { get { return null; } }
63 public void RegionLoaded(Scene scene) { }
64 public void PostInitialise() { }
65 public void Close() { }
66
67 public SimianAvatarServiceConnector() { }
68 public string Name { get { return "SimianAvatarServiceConnector"; } }
69 public void AddRegion(Scene scene) { scene.RegisterModuleInterface<IAvatarService>(this); }
70 public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface<IAvatarService>(this); }
71
72 #endregion ISharedRegionModule
73
74 public SimianAvatarServiceConnector(IConfigSource source)
75 {
76 Initialise(source);
77 }
78
79 public void Initialise(IConfigSource source)
80 {
81 IConfig gridConfig = source.Configs["AvatarService"];
82 if (gridConfig == null)
83 {
84 m_log.Error("[AVATAR CONNECTOR]: AvatarService missing from OpenSim.ini");
85 throw new Exception("Avatar connector init error");
86 }
87
88 string serviceUrl = gridConfig.GetString("AvatarServerURI");
89 if (String.IsNullOrEmpty(serviceUrl))
90 {
91 m_log.Error("[AVATAR CONNECTOR]: No AvatarServerURI in section AvatarService");
92 throw new Exception("Avatar connector init error");
93 }
94
95 if (!serviceUrl.EndsWith("/"))
96 serviceUrl = serviceUrl + '/';
97
98 m_serverUrl = serviceUrl;
99 }
100
101 #region IAvatarService
102
103 public AvatarData GetAvatar(UUID userID)
104 {
105 NameValueCollection requestArgs = new NameValueCollection
106 {
107 { "RequestMethod", "GetUser" },
108 { "UserID", userID.ToString() }
109 };
110
111 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
112 if (response["Success"].AsBoolean())
113 {
114 OSDMap map = null;
115 try { map = OSDParser.DeserializeJson(response["LLAppearance"].AsString()) as OSDMap; }
116 catch { }
117
118 if (map != null)
119 {
120 AvatarWearable[] wearables = new AvatarWearable[13];
121 wearables[0] = new AvatarWearable(map["ShapeItem"].AsUUID(), map["ShapeAsset"].AsUUID());
122 wearables[1] = new AvatarWearable(map["SkinItem"].AsUUID(), map["SkinAsset"].AsUUID());
123 wearables[2] = new AvatarWearable(map["HairItem"].AsUUID(), map["HairAsset"].AsUUID());
124 wearables[3] = new AvatarWearable(map["EyesItem"].AsUUID(), map["EyesAsset"].AsUUID());
125 wearables[4] = new AvatarWearable(map["ShirtItem"].AsUUID(), map["ShirtAsset"].AsUUID());
126 wearables[5] = new AvatarWearable(map["PantsItem"].AsUUID(), map["PantsAsset"].AsUUID());
127 wearables[6] = new AvatarWearable(map["ShoesItem"].AsUUID(), map["ShoesAsset"].AsUUID());
128 wearables[7] = new AvatarWearable(map["SocksItem"].AsUUID(), map["SocksAsset"].AsUUID());
129 wearables[8] = new AvatarWearable(map["JacketItem"].AsUUID(), map["JacketAsset"].AsUUID());
130 wearables[9] = new AvatarWearable(map["GlovesItem"].AsUUID(), map["GlovesAsset"].AsUUID());
131 wearables[10] = new AvatarWearable(map["UndershirtItem"].AsUUID(), map["UndershirtAsset"].AsUUID());
132 wearables[11] = new AvatarWearable(map["UnderpantsItem"].AsUUID(), map["UnderpantsAsset"].AsUUID());
133 wearables[12] = new AvatarWearable(map["SkirtItem"].AsUUID(), map["SkirtAsset"].AsUUID());
134
135 AvatarAppearance appearance = new AvatarAppearance(userID);
136 appearance.Wearables = wearables;
137 appearance.AvatarHeight = (float)map["Height"].AsReal();
138
139 AvatarData avatar = new AvatarData(appearance);
140
141 // Get attachments
142 map = null;
143 try { map = OSDParser.DeserializeJson(response["LLAttachments"].AsString()) as OSDMap; }
144 catch { }
145
146 if (map != null)
147 {
148 foreach (KeyValuePair<string, OSD> kvp in map)
149 avatar.Data[kvp.Key] = kvp.Value.AsString();
150 }
151
152 return avatar;
153 }
154 else
155 {
156 m_log.Warn("[AVATAR CONNECTOR]: Failed to get user appearance for " + userID +
157 ", LLAppearance is missing or invalid");
158 return null;
159 }
160 }
161 else
162 {
163 m_log.Warn("[AVATAR CONNECTOR]: Failed to get user appearance for " + userID + ": " +
164 response["Message"].AsString());
165 }
166
167 return null;
168 }
169
170 public bool SetAvatar(UUID userID, AvatarData avatar)
171 {
172 m_log.Debug("[AVATAR CONNECTOR]: SetAvatar called for " + userID);
173
174 if (avatar.AvatarType == 1) // LLAvatar
175 {
176 AvatarAppearance appearance = avatar.ToAvatarAppearance(userID);
177
178 OSDMap map = new OSDMap();
179
180 map["Height"] = OSD.FromReal(appearance.AvatarHeight);
181
182 map["ShapeItem"] = OSD.FromUUID(appearance.BodyItem);
183 map["ShapeAsset"] = OSD.FromUUID(appearance.BodyAsset);
184 map["SkinItem"] = OSD.FromUUID(appearance.SkinItem);
185 map["SkinAsset"] = OSD.FromUUID(appearance.SkinAsset);
186 map["HairItem"] = OSD.FromUUID(appearance.HairItem);
187 map["HairAsset"] = OSD.FromUUID(appearance.HairAsset);
188 map["EyesItem"] = OSD.FromUUID(appearance.EyesItem);
189 map["EyesAsset"] = OSD.FromUUID(appearance.EyesAsset);
190 map["ShirtItem"] = OSD.FromUUID(appearance.ShirtItem);
191 map["ShirtAsset"] = OSD.FromUUID(appearance.ShirtAsset);
192 map["PantsItem"] = OSD.FromUUID(appearance.PantsItem);
193 map["PantsAsset"] = OSD.FromUUID(appearance.PantsAsset);
194 map["ShoesItem"] = OSD.FromUUID(appearance.ShoesItem);
195 map["ShoesAsset"] = OSD.FromUUID(appearance.ShoesAsset);
196 map["SocksItem"] = OSD.FromUUID(appearance.SocksItem);
197 map["SocksAsset"] = OSD.FromUUID(appearance.SocksAsset);
198 map["JacketItem"] = OSD.FromUUID(appearance.JacketItem);
199 map["JacketAsset"] = OSD.FromUUID(appearance.JacketAsset);
200 map["GlovesItem"] = OSD.FromUUID(appearance.GlovesItem);
201 map["GlovesAsset"] = OSD.FromUUID(appearance.GlovesAsset);
202 map["UndershirtItem"] = OSD.FromUUID(appearance.UnderShirtItem);
203 map["UndershirtAsset"] = OSD.FromUUID(appearance.UnderShirtAsset);
204 map["UnderpantsItem"] = OSD.FromUUID(appearance.UnderPantsItem);
205 map["UnderpantsAsset"] = OSD.FromUUID(appearance.UnderPantsAsset);
206 map["SkirtItem"] = OSD.FromUUID(appearance.SkirtItem);
207 map["SkirtAsset"] = OSD.FromUUID(appearance.SkirtAsset);
208
209 OSDMap items = new OSDMap();
210 foreach (KeyValuePair<string, string> kvp in avatar.Data)
211 {
212 if (kvp.Key.StartsWith("_ap_"))
213 items.Add(kvp.Key, OSD.FromString(kvp.Value));
214 }
215
216 NameValueCollection requestArgs = new NameValueCollection
217 {
218 { "RequestMethod", "AddUserData" },
219 { "UserID", userID.ToString() },
220 { "LLAppearance", OSDParser.SerializeJsonString(map) },
221 { "LLAttachments", OSDParser.SerializeJsonString(items) }
222 };
223
224 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
225 bool success = response["Success"].AsBoolean();
226
227 if (!success)
228 m_log.Warn("[AVATAR CONNECTOR]: Failed saving appearance for " + userID + ": " + response["Message"].AsString());
229
230 return success;
231 }
232 else
233 {
234 m_log.Error("[AVATAR CONNECTOR]: Can't save appearance for " + userID + ". Unhandled avatar type " + avatar.AvatarType);
235 return false;
236 }
237 }
238
239 public bool ResetAvatar(UUID userID)
240 {
241 m_log.Error("[AVATAR CONNECTOR]: ResetAvatar called for " + userID + ", implement this");
242 return false;
243 }
244
245 public bool SetItems(UUID userID, string[] names, string[] values)
246 {
247 m_log.Error("[AVATAR CONNECTOR]: SetItems called for " + userID + " with " + names.Length + " names and " + values.Length + " values, implement this");
248 return false;
249 }
250
251 public bool RemoveItems(UUID userID, string[] names)
252 {
253 m_log.Error("[AVATAR CONNECTOR]: RemoveItems called for " + userID + " with " + names.Length + " names, implement this");
254 return false;
255 }
256
257 #endregion IAvatarService
258 }
259}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs
new file mode 100644
index 0000000..3952a8c
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs
@@ -0,0 +1,229 @@
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;
41
42using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
43
44namespace OpenSim.Services.Connectors.SimianGrid
45{
46 /// <summary>
47 /// Stores and retrieves friend lists from the SimianGrid backend
48 /// </summary>
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
50 public class SimianFriendsServiceConnector : IFriendsService, ISharedRegionModule
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(
54 MethodBase.GetCurrentMethod().DeclaringType);
55
56 private string m_serverUrl = String.Empty;
57
58 #region ISharedRegionModule
59
60 public Type ReplaceableInterface { get { return null; } }
61 public void RegionLoaded(Scene scene) { }
62 public void PostInitialise() { }
63 public void Close() { }
64
65 public SimianFriendsServiceConnector() { }
66 public string Name { get { return "SimianFriendsServiceConnector"; } }
67 public void AddRegion(Scene scene) { scene.RegisterModuleInterface<IFriendsService>(this); }
68 public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface<IFriendsService>(this); }
69
70 #endregion ISharedRegionModule
71
72 public SimianFriendsServiceConnector(IConfigSource source)
73 {
74 Initialise(source);
75 }
76
77 public void Initialise(IConfigSource source)
78 {
79 IConfig assetConfig = source.Configs["FriendsService"];
80 if (assetConfig == null)
81 {
82 m_log.Error("[FRIENDS CONNECTOR]: FriendsService missing from OpenSim.ini");
83 throw new Exception("Friends connector init error");
84 }
85
86 string serviceURI = assetConfig.GetString("FriendsServerURI");
87 if (String.IsNullOrEmpty(serviceURI))
88 {
89 m_log.Error("[FRIENDS CONNECTOR]: No Server URI named in section FriendsService");
90 throw new Exception("Friends connector init error");
91 }
92
93 m_serverUrl = serviceURI;
94 }
95
96 #region IFriendsService
97
98 public FriendInfo[] GetFriends(UUID principalID)
99 {
100 Dictionary<UUID, FriendInfo> friends = new Dictionary<UUID, FriendInfo>();
101
102 OSDArray friendsArray = GetFriended(principalID);
103 OSDArray friendedMeArray = GetFriendedBy(principalID);
104
105 // Load the list of friends and their granted permissions
106 for (int i = 0; i < friendsArray.Count; i++)
107 {
108 OSDMap friendEntry = friendsArray[i] as OSDMap;
109 if (friendEntry != null)
110 {
111 UUID friendID = friendEntry["Key"].AsUUID();
112
113 FriendInfo friend = new FriendInfo();
114 friend.PrincipalID = principalID;
115 friend.Friend = friendID.ToString();
116 friend.MyFlags = friendEntry["Value"].AsInteger();
117 friend.TheirFlags = -1;
118
119 friends[friendID] = friend;
120 }
121 }
122
123 // Load the permissions those friends have granted to this user
124 for (int i = 0; i < friendedMeArray.Count; i++)
125 {
126 OSDMap friendedMeEntry = friendedMeArray[i] as OSDMap;
127 if (friendedMeEntry != null)
128 {
129 UUID friendID = friendedMeEntry["OwnerID"].AsUUID();
130
131 FriendInfo friend;
132 if (friends.TryGetValue(friendID, out friend))
133 friend.TheirFlags = friendedMeEntry["Value"].AsInteger();
134 }
135 }
136
137 // Convert the dictionary of friends to an array and return it
138 FriendInfo[] array = new FriendInfo[friends.Count];
139 int j = 0;
140 foreach (FriendInfo friend in friends.Values)
141 array[j++] = friend;
142
143 return array;
144 }
145
146 public bool StoreFriend(UUID principalID, string friend, int flags)
147 {
148 NameValueCollection requestArgs = new NameValueCollection
149 {
150 { "RequestMethod", "AddGeneric" },
151 { "OwnerID", principalID.ToString() },
152 { "Type", "Friend" },
153 { "Key", friend },
154 { "Value", flags.ToString() }
155 };
156
157 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
158 bool success = response["Success"].AsBoolean();
159
160 if (!success)
161 m_log.Error("[FRIENDS CONNECTOR]: Failed to store friend " + friend + " for user " + principalID + ": " + response["Message"].AsString());
162
163 return success;
164 }
165
166 public bool Delete(UUID principalID, string friend)
167 {
168 NameValueCollection requestArgs = new NameValueCollection
169 {
170 { "RequestMethod", "RemoveGeneric" },
171 { "OwnerID", principalID.ToString() },
172 { "Type", "Friend" },
173 { "Key", friend }
174 };
175
176 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
177 bool success = response["Success"].AsBoolean();
178
179 if (!success)
180 m_log.Error("[FRIENDS CONNECTOR]: Failed to remove friend " + friend + " for user " + principalID + ": " + response["Message"].AsString());
181
182 return success;
183 }
184
185 #endregion IFriendsService
186
187 private OSDArray GetFriended(UUID ownerID)
188 {
189 NameValueCollection requestArgs = new NameValueCollection
190 {
191 { "RequestMethod", "GetGenerics" },
192 { "OwnerID", ownerID.ToString() },
193 { "Type", "Friend" }
194 };
195
196 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
197 if (response["Success"].AsBoolean() && response["Entries"] is OSDArray)
198 {
199 return (OSDArray)response["Entries"];
200 }
201 else
202 {
203 m_log.Warn("[FRIENDS CONNECTOR]: Failed to retrieve friends for user " + ownerID + ": " + response["Message"].AsString());
204 return new OSDArray(0);
205 }
206 }
207
208 private OSDArray GetFriendedBy(UUID ownerID)
209 {
210 NameValueCollection requestArgs = new NameValueCollection
211 {
212 { "RequestMethod", "GetGenerics" },
213 { "Key", ownerID.ToString() },
214 { "Type", "Friend" }
215 };
216
217 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
218 if (response["Success"].AsBoolean() && response["Entries"] is OSDArray)
219 {
220 return (OSDArray)response["Entries"];
221 }
222 else
223 {
224 m_log.Warn("[FRIENDS CONNECTOR]: Failed to retrieve reverse friends for user " + ownerID + ": " + response["Message"].AsString());
225 return new OSDArray(0);
226 }
227 }
228 }
229}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs
new file mode 100644
index 0000000..41ed2f1
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs
@@ -0,0 +1,31 @@
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 Mono.Addins;
29
30[assembly: Addin("SimianGrid", "1.0")]
31[assembly: AddinDependency("OpenSim", "0.5")]
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
new file mode 100644
index 0000000..16819d1
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
@@ -0,0 +1,418 @@
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.Net;
32using System.Reflection;
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36using OpenSim.Framework;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Server.Base;
42using OpenMetaverse;
43using OpenMetaverse.StructuredData;
44
45using GridRegion = OpenSim.Services.Interfaces.GridRegion;
46
47namespace OpenSim.Services.Connectors.SimianGrid
48{
49 /// <summary>
50 /// Connects region registration and neighbor lookups to the SimianGrid
51 /// backend
52 /// </summary>
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
54 public class SimianGridServiceConnector : IGridService, ISharedRegionModule
55 {
56 private static readonly ILog m_log =
57 LogManager.GetLogger(
58 MethodBase.GetCurrentMethod().DeclaringType);
59
60 private string m_serverUrl = String.Empty;
61
62 #region ISharedRegionModule
63
64 public Type ReplaceableInterface { get { return null; } }
65 public void RegionLoaded(Scene scene) { }
66 public void PostInitialise() { }
67 public void Close() { }
68
69 public SimianGridServiceConnector() { }
70 public string Name { get { return "SimianGridServiceConnector"; } }
71 public void AddRegion(Scene scene) { scene.RegisterModuleInterface<IGridService>(this); }
72 public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface<IGridService>(this); }
73
74 #endregion ISharedRegionModule
75
76 public SimianGridServiceConnector(IConfigSource source)
77 {
78 Initialise(source);
79 }
80
81 public void Initialise(IConfigSource source)
82 {
83 IConfig gridConfig = source.Configs["GridService"];
84 if (gridConfig == null)
85 {
86 m_log.Error("[GRID CONNECTOR]: GridService missing from OpenSim.ini");
87 throw new Exception("Grid connector init error");
88 }
89
90 string serviceUrl = gridConfig.GetString("GridServerURI");
91 if (String.IsNullOrEmpty(serviceUrl))
92 {
93 m_log.Error("[GRID CONNECTOR]: No Server URI named in section GridService");
94 throw new Exception("Grid connector init error");
95 }
96
97 m_serverUrl = serviceUrl;
98 }
99
100 #region IGridService
101
102 public string RegisterRegion(UUID scopeID, GridRegion regionInfo)
103 {
104 Vector3d minPosition = new Vector3d(regionInfo.RegionLocX, regionInfo.RegionLocY, 0.0);
105 Vector3d maxPosition = minPosition + new Vector3d(Constants.RegionSize, Constants.RegionSize, 4096.0);
106
107 string httpAddress = "http://" + regionInfo.ExternalHostName + ":" + regionInfo.HttpPort + "/";
108
109 OSDMap extraData = new OSDMap
110 {
111 { "ServerURI", OSD.FromString(regionInfo.ServerURI) },
112 { "InternalAddress", OSD.FromString(regionInfo.InternalEndPoint.Address.ToString()) },
113 { "InternalPort", OSD.FromInteger(regionInfo.InternalEndPoint.Port) },
114 { "ExternalAddress", OSD.FromString(regionInfo.ExternalEndPoint.Address.ToString()) },
115 { "ExternalPort", OSD.FromInteger(regionInfo.ExternalEndPoint.Port) },
116 { "MapTexture", OSD.FromUUID(regionInfo.TerrainImage) },
117 { "Access", OSD.FromInteger(regionInfo.Access) },
118 { "RegionSecret", OSD.FromString(regionInfo.RegionSecret) },
119 { "EstateOwner", OSD.FromUUID(regionInfo.EstateOwner) },
120 { "Token", OSD.FromString(regionInfo.Token) }
121 };
122
123 NameValueCollection requestArgs = new NameValueCollection
124 {
125 { "RequestMethod", "AddScene" },
126 { "SceneID", regionInfo.RegionID.ToString() },
127 { "Name", regionInfo.RegionName },
128 { "MinPosition", minPosition.ToString() },
129 { "MaxPosition", maxPosition.ToString() },
130 { "Address", httpAddress },
131 { "Enabled", "1" },
132 { "ExtraData", OSDParser.SerializeJsonString(extraData) }
133 };
134
135 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
136 if (response["Success"].AsBoolean())
137 return String.Empty;
138 else
139 return "Region registration for " + regionInfo.RegionName + " failed: " + response["Message"].AsString();
140 }
141
142 public bool DeregisterRegion(UUID regionID)
143 {
144 NameValueCollection requestArgs = new NameValueCollection
145 {
146 { "RequestMethod", "AddScene" },
147 { "SceneID", regionID.ToString() },
148 { "Enabled", "0" }
149 };
150
151 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
152 bool success = response["Success"].AsBoolean();
153
154 if (!success)
155 m_log.Warn("[GRID CONNECTOR]: Region deregistration for " + regionID + " failed: " + response["Message"].AsString());
156
157 return success;
158 }
159
160 public List<GridRegion> GetNeighbours(UUID scopeID, UUID regionID)
161 {
162 const int NEIGHBOR_RADIUS = 128;
163
164 GridRegion region = GetRegionByUUID(scopeID, regionID);
165
166 if (region != null)
167 {
168 List<GridRegion> regions = GetRegionRange(scopeID,
169 region.RegionLocX - NEIGHBOR_RADIUS, region.RegionLocX + (int)Constants.RegionSize + NEIGHBOR_RADIUS,
170 region.RegionLocY - NEIGHBOR_RADIUS, region.RegionLocY + (int)Constants.RegionSize + NEIGHBOR_RADIUS);
171
172 for (int i = 0; i < regions.Count; i++)
173 {
174 if (regions[i].RegionID == regionID)
175 {
176 regions.RemoveAt(i);
177 break;
178 }
179 }
180
181 m_log.Debug("[GRID CONNECTOR]: Found " + regions.Count + " neighbors for region " + regionID);
182 return regions;
183 }
184
185 return new List<GridRegion>(0);
186 }
187
188 public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID)
189 {
190 NameValueCollection requestArgs = new NameValueCollection
191 {
192 { "RequestMethod", "GetScene" },
193 { "SceneID", regionID.ToString() }
194 };
195
196 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
197 if (response["Success"].AsBoolean())
198 {
199 return ResponseToGridRegion(response);
200 }
201 else
202 {
203 m_log.Warn("[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 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
222 if (response["Success"].AsBoolean())
223 {
224 return ResponseToGridRegion(response);
225 }
226 else
227 {
228 //m_log.InfoFormat("[GRID CONNECTOR]: Grid service did not find a match for region at {0},{1}",
229 // x / Constants.RegionSize, y / Constants.RegionSize);
230 return null;
231 }
232 }
233
234 public GridRegion GetRegionByName(UUID scopeID, string regionName)
235 {
236 List<GridRegion> regions = GetRegionsByName(scopeID, regionName, 1);
237
238 m_log.Debug("[GRID CONNECTOR]: Got " + regions.Count + " matches for region name " + regionName);
239
240 if (regions.Count > 0)
241 return regions[0];
242
243 return null;
244 }
245
246 public List<GridRegion> GetRegionsByName(UUID scopeID, string name, int maxNumber)
247 {
248 List<GridRegion> foundRegions = new List<GridRegion>();
249
250 NameValueCollection requestArgs = new NameValueCollection
251 {
252 { "RequestMethod", "GetScenes" },
253 { "NameQuery", name },
254 { "Enabled", "1" }
255 };
256 if (maxNumber > 0)
257 requestArgs["MaxNumber"] = maxNumber.ToString();
258
259 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
260 if (response["Success"].AsBoolean())
261 {
262 OSDArray array = response["Scenes"] as OSDArray;
263 if (array != null)
264 {
265 for (int i = 0; i < array.Count; i++)
266 {
267 GridRegion region = ResponseToGridRegion(array[i] as OSDMap);
268 if (region != null)
269 foundRegions.Add(region);
270 }
271 }
272 }
273
274 return foundRegions;
275 }
276
277 public List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax)
278 {
279 List<GridRegion> foundRegions = new List<GridRegion>();
280
281 Vector3d minPosition = new Vector3d(xmin, ymin, 0.0);
282 Vector3d maxPosition = new Vector3d(xmax, ymax, 4096.0);
283
284 NameValueCollection requestArgs = new NameValueCollection
285 {
286 { "RequestMethod", "GetScenes" },
287 { "MinPosition", minPosition.ToString() },
288 { "MaxPosition", maxPosition.ToString() },
289 { "Enabled", "1" }
290 };
291
292 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
293 if (response["Success"].AsBoolean())
294 {
295 OSDArray array = response["Scenes"] as OSDArray;
296 if (array != null)
297 {
298 for (int i = 0; i < array.Count; i++)
299 {
300 GridRegion region = ResponseToGridRegion(array[i] as OSDMap);
301 if (region != null)
302 foundRegions.Add(region);
303 }
304 }
305 }
306
307 return foundRegions;
308 }
309
310 public List<GridRegion> GetDefaultRegions(UUID scopeID)
311 {
312 // TODO: Allow specifying the default grid location
313 const int DEFAULT_X = 1000 * 256;
314 const int DEFAULT_Y = 1000 * 256;
315
316 GridRegion defRegion = GetNearestRegion(new Vector3d(DEFAULT_X, DEFAULT_Y, 0.0), true);
317 if (defRegion != null)
318 return new List<GridRegion>(1) { defRegion };
319 else
320 return new List<GridRegion>(0);
321 }
322
323 public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y)
324 {
325 GridRegion defRegion = GetNearestRegion(new Vector3d(x, y, 0.0), true);
326 if (defRegion != null)
327 return new List<GridRegion>(1) { defRegion };
328 else
329 return new List<GridRegion>(0);
330 }
331
332 public int GetRegionFlags(UUID scopeID, UUID regionID)
333 {
334 const int REGION_ONLINE = 4;
335
336 NameValueCollection requestArgs = new NameValueCollection
337 {
338 { "RequestMethod", "GetScene" },
339 { "SceneID", regionID.ToString() }
340 };
341
342 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
343 if (response["Success"].AsBoolean())
344 {
345 return response["Enabled"].AsBoolean() ? REGION_ONLINE : 0;
346 }
347 else
348 {
349 m_log.Warn("[GRID CONNECTOR]: Grid service did not find a match for region " + regionID + " during region flags check");
350 return -1;
351 }
352 }
353
354 #endregion IGridService
355
356 private GridRegion GetNearestRegion(Vector3d position, bool onlyEnabled)
357 {
358 NameValueCollection requestArgs = new NameValueCollection
359 {
360 { "RequestMethod", "GetScene" },
361 { "Position", position.ToString() },
362 { "FindClosest", "1" }
363 };
364 if (onlyEnabled)
365 requestArgs["Enabled"] = "1";
366
367 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
368 if (response["Success"].AsBoolean())
369 {
370 return ResponseToGridRegion(response);
371 }
372 else
373 {
374 m_log.Warn("[GRID CONNECTOR]: Grid service did not find a match for region at " + position);
375 return null;
376 }
377 }
378
379 private GridRegion ResponseToGridRegion(OSDMap response)
380 {
381 if (response == null)
382 return null;
383
384 OSDMap extraData = response["ExtraData"] as OSDMap;
385 if (extraData == null)
386 return null;
387
388 GridRegion region = new GridRegion();
389
390 region.RegionID = response["SceneID"].AsUUID();
391 region.RegionName = response["Name"].AsString();
392
393 Vector3d minPosition = response["MinPosition"].AsVector3d();
394 region.RegionLocX = (int)minPosition.X;
395 region.RegionLocY = (int)minPosition.Y;
396
397 Uri httpAddress = response["Address"].AsUri();
398 region.ExternalHostName = httpAddress.Host;
399 region.HttpPort = (uint)httpAddress.Port;
400
401 region.ServerURI = extraData["ServerURI"].AsString();
402
403 IPAddress internalAddress;
404 IPAddress.TryParse(extraData["InternalAddress"].AsString(), out internalAddress);
405 if (internalAddress == null)
406 internalAddress = IPAddress.Any;
407
408 region.InternalEndPoint = new IPEndPoint(internalAddress, extraData["InternalPort"].AsInteger());
409 region.TerrainImage = extraData["MapTexture"].AsUUID();
410 region.Access = (byte)extraData["Access"].AsInteger();
411 region.RegionSecret = extraData["RegionSecret"].AsString();
412 region.EstateOwner = extraData["EstateOwner"].AsUUID();
413 region.Token = extraData["Token"].AsString();
414
415 return region;
416 }
417 }
418}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs
new file mode 100644
index 0000000..c812899
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs
@@ -0,0 +1,880 @@
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.Server.Base;
41using OpenSim.Services.Interfaces;
42
43namespace OpenSim.Services.Connectors.SimianGrid
44{
45 /// <summary>
46 /// Permissions bitflags
47 /// </summary>
48 [Flags]
49 public enum PermissionMask : uint
50 {
51 None = 0,
52 Transfer = 1 << 13,
53 Modify = 1 << 14,
54 Copy = 1 << 15,
55 Move = 1 << 19,
56 Damage = 1 << 20,
57 All = 0x7FFFFFFF
58 }
59
60 /// <summary>
61 /// Connects avatar inventories to the SimianGrid backend
62 /// </summary>
63 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
64 public class SimianInventoryServiceConnector : IInventoryService, ISharedRegionModule
65 {
66 private static readonly ILog m_log =
67 LogManager.GetLogger(
68 MethodBase.GetCurrentMethod().DeclaringType);
69
70 private string m_serverUrl = String.Empty;
71 private string m_userServerUrl = String.Empty;
72 private object m_gestureSyncRoot = new object();
73
74 #region ISharedRegionModule
75
76 public Type ReplaceableInterface { get { return null; } }
77 public void RegionLoaded(Scene scene) { }
78 public void PostInitialise() { }
79 public void Close() { }
80
81 public SimianInventoryServiceConnector() { }
82 public string Name { get { return "SimianInventoryServiceConnector"; } }
83 public void AddRegion(Scene scene) { scene.RegisterModuleInterface<IInventoryService>(this); }
84 public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface<IInventoryService>(this); }
85
86 #endregion ISharedRegionModule
87
88 public SimianInventoryServiceConnector(IConfigSource source)
89 {
90 Initialise(source);
91 }
92
93 public void Initialise(IConfigSource source)
94 {
95 IConfig gridConfig = source.Configs["InventoryService"];
96 if (gridConfig == null)
97 {
98 m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini");
99 throw new Exception("Inventory connector init error");
100 }
101
102 string serviceUrl = gridConfig.GetString("InventoryServerURI");
103 if (String.IsNullOrEmpty(serviceUrl))
104 {
105 m_log.Error("[INVENTORY CONNECTOR]: No Server URI named in section InventoryService");
106 throw new Exception("Inventory connector init error");
107 }
108
109 // FIXME: Get the user server URL too
110
111 m_serverUrl = serviceUrl;
112 }
113
114 /// <summary>
115 /// Create the entire inventory for a given user
116 /// </summary>
117 /// <param name="user"></param>
118 /// <returns></returns>
119 public bool CreateUserInventory(UUID userID)
120 {
121 NameValueCollection requestArgs = new NameValueCollection
122 {
123 { "RequestMethod", "AddInventory" },
124 { "OwnerID", userID.ToString() }
125 };
126
127 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
128 bool success = response["Success"].AsBoolean();
129
130 if (!success)
131 m_log.Warn("[INVENTORY CONNECTOR]: Inventory creation for " + userID + " failed: " + response["Message"].AsString());
132
133 return success;
134 }
135
136 /// <summary>
137 /// Gets the skeleton of the inventory -- folders only
138 /// </summary>
139 /// <param name="userID"></param>
140 /// <returns></returns>
141 public List<InventoryFolderBase> GetInventorySkeleton(UUID userID)
142 {
143 NameValueCollection requestArgs = new NameValueCollection
144 {
145 { "RequestMethod", "GetInventoryNode" },
146 { "ItemID", userID.ToString() },
147 { "OwnerID", userID.ToString() },
148 { "IncludeFolders", "1" },
149 { "IncludeItems", "0" },
150 { "ChildrenOnly", "0" }
151 };
152
153 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
154 if (response["Success"].AsBoolean() && response["Items"] is OSDArray)
155 {
156 OSDArray items = (OSDArray)response["Items"];
157 return GetFoldersFromResponse(items, userID, true);
158 }
159 else
160 {
161 m_log.Warn("[INVENTORY CONNECTOR]: Failed to retrieve inventory skeleton for " + userID + ": " +
162 response["Message"].AsString());
163 return new List<InventoryFolderBase>(0);
164 }
165 }
166
167 /// <summary>
168 /// Synchronous inventory fetch.
169 /// </summary>
170 /// <param name="userID"></param>
171 /// <returns></returns>
172 [Obsolete]
173 public InventoryCollection GetUserInventory(UUID userID)
174 {
175 m_log.Error("[INVENTORY CONNECTOR]: Obsolete GetUserInventory called for " + userID);
176
177 InventoryCollection inventory = new InventoryCollection();
178 inventory.UserID = userID;
179 inventory.Folders = new List<InventoryFolderBase>();
180 inventory.Items = new List<InventoryItemBase>();
181
182 return inventory;
183 }
184
185 /// <summary>
186 /// Request the inventory for a user. This is an asynchronous operation that will call the callback when the
187 /// inventory has been received
188 /// </summary>
189 /// <param name="userID"></param>
190 /// <param name="callback"></param>
191 [Obsolete]
192 public void GetUserInventory(UUID userID, InventoryReceiptCallback callback)
193 {
194 m_log.Error("[INVENTORY CONNECTOR]: Obsolete GetUserInventory called for " + userID);
195 callback(new List<InventoryFolderImpl>(0), new List<InventoryItemBase>(0));
196 }
197
198 /// <summary>
199 /// Retrieve the root inventory folder for the given user.
200 /// </summary>
201 /// <param name="userID"></param>
202 /// <returns>null if no root folder was found</returns>
203 public InventoryFolderBase GetRootFolder(UUID userID)
204 {
205 NameValueCollection requestArgs = new NameValueCollection
206 {
207 { "RequestMethod", "GetInventoryNode" },
208 { "ItemID", userID.ToString() },
209 { "OwnerID", userID.ToString() },
210 { "IncludeFolders", "1" },
211 { "IncludeItems", "0" },
212 { "ChildrenOnly", "1" }
213 };
214
215 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
216 if (response["Success"].AsBoolean() && response["Items"] is OSDArray)
217 {
218 OSDArray items = (OSDArray)response["Items"];
219 List<InventoryFolderBase> folders = GetFoldersFromResponse(items, userID, true);
220
221 if (folders.Count > 0)
222 return folders[0];
223 }
224
225 return null;
226 }
227
228 /// <summary>
229 /// Gets the user folder for the given folder-type
230 /// </summary>
231 /// <param name="userID"></param>
232 /// <param name="type"></param>
233 /// <returns></returns>
234 public InventoryFolderBase GetFolderForType(UUID userID, AssetType type)
235 {
236 string contentType = SLUtil.SLAssetTypeToContentType((int)type);
237
238 NameValueCollection requestArgs = new NameValueCollection
239 {
240 { "RequestMethod", "GetFolderForType" },
241 { "ContentType", contentType },
242 { "OwnerID", userID.ToString() }
243 };
244
245 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
246 if (response["Success"].AsBoolean() && response["Folder"] is OSDMap)
247 {
248 OSDMap folder = (OSDMap)response["Folder"];
249
250 return new InventoryFolderBase(
251 folder["ID"].AsUUID(),
252 folder["Name"].AsString(),
253 folder["OwnerID"].AsUUID(),
254 (short)SLUtil.ContentTypeToSLAssetType(folder["ContentType"].AsString()),
255 folder["ParentID"].AsUUID(),
256 (ushort)folder["Version"].AsInteger()
257 );
258 }
259 else
260 {
261 m_log.Warn("[INVENTORY CONNECTOR]: Default folder not found for content type " + contentType);
262 return GetRootFolder(userID);
263 }
264 }
265
266 /// <summary>
267 /// Get an item, given by its UUID
268 /// </summary>
269 /// <param name="item"></param>
270 /// <returns></returns>
271 public InventoryItemBase GetItem(InventoryItemBase item)
272 {
273 NameValueCollection requestArgs = new NameValueCollection
274 {
275 { "RequestMethod", "GetInventoryNode" },
276 { "ItemID", item.ID.ToString() },
277 { "OwnerID", item.Owner.ToString() },
278 { "IncludeFolders", "1" },
279 { "IncludeItems", "1" },
280 { "ChildrenOnly", "1" }
281 };
282
283 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
284 if (response["Success"].AsBoolean() && response["Items"] is OSDArray)
285 {
286 List<InventoryItemBase> items = GetItemsFromResponse((OSDArray)response["Items"]);
287 if (items.Count > 0)
288 {
289 // The requested item should be the first in this list, but loop through
290 // and sanity check just in case
291 for (int i = 0; i < items.Count; i++)
292 {
293 if (items[i].ID == item.ID)
294 return items[i];
295 }
296 }
297 }
298
299 m_log.Warn("[INVENTORY CONNECTOR]: Item " + item.ID + " owned by " + item.Owner + " not found");
300 return null;
301 }
302
303 /// <summary>
304 /// Get a folder, given by its UUID
305 /// </summary>
306 /// <param name="folder"></param>
307 /// <returns></returns>
308 public InventoryFolderBase GetFolder(InventoryFolderBase folder)
309 {
310 NameValueCollection requestArgs = new NameValueCollection
311 {
312 { "RequestMethod", "GetInventoryNode" },
313 { "ItemID", folder.ID.ToString() },
314 { "OwnerID", folder.Owner.ToString() },
315 { "IncludeFolders", "1" },
316 { "IncludeItems", "0" },
317 { "ChildrenOnly", "1" }
318 };
319
320 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
321 if (response["Success"].AsBoolean() && response["Items"] is OSDArray)
322 {
323 OSDArray items = (OSDArray)response["Items"];
324 List<InventoryFolderBase> folders = GetFoldersFromResponse(items, folder.ID, true);
325
326 if (folders.Count > 0)
327 return folders[0];
328 }
329
330 return null;
331 }
332
333 /// <summary>
334 /// Gets everything (folders and items) inside a folder
335 /// </summary>
336 /// <param name="userID"></param>
337 /// <param name="folderID"></param>
338 /// <returns></returns>
339 public InventoryCollection GetFolderContent(UUID userID, UUID folderID)
340 {
341 InventoryCollection inventory = new InventoryCollection();
342 inventory.UserID = userID;
343
344 NameValueCollection requestArgs = new NameValueCollection
345 {
346 { "RequestMethod", "GetInventoryNode" },
347 { "ItemID", folderID.ToString() },
348 { "OwnerID", userID.ToString() },
349 { "IncludeFolders", "1" },
350 { "IncludeItems", "1" },
351 { "ChildrenOnly", "1" }
352 };
353
354 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
355 if (response["Success"].AsBoolean() && response["Items"] is OSDArray)
356 {
357 OSDArray items = (OSDArray)response["Items"];
358
359 inventory.Folders = GetFoldersFromResponse(items, folderID, false);
360 inventory.Items = GetItemsFromResponse(items);
361 }
362 else
363 {
364 m_log.Warn("[INVENTORY CONNECTOR]: Error fetching folder " + folderID + " content for " + userID + ": " +
365 response["Message"].AsString());
366 inventory.Folders = new List<InventoryFolderBase>(0);
367 inventory.Items = new List<InventoryItemBase>(0);
368 }
369
370 return inventory;
371 }
372
373 /// <summary>
374 /// Gets the items inside a folder
375 /// </summary>
376 /// <param name="userID"></param>
377 /// <param name="folderID"></param>
378 /// <returns></returns>
379 public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
380 {
381 InventoryCollection inventory = new InventoryCollection();
382 inventory.UserID = userID;
383
384 NameValueCollection requestArgs = new NameValueCollection
385 {
386 { "RequestMethod", "GetInventoryNode" },
387 { "ItemID", folderID.ToString() },
388 { "OwnerID", userID.ToString() },
389 { "IncludeFolders", "0" },
390 { "IncludeItems", "1" },
391 { "ChildrenOnly", "1" }
392 };
393
394 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
395 if (response["Success"].AsBoolean() && response["Items"] is OSDArray)
396 {
397 OSDArray items = (OSDArray)response["Items"];
398 return GetItemsFromResponse(items);
399 }
400 else
401 {
402 m_log.Warn("[INVENTORY CONNECTOR]: Error fetching folder " + folderID + " for " + userID + ": " +
403 response["Message"].AsString());
404 return new List<InventoryItemBase>(0);
405 }
406 }
407
408 /// <summary>
409 /// Add a new folder to the user's inventory
410 /// </summary>
411 /// <param name="folder"></param>
412 /// <returns>true if the folder was successfully added</returns>
413 public bool AddFolder(InventoryFolderBase folder)
414 {
415 NameValueCollection requestArgs = new NameValueCollection
416 {
417 { "RequestMethod", "AddInventoryFolder" },
418 { "FolderID", folder.ID.ToString() },
419 { "ParentID", folder.ParentID.ToString() },
420 { "OwnerID", folder.Owner.ToString() },
421 { "Name", folder.Name },
422 { "ContentType", SLUtil.SLAssetTypeToContentType(folder.Type) }
423 };
424
425 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
426 bool success = response["Success"].AsBoolean();
427
428 if (!success)
429 {
430 m_log.Warn("[INVENTORY CONNECTOR]: Error creating folder " + folder.Name + " for " + folder.Owner + ": " +
431 response["Message"].AsString());
432 }
433
434 return success;
435 }
436
437 /// <summary>
438 /// Update a folder in the user's inventory
439 /// </summary>
440 /// <param name="folder"></param>
441 /// <returns>true if the folder was successfully updated</returns>
442 public bool UpdateFolder(InventoryFolderBase folder)
443 {
444 return AddFolder(folder);
445 }
446
447 /// <summary>
448 /// Move an inventory folder to a new location
449 /// </summary>
450 /// <param name="folder">A folder containing the details of the new location</param>
451 /// <returns>true if the folder was successfully moved</returns>
452 public bool MoveFolder(InventoryFolderBase folder)
453 {
454 return AddFolder(folder);
455 }
456
457 /// <summary>
458 /// Delete an item from the user's inventory
459 /// </summary>
460 /// <param name="item"></param>
461 /// <returns>true if the item was successfully deleted</returns>
462 //bool DeleteItem(InventoryItemBase item);
463 public bool DeleteFolders(UUID userID, List<UUID> folderIDs)
464 {
465 return DeleteItems(userID, folderIDs);
466 }
467
468 /// <summary>
469 /// Delete an item from the user's inventory
470 /// </summary>
471 /// <param name="item"></param>
472 /// <returns>true if the item was successfully deleted</returns>
473 public bool DeleteItems(UUID userID, List<UUID> itemIDs)
474 {
475 // TODO: RemoveInventoryNode should be replaced with RemoveInventoryNodes
476 bool allSuccess = true;
477
478 for (int i = 0; i < itemIDs.Count; i++)
479 {
480 UUID itemID = itemIDs[i];
481
482 NameValueCollection requestArgs = new NameValueCollection
483 {
484 { "RequestMethod", "RemoveInventoryNode" },
485 { "OwnerID", userID.ToString() },
486 { "ItemID", itemID.ToString() }
487 };
488
489 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
490 bool success = response["Success"].AsBoolean();
491
492 if (!success)
493 {
494 m_log.Warn("[INVENTORY CONNECTOR]: Error removing item " + itemID + " for " + userID + ": " +
495 response["Message"].AsString());
496 allSuccess = false;
497 }
498 }
499
500 return allSuccess;
501 }
502
503 /// <summary>
504 /// Purge an inventory folder of all its items and subfolders.
505 /// </summary>
506 /// <param name="folder"></param>
507 /// <returns>true if the folder was successfully purged</returns>
508 public bool PurgeFolder(InventoryFolderBase folder)
509 {
510 NameValueCollection requestArgs = new NameValueCollection
511 {
512 { "RequestMethod", "PurgeInventoryFolder" },
513 { "OwnerID", folder.Owner.ToString() },
514 { "FolderID", folder.ID.ToString() }
515 };
516
517 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
518 bool success = response["Success"].AsBoolean();
519
520 if (!success)
521 {
522 m_log.Warn("[INVENTORY CONNECTOR]: Error purging folder " + folder.ID + " for " + folder.Owner + ": " +
523 response["Message"].AsString());
524 }
525
526 return success;
527 }
528
529 /// <summary>
530 /// Add a new item to the user's inventory
531 /// </summary>
532 /// <param name="item"></param>
533 /// <returns>true if the item was successfully added</returns>
534 public bool AddItem(InventoryItemBase item)
535 {
536 // A folder of UUID.Zero means we need to find the most appropriate home for this item
537 if (item.Folder == UUID.Zero)
538 {
539 InventoryFolderBase folder = GetFolderForType(item.Owner, (AssetType)item.AssetType);
540 if (folder != null && folder.ID != UUID.Zero)
541 item.Folder = folder.ID;
542 else
543 item.Folder = item.Owner; // Root folder
544 }
545
546 if ((AssetType)item.AssetType == AssetType.Gesture)
547 UpdateGesture(item.Owner, item.ID, item.Flags == 1);
548
549 if (item.BasePermissions == 0)
550 m_log.WarnFormat("[INVENTORY CONNECTOR]: Adding inventory item {0} ({1}) with no base permissions", item.Name, item.ID);
551
552 OSDMap permissions = new OSDMap
553 {
554 { "BaseMask", OSD.FromInteger(item.BasePermissions) },
555 { "EveryoneMask", OSD.FromInteger(item.EveryOnePermissions) },
556 { "GroupMask", OSD.FromInteger(item.GroupPermissions) },
557 { "NextOwnerMask", OSD.FromInteger(item.NextPermissions) },
558 { "OwnerMask", OSD.FromInteger(item.CurrentPermissions) }
559 };
560
561 OSDMap extraData = new OSDMap()
562 {
563 { "Flags", OSD.FromInteger(item.Flags) },
564 { "GroupID", OSD.FromUUID(item.GroupID) },
565 { "GroupOwned", OSD.FromBoolean(item.GroupOwned) },
566 { "SalePrice", OSD.FromInteger(item.SalePrice) },
567 { "SaleType", OSD.FromInteger(item.SaleType) },
568 { "Permissions", permissions }
569 };
570
571 NameValueCollection requestArgs = new NameValueCollection
572 {
573 { "RequestMethod", "AddInventoryItem" },
574 { "ItemID", item.ID.ToString() },
575 { "AssetID", item.AssetID.ToString() },
576 { "ParentID", item.Folder.ToString() },
577 { "OwnerID", item.Owner.ToString() },
578 { "Name", item.Name },
579 { "Description", item.Description },
580 { "CreatorID", item.CreatorId },
581 { "ExtraData", OSDParser.SerializeJsonString(extraData) }
582 };
583
584 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
585 bool success = response["Success"].AsBoolean();
586
587 if (!success)
588 {
589 m_log.Warn("[INVENTORY CONNECTOR]: Error creating item " + item.Name + " for " + item.Owner + ": " +
590 response["Message"].AsString());
591 }
592
593 return success;
594 }
595
596 /// <summary>
597 /// Update an item in the user's inventory
598 /// </summary>
599 /// <param name="item"></param>
600 /// <returns>true if the item was successfully updated</returns>
601 public bool UpdateItem(InventoryItemBase item)
602 {
603 if (item.AssetID != UUID.Zero)
604 {
605 return AddItem(item);
606 }
607 else
608 {
609 // This is actually a folder update
610 InventoryFolderBase folder = new InventoryFolderBase(item.ID, item.Name, item.Owner, (short)item.AssetType, item.Folder, 0);
611 return UpdateFolder(folder);
612 }
613 }
614
615 public bool MoveItems(UUID ownerID, List<InventoryItemBase> items)
616 {
617 bool success = true;
618
619 while (items.Count > 0)
620 {
621 List<InventoryItemBase> currentItems = new List<InventoryItemBase>();
622 UUID destFolderID = items[0].Folder;
623
624 // Find all of the items being moved to the current destination folder
625 for (int i = 0; i < items.Count; i++)
626 {
627 InventoryItemBase item = items[i];
628 if (item.Folder == destFolderID)
629 currentItems.Add(item);
630 }
631
632 // Do the inventory move for the current items
633 success &= MoveItems(ownerID, items, destFolderID);
634
635 // Remove the processed items from the list
636 for (int i = 0; i < currentItems.Count; i++)
637 items.Remove(currentItems[i]);
638 }
639
640 return success;
641 }
642
643 /// <summary>
644 /// Does the given user have an inventory structure?
645 /// </summary>
646 /// <param name="userID"></param>
647 /// <returns></returns>
648 public bool HasInventoryForUser(UUID userID)
649 {
650 return GetRootFolder(userID) != null;
651 }
652
653 /// <summary>
654 /// Get the active gestures of the agent.
655 /// </summary>
656 /// <param name="userID"></param>
657 /// <returns></returns>
658 public List<InventoryItemBase> GetActiveGestures(UUID userID)
659 {
660 OSDArray items = FetchGestures(userID);
661
662 string[] itemIDs = new string[items.Count];
663 for (int i = 0; i < items.Count; i++)
664 itemIDs[i] = items[i].AsUUID().ToString();
665
666 NameValueCollection requestArgs = new NameValueCollection
667 {
668 { "RequestMethod", "GetInventoryNodes" },
669 { "OwnerID", userID.ToString() },
670 { "Items", String.Join(",", itemIDs) }
671 };
672
673 // FIXME: Implement this in SimianGrid
674 return new List<InventoryItemBase>(0);
675 }
676
677 /// <summary>
678 /// Get the union of permissions of all inventory items
679 /// that hold the given assetID.
680 /// </summary>
681 /// <param name="userID"></param>
682 /// <param name="assetID"></param>
683 /// <returns>The permissions or 0 if no such asset is found in
684 /// the user's inventory</returns>
685 public int GetAssetPermissions(UUID userID, UUID assetID)
686 {
687 NameValueCollection requestArgs = new NameValueCollection
688 {
689 { "RequestMethod", "GetInventoryNodes" },
690 { "OwnerID", userID.ToString() },
691 { "AssetID", assetID.ToString() }
692 };
693
694 // FIXME: Implement this in SimianGrid
695 return (int)PermissionMask.All;
696 }
697
698 private List<InventoryFolderBase> GetFoldersFromResponse(OSDArray items, UUID baseFolder, bool includeBaseFolder)
699 {
700 List<InventoryFolderBase> invFolders = new List<InventoryFolderBase>(items.Count);
701
702 for (int i = 0; i < items.Count; i++)
703 {
704 OSDMap item = items[i] as OSDMap;
705
706 if (item != null && item["Type"].AsString() == "Folder")
707 {
708 UUID folderID = item["ID"].AsUUID();
709
710 if (folderID == baseFolder && !includeBaseFolder)
711 continue;
712
713 invFolders.Add(new InventoryFolderBase(
714 folderID,
715 item["Name"].AsString(),
716 item["OwnerID"].AsUUID(),
717 (short)SLUtil.ContentTypeToSLAssetType(item["ContentType"].AsString()),
718 item["ParentID"].AsUUID(),
719 (ushort)item["Version"].AsInteger()
720 ));
721 }
722 }
723
724 return invFolders;
725 }
726
727 private List<InventoryItemBase> GetItemsFromResponse(OSDArray items)
728 {
729 List<InventoryItemBase> invItems = new List<InventoryItemBase>(items.Count);
730
731 for (int i = 0; i < items.Count; i++)
732 {
733 OSDMap item = items[i] as OSDMap;
734
735 if (item != null && item["Type"].AsString() == "Item")
736 {
737 InventoryItemBase invItem = new InventoryItemBase();
738
739 invItem.AssetID = item["AssetID"].AsUUID();
740 invItem.AssetType = SLUtil.ContentTypeToSLAssetType(item["ContentType"].AsString());
741 invItem.CreationDate = item["CreationDate"].AsInteger();
742 invItem.CreatorId = item["CreatorID"].AsString();
743 invItem.CreatorIdAsUuid = item["CreatorID"].AsUUID();
744 invItem.Description = item["Description"].AsString();
745 invItem.Folder = item["ParentID"].AsUUID();
746 invItem.ID = item["ID"].AsUUID();
747 invItem.InvType = SLUtil.ContentTypeToSLInvType(item["ContentType"].AsString());
748 invItem.Name = item["Name"].AsString();
749 invItem.Owner = item["OwnerID"].AsUUID();
750
751 OSDMap extraData = item["ExtraData"] as OSDMap;
752 if (extraData != null && extraData.Count > 0)
753 {
754 invItem.Flags = extraData["Flags"].AsUInteger();
755 invItem.GroupID = extraData["GroupID"].AsUUID();
756 invItem.GroupOwned = extraData["GroupOwned"].AsBoolean();
757 invItem.SalePrice = extraData["SalePrice"].AsInteger();
758 invItem.SaleType = (byte)extraData["SaleType"].AsInteger();
759
760 OSDMap perms = extraData["Permissions"] as OSDMap;
761 if (perms != null)
762 {
763 invItem.BasePermissions = perms["BaseMask"].AsUInteger();
764 invItem.CurrentPermissions = perms["OwnerMask"].AsUInteger();
765 invItem.EveryOnePermissions = perms["EveryoneMask"].AsUInteger();
766 invItem.GroupPermissions = perms["GroupMask"].AsUInteger();
767 invItem.NextPermissions = perms["NextOwnerMask"].AsUInteger();
768 }
769 }
770
771 if (invItem.BasePermissions == 0)
772 {
773 m_log.InfoFormat("[INVENTORY CONNECTOR]: Forcing item permissions to full for item {0} ({1})",
774 invItem.Name, invItem.ID);
775 invItem.BasePermissions = (uint)PermissionMask.All;
776 invItem.CurrentPermissions = (uint)PermissionMask.All;
777 invItem.EveryOnePermissions = (uint)PermissionMask.All;
778 invItem.GroupPermissions = (uint)PermissionMask.All;
779 invItem.NextPermissions = (uint)PermissionMask.All;
780 }
781
782 invItems.Add(invItem);
783 }
784 }
785
786 return invItems;
787 }
788
789 private bool MoveItems(UUID ownerID, List<InventoryItemBase> items, UUID destFolderID)
790 {
791 string[] itemIDs = new string[items.Count];
792 for (int i = 0; i < items.Count; i++)
793 itemIDs[i] = items[i].ID.ToString();
794
795 NameValueCollection requestArgs = new NameValueCollection
796 {
797 { "RequestMethod", "MoveInventoryNodes" },
798 { "OwnerID", ownerID.ToString() },
799 { "FolderID", destFolderID.ToString() },
800 { "Items", String.Join(",", itemIDs) }
801 };
802
803 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
804 bool success = response["Success"].AsBoolean();
805
806 if (!success)
807 {
808 m_log.Warn("[INVENTORY CONNECTOR]: Failed to move " + items.Count + " items to " +
809 destFolderID + ": " + response["Message"].AsString());
810 }
811
812 return success;
813 }
814
815 private void UpdateGesture(UUID userID, UUID itemID, bool enabled)
816 {
817 OSDArray gestures = FetchGestures(userID);
818 OSDArray newGestures = new OSDArray();
819
820 for (int i = 0; i < gestures.Count; i++)
821 {
822 UUID gesture = gestures[i].AsUUID();
823 if (gesture != itemID)
824 newGestures.Add(OSD.FromUUID(gesture));
825 }
826
827 if (enabled)
828 newGestures.Add(OSD.FromUUID(itemID));
829
830 SaveGestures(userID, newGestures);
831 }
832
833 private OSDArray FetchGestures(UUID userID)
834 {
835 NameValueCollection requestArgs = new NameValueCollection
836 {
837 { "RequestMethod", "GetUser" },
838 { "UserID", userID.ToString() }
839 };
840
841 OSDMap response = WebUtil.PostToService(m_userServerUrl, requestArgs);
842 if (response["Success"].AsBoolean())
843 {
844 OSDMap user = response["User"] as OSDMap;
845 if (user != null && response.ContainsKey("Gestures"))
846 {
847 OSD gestures = OSDParser.DeserializeJson(response["Gestures"].AsString());
848 if (gestures != null && gestures is OSDArray)
849 return (OSDArray)gestures;
850 else
851 m_log.Error("[INVENTORY CONNECTOR]: Unrecognized active gestures data for " + userID);
852 }
853 }
854 else
855 {
856 m_log.Warn("[INVENTORY CONNECTOR]: Failed to fetch active gestures for " + userID + ": " +
857 response["Message"].AsString());
858 }
859
860 return new OSDArray();
861 }
862
863 private void SaveGestures(UUID userID, OSDArray gestures)
864 {
865 NameValueCollection requestArgs = new NameValueCollection
866 {
867 { "RequestMethod", "AddUserData" },
868 { "UserID", userID.ToString() },
869 { "Gestures", OSDParser.SerializeJsonString(gestures) }
870 };
871
872 OSDMap response = WebUtil.PostToService(m_userServerUrl, requestArgs);
873 if (!response["Success"].AsBoolean())
874 {
875 m_log.Warn("[INVENTORY CONNECTOR]: Failed to save active gestures for " + userID + ": " +
876 response["Message"].AsString());
877 }
878 }
879 }
880}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs
new file mode 100644
index 0000000..65de1c5
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs
@@ -0,0 +1,502 @@
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.Net;
32using System.Reflection;
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36using OpenSim.Framework;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Server.Base;
42using OpenMetaverse;
43using OpenMetaverse.StructuredData;
44
45using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
46
47namespace OpenSim.Services.Connectors.SimianGrid
48{
49 /// <summary>
50 /// Connects avatar presence information (for tracking current location and
51 /// message routing) to the SimianGrid backend
52 /// </summary>
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
54 public class SimianPresenceServiceConnector : IPresenceService, ISharedRegionModule
55 {
56 private static readonly ILog m_log =
57 LogManager.GetLogger(
58 MethodBase.GetCurrentMethod().DeclaringType);
59
60 private string m_serverUrl = String.Empty;
61
62 #region ISharedRegionModule
63
64 public Type ReplaceableInterface { get { return null; } }
65 public void RegionLoaded(Scene scene) { }
66 public void PostInitialise() { }
67 public void Close() { }
68
69 public SimianPresenceServiceConnector() { }
70 public string Name { get { return "SimianPresenceServiceConnector"; } }
71 public void AddRegion(Scene scene)
72 {
73 scene.RegisterModuleInterface<IPresenceService>(this);
74
75 scene.EventManager.OnMakeRootAgent += MakeRootAgentHandler;
76 scene.EventManager.OnNewClient += NewClientHandler;
77 scene.EventManager.OnSignificantClientMovement += SignificantClientMovementHandler;
78
79 LogoutRegionAgents(scene.RegionInfo.RegionID);
80 }
81 public void RemoveRegion(Scene scene)
82 {
83 scene.UnregisterModuleInterface<IPresenceService>(this);
84
85 scene.EventManager.OnMakeRootAgent -= MakeRootAgentHandler;
86 scene.EventManager.OnNewClient -= NewClientHandler;
87 scene.EventManager.OnSignificantClientMovement -= SignificantClientMovementHandler;
88
89 LogoutRegionAgents(scene.RegionInfo.RegionID);
90 }
91
92 #endregion ISharedRegionModule
93
94 public SimianPresenceServiceConnector(IConfigSource source)
95 {
96 Initialise(source);
97 }
98
99 public void Initialise(IConfigSource source)
100 {
101 IConfig gridConfig = source.Configs["PresenceService"];
102 if (gridConfig == null)
103 {
104 m_log.Error("[PRESENCE CONNECTOR]: PresenceService missing from OpenSim.ini");
105 throw new Exception("Presence connector init error");
106 }
107
108 string serviceUrl = gridConfig.GetString("PresenceServerURI");
109 if (String.IsNullOrEmpty(serviceUrl))
110 {
111 m_log.Error("[PRESENCE CONNECTOR]: No PresenceServerURI in section PresenceService");
112 throw new Exception("Presence connector init error");
113 }
114
115 m_serverUrl = serviceUrl;
116 }
117
118 #region IPresenceService
119
120 public bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID)
121 {
122 m_log.ErrorFormat("[PRESENCE CONNECTOR]: Login requested, UserID={0}, SessionID={1}, SecureSessionID={2}",
123 userID, sessionID, secureSessionID);
124
125 NameValueCollection requestArgs = new NameValueCollection
126 {
127 { "RequestMethod", "AddSession" },
128 { "UserID", userID.ToString() }
129 };
130 if (sessionID != UUID.Zero)
131 {
132 requestArgs["SessionID"] = sessionID.ToString();
133 requestArgs["SecureSessionID"] = secureSessionID.ToString();
134 }
135
136 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
137 bool success = response["Success"].AsBoolean();
138
139 if (!success)
140 m_log.Warn("[PRESENCE CONNECTOR]: Failed to login agent " + userID + ": " + response["Message"].AsString());
141
142 return success;
143 }
144
145 public bool LogoutAgent(UUID sessionID, Vector3 position, Vector3 lookAt)
146 {
147 m_log.InfoFormat("[PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID);
148
149 NameValueCollection requestArgs = new NameValueCollection
150 {
151 { "RequestMethod", "RemoveSession" },
152 { "SessionID", sessionID.ToString() }
153 };
154
155 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
156 bool success = response["Success"].AsBoolean();
157
158 if (!success)
159 m_log.Warn("[PRESENCE CONNECTOR]: Failed to logout agent with sessionID " + sessionID + ": " + response["Message"].AsString());
160
161 return success;
162 }
163
164 public bool LogoutRegionAgents(UUID regionID)
165 {
166 m_log.InfoFormat("[PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID);
167
168 NameValueCollection requestArgs = new NameValueCollection
169 {
170 { "RequestMethod", "RemoveSessions" },
171 { "SceneID", regionID.ToString() }
172 };
173
174 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
175 bool success = response["Success"].AsBoolean();
176
177 if (!success)
178 m_log.Warn("[PRESENCE CONNECTOR]: Failed to logout agents from region " + regionID + ": " + response["Message"].AsString());
179
180 return success;
181 }
182
183 public bool ReportAgent(UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt)
184 {
185 //m_log.DebugFormat("[PRESENCE CONNECTOR]: Updating session data for agent with sessionID " + sessionID);
186
187 NameValueCollection requestArgs = new NameValueCollection
188 {
189 { "RequestMethod", "UpdateSession" },
190 { "SessionID", sessionID.ToString() },
191 { "SceneID", regionID.ToString() },
192 { "ScenePosition", position.ToString() },
193 { "SceneLookAt", lookAt.ToString() }
194 };
195
196 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
197 bool success = response["Success"].AsBoolean();
198
199 if (!success)
200 m_log.Warn("[PRESENCE CONNECTOR]: Failed to update agent session " + sessionID + ": " + response["Message"].AsString());
201
202 return success;
203 }
204
205 public PresenceInfo GetAgent(UUID sessionID)
206 {
207 m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting session data for agent with sessionID " + sessionID);
208
209 NameValueCollection requestArgs = new NameValueCollection
210 {
211 { "RequestMethod", "GetSession" },
212 { "SessionID", sessionID.ToString() }
213 };
214
215 OSDMap sessionResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
216 if (sessionResponse["Success"].AsBoolean())
217 {
218 UUID userID = sessionResponse["UserID"].AsUUID();
219 m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting user data for " + userID);
220
221 requestArgs = new NameValueCollection
222 {
223 { "RequestMethod", "GetUser" },
224 { "UserID", userID.ToString() }
225 };
226
227 OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
228 if (userResponse["Success"].AsBoolean())
229 return ResponseToPresenceInfo(sessionResponse, userResponse);
230 else
231 m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString());
232 }
233 else
234 {
235 m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve session " + sessionID + ": " + sessionResponse["Message"].AsString());
236 }
237
238 return null;
239 }
240
241 public PresenceInfo[] GetAgents(string[] userIDs)
242 {
243 List<PresenceInfo> presences = new List<PresenceInfo>(userIDs.Length);
244
245 for (int i = 0; i < userIDs.Length; i++)
246 {
247 UUID userID;
248 if (UUID.TryParse(userIDs[i], out userID) && userID != UUID.Zero)
249 presences.AddRange(GetSessions(userID));
250 }
251
252 return presences.ToArray();
253 }
254
255 public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
256 {
257 m_log.DebugFormat("[PRESENCE CONNECTOR]: Setting home location for user " + userID);
258
259 NameValueCollection requestArgs = new NameValueCollection
260 {
261 { "RequestMethod", "AddUserData" },
262 { "UserID", userID.ToString() },
263 { "HomeLocation", SerializeLocation(regionID, position, lookAt) }
264 };
265
266 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
267 bool success = response["Success"].AsBoolean();
268
269 if (!success)
270 m_log.Warn("[PRESENCE CONNECTOR]: Failed to set home location for " + userID + ": " + response["Message"].AsString());
271
272 return success;
273 }
274
275 #endregion IPresenceService
276
277 #region Presence Detection
278
279 private void MakeRootAgentHandler(ScenePresence sp)
280 {
281 m_log.DebugFormat("[PRESENCE DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName);
282
283 ReportAgent(sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
284 SetLastLocation(sp.UUID, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
285 }
286
287 private void NewClientHandler(IClientAPI client)
288 {
289 client.OnConnectionClosed += LogoutHandler;
290 }
291
292 private void SignificantClientMovementHandler(IClientAPI client)
293 {
294 ScenePresence sp;
295 if (client.Scene is Scene && ((Scene)client.Scene).TryGetAvatar(client.AgentId, out sp))
296 ReportAgent(sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
297 }
298
299 private void LogoutHandler(IClientAPI client)
300 {
301 if (client.IsLoggingOut)
302 {
303 client.OnConnectionClosed -= LogoutHandler;
304
305 object obj;
306 if (client.Scene.TryGetAvatar(client.AgentId, out obj) && obj is ScenePresence)
307 {
308 // The avatar is still in the scene, we can get the exact logout position
309 ScenePresence sp = (ScenePresence)obj;
310 SetLastLocation(client.AgentId, client.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
311 }
312 else
313 {
314 // The avatar was already removed from the scene, store LastLocation using the most recent session data
315 m_log.Warn("[PRESENCE]: " + client.Name + " has already been removed from the scene, storing approximate LastLocation");
316 SetLastLocation(client.SessionId);
317 }
318
319 LogoutAgent(client.SessionId, Vector3.Zero, Vector3.UnitX);
320 }
321 }
322
323 #endregion Presence Detection
324
325 #region Helpers
326
327 private OSDMap GetUserData(UUID userID)
328 {
329 m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting user data for " + userID);
330
331 NameValueCollection requestArgs = new NameValueCollection
332 {
333 { "RequestMethod", "GetUser" },
334 { "UserID", userID.ToString() }
335 };
336
337 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
338 if (response["Success"].AsBoolean() && response["User"] is OSDMap)
339 return response;
340 else
341 m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + response["Message"].AsString());
342
343 return null;
344 }
345
346 private OSDMap GetSessionData(UUID sessionID)
347 {
348 m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting session data for session " + sessionID);
349
350 NameValueCollection requestArgs = new NameValueCollection
351 {
352 { "RequestMethod", "GetSession" },
353 { "SessionID", sessionID.ToString() }
354 };
355
356 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
357 if (response["Success"].AsBoolean())
358 return response;
359 else
360 m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve session data for session " + sessionID);
361
362 return null;
363 }
364
365 private List<PresenceInfo> GetSessions(UUID userID)
366 {
367 List<PresenceInfo> presences = new List<PresenceInfo>(1);
368
369 OSDMap userResponse = GetUserData(userID);
370 if (userResponse != null)
371 {
372 m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting sessions for " + userID);
373
374 NameValueCollection requestArgs = new NameValueCollection
375 {
376 { "RequestMethod", "GetSession" },
377 { "UserID", userID.ToString() }
378 };
379
380 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
381 if (response["Success"].AsBoolean())
382 {
383 PresenceInfo presence = ResponseToPresenceInfo(response, userResponse);
384 if (presence != null)
385 presences.Add(presence);
386 }
387 else
388 {
389 m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve sessions for " + userID + ": " + response["Message"].AsString());
390 }
391 }
392
393 return presences;
394 }
395
396 /// <summary>
397 /// Fetch the last known avatar location with GetSession and persist it
398 /// as user data with AddUserData
399 /// </summary>
400 private bool SetLastLocation(UUID sessionID)
401 {
402 NameValueCollection requestArgs = new NameValueCollection
403 {
404 { "RequestMethod", "GetSession" },
405 { "SessionID", sessionID.ToString() }
406 };
407
408 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
409 bool success = response["Success"].AsBoolean();
410
411 if (success)
412 {
413 UUID userID = response["UserID"].AsUUID();
414 UUID sceneID = response["SceneID"].AsUUID();
415 Vector3 position = response["ScenePosition"].AsVector3();
416 Vector3 lookAt = response["SceneLookAt"].AsVector3();
417
418 return SetLastLocation(userID, sceneID, position, lookAt);
419 }
420 else
421 {
422 m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve presence information for session " + sessionID +
423 " while saving last location: " + response["Message"].AsString());
424 }
425
426 return success;
427 }
428
429 private bool SetLastLocation(UUID userID, UUID sceneID, Vector3 position, Vector3 lookAt)
430 {
431 NameValueCollection requestArgs = new NameValueCollection
432 {
433 { "RequestMethod", "AddUserData" },
434 { "UserID", userID.ToString() },
435 { "LastLocation", SerializeLocation(sceneID, position, lookAt) }
436 };
437
438 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
439 bool success = response["Success"].AsBoolean();
440
441 if (!success)
442 m_log.Warn("[PRESENCE CONNECTOR]: Failed to set last location for " + userID + ": " + response["Message"].AsString());
443
444 return success;
445 }
446
447 private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse, OSDMap userResponse)
448 {
449 if (sessionResponse == null)
450 return null;
451
452 PresenceInfo info = new PresenceInfo();
453
454 info.Online = true;
455 info.UserID = sessionResponse["UserID"].AsUUID().ToString();
456 info.RegionID = sessionResponse["SceneID"].AsUUID();
457 info.Position = sessionResponse["ScenePosition"].AsVector3();
458 info.LookAt = sessionResponse["SceneLookAt"].AsVector3();
459
460 if (userResponse != null && userResponse["User"] is OSDMap)
461 {
462 OSDMap user = (OSDMap)userResponse["User"];
463
464 info.Login = user["LastLoginDate"].AsDate();
465 info.Logout = user["LastLogoutDate"].AsDate();
466 DeserializeLocation(user["HomeLocation"].AsString(), out info.HomeRegionID, out info.HomePosition, out info.HomeLookAt);
467 }
468
469 return info;
470 }
471
472 private string SerializeLocation(UUID regionID, Vector3 position, Vector3 lookAt)
473 {
474 return "{" + String.Format("\"SceneID\":\"{0}\",\"Position\":\"{1}\",\"LookAt\":\"{2}\"", regionID, position, lookAt) + "}";
475 }
476
477 private bool DeserializeLocation(string location, out UUID regionID, out Vector3 position, out Vector3 lookAt)
478 {
479 OSDMap map = null;
480
481 try { map = OSDParser.DeserializeJson(location) as OSDMap; }
482 catch { }
483
484 if (map != null)
485 {
486 regionID = map["SceneID"].AsUUID();
487 if (Vector3.TryParse(map["Position"].AsString(), out position) &&
488 Vector3.TryParse(map["LookAt"].AsString(), out lookAt))
489 {
490 return true;
491 }
492 }
493
494 regionID = UUID.Zero;
495 position = Vector3.Zero;
496 lookAt = Vector3.Zero;
497 return false;
498 }
499
500 #endregion Helpers
501 }
502}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs
new file mode 100644
index 0000000..1e19982
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs
@@ -0,0 +1,432 @@
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")]
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
71 #region INonSharedRegionModule
72
73 public Type ReplaceableInterface { get { return null; } }
74 public void RegionLoaded(Scene scene) { }
75 public void Close() { }
76
77 public SimianProfiles() { }
78 public string Name { get { return "SimianProfiles"; } }
79 public void AddRegion(Scene scene) { CheckEstateManager(scene); scene.EventManager.OnClientConnect += ClientConnectHandler; }
80 public void RemoveRegion(Scene scene) { scene.EventManager.OnClientConnect -= ClientConnectHandler; }
81
82 #endregion INonSharedRegionModule
83
84 public SimianProfiles(IConfigSource source)
85 {
86 Initialise(source);
87 }
88
89 public void Initialise(IConfigSource source)
90 {
91 IConfig gridConfig = source.Configs["UserAccountService"];
92 if (gridConfig == null)
93 {
94 m_log.Error("[PROFILES]: UserAccountService missing from OpenSim.ini");
95 throw new Exception("Profiles init error");
96 }
97
98 string serviceUrl = gridConfig.GetString("UserAccountServerURI");
99 if (String.IsNullOrEmpty(serviceUrl))
100 {
101 m_log.Error("[PROFILES]: No UserAccountServerURI in section UserAccountService");
102 throw new Exception("Profiles init error");
103 }
104
105 if (!serviceUrl.EndsWith("/"))
106 serviceUrl = serviceUrl + '/';
107
108 m_serverUrl = serviceUrl;
109 }
110
111 private void ClientConnectHandler(IClientCore clientCore)
112 {
113 if (clientCore is IClientAPI)
114 {
115 IClientAPI client = (IClientAPI)clientCore;
116
117 // Classifieds
118 client.AddGenericPacketHandler("avatarclassifiedsrequest", AvatarClassifiedsRequestHandler);
119 client.OnClassifiedInfoRequest += ClassifiedInfoRequestHandler;
120 client.OnClassifiedInfoUpdate += ClassifiedInfoUpdateHandler;
121 client.OnClassifiedDelete += ClassifiedDeleteHandler;
122
123 // Picks
124 client.AddGenericPacketHandler("avatarpicksrequest", HandleAvatarPicksRequest);
125 client.AddGenericPacketHandler("pickinforequest", HandlePickInfoRequest);
126 client.OnPickInfoUpdate += PickInfoUpdateHandler;
127 client.OnPickDelete += PickDeleteHandler;
128
129 // Notes
130 client.AddGenericPacketHandler("avatarnotesrequest", HandleAvatarNotesRequest);
131 client.OnAvatarNotesUpdate += AvatarNotesUpdateHandler;
132
133 // Profiles
134 client.OnRequestAvatarProperties += RequestAvatarPropertiesHandler;
135 client.OnUpdateAvatarProperties += UpdateAvatarPropertiesHandler;
136 client.OnAvatarInterestUpdate += AvatarInterestUpdateHandler;
137 client.OnUserInfoRequest += UserInfoRequestHandler;
138 client.OnUpdateUserInfo += UpdateUserInfoHandler;
139 }
140 }
141
142 #region Classifieds
143
144 private void AvatarClassifiedsRequestHandler(Object sender, string method, List<String> args)
145 {
146 if (!(sender is IClientAPI))
147 return;
148 IClientAPI client = (IClientAPI)sender;
149
150 UUID targetAvatarID;
151 if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID))
152 {
153 m_log.Error("[PROFILES]: Unrecognized arguments for " + method);
154 return;
155 }
156
157 // FIXME: Query the generic key/value store for classifieds
158 client.SendAvatarClassifiedReply(targetAvatarID, new Dictionary<UUID, string>(0));
159 }
160
161 private void ClassifiedInfoRequestHandler(UUID classifiedID, IClientAPI client)
162 {
163 // FIXME: Fetch this info
164 client.SendClassifiedInfoReply(classifiedID, UUID.Zero, 0, Utils.DateTimeToUnixTime(DateTime.UtcNow + TimeSpan.FromDays(1)),
165 0, String.Empty, String.Empty, UUID.Zero, 0, UUID.Zero, String.Empty, Vector3.Zero, String.Empty, 0, 0);
166 }
167
168 private void ClassifiedInfoUpdateHandler(UUID classifiedID, uint category, string name, string description,
169 UUID parcelID, uint parentEstate, UUID snapshotID, Vector3 globalPos, byte classifiedFlags, int price,
170 IClientAPI client)
171 {
172 // FIXME: Save this info
173 }
174
175 private void ClassifiedDeleteHandler(UUID classifiedID, IClientAPI client)
176 {
177 // FIXME: Delete the specified classified ad
178 }
179
180 #endregion Classifieds
181
182 #region Picks
183
184 private void HandleAvatarPicksRequest(Object sender, string method, List<String> args)
185 {
186 if (!(sender is IClientAPI))
187 return;
188 IClientAPI client = (IClientAPI)sender;
189
190 UUID targetAvatarID;
191 if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID))
192 {
193 m_log.Error("[PROFILES]: Unrecognized arguments for " + method);
194 return;
195 }
196
197 // FIXME: Fetch these
198 client.SendAvatarPicksReply(targetAvatarID, new Dictionary<UUID, string>(0));
199 }
200
201 private void HandlePickInfoRequest(Object sender, string method, List<String> args)
202 {
203 if (!(sender is IClientAPI))
204 return;
205 IClientAPI client = (IClientAPI)sender;
206
207 UUID avatarID;
208 UUID pickID;
209 if (args.Count < 2 || !UUID.TryParse(args[0], out avatarID) || !UUID.TryParse(args[1], out pickID))
210 {
211 m_log.Error("[PROFILES]: Unrecognized arguments for " + method);
212 return;
213 }
214
215 // FIXME: Fetch this
216 client.SendPickInfoReply(pickID, avatarID, false, UUID.Zero, String.Empty, String.Empty, UUID.Zero, String.Empty,
217 String.Empty, String.Empty, Vector3.Zero, 0, false);
218 }
219
220 private void PickInfoUpdateHandler(IClientAPI client, UUID pickID, UUID creatorID, bool topPick, string name,
221 string desc, UUID snapshotID, int sortOrder, bool enabled)
222 {
223 // FIXME: Save this
224 }
225
226 private void PickDeleteHandler(IClientAPI client, UUID pickID)
227 {
228 // FIXME: Delete
229 }
230
231 #endregion Picks
232
233 #region Notes
234
235 private void HandleAvatarNotesRequest(Object sender, string method, List<String> args)
236 {
237 if (!(sender is IClientAPI))
238 return;
239 IClientAPI client = (IClientAPI)sender;
240
241 UUID targetAvatarID;
242 if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID))
243 {
244 m_log.Error("[PROFILES]: Unrecognized arguments for " + method);
245 return;
246 }
247
248 // FIXME: Fetch this
249 client.SendAvatarNotesReply(targetAvatarID, String.Empty);
250 }
251
252 private void AvatarNotesUpdateHandler(IClientAPI client, UUID targetID, string notes)
253 {
254 // FIXME: Save this
255 }
256
257 #endregion Notes
258
259 #region Profiles
260
261 private void RequestAvatarPropertiesHandler(IClientAPI client, UUID avatarID)
262 {
263 OSDMap user = FetchUserData(avatarID);
264
265 ProfileFlags flags = ProfileFlags.AllowPublish | ProfileFlags.MaturePublish;
266
267 if (user != null)
268 {
269 OSDMap about = null;
270 if (user.ContainsKey("LLAbout"))
271 {
272 try { about = OSDParser.DeserializeJson(user["LLAbout"].AsString()) as OSDMap; }
273 catch { }
274 }
275
276 if (about == null)
277 about = new OSDMap(0);
278
279 // Check if this user is a grid operator
280 byte[] charterMember;
281 if (user["AccessLevel"].AsInteger() >= 200)
282 charterMember = Utils.StringToBytes("Operator");
283 else
284 charterMember = Utils.EmptyBytes;
285
286 // Check if the user is online
287 if (client.Scene is Scene)
288 {
289 OpenSim.Services.Interfaces.PresenceInfo[] presences = ((Scene)client.Scene).PresenceService.GetAgents(new string[] { avatarID.ToString() });
290 if (presences != null && presences.Length > 0)
291 flags |= ProfileFlags.Online;
292 }
293
294 // Check if the user is identified
295 if (user["Identified"].AsBoolean())
296 flags |= ProfileFlags.Identified;
297
298 client.SendAvatarProperties(avatarID, about["About"].AsString(), user["CreationDate"].AsDate().ToString("M/d/yyyy",
299 System.Globalization.CultureInfo.InvariantCulture), charterMember, about["FLAbout"].AsString(), (uint)flags,
300 about["FLImage"].AsUUID(), about["Image"].AsUUID(), about["URL"].AsString(), user["Partner"].AsUUID());
301
302 }
303 else
304 {
305 m_log.Warn("[PROFILES]: Failed to fetch profile information for " + client.Name + ", returning default values");
306 client.SendAvatarProperties(avatarID, String.Empty, "1/1/1970", Utils.EmptyBytes,
307 String.Empty, (uint)flags, UUID.Zero, UUID.Zero, String.Empty, UUID.Zero);
308 }
309 }
310
311 private void UpdateAvatarPropertiesHandler(IClientAPI client, UserProfileData profileData)
312 {
313 OSDMap map = new OSDMap
314 {
315 { "About", OSD.FromString(profileData.AboutText) },
316 { "Image", OSD.FromUUID(profileData.Image) },
317 { "FLAbout", OSD.FromString(profileData.FirstLifeAboutText) },
318 { "FLImage", OSD.FromUUID(profileData.FirstLifeImage) },
319 { "URL", OSD.FromString(profileData.ProfileUrl) }
320 };
321
322 AddUserData(client.AgentId, "LLAbout", map);
323 }
324
325 private void AvatarInterestUpdateHandler(IClientAPI client, uint wantmask, string wanttext, uint skillsmask,
326 string skillstext, string languages)
327 {
328 OSDMap map = new OSDMap
329 {
330 { "WantMask", OSD.FromInteger(wantmask) },
331 { "WantText", OSD.FromString(wanttext) },
332 { "SkillsMask", OSD.FromInteger(skillsmask) },
333 { "SkillsText", OSD.FromString(skillstext) },
334 { "Languages", OSD.FromString(languages) }
335 };
336
337 AddUserData(client.AgentId, "LLInterests", map);
338 }
339
340 private void UserInfoRequestHandler(IClientAPI client)
341 {
342 m_log.Error("[PROFILES]: UserInfoRequestHandler");
343
344 // Fetch this user's e-mail address
345 NameValueCollection requestArgs = new NameValueCollection
346 {
347 { "RequestMethod", "GetUser" },
348 { "UserID", client.AgentId.ToString() }
349 };
350
351 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
352 string email = response["Email"].AsString();
353
354 if (!response["Success"].AsBoolean())
355 m_log.Warn("[PROFILES]: GetUser failed during a user info request for " + client.Name);
356
357 client.SendUserInfoReply(false, true, email);
358 }
359
360 private void UpdateUserInfoHandler(bool imViaEmail, bool visible, IClientAPI client)
361 {
362 m_log.Info("[PROFILES]: Ignoring user info update from " + client.Name);
363 }
364
365 #endregion Profiles
366
367 /// <summary>
368 /// Sanity checks regions for a valid estate owner at startup
369 /// </summary>
370 private void CheckEstateManager(Scene scene)
371 {
372 EstateSettings estate = scene.RegionInfo.EstateSettings;
373
374 if (estate.EstateOwner == UUID.Zero)
375 {
376 // Attempt to lookup the grid admin
377 UserAccount admin = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, UUID.Zero);
378 if (admin != null)
379 {
380 m_log.InfoFormat("[PROFILES]: Setting estate {0} (ID: {1}) owner to {2}", estate.EstateName,
381 estate.EstateID, admin.Name);
382
383 estate.EstateOwner = admin.PrincipalID;
384 estate.Save();
385 }
386 else
387 {
388 m_log.WarnFormat("[PROFILES]: Estate {0} (ID: {1}) does not have an owner", estate.EstateName, estate.EstateID);
389 }
390 }
391 }
392
393 private bool AddUserData(UUID userID, string key, OSDMap value)
394 {
395 NameValueCollection requestArgs = new NameValueCollection
396 {
397 { "RequestMethod", "AddUserData" },
398 { "UserID", userID.ToString() },
399 { key, OSDParser.SerializeJsonString(value) }
400 };
401
402 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
403 bool success = response["Success"].AsBoolean();
404
405 if (!success)
406 m_log.WarnFormat("[PROFILES]: Failed to add user data with key {0} for {1}: {2}", key, userID, response["Message"].AsString());
407
408 return success;
409 }
410
411 private OSDMap FetchUserData(UUID userID)
412 {
413 NameValueCollection requestArgs = new NameValueCollection
414 {
415 { "RequestMethod", "GetUser" },
416 { "UserID", userID.ToString() }
417 };
418
419 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
420 if (response["Success"].AsBoolean() && response["User"] is OSDMap)
421 {
422 return (OSDMap)response["User"];
423 }
424 else
425 {
426 m_log.Error("[PROFILES]: Failed to fetch user data for " + userID + ": " + response["Message"].AsString());
427 }
428
429 return null;
430 }
431 }
432}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs
new file mode 100644
index 0000000..14097d0
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.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.Generic;
30using System.Collections.Specialized;
31using System.IO;
32using System.Reflection;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Services.Interfaces;
37using log4net;
38using Mono.Addins;
39using Nini.Config;
40using OpenMetaverse;
41using OpenMetaverse.StructuredData;
42
43namespace OpenSim.Services.Connectors.SimianGrid
44{
45 /// <summary>
46 /// Connects user account data (creating new users, looking up existing
47 /// users) to the SimianGrid backend
48 /// </summary>
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
50 public class SimianUserAccountServiceConnector : IUserAccountService, ISharedRegionModule
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(
54 MethodBase.GetCurrentMethod().DeclaringType);
55
56 private string m_serverUrl = String.Empty;
57 private ExpiringCache<UUID, UserAccount> m_accountCache = new ExpiringCache<UUID, UserAccount>();
58
59 #region ISharedRegionModule
60
61 public Type ReplaceableInterface { get { return null; } }
62 public void RegionLoaded(Scene scene) { }
63 public void PostInitialise() { }
64 public void Close() { }
65
66 public SimianUserAccountServiceConnector() { }
67 public string Name { get { return "SimianUserAccountServiceConnector"; } }
68 public void AddRegion(Scene scene) { scene.RegisterModuleInterface<IUserAccountService>(this); }
69 public void RemoveRegion(Scene scene) { scene.UnregisterModuleInterface<IUserAccountService>(this); }
70
71 #endregion ISharedRegionModule
72
73 public SimianUserAccountServiceConnector(IConfigSource source)
74 {
75 Initialise(source);
76 }
77
78 public void Initialise(IConfigSource source)
79 {
80 IConfig assetConfig = source.Configs["UserAccountService"];
81 if (assetConfig == null)
82 {
83 m_log.Error("[ACCOUNT CONNECTOR]: UserAccountService missing from OpenSim.ini");
84 throw new Exception("User account connector init error");
85 }
86
87 string serviceURI = assetConfig.GetString("UserAccountServerURI");
88 if (String.IsNullOrEmpty(serviceURI))
89 {
90 m_log.Error("[ACCOUNT CONNECTOR]: No UserAccountServerURI in section UserAccountService");
91 throw new Exception("User account connector init error");
92 }
93
94 m_serverUrl = serviceURI;
95 }
96
97 public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName)
98 {
99 NameValueCollection requestArgs = new NameValueCollection
100 {
101 { "RequestMethod", "GetUser" },
102 { "Name", firstName + ' ' + lastName }
103 };
104
105 return GetUser(requestArgs);
106 }
107
108 public UserAccount GetUserAccount(UUID scopeID, string email)
109 {
110 NameValueCollection requestArgs = new NameValueCollection
111 {
112 { "RequestMethod", "GetUser" },
113 { "Email", email }
114 };
115
116 return GetUser(requestArgs);
117 }
118
119 public UserAccount GetUserAccount(UUID scopeID, UUID userID)
120 {
121 // Cache check
122 UserAccount account;
123 if (m_accountCache.TryGetValue(userID, out account))
124 return account;
125
126 NameValueCollection requestArgs = new NameValueCollection
127 {
128 { "RequestMethod", "GetUser" },
129 { "UserID", userID.ToString() }
130 };
131
132 return GetUser(requestArgs);
133 }
134
135 public List<UserAccount> GetUserAccounts(UUID scopeID, string query)
136 {
137 List<UserAccount> accounts = new List<UserAccount>();
138
139 m_log.DebugFormat("[ACCOUNT CONNECTOR]: Searching for user accounts with name query " + query);
140
141 NameValueCollection requestArgs = new NameValueCollection
142 {
143 { "RequestMethod", "GetUsers" },
144 { "NameQuery", query }
145 };
146
147 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
148 if (response["Success"].AsBoolean())
149 {
150 OSDArray array = response["Users"] as OSDArray;
151 if (array != null && array.Count > 0)
152 {
153 for (int i = 0; i < array.Count; i++)
154 {
155 UserAccount account = ResponseToUserAccount(array[i] as OSDMap);
156 if (account != null)
157 accounts.Add(account);
158 }
159 }
160 else
161 {
162 m_log.Warn("[ACCOUNT CONNECTOR]: Account search failed, response data was in an invalid format");
163 }
164 }
165 else
166 {
167 m_log.Warn("[ACCOUNT CONNECTOR]: Failed to search for account data by name " + query);
168 }
169
170 return accounts;
171 }
172
173 public bool StoreUserAccount(UserAccount data)
174 {
175 m_log.InfoFormat("[ACCOUNT CONNECTOR]: Storing user account for " + data.Name);
176
177 NameValueCollection requestArgs = new NameValueCollection
178 {
179 { "RequestMethod", "AddUser" },
180 { "UserID", data.PrincipalID.ToString() },
181 { "Name", data.Name },
182 { "Email", data.Email },
183 { "AccessLevel", data.UserLevel.ToString() }
184 };
185
186 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
187
188 if (response["Success"].AsBoolean())
189 {
190 m_log.InfoFormat("[ACCOUNT CONNECTOR]: Storing user account data for " + data.Name);
191
192 requestArgs = new NameValueCollection
193 {
194 { "RequestMethod", "AddUserData" },
195 { "UserID", data.PrincipalID.ToString() },
196 { "CreationDate", data.Created.ToString() },
197 { "UserFlags", data.UserFlags.ToString() },
198 { "UserTitle", data.UserTitle }
199 };
200
201 response = WebUtil.PostToService(m_serverUrl, requestArgs);
202 bool success = response["Success"].AsBoolean();
203
204 if (success)
205 {
206 // Cache the user account info
207 m_accountCache.AddOrUpdate(data.PrincipalID, data, DateTime.Now + TimeSpan.FromMinutes(2.0d));
208 }
209 else
210 {
211 m_log.Warn("[ACCOUNT CONNECTOR]: Failed to store user account data for " + data.Name + ": " + response["Message"].AsString());
212 }
213
214 return success;
215 }
216 else
217 {
218 m_log.Warn("[ACCOUNT CONNECTOR]: Failed to store user account for " + data.Name + ": " + response["Message"].AsString());
219 }
220
221 return false;
222 }
223
224 /// <summary>
225 /// Helper method for the various ways of retrieving a user account
226 /// </summary>
227 /// <param name="requestArgs">Service query parameters</param>
228 /// <returns>A UserAccount object on success, null on failure</returns>
229 private UserAccount GetUser(NameValueCollection requestArgs)
230 {
231 string lookupValue = (requestArgs.Count > 1) ? requestArgs[1] : "(Unknown)";
232 m_log.DebugFormat("[ACCOUNT CONNECTOR]: Looking up user account with query: " + lookupValue);
233
234 OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
235 if (response["Success"].AsBoolean())
236 {
237 OSDMap user = response["User"] as OSDMap;
238 if (user != null)
239 return ResponseToUserAccount(user);
240 else
241 m_log.Warn("[ACCOUNT CONNECTOR]: Account search failed, response data was in an invalid format");
242 }
243 else
244 {
245 m_log.Warn("[ACCOUNT CONNECTOR]: Failed to lookup user account with query: " + lookupValue);
246 }
247
248 return null;
249 }
250
251 /// <summary>
252 /// Convert a User object in LLSD format to a UserAccount
253 /// </summary>
254 /// <param name="response">LLSD containing user account data</param>
255 /// <returns>A UserAccount object on success, null on failure</returns>
256 private UserAccount ResponseToUserAccount(OSDMap response)
257 {
258 if (response == null)
259 return null;
260
261 UserAccount account = new UserAccount();
262 account.PrincipalID = response["UserID"].AsUUID();
263 account.Created = response["CreationDate"].AsInteger();
264 account.Email = response["Email"].AsString();
265 account.ServiceURLs = new Dictionary<string, object>(0);
266 account.UserFlags = response["UserFlags"].AsInteger();
267 account.UserLevel = response["AccessLevel"].AsInteger();
268 account.UserTitle = response["UserTitle"].AsString();
269 GetFirstLastName(response["Name"].AsString(), out account.FirstName, out account.LastName);
270
271 // Cache the user account info
272 m_accountCache.AddOrUpdate(account.PrincipalID, account, DateTime.Now + TimeSpan.FromMinutes(2.0d));
273
274 return account;
275 }
276
277 /// <summary>
278 /// Convert a name with a single space in it to a first and last name
279 /// </summary>
280 /// <param name="name">A full name such as "John Doe"</param>
281 /// <param name="firstName">First name</param>
282 /// <param name="lastName">Last name (surname)</param>
283 private static void GetFirstLastName(string name, out string firstName, out string lastName)
284 {
285 if (String.IsNullOrEmpty(name))
286 {
287 firstName = String.Empty;
288 lastName = String.Empty;
289 }
290 else
291 {
292 string[] names = name.Split(' ');
293
294 if (names.Length == 2)
295 {
296 firstName = names[0];
297 lastName = names[1];
298 }
299 else
300 {
301 firstName = String.Empty;
302 lastName = name;
303 }
304 }
305 }
306 }
307}