From 4a9ca3ca8ff18f4fcf05c3983db5e6b1d49c97ee Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 21 Mar 2012 10:35:06 -0700 Subject: [PATCH] HG Friends: reroute the status notifications to the HGFriends service, so that they can scale better. They were previously being handled by the UAS; that is still there, but it's now obsolete and will be removed in a future release. --- .../Avatar/Friends/HGFriendsModule.cs | 2 +- .../Avatar/Friends/HGStatusNotifier.cs | 31 ++++- .../Hypergrid/HGFriendsServerPostHandler.cs | 56 +++++++++ .../Hypergrid/UserAgentServerConnector.cs | 1 + .../Hypergrid/HGFriendsServiceConnector.cs | 52 +++++++++ .../Hypergrid/UserAgentServiceConnector.cs | 1 + .../HypergridService/HGFriendsService.cs | 107 ++++++++++++++++++ .../HypergridService/UserAgentService.cs | 2 + .../Services/Interfaces/IHypergridServices.cs | 4 +- 9 files changed, 248 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index f50e52b8fa..e50a84a76e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs @@ -51,7 +51,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); IUserManagement m_uMan; - IUserManagement UserManagementModule + public IUserManagement UserManagementModule { get { diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGStatusNotifier.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGStatusNotifier.cs index 62d54e4f65..61c6a30113 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGStatusNotifier.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGStatusNotifier.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; @@ -10,10 +11,14 @@ using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; using OpenMetaverse; +using log4net; + namespace OpenSim.Region.CoreModules.Avatar.Friends { public class HGStatusNotifier { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private HGFriendsModule m_FriendsModule; public HGStatusNotifier(HGFriendsModule friendsModule) @@ -31,14 +36,28 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends List ids = new List(); foreach (FriendInfo f in kvp.Value) ids.Add(f.Friend); - UserAgentServiceConnector uConn = new UserAgentServiceConnector(kvp.Key); - List friendsOnline = uConn.StatusNotification(ids, userID, online); - if (online && friendsOnline.Count > 0) + if (ids.Count == 0) + continue; // no one to notify. caller don't do this + + m_log.DebugFormat("[HG STATUS NOTIFIER]: Notifying {0} friends in {1}", ids.Count, kvp.Key); + // ASSUMPTION: we assume that all users for one home domain + // have exactly the same set of service URLs. + // If this is ever not true, we need to change this. + UUID friendID = UUID.Zero; String tmp = String.Empty; + if (Util.ParseUniversalUserIdentifier(ids[0], out friendID, out tmp, out tmp, out tmp, out tmp)) { - IClientAPI client = m_FriendsModule.LocateClientObject(userID); - if (client != null) - client.SendAgentOnline(friendsOnline.ToArray()); + string friendsServerURI = m_FriendsModule.UserManagementModule.GetUserServerURL(friendID, "FriendsServerURI"); + HGFriendsServicesConnector fConn = new HGFriendsServicesConnector(friendsServerURI); + + List friendsOnline = fConn.StatusNotification(ids, userID, online); + + if (online && friendsOnline.Count > 0) + { + IClientAPI client = m_FriendsModule.LocateClientObject(userID); + if (client != null) + client.SendAgentOnline(friendsOnline.ToArray()); + } } } } diff --git a/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs b/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs index e0876cd5b9..8ef03e7a71 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs @@ -105,6 +105,9 @@ namespace OpenSim.Server.Handlers.Hypergrid case "validate_friendship_offered": return ValidateFriendshipOffered(request); + + case "statusnotification": + return StatusNotification(request); /* case "friendship_approved": return FriendshipApproved(request); @@ -228,6 +231,59 @@ namespace OpenSim.Server.Handlers.Hypergrid return BoolResult(success); } + byte[] StatusNotification(Dictionary request) + { + UUID principalID = UUID.Zero; + if (request.ContainsKey("userID")) + UUID.TryParse(request["userID"].ToString(), out principalID); + else + { + m_log.WarnFormat("[HGFRIENDS HANDLER]: no userID in request to notify"); + return FailureResult(); + } + + bool online = true; + if (request.ContainsKey("online")) + Boolean.TryParse(request["online"].ToString(), out online); + else + { + m_log.WarnFormat("[HGFRIENDS HANDLER]: no online in request to notify"); + return FailureResult(); + } + + List friends = new List(); + int i = 0; + foreach (KeyValuePair kvp in request) + { + if (kvp.Key.Equals("friend_" + i.ToString())) + { + friends.Add(kvp.Value.ToString()); + i++; + } + } + + List onlineFriends = m_TheService.StatusNotification(friends, principalID, online); + + Dictionary result = new Dictionary(); + if ((onlineFriends == null) || ((onlineFriends != null) && (onlineFriends.Count == 0))) + result["RESULT"] = "NULL"; + else + { + i = 0; + foreach (UUID f in onlineFriends) + { + result["friend_" + i] = f.ToString(); + i++; + } + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); + UTF8Encoding encoding = new UTF8Encoding(); + return encoding.GetBytes(xmlString); + + } + #endregion diff --git a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs index 9a0e27e2f1..db62aaa1d5 100644 --- a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs @@ -222,6 +222,7 @@ namespace OpenSim.Server.Handlers.Hypergrid } + [Obsolete] public XmlRpcResponse StatusNotification(XmlRpcRequest request, IPEndPoint remoteClient) { Hashtable hash = new Hashtable(); diff --git a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs index e3f326037c..e984a544fd 100644 --- a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs @@ -255,6 +255,58 @@ namespace OpenSim.Services.Connectors.Hypergrid return false; } + + public List StatusNotification(List friends, UUID userID, bool online) + { + Dictionary sendData = new Dictionary(); + List friendsOnline = new List(); + + sendData["METHOD"] = "statusnotification"; + sendData["userID"] = userID.ToString(); + sendData["online"] = online.ToString(); + int i = 0; + foreach (string s in friends) + { + sendData["friend_" + i.ToString()] = s; + i++; + } + + string reply = string.Empty; + string uri = m_ServerURI + "/hgfriends"; + try + { + reply = SynchronousRestFormsRequester.MakeRequest("POST", + uri, + ServerUtils.BuildQueryString(sendData)); + } + catch (Exception e) + { + m_log.DebugFormat("[HGFRIENDS CONNECTOR]: Exception when contacting friends server at {0}: {1}", uri, e.Message); + return friendsOnline; + } + + if (reply != string.Empty) + { + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + // Here is the actual response + foreach (string key in replyData.Keys) + { + if (key.StartsWith("friend_") && replyData[key] != null) + { + UUID uuid; + if (UUID.TryParse(replyData[key].ToString(), out uuid)) + friendsOnline.Add(uuid); + } + } + } + else + m_log.DebugFormat("[HGFRIENDS CONNECTOR]: Received empty reply from remote StatusNotify"); + + return friendsOnline; + + } + #endregion } } \ No newline at end of file diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs index bf86035f6a..2f263ae127 100644 --- a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs @@ -417,6 +417,7 @@ namespace OpenSim.Services.Connectors.Hypergrid GetBoolResponse(request, out reason); } + [Obsolete] public List StatusNotification(List friends, UUID userID, bool online) { Hashtable hash = new Hashtable(); diff --git a/OpenSim/Services/HypergridService/HGFriendsService.cs b/OpenSim/Services/HypergridService/HGFriendsService.cs index 19ee3e27f9..39524ab93e 100644 --- a/OpenSim/Services/HypergridService/HGFriendsService.cs +++ b/OpenSim/Services/HypergridService/HGFriendsService.cs @@ -214,6 +214,91 @@ namespace OpenSim.Services.HypergridService return false; } + public List StatusNotification(List friends, UUID foreignUserID, bool online) + { + if (m_FriendsService == null || m_PresenceService == null) + { + m_log.WarnFormat("[HGFRIENDS SERVICE]: Unable to perform status notifications because friends or presence services are missing"); + return new List(); + } + + // Let's unblock the caller right now, and take it from here async + + List localFriendsOnline = new List(); + + m_log.DebugFormat("[HGFRIENDS SERVICE]: Status notification: foreign user {0} wants to notify {1} local friends of {2} status", + foreignUserID, friends.Count, (online ? "online" : "offline")); + + // First, let's double check that the reported friends are, indeed, friends of that user + // And let's check that the secret matches + List usersToBeNotified = new List(); + foreach (string uui in friends) + { + UUID localUserID; + string secret = string.Empty, tmp = string.Empty; + if (Util.ParseUniversalUserIdentifier(uui, out localUserID, out tmp, out tmp, out tmp, out secret)) + { + FriendInfo[] friendInfos = m_FriendsService.GetFriends(localUserID); + foreach (FriendInfo finfo in friendInfos) + { + if (finfo.Friend.StartsWith(foreignUserID.ToString()) && finfo.Friend.EndsWith(secret)) + { + // great! + usersToBeNotified.Add(localUserID.ToString()); + } + } + } + } + + // Now, let's send the notifications + //m_log.DebugFormat("[HGFRIENDS SERVICE]: Status notification: user has {0} local friends", usersToBeNotified.Count); + + // First, let's send notifications to local users who are online in the home grid + PresenceInfo[] friendSessions = m_PresenceService.GetAgents(usersToBeNotified.ToArray()); + if (friendSessions != null && friendSessions.Length > 0) + { + PresenceInfo friendSession = null; + foreach (PresenceInfo pinfo in friendSessions) + if (pinfo.RegionID != UUID.Zero) // let's guard against traveling agents + { + friendSession = pinfo; + break; + } + + if (friendSession != null) + { + ForwardStatusNotificationToSim(friendSession.RegionID, foreignUserID, friendSession.UserID, online); + usersToBeNotified.Remove(friendSession.UserID.ToString()); + UUID id; + if (UUID.TryParse(friendSession.UserID, out id)) + localFriendsOnline.Add(id); + + } + } + + // Lastly, let's notify the rest who may be online somewhere else + foreach (string user in usersToBeNotified) + { + UUID id = new UUID(user); + //m_UserAgentService.LocateUser(id); + //etc... + //if (m_TravelingAgents.ContainsKey(id) && m_TravelingAgents[id].GridExternalName != m_GridName) + //{ + // string url = m_TravelingAgents[id].GridExternalName; + // // forward + //} + //m_log.WarnFormat("[HGFRIENDS SERVICE]: User {0} is visiting another grid. HG Status notifications still not implemented.", user); + } + + // and finally, let's send the online friends + if (online) + { + return localFriendsOnline; + } + else + return new List(); + } + #endregion IHGFriendsService #region Aux @@ -296,6 +381,28 @@ namespace OpenSim.Services.HypergridService return false; } + protected void ForwardStatusNotificationToSim(UUID regionID, UUID foreignUserID, string user, bool online) + { + UUID userID; + if (UUID.TryParse(user, out userID)) + { + if (m_FriendsLocalSimConnector != null) + { + m_log.DebugFormat("[HGFRIENDS SERVICE]: Local Notify, user {0} is {1}", foreignUserID, (online ? "online" : "offline")); + m_FriendsLocalSimConnector.StatusNotify(foreignUserID, userID, online); + } + else + { + GridRegion region = m_GridService.GetRegionByUUID(UUID.Zero /* !!! */, regionID); + if (region != null) + { + m_log.DebugFormat("[HGFRIENDS SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, foreignUserID, (online ? "online" : "offline")); + m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID, online); + } + } + } + } + #endregion Aux } } diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs index 5eca801deb..6a5007ff26 100644 --- a/OpenSim/Services/HypergridService/UserAgentService.cs +++ b/OpenSim/Services/HypergridService/UserAgentService.cs @@ -334,6 +334,7 @@ namespace OpenSim.Services.HypergridService return false; } + [Obsolete] public List StatusNotification(List friends, UUID foreignUserID, bool online) { if (m_FriendsService == null || m_PresenceService == null) @@ -414,6 +415,7 @@ namespace OpenSim.Services.HypergridService return new List(); } + [Obsolete] protected void ForwardStatusNotificationToSim(UUID regionID, UUID foreignUserID, string user, bool online) { UUID userID; diff --git a/OpenSim/Services/Interfaces/IHypergridServices.cs b/OpenSim/Services/Interfaces/IHypergridServices.cs index f48b8a9a76..3dc877a870 100644 --- a/OpenSim/Services/Interfaces/IHypergridServices.cs +++ b/OpenSim/Services/Interfaces/IHypergridServices.cs @@ -65,8 +65,8 @@ namespace OpenSim.Services.Interfaces UUID GetUUID(String first, String last); // Returns the local friends online + [Obsolete] List StatusNotification(List friends, UUID userID, bool online); - //List GetOnlineFriends(UUID userID, List friends); bool IsAgentComingHome(UUID sessionID, string thisGridExternalName); bool VerifyAgent(UUID sessionID, string token); @@ -92,6 +92,8 @@ namespace OpenSim.Services.Interfaces bool DeleteFriendship(FriendInfo finfo, string secret); bool FriendshipOffered(UUID from, string fromName, UUID to, string message); bool ValidateFriendshipOffered(UUID fromID, UUID toID); + // Returns the local friends online + List StatusNotification(List friends, UUID userID, bool online); } public interface IInstantMessageSimConnector