OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
SimianPresenceServiceConnector.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Collections.Specialized;
31 using System.Reflection;
32 using log4net;
33 using Mono.Addins;
34 using Nini.Config;
35 using OpenSim.Framework;
36 using OpenSim.Region.Framework.Interfaces;
37 using OpenSim.Region.Framework.Scenes;
38 using OpenSim.Services.Interfaces;
39 using OpenMetaverse;
40 using OpenMetaverse.StructuredData;
41 
43 
44 namespace OpenSim.Services.Connectors.SimianGrid
45 {
50  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianPresenceServiceConnector")]
52  {
53  private static readonly ILog m_log =
54  LogManager.GetLogger(
55  MethodBase.GetCurrentMethod().DeclaringType);
56 
57  private string m_serverUrl = String.Empty;
58  private SimianActivityDetector m_activityDetector;
59  private bool m_Enabled = false;
60 
61  #region ISharedRegionModule
62 
63  public Type ReplaceableInterface { get { return null; } }
64  public void RegionLoaded(Scene scene) { }
65  public void PostInitialise() { }
66  public void Close() { }
67 
69  public string Name { get { return "SimianPresenceServiceConnector"; } }
70  public void AddRegion(Scene scene)
71  {
72  if (m_Enabled)
73  {
74  scene.RegisterModuleInterface<IPresenceService>(this);
75  scene.RegisterModuleInterface<IGridUserService>(this);
76 
77  m_activityDetector.AddRegion(scene);
78 
79  LogoutRegionAgents(scene.RegionInfo.RegionID);
80  }
81  }
82  public void RemoveRegion(Scene scene)
83  {
84  if (m_Enabled)
85  {
86  scene.UnregisterModuleInterface<IPresenceService>(this);
87  scene.UnregisterModuleInterface<IGridUserService>(this);
88 
89  m_activityDetector.RemoveRegion(scene);
90 
91  LogoutRegionAgents(scene.RegionInfo.RegionID);
92  }
93  }
94 
95  #endregion ISharedRegionModule
96 
97  public SimianPresenceServiceConnector(IConfigSource source)
98  {
99  CommonInit(source);
100  }
101 
102  public void Initialise(IConfigSource source)
103  {
104  IConfig moduleConfig = source.Configs["Modules"];
105  if (moduleConfig != null)
106  {
107  string name = moduleConfig.GetString("PresenceServices", "");
108  if (name == Name)
109  CommonInit(source);
110  }
111  }
112 
113  private void CommonInit(IConfigSource source)
114  {
115  IConfig gridConfig = source.Configs["PresenceService"];
116  if (gridConfig != null)
117  {
118  string serviceUrl = gridConfig.GetString("PresenceServerURI");
119  if (!String.IsNullOrEmpty(serviceUrl))
120  {
121  if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
122  serviceUrl = serviceUrl + '/';
123  m_serverUrl = serviceUrl;
124  m_activityDetector = new SimianActivityDetector(this);
125  m_Enabled = true;
126  }
127  }
128 
129  if (String.IsNullOrEmpty(m_serverUrl))
130  m_log.Info("[SIMIAN PRESENCE CONNECTOR]: No PresenceServerURI specified, disabling connector");
131  }
132 
133  #region IPresenceService
134 
135  public bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID)
136  {
137  m_log.ErrorFormat("[SIMIAN PRESENCE CONNECTOR]: Login requested, UserID={0}, SessionID={1}, SecureSessionID={2}",
138  userID, sessionID, secureSessionID);
139 
140  NameValueCollection requestArgs = new NameValueCollection
141  {
142  { "RequestMethod", "AddSession" },
143  { "UserID", userID.ToString() }
144  };
145 
146  if (sessionID != UUID.Zero)
147  {
148  requestArgs["SessionID"] = sessionID.ToString();
149  requestArgs["SecureSessionID"] = secureSessionID.ToString();
150  }
151 
152  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
153  bool success = response["Success"].AsBoolean();
154 
155  if (!success)
156  m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to login agent " + userID + ": " + response["Message"].AsString());
157 
158  return success;
159  }
160 
161  public bool LogoutAgent(UUID sessionID)
162  {
163  // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID);
164 
165  NameValueCollection requestArgs = new NameValueCollection
166  {
167  { "RequestMethod", "RemoveSession" },
168  { "SessionID", sessionID.ToString() }
169  };
170 
171  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
172  bool success = response["Success"].AsBoolean();
173 
174  if (!success)
175  m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to logout agent with sessionID " + sessionID + ": " + response["Message"].AsString());
176 
177  return success;
178  }
179 
180  public bool LogoutRegionAgents(UUID regionID)
181  {
182  // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID);
183 
184  NameValueCollection requestArgs = new NameValueCollection
185  {
186  { "RequestMethod", "RemoveSessions" },
187  { "SceneID", regionID.ToString() }
188  };
189 
190  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
191  bool success = response["Success"].AsBoolean();
192 
193  if (!success)
194  m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to logout agents from region " + regionID + ": " + response["Message"].AsString());
195 
196  return success;
197  }
198 
199  public bool ReportAgent(UUID sessionID, UUID regionID)
200  {
201  // Not needed for SimianGrid
202  return true;
203  }
204 
205  public PresenceInfo GetAgent(UUID sessionID)
206  {
207  OSDMap sessionResponse = GetSessionDataFromSessionID(sessionID);
208  if (sessionResponse == null)
209  {
210  m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session {0}: {1}",sessionID.ToString(),sessionResponse["Message"].AsString());
211  return null;
212  }
213 
214  UUID userID = sessionResponse["UserID"].AsUUID();
215  OSDMap userResponse = GetUserData(userID);
216  if (userResponse == null)
217  {
218  m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID.ToString(),userResponse["Message"].AsString());
219  return null;
220  }
221 
222  return ResponseToPresenceInfo(sessionResponse);
223  }
224 
225  public PresenceInfo[] GetAgents(string[] userIDs)
226  {
227  List<PresenceInfo> presences = new List<PresenceInfo>();
228 
229  NameValueCollection requestArgs = new NameValueCollection
230  {
231  { "RequestMethod", "GetSessions" },
232  { "UserIDList", String.Join(",",userIDs) }
233  };
234 
235  OSDMap sessionListResponse = SimianGrid.PostToService(m_serverUrl, requestArgs);
236  if (! sessionListResponse["Success"].AsBoolean())
237  {
238  m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve sessions: {0}",sessionListResponse["Message"].AsString());
239  return null;
240  }
241 
242  OSDArray sessionList = sessionListResponse["Sessions"] as OSDArray;
243  for (int i = 0; i < sessionList.Count; i++)
244  {
245  OSDMap sessionInfo = sessionList[i] as OSDMap;
246  presences.Add(ResponseToPresenceInfo(sessionInfo));
247  }
248 
249  return presences.ToArray();
250  }
251 
252  #endregion IPresenceService
253 
254  #region IGridUserService
255 
256  public GridUserInfo LoggedIn(string userID)
257  {
258  // Never implemented at the sim
259  return null;
260  }
261 
262  public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
263  {
264  // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID);
265 
266  // Remove the session to mark this user offline
267  if (!LogoutAgent(sessionID))
268  return false;
269 
270  // Save our last position as user data
271  NameValueCollection requestArgs = new NameValueCollection
272  {
273  { "RequestMethod", "AddUserData" },
274  { "UserID", userID.ToString() },
275  { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) }
276  };
277 
278  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
279  bool success = response["Success"].AsBoolean();
280 
281  if (!success)
282  m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to set last location for " + userID + ": " + response["Message"].AsString());
283 
284  return success;
285  }
286 
287  public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
288  {
289  // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID);
290 
291  NameValueCollection requestArgs = new NameValueCollection
292  {
293  { "RequestMethod", "AddUserData" },
294  { "UserID", userID.ToString() },
295  { "HomeLocation", SerializeLocation(regionID, position, lookAt) }
296  };
297 
298  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
299  bool success = response["Success"].AsBoolean();
300 
301  if (!success)
302  m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to set home location for " + userID + ": " + response["Message"].AsString());
303 
304  return success;
305  }
306 
307  public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
308  {
309  return UpdateSession(sessionID, regionID, lastPosition, lastLookAt);
310  }
311 
312  public GridUserInfo GetGridUserInfo(string user)
313  {
314  // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user);
315 
316  UUID userID = new UUID(user);
317  OSDMap userResponse = GetUserData(userID);
318 
319  if (userResponse == null)
320  {
321  m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}", userID);
322  }
323 
324  // Note that ResponseToGridUserInfo properly checks for and returns a null if passed a null.
325  return ResponseToGridUserInfo(userResponse);
326 
327  }
328 
329  #endregion
330 
331  #region Helpers
332 
333  private OSDMap GetUserData(UUID userID)
334  {
335  // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID);
336 
337  NameValueCollection requestArgs = new NameValueCollection
338  {
339  { "RequestMethod", "GetUser" },
340  { "UserID", userID.ToString() }
341  };
342 
343  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
344  if (response["Success"].AsBoolean() && response["User"] is OSDMap)
345  return response;
346 
347  m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}; {1}",userID.ToString(),response["Message"].AsString());
348  return null;
349  }
350 
351  private OSDMap GetSessionDataFromSessionID(UUID sessionID)
352  {
353  NameValueCollection requestArgs = new NameValueCollection
354  {
355  { "RequestMethod", "GetSession" },
356  { "SessionID", sessionID.ToString() }
357  };
358 
359  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
360  if (response["Success"].AsBoolean())
361  return response;
362 
363  m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session data for {0}; {1}",sessionID.ToString(),response["Message"].AsString());
364  return null;
365  }
366 
367  private bool UpdateSession(UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
368  {
369  // Save our current location as session data
370  NameValueCollection requestArgs = new NameValueCollection
371  {
372  { "RequestMethod", "UpdateSession" },
373  { "SessionID", sessionID.ToString() },
374  { "SceneID", regionID.ToString() },
375  { "ScenePosition", lastPosition.ToString() },
376  { "SceneLookAt", lastLookAt.ToString() }
377  };
378 
379  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
380  bool success = response["Success"].AsBoolean();
381 
382  if (!success)
383  m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to update agent session " + sessionID + ": " + response["Message"].AsString());
384 
385  return success;
386  }
387 
388  private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse)
389  {
390  if (sessionResponse == null)
391  return null;
392 
393  PresenceInfo info = new PresenceInfo();
394 
395  info.UserID = sessionResponse["UserID"].AsUUID().ToString();
396  info.RegionID = sessionResponse["SceneID"].AsUUID();
397 
398  return info;
399  }
400 
401  private GridUserInfo ResponseToGridUserInfo(OSDMap userResponse)
402  {
403  if (userResponse != null && userResponse["User"] is OSDMap)
404  {
405  GridUserInfo info = new GridUserInfo();
406 
407  info.Online = true;
408  info.UserID = userResponse["UserID"].AsUUID().ToString();
409  info.LastRegionID = userResponse["SceneID"].AsUUID();
410  info.LastPosition = userResponse["ScenePosition"].AsVector3();
411  info.LastLookAt = userResponse["SceneLookAt"].AsVector3();
412 
413  OSDMap user = (OSDMap)userResponse["User"];
414 
415  info.Login = user["LastLoginDate"].AsDate();
416  info.Logout = user["LastLogoutDate"].AsDate();
417  DeserializeLocation(user["HomeLocation"].AsString(), out info.HomeRegionID, out info.HomePosition, out info.HomeLookAt);
418 
419  return info;
420  }
421 
422  return null;
423  }
424 
425  private string SerializeLocation(UUID regionID, Vector3 position, Vector3 lookAt)
426  {
427  return "{" + String.Format("\"SceneID\":\"{0}\",\"Position\":\"{1}\",\"LookAt\":\"{2}\"", regionID, position, lookAt) + "}";
428  }
429 
430  private bool DeserializeLocation(string location, out UUID regionID, out Vector3 position, out Vector3 lookAt)
431  {
432  OSDMap map = null;
433 
434  try { map = OSDParser.DeserializeJson(location) as OSDMap; }
435  catch { }
436 
437  if (map != null)
438  {
439  regionID = map["SceneID"].AsUUID();
440  if (Vector3.TryParse(map["Position"].AsString(), out position) &&
441  Vector3.TryParse(map["LookAt"].AsString(), out lookAt))
442  {
443  return true;
444  }
445  }
446 
447  regionID = UUID.Zero;
448  position = Vector3.Zero;
449  lookAt = Vector3.Zero;
450  return false;
451  }
452 
453  public GridUserInfo[] GetGridUserInfo(string[] userIDs)
454  {
455  return new GridUserInfo[0];
456  }
457  #endregion Helpers
458  }
459 }
void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
Connects avatar presence information (for tracking current location and message routing) to the Simia...
bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
Stores the last known user position at the grid level
OpenSim.Services.Interfaces.PresenceInfo PresenceInfo
OpenMetaverse.StructuredData.OSDArray OSDArray
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
OpenMetaverse.StructuredData.OSDMap OSDMap
PresenceInfo GetAgent(UUID sessionID)
Get session information for a given session ID.
bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
Informs the grid that a user is logged out and to remove any session data for them ...
Records user information specific to a grid but which is not part of a user's account.
bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID)
Store session information.
bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
bool LogoutRegionAgents(UUID regionID)
Remove session information for all agents in the given region.
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
bool ReportAgent(UUID sessionID, UUID regionID)
Update data for an existing session.
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
PresenceInfo[] GetAgents(string[] userIDs)
Get session information for a collection of users.
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...