aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs')
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs502
1 files changed, 502 insertions, 0 deletions
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}