From 24f28d353427d1905ae1a46408841265379e29c3 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 23 May 2011 19:45:39 -0700 Subject: HG friends: Status notifications working. Also initial logins get the online friends in other grids. --- .../Hypergrid/UserAgentServiceConnector.cs | 91 +++++++++++ .../Services/HypergridService/UserAgentService.cs | 172 ++++++++++++++++++++- OpenSim/Services/Interfaces/IGatekeeperService.cs | 3 + .../Services/Interfaces/ISimulatorSocialService.cs | 40 +++++ 4 files changed, 303 insertions(+), 3 deletions(-) create mode 100644 OpenSim/Services/Interfaces/ISimulatorSocialService.cs (limited to 'OpenSim/Services') diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs index c40a347..46d30df 100644 --- a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs @@ -404,6 +404,97 @@ namespace OpenSim.Services.Connectors.Hypergrid GetBoolResponse(request, out reason); } + public void StatusNotification(List friends, UUID userID, bool online) + { + Hashtable hash = new Hashtable(); + hash["userID"] = userID.ToString(); + hash["online"] = online.ToString(); + int i = 0; + foreach (string s in friends) + { + hash["friend_" + i.ToString()] = s; + i++; + } + + IList paramList = new ArrayList(); + paramList.Add(hash); + + XmlRpcRequest request = new XmlRpcRequest("status_notification", paramList); + string reason = string.Empty; + GetBoolResponse(request, out reason); + + } + + public List GetOnlineFriends(UUID userID, List friends) + { + Hashtable hash = new Hashtable(); + hash["userID"] = userID.ToString(); + int i = 0; + foreach (string s in friends) + { + hash["friend_" + i.ToString()] = s; + i++; + } + + IList paramList = new ArrayList(); + paramList.Add(hash); + + XmlRpcRequest request = new XmlRpcRequest("get_online_friends", paramList); + string reason = string.Empty; + + // Send and get reply + List online = new List(); + XmlRpcResponse response = null; + try + { + response = request.Send(m_ServerURL, 10000); + } + catch (Exception e) + { + m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0}", m_ServerURL); + reason = "Exception: " + e.Message; + return online; + } + + if (response.IsFault) + { + m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} returned an error: {1}", m_ServerURL, response.FaultString); + reason = "XMLRPC Fault"; + return online; + } + + hash = (Hashtable)response.Value; + //foreach (Object o in hash) + // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); + try + { + if (hash == null) + { + m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got null response from {0}! THIS IS BAAAAD", m_ServerURL); + reason = "Internal error 1"; + return online; + } + + // Here is the actual response + foreach (object key in hash.Keys) + { + if (key is string && ((string)key).StartsWith("friend_") && hash[key] != null) + { + UUID uuid; + if (UUID.TryParse(hash[key].ToString(), out uuid)) + online.Add(uuid); + } + } + + } + catch (Exception e) + { + m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on GetOnlineFriends response."); + reason = "Exception: " + e.Message; + } + + return online; + } private bool GetBoolResponse(XmlRpcRequest request, out string reason) { diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs index 445d45e..0181533 100644 --- a/OpenSim/Services/HypergridService/UserAgentService.cs +++ b/OpenSim/Services/HypergridService/UserAgentService.cs @@ -31,10 +31,12 @@ using System.Net; using System.Reflection; using OpenSim.Framework; +using OpenSim.Services.Connectors.Friends; using OpenSim.Services.Connectors.Hypergrid; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Server.Base; +using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; using OpenMetaverse; using log4net; @@ -63,19 +65,34 @@ namespace OpenSim.Services.HypergridService protected static IGridService m_GridService; protected static GatekeeperServiceConnector m_GatekeeperConnector; protected static IGatekeeperService m_GatekeeperService; + protected static IFriendsService m_FriendsService; + protected static IPresenceService m_PresenceService; + protected static IFriendsSimConnector m_FriendsLocalSimConnector; // standalone, points to HGFriendsModule + protected static FriendsSimConnector m_FriendsSimConnector; // grid protected static string m_GridName; protected static bool m_BypassClientVerification; - public UserAgentService(IConfigSource config) + public UserAgentService(IConfigSource config) : this(config, null) { + } + + public UserAgentService(IConfigSource config, IFriendsSimConnector friendsConnector) + { + // Let's set this always, because we don't know the sequence + // of instantiations + if (friendsConnector != null) + m_FriendsLocalSimConnector = friendsConnector; + if (!m_Initialized) { m_Initialized = true; m_log.DebugFormat("[HOME USERS SECURITY]: Starting..."); - + + m_FriendsSimConnector = new FriendsSimConnector(); + IConfig serverConfig = config.Configs["UserAgentService"]; if (serverConfig == null) throw new Exception(String.Format("No section UserAgentService in config file")); @@ -83,6 +100,8 @@ namespace OpenSim.Services.HypergridService string gridService = serverConfig.GetString("GridService", String.Empty); string gridUserService = serverConfig.GetString("GridUserService", String.Empty); string gatekeeperService = serverConfig.GetString("GatekeeperService", String.Empty); + string friendsService = serverConfig.GetString("FriendsService", String.Empty); + string presenceService = serverConfig.GetString("PresenceService", String.Empty); m_BypassClientVerification = serverConfig.GetBoolean("BypassClientVerification", false); @@ -94,6 +113,8 @@ namespace OpenSim.Services.HypergridService m_GridUserService = ServerUtils.LoadPlugin(gridUserService, args); m_GatekeeperConnector = new GatekeeperServiceConnector(); m_GatekeeperService = ServerUtils.LoadPlugin(gatekeeperService, args); + m_FriendsService = ServerUtils.LoadPlugin(friendsService, args); + m_PresenceService = ServerUtils.LoadPlugin(presenceService, args); m_GridName = serverConfig.GetString("ExternalName", string.Empty); if (m_GridName == string.Empty) @@ -156,11 +177,16 @@ namespace OpenSim.Services.HypergridService string gridName = gatekeeper.ServerURI; m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}", m_GridName, gridName); - + if (m_GridName == gridName) success = m_GatekeeperService.LoginAgent(agentCircuit, finalDestination, out reason); else + { success = m_GatekeeperConnector.CreateAgent(region, agentCircuit, (uint)Constants.TeleportFlags.ViaLogin, out myExternalIP, out reason); + if (success) + // Report them as nowhere + m_PresenceService.ReportAgent(agentCircuit.SessionID, UUID.Zero); + } if (!success) { @@ -179,6 +205,7 @@ namespace OpenSim.Services.HypergridService if (clientIP != null) m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress = clientIP.Address.ToString(); m_TravelingAgents[agentCircuit.SessionID].MyIpAddress = myExternalIP; + return true; } @@ -291,6 +318,145 @@ namespace OpenSim.Services.HypergridService return false; } + public void StatusNotification(List friends, UUID foreignUserID, bool online) + { + if (m_FriendsService == null || m_PresenceService == null) + { + m_log.WarnFormat("[USER AGENT SERVICE]: Unable to perform status notifications because friends or presence services are missing"); + return; + } + + m_log.DebugFormat("[USER AGENT SERVICE]: Status notification: foreign user {0} wants to notify {1} local friends", foreignUserID, friends.Count); + + // 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("[USER AGENT 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, friendSession.UserID, foreignUserID, online); + usersToBeNotified.Remove(friendSession.UserID.ToString()); + } + } + + // Lastly, let's notify the rest who may be online somewhere else + foreach (string user in usersToBeNotified) + { + UUID id = new UUID(user); + if (m_TravelingAgents.ContainsKey(id) && m_TravelingAgents[id].GridExternalName != m_GridName) + { + string url = m_TravelingAgents[id].GridExternalName; + // forward + m_log.WarnFormat("[USER AGENT SERVICE]: User {0} is visiting {1}. HG Status notifications still not implemented.", user, url); + } + } + } + + protected void ForwardStatusNotificationToSim(UUID regionID, string user, UUID foreignUserID, bool online) + { + UUID userID; + if (UUID.TryParse(user, out userID)) + { + if (m_FriendsLocalSimConnector != null) + { + m_log.DebugFormat("[USER AGENT SERVICE]: Local Notify, user {0} is {1}", foreignUserID, (online ? "online" : "offline")); + m_FriendsLocalSimConnector.StatusNotify(userID, foreignUserID, online); + } + else + { + GridRegion region = m_GridService.GetRegionByUUID(UUID.Zero /* !!! */, regionID); + if (region != null) + { + m_log.DebugFormat("[USER AGENT SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, user, foreignUserID, (online ? "online" : "offline")); + m_FriendsSimConnector.StatusNotify(region, userID, foreignUserID, online); + } + } + } + } + + public List GetOnlineFriends(UUID foreignUserID, List friends) + { + List online = new List(); + + if (m_FriendsService == null || m_PresenceService == null) + { + m_log.WarnFormat("[USER AGENT SERVICE]: Unable to get online friends because friends or presence services are missing"); + return online; + } + + m_log.DebugFormat("[USER AGENT SERVICE]: Foreign user {0} wants to know status of {1} local friends", foreignUserID, friends.Count); + + // First, let's double check that the reported friends are, indeed, friends of that user + // And let's check that the secret matches and the rights + 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) && + (finfo.TheirFlags & (int)FriendRights.CanSeeOnline) != 0 && (finfo.TheirFlags != -1)) + { + // great! + usersToBeNotified.Add(localUserID.ToString()); + } + } + } + } + + // Now, let's find out their status + m_log.DebugFormat("[USER AGENT SERVICE]: GetOnlineFriends: user has {0} local friends with status rights", 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) + { + foreach (PresenceInfo pi in friendSessions) + { + UUID presenceID; + if (UUID.TryParse(pi.UserID, out presenceID)) + online.Add(presenceID); + } + } + + return online; + } } class TravelingAgentInfo diff --git a/OpenSim/Services/Interfaces/IGatekeeperService.cs b/OpenSim/Services/Interfaces/IGatekeeperService.cs index aac8293..fa1ab1c 100644 --- a/OpenSim/Services/Interfaces/IGatekeeperService.cs +++ b/OpenSim/Services/Interfaces/IGatekeeperService.cs @@ -55,6 +55,9 @@ namespace OpenSim.Services.Interfaces void LogoutAgent(UUID userID, UUID sessionID); GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt); + void StatusNotification(List friends, UUID userID, bool online); + List GetOnlineFriends(UUID userID, List friends); + bool AgentIsComingHome(UUID sessionID, string thisGridExternalName); bool VerifyAgent(UUID sessionID, string token); bool VerifyClient(UUID sessionID, string reportedIP); diff --git a/OpenSim/Services/Interfaces/ISimulatorSocialService.cs b/OpenSim/Services/Interfaces/ISimulatorSocialService.cs new file mode 100644 index 0000000..0b7aefc --- /dev/null +++ b/OpenSim/Services/Interfaces/ISimulatorSocialService.cs @@ -0,0 +1,40 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenSim.Framework; +using OpenMetaverse; + +using GridRegion = OpenSim.Services.Interfaces.GridRegion; + +namespace OpenSim.Services.Interfaces +{ + public interface IFriendsSimConnector + { + bool StatusNotify(UUID userID, UUID friendID, bool online); + } +} -- cgit v1.1