SimianPresenceServiceConnector.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  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. using System;
  28. using System.Collections.Generic;
  29. using System.Collections.Specialized;
  30. using System.Reflection;
  31. using log4net;
  32. using Mono.Addins;
  33. using Nini.Config;
  34. using OpenSim.Framework;
  35. using OpenSim.Region.Framework.Interfaces;
  36. using OpenSim.Region.Framework.Scenes;
  37. using OpenSim.Services.Interfaces;
  38. using OpenMetaverse;
  39. using OpenMetaverse.StructuredData;
  40. using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
  41. namespace OpenSim.Services.Connectors.SimianGrid
  42. {
  43. /// <summary>
  44. /// Connects avatar presence information (for tracking current location and
  45. /// message routing) to the SimianGrid backend
  46. /// </summary>
  47. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianPresenceServiceConnector")]
  48. public class SimianPresenceServiceConnector : IPresenceService, IGridUserService, ISharedRegionModule
  49. {
  50. private static readonly ILog m_log =
  51. LogManager.GetLogger(
  52. MethodBase.GetCurrentMethod().DeclaringType);
  53. private string m_serverUrl = String.Empty;
  54. private SimianActivityDetector m_activityDetector;
  55. private bool m_Enabled = false;
  56. #region ISharedRegionModule
  57. public Type ReplaceableInterface { get { return null; } }
  58. public void RegionLoaded(Scene scene) { }
  59. public void PostInitialise() { }
  60. public void Close() { }
  61. public SimianPresenceServiceConnector() { }
  62. public string Name { get { return "SimianPresenceServiceConnector"; } }
  63. public void AddRegion(Scene scene)
  64. {
  65. if (m_Enabled)
  66. {
  67. scene.RegisterModuleInterface<IPresenceService>(this);
  68. scene.RegisterModuleInterface<IGridUserService>(this);
  69. m_activityDetector.AddRegion(scene);
  70. LogoutRegionAgents(scene.RegionInfo.RegionID);
  71. }
  72. }
  73. public void RemoveRegion(Scene scene)
  74. {
  75. if (m_Enabled)
  76. {
  77. scene.UnregisterModuleInterface<IPresenceService>(this);
  78. scene.UnregisterModuleInterface<IGridUserService>(this);
  79. m_activityDetector.RemoveRegion(scene);
  80. LogoutRegionAgents(scene.RegionInfo.RegionID);
  81. }
  82. }
  83. #endregion ISharedRegionModule
  84. public SimianPresenceServiceConnector(IConfigSource source)
  85. {
  86. CommonInit(source);
  87. }
  88. public void Initialise(IConfigSource source)
  89. {
  90. IConfig moduleConfig = source.Configs["Modules"];
  91. if (moduleConfig != null)
  92. {
  93. string name = moduleConfig.GetString("PresenceServices", "");
  94. if (name == Name)
  95. CommonInit(source);
  96. }
  97. }
  98. private void CommonInit(IConfigSource source)
  99. {
  100. IConfig gridConfig = source.Configs["PresenceService"];
  101. if (gridConfig != null)
  102. {
  103. string serviceUrl = gridConfig.GetString("PresenceServerURI");
  104. if (!String.IsNullOrEmpty(serviceUrl))
  105. {
  106. if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
  107. serviceUrl = serviceUrl + '/';
  108. m_serverUrl = serviceUrl;
  109. m_activityDetector = new SimianActivityDetector(this);
  110. m_Enabled = true;
  111. }
  112. }
  113. if (String.IsNullOrEmpty(m_serverUrl))
  114. m_log.Info("[SIMIAN PRESENCE CONNECTOR]: No PresenceServerURI specified, disabling connector");
  115. }
  116. #region IPresenceService
  117. public bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID)
  118. {
  119. m_log.ErrorFormat("[SIMIAN PRESENCE CONNECTOR]: Login requested, UserID={0}, SessionID={1}, SecureSessionID={2}",
  120. userID, sessionID, secureSessionID);
  121. NameValueCollection requestArgs = new NameValueCollection
  122. {
  123. { "RequestMethod", "AddSession" },
  124. { "UserID", userID.ToString() }
  125. };
  126. if (sessionID != UUID.Zero)
  127. {
  128. requestArgs["SessionID"] = sessionID.ToString();
  129. requestArgs["SecureSessionID"] = secureSessionID.ToString();
  130. }
  131. OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
  132. bool success = response["Success"].AsBoolean();
  133. if (!success)
  134. m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to login agent " + userID + ": " + response["Message"].AsString());
  135. return success;
  136. }
  137. public bool LogoutAgent(UUID sessionID)
  138. {
  139. // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID);
  140. NameValueCollection requestArgs = new NameValueCollection
  141. {
  142. { "RequestMethod", "RemoveSession" },
  143. { "SessionID", sessionID.ToString() }
  144. };
  145. OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
  146. bool success = response["Success"].AsBoolean();
  147. if (!success)
  148. m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to logout agent with sessionID " + sessionID + ": " + response["Message"].AsString());
  149. return success;
  150. }
  151. public bool LogoutRegionAgents(UUID regionID)
  152. {
  153. // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID);
  154. NameValueCollection requestArgs = new NameValueCollection
  155. {
  156. { "RequestMethod", "RemoveSessions" },
  157. { "SceneID", regionID.ToString() }
  158. };
  159. OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
  160. bool success = response["Success"].AsBoolean();
  161. if (!success)
  162. m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to logout agents from region " + regionID + ": " + response["Message"].AsString());
  163. return success;
  164. }
  165. public bool ReportAgent(UUID sessionID, UUID regionID)
  166. {
  167. // Not needed for SimianGrid
  168. return true;
  169. }
  170. public PresenceInfo GetAgent(UUID sessionID)
  171. {
  172. OSDMap sessionResponse = GetSessionDataFromSessionID(sessionID);
  173. if (sessionResponse == null)
  174. {
  175. m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session {0}: {1}",sessionID.ToString(),sessionResponse["Message"].AsString());
  176. return null;
  177. }
  178. UUID userID = sessionResponse["UserID"].AsUUID();
  179. OSDMap userResponse = GetUserData(userID);
  180. if (userResponse == null)
  181. {
  182. m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID.ToString(),userResponse["Message"].AsString());
  183. return null;
  184. }
  185. return ResponseToPresenceInfo(sessionResponse);
  186. }
  187. public PresenceInfo[] GetAgents(string[] userIDs)
  188. {
  189. List<PresenceInfo> presences = new List<PresenceInfo>();
  190. NameValueCollection requestArgs = new NameValueCollection
  191. {
  192. { "RequestMethod", "GetSessions" },
  193. { "UserIDList", String.Join(",",userIDs) }
  194. };
  195. OSDMap sessionListResponse = SimianGrid.PostToService(m_serverUrl, requestArgs);
  196. if (! sessionListResponse["Success"].AsBoolean())
  197. {
  198. m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve sessions: {0}",sessionListResponse["Message"].AsString());
  199. return null;
  200. }
  201. OSDArray sessionList = sessionListResponse["Sessions"] as OSDArray;
  202. for (int i = 0; i < sessionList.Count; i++)
  203. {
  204. OSDMap sessionInfo = sessionList[i] as OSDMap;
  205. presences.Add(ResponseToPresenceInfo(sessionInfo));
  206. }
  207. return presences.ToArray();
  208. }
  209. #endregion IPresenceService
  210. #region IGridUserService
  211. public GridUserInfo LoggedIn(string userID)
  212. {
  213. // Never implemented at the sim
  214. return null;
  215. }
  216. public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
  217. {
  218. // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID);
  219. // Remove the session to mark this user offline
  220. if (!LogoutAgent(sessionID))
  221. return false;
  222. // Save our last position as user data
  223. NameValueCollection requestArgs = new NameValueCollection
  224. {
  225. { "RequestMethod", "AddUserData" },
  226. { "UserID", userID.ToString() },
  227. { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) }
  228. };
  229. OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
  230. bool success = response["Success"].AsBoolean();
  231. if (!success)
  232. m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to set last location for " + userID + ": " + response["Message"].AsString());
  233. return success;
  234. }
  235. public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
  236. {
  237. // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID);
  238. NameValueCollection requestArgs = new NameValueCollection
  239. {
  240. { "RequestMethod", "AddUserData" },
  241. { "UserID", userID.ToString() },
  242. { "HomeLocation", SerializeLocation(regionID, position, lookAt) }
  243. };
  244. OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
  245. bool success = response["Success"].AsBoolean();
  246. if (!success)
  247. m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to set home location for " + userID + ": " + response["Message"].AsString());
  248. return success;
  249. }
  250. public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
  251. {
  252. return UpdateSession(sessionID, regionID, lastPosition, lastLookAt);
  253. }
  254. public GridUserInfo GetGridUserInfo(string user)
  255. {
  256. // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user);
  257. UUID userID = new UUID(user);
  258. OSDMap userResponse = GetUserData(userID);
  259. if (userResponse == null)
  260. {
  261. m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}", userID);
  262. }
  263. // Note that ResponseToGridUserInfo properly checks for and returns a null if passed a null.
  264. return ResponseToGridUserInfo(userResponse);
  265. }
  266. #endregion
  267. #region Helpers
  268. private OSDMap GetUserData(UUID userID)
  269. {
  270. // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID);
  271. NameValueCollection requestArgs = new NameValueCollection
  272. {
  273. { "RequestMethod", "GetUser" },
  274. { "UserID", userID.ToString() }
  275. };
  276. OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
  277. if (response["Success"].AsBoolean() && response["User"] is OSDMap)
  278. return response;
  279. m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}; {1}",userID.ToString(),response["Message"].AsString());
  280. return null;
  281. }
  282. private OSDMap GetSessionDataFromSessionID(UUID sessionID)
  283. {
  284. NameValueCollection requestArgs = new NameValueCollection
  285. {
  286. { "RequestMethod", "GetSession" },
  287. { "SessionID", sessionID.ToString() }
  288. };
  289. OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
  290. if (response["Success"].AsBoolean())
  291. return response;
  292. m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session data for {0}; {1}",sessionID.ToString(),response["Message"].AsString());
  293. return null;
  294. }
  295. private bool UpdateSession(UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
  296. {
  297. // Save our current location as session data
  298. NameValueCollection requestArgs = new NameValueCollection
  299. {
  300. { "RequestMethod", "UpdateSession" },
  301. { "SessionID", sessionID.ToString() },
  302. { "SceneID", regionID.ToString() },
  303. { "ScenePosition", lastPosition.ToString() },
  304. { "SceneLookAt", lastLookAt.ToString() }
  305. };
  306. OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
  307. bool success = response["Success"].AsBoolean();
  308. if (!success)
  309. m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to update agent session " + sessionID + ": " + response["Message"].AsString());
  310. return success;
  311. }
  312. private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse)
  313. {
  314. if (sessionResponse == null)
  315. return null;
  316. PresenceInfo info = new PresenceInfo();
  317. info.UserID = sessionResponse["UserID"].AsUUID().ToString();
  318. info.RegionID = sessionResponse["SceneID"].AsUUID();
  319. return info;
  320. }
  321. private GridUserInfo ResponseToGridUserInfo(OSDMap userResponse)
  322. {
  323. if (userResponse != null && userResponse["User"] is OSDMap)
  324. {
  325. GridUserInfo info = new GridUserInfo();
  326. info.Online = true;
  327. info.UserID = userResponse["UserID"].AsUUID().ToString();
  328. info.LastRegionID = userResponse["SceneID"].AsUUID();
  329. info.LastPosition = userResponse["ScenePosition"].AsVector3();
  330. info.LastLookAt = userResponse["SceneLookAt"].AsVector3();
  331. OSDMap user = (OSDMap)userResponse["User"];
  332. info.Login = user["LastLoginDate"].AsDate();
  333. info.Logout = user["LastLogoutDate"].AsDate();
  334. DeserializeLocation(user["HomeLocation"].AsString(), out info.HomeRegionID, out info.HomePosition, out info.HomeLookAt);
  335. return info;
  336. }
  337. return null;
  338. }
  339. private string SerializeLocation(UUID regionID, Vector3 position, Vector3 lookAt)
  340. {
  341. return "{" + String.Format("\"SceneID\":\"{0}\",\"Position\":\"{1}\",\"LookAt\":\"{2}\"", regionID, position, lookAt) + "}";
  342. }
  343. private bool DeserializeLocation(string location, out UUID regionID, out Vector3 position, out Vector3 lookAt)
  344. {
  345. OSDMap map = null;
  346. try { map = OSDParser.DeserializeJson(location) as OSDMap; }
  347. catch { }
  348. if (map != null)
  349. {
  350. regionID = map["SceneID"].AsUUID();
  351. if (Vector3.TryParse(map["Position"].AsString(), out position) &&
  352. Vector3.TryParse(map["LookAt"].AsString(), out lookAt))
  353. {
  354. return true;
  355. }
  356. }
  357. regionID = UUID.Zero;
  358. position = Vector3.Zero;
  359. lookAt = Vector3.Zero;
  360. return false;
  361. }
  362. public GridUserInfo[] GetGridUserInfo(string[] userIDs)
  363. {
  364. return new GridUserInfo[0];
  365. }
  366. #endregion Helpers
  367. }
  368. }