HG friends: Status notifications working. Also initial logins get the online friends in other grids.

bulletsim
Diva Canto 2011-05-23 19:45:39 -07:00
parent 336665e035
commit 24f28d3534
10 changed files with 603 additions and 53 deletions

View File

@ -139,7 +139,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
if (moduleConfig != null) if (moduleConfig != null)
{ {
string name = moduleConfig.GetString("FriendsModule", "FriendsModule"); string name = moduleConfig.GetString("FriendsModule", "FriendsModule");
m_log.DebugFormat("[XXX] {0} compared to {1}", name, Name);
if (name == Name) if (name == Name)
{ {
InitModule(config); InitModule(config);
@ -183,7 +182,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
{ {
} }
public void AddRegion(Scene scene) public virtual void AddRegion(Scene scene)
{ {
if (!m_Enabled) if (!m_Enabled)
return; return;
@ -302,6 +301,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
{ {
UUID agentID = client.AgentId; UUID agentID = client.AgentId;
//m_log.DebugFormat("[XXX]: OnClientLogin!");
// Inform the friends that this user is online // Inform the friends that this user is online
StatusChange(agentID, true); StatusChange(agentID, true);
@ -405,19 +405,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
} }
if (friendList.Count > 0) if (friendList.Count > 0)
{ GetOnlineFriends(userID, friendList, online);
PresenceInfo[] presence = PresenceService.GetAgents(friendList.ToArray());
foreach (PresenceInfo pi in presence)
{
UUID presenceID;
if (UUID.TryParse(pi.UserID, out presenceID))
online.Add(presenceID);
}
}
return online; return online;
} }
protected virtual void GetOnlineFriends(UUID userID, List<string> friendList, /*collector*/ List<UUID> online)
{
PresenceInfo[] presence = PresenceService.GetAgents(friendList.ToArray());
foreach (PresenceInfo pi in presence)
{
UUID presenceID;
if (UUID.TryParse(pi.UserID, out presenceID))
online.Add(presenceID);
}
}
/// <summary> /// <summary>
/// Find the client for a ID /// Find the client for a ID
/// </summary> /// </summary>
@ -472,51 +475,51 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
Util.FireAndForget( Util.FireAndForget(
delegate delegate
{ {
foreach (FriendInfo fi in friendList) m_log.DebugFormat("[FRIENDS MODULE]: Notifying {0} friends", friendList.Count);
{ // Notify about this user status
//m_log.DebugFormat("[FRIENDS]: Notifying {0}", fi.PrincipalID); StatusNotify(friendList, agentID, online);
// Notify about this user status
StatusNotify(fi, agentID, online);
}
} }
); );
} }
} }
private void StatusNotify(FriendInfo friend, UUID userID, bool online) protected virtual void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
{ {
UUID friendID; foreach (FriendInfo friend in friendList)
if (UUID.TryParse(friend.Friend, out friendID))
{ {
// Try local UUID friendID;
if (LocalStatusNotification(userID, friendID, online)) if (UUID.TryParse(friend.Friend, out friendID))
return;
// The friend is not here [as root]. Let's forward.
PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
if (friendSessions != null && friendSessions.Length > 0)
{ {
PresenceInfo friendSession = null; // Try local
foreach (PresenceInfo pinfo in friendSessions) if (LocalStatusNotification(userID, friendID, online))
if (pinfo.RegionID != UUID.Zero) // let's guard against sessions-gone-bad return;
{
friendSession = pinfo;
break;
}
if (friendSession != null) // The friend is not here [as root]. Let's forward.
PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
if (friendSessions != null && friendSessions.Length > 0)
{ {
GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); PresenceInfo friendSession = null;
//m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName); foreach (PresenceInfo pinfo in friendSessions)
m_FriendsSimConnector.StatusNotify(region, userID, friendID, online); if (pinfo.RegionID != UUID.Zero) // let's guard against sessions-gone-bad
} {
} friendSession = pinfo;
break;
}
// Friend is not online. Ignore. if (friendSession != null)
} {
else GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
{ //m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName);
m_log.WarnFormat("[FRIENDS]: Error parsing friend ID {0}", friend.Friend); m_FriendsSimConnector.StatusNotify(region, userID, friendID, online);
}
}
// Friend is not online. Ignore.
}
else
{
m_log.WarnFormat("[FRIENDS]: Error parsing friend ID {0}", friend.Friend);
}
} }
} }
@ -670,7 +673,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
FriendInfo[] friends = GetFriends(remoteClient.AgentId); FriendInfo[] friends = GetFriends(remoteClient.AgentId);
if (friends.Length == 0) if (friends.Length == 0)
{ {
m_log.DebugFormat("[XXX]: agent {0} has no friends", requester);
return; return;
} }

View File

@ -46,7 +46,7 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion;
namespace OpenSim.Region.CoreModules.Avatar.Friends namespace OpenSim.Region.CoreModules.Avatar.Friends
{ {
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
public class HGFriendsModule : FriendsModule, ISharedRegionModule, IFriendsModule public class HGFriendsModule : FriendsModule, ISharedRegionModule, IFriendsModule, IFriendsSimConnector
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@ -56,6 +56,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
get { return "HGFriendsModule"; } get { return "HGFriendsModule"; }
} }
public override void AddRegion(Scene scene)
{
if (!m_Enabled)
return;
base.AddRegion(scene);
scene.RegisterModuleInterface<IFriendsSimConnector>(this);
}
#endregion
#region IFriendsSimConnector
/// <summary>
/// Notify the user that the friend's status changed
/// </summary>
/// <param name="userID">user to be notified</param>
/// <param name="friendID">friend whose status changed</param>
/// <param name="online">status</param>
/// <returns></returns>
public bool StatusNotify(UUID userID, UUID friendID, bool online)
{
return LocalStatusNotification(friendID, userID, online);
}
#endregion #endregion
protected override bool FetchFriendslist(IClientAPI client) protected override bool FetchFriendslist(IClientAPI client)
@ -103,6 +128,140 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
return false; return false;
} }
protected override void GetOnlineFriends(UUID userID, List<string> friendList, /*collector*/ List<UUID> online)
{
// Let's single out the UUIs
List<string> localFriends = new List<string>();
List<string> foreignFriends = new List<string>();
string tmp = string.Empty;
foreach (string s in friendList)
{
UUID id;
if (UUID.TryParse(s, out id))
localFriends.Add(s);
else if (Util.ParseUniversalUserIdentifier(s, out id, out tmp, out tmp, out tmp, out tmp))
{
foreignFriends.Add(s);
// add it here too, who knows maybe the foreign friends happens to be on this grid
localFriends.Add(id.ToString());
}
}
// OK, see who's present on this grid
List<string> toBeRemoved = new List<string>();
PresenceInfo[] presence = PresenceService.GetAgents(localFriends.ToArray());
foreach (PresenceInfo pi in presence)
{
UUID presenceID;
if (UUID.TryParse(pi.UserID, out presenceID))
{
online.Add(presenceID);
foreach (string s in foreignFriends)
if (s.StartsWith(pi.UserID))
toBeRemoved.Add(s);
}
}
foreach (string s in toBeRemoved)
foreignFriends.Remove(s);
// OK, let's send this up the stack, and leave a closure here
// collecting online friends in other grids
Util.FireAndForget(delegate { CollectOnlineFriendsElsewhere(userID, foreignFriends); });
}
private void CollectOnlineFriendsElsewhere(UUID userID, List<string> foreignFriends)
{
// let's divide the friends on a per-domain basis
Dictionary<string, List<string>> friendsPerDomain = new Dictionary<string, List<string>>();
foreach (string friend in foreignFriends)
{
UUID friendID;
if (!UUID.TryParse(friend, out friendID))
{
// it's a foreign friend
string url = string.Empty, tmp = string.Empty;
if (Util.ParseUniversalUserIdentifier(friend, out friendID, out url, out tmp, out tmp, out tmp))
{
if (!friendsPerDomain.ContainsKey(url))
friendsPerDomain[url] = new List<string>();
friendsPerDomain[url].Add(friend);
}
}
}
// Now, call those worlds
foreach (KeyValuePair<string, List<string>> kvp in friendsPerDomain)
{
List<string> ids = new List<string>();
foreach (string f in kvp.Value)
ids.Add(f);
UserAgentServiceConnector uConn = new UserAgentServiceConnector(kvp.Key);
List<UUID> online = uConn.GetOnlineFriends(userID, ids);
// Finally send the notifications to the user
// this whole process may take a while, so let's check at every
// iteration that the user is still here
IClientAPI client = LocateClientObject(userID);
if (client != null)
client.SendAgentOnline(online.ToArray());
else
break;
}
}
protected override void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
{
// First, let's divide the friends on a per-domain basis
Dictionary<string, List<FriendInfo>> friendsPerDomain = new Dictionary<string, List<FriendInfo>>();
foreach (FriendInfo friend in friendList)
{
UUID friendID;
if (UUID.TryParse(friend.Friend, out friendID))
{
if (!friendsPerDomain.ContainsKey("local"))
friendsPerDomain["local"] = new List<FriendInfo>();
friendsPerDomain["local"].Add(friend);
}
else
{
// it's a foreign friend
string url = string.Empty, tmp = string.Empty;
if (Util.ParseUniversalUserIdentifier(friend.Friend, out friendID, out url, out tmp, out tmp, out tmp))
{
// Let's try our luck in the local sim. Who knows, maybe it's here
if (LocalStatusNotification(userID, friendID, online))
continue;
if (!friendsPerDomain.ContainsKey(url))
friendsPerDomain[url] = new List<FriendInfo>();
friendsPerDomain[url].Add(friend);
}
}
}
// For the local friends, just call the base method
// Let's do this first of all
if (friendsPerDomain.ContainsKey("local"))
base.StatusNotify(friendsPerDomain["local"], userID, online);
foreach (KeyValuePair<string, List<FriendInfo>> kvp in friendsPerDomain)
{
if (kvp.Key != "local")
{
// For the others, call the user agent service
List<string> ids = new List<string>();
foreach (FriendInfo f in kvp.Value)
ids.Add(f.Friend);
UserAgentServiceConnector uConn = new UserAgentServiceConnector(kvp.Key);
uConn.StatusNotification(ids, userID, online);
}
}
}
protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last)
{ {
first = "Unknown"; last = "User"; first = "Unknown"; last = "User";
@ -172,7 +331,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
{ {
string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit);
m_log.DebugFormat("[XXX] GetFriendsFromService to {0}", agentUUI);
finfos = FriendsService.GetFriends(agentUUI); finfos = FriendsService.GetFriends(agentUUI);
m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, agentUUI); m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, agentUUI);
} }

View File

@ -113,7 +113,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Hypergrid
ISimulationService simService = scene.RequestModuleInterface<ISimulationService>(); ISimulationService simService = scene.RequestModuleInterface<ISimulationService>();
m_HypergridHandler = new GatekeeperServiceInConnector(m_Config, MainServer.Instance, simService); m_HypergridHandler = new GatekeeperServiceInConnector(m_Config, MainServer.Instance, simService);
new UserAgentServerConnector(m_Config, MainServer.Instance); IFriendsSimConnector friendsConn = scene.RequestModuleInterface<IFriendsSimConnector>();
new UserAgentServerConnector(m_Config, MainServer.Instance, friendsConn);
new HeloServiceInConnector(m_Config, MainServer.Instance, "HeloService"); new HeloServiceInConnector(m_Config, MainServer.Instance, "HeloService");
new HGFriendsServerConnector(m_Config, MainServer.Instance, "HGFriendsService"); new HGFriendsServerConnector(m_Config, MainServer.Instance, "HGFriendsService");
} }

View File

@ -140,16 +140,20 @@ namespace OpenSim.Server.Handlers.Hypergrid
byte[] NewFriendship(Dictionary<string, object> request) byte[] NewFriendship(Dictionary<string, object> request)
{ {
m_log.DebugFormat("[XXX] 1");
if (!VerifyServiceKey(request)) if (!VerifyServiceKey(request))
return FailureResult(); return FailureResult();
m_log.DebugFormat("[XXX] 2");
// OK, can proceed // OK, can proceed
FriendInfo friend = new FriendInfo(request); FriendInfo friend = new FriendInfo(request);
UUID friendID; UUID friendID;
string tmp = string.Empty; string tmp = string.Empty;
m_log.DebugFormat("[XXX] 3");
if (!Util.ParseUniversalUserIdentifier(friend.Friend, out friendID, out tmp, out tmp, out tmp, out tmp)) if (!Util.ParseUniversalUserIdentifier(friend.Friend, out friendID, out tmp, out tmp, out tmp, out tmp))
return FailureResult(); return FailureResult();
m_log.DebugFormat("[HGFRIENDS HANDLER]: New friendship {0} {1}", friend.PrincipalID, friend.Friend); m_log.DebugFormat("[HGFRIENDS HANDLER]: New friendship {0} {1}", friend.PrincipalID, friend.Friend);
// If the friendship already exists, return fail // If the friendship already exists, return fail

View File

@ -54,13 +54,19 @@ namespace OpenSim.Server.Handlers.Hypergrid
private IUserAgentService m_HomeUsersService; private IUserAgentService m_HomeUsersService;
public UserAgentServerConnector(IConfigSource config, IHttpServer server) : public UserAgentServerConnector(IConfigSource config, IHttpServer server) :
this(config, server, null)
{
}
public UserAgentServerConnector(IConfigSource config, IHttpServer server, IFriendsSimConnector friendsConnector) :
base(config, server, String.Empty) base(config, server, String.Empty)
{ {
IConfig gridConfig = config.Configs["UserAgentService"]; IConfig gridConfig = config.Configs["UserAgentService"];
if (gridConfig != null) if (gridConfig != null)
{ {
string serviceDll = gridConfig.GetString("LocalServiceModule", string.Empty); string serviceDll = gridConfig.GetString("LocalServiceModule", string.Empty);
Object[] args = new Object[] { config };
Object[] args = new Object[] { config, friendsConnector };
m_HomeUsersService = ServerUtils.LoadPlugin<IUserAgentService>(serviceDll, args); m_HomeUsersService = ServerUtils.LoadPlugin<IUserAgentService>(serviceDll, args);
} }
if (m_HomeUsersService == null) if (m_HomeUsersService == null)
@ -75,6 +81,9 @@ namespace OpenSim.Server.Handlers.Hypergrid
server.AddXmlRPCHandler("verify_client", VerifyClient, false); server.AddXmlRPCHandler("verify_client", VerifyClient, false);
server.AddXmlRPCHandler("logout_agent", LogoutAgent, false); server.AddXmlRPCHandler("logout_agent", LogoutAgent, false);
server.AddXmlRPCHandler("status_notification", StatusNotification, false);
server.AddXmlRPCHandler("get_online_friends", GetOnlineFriends, false);
server.AddHTTPHandler("/homeagent/", new HomeAgentHandler(m_HomeUsersService, loginServerIP, proxy).Handler); server.AddHTTPHandler("/homeagent/", new HomeAgentHandler(m_HomeUsersService, loginServerIP, proxy).Handler);
} }
@ -194,5 +203,78 @@ namespace OpenSim.Server.Handlers.Hypergrid
} }
public XmlRpcResponse StatusNotification(XmlRpcRequest request, IPEndPoint remoteClient)
{
Hashtable hash = new Hashtable();
hash["result"] = "false";
Hashtable requestData = (Hashtable)request.Params[0];
//string host = (string)requestData["host"];
//string portstr = (string)requestData["port"];
if (requestData.ContainsKey("userID") && requestData.ContainsKey("online"))
{
string userID_str = (string)requestData["userID"];
UUID userID = UUID.Zero;
UUID.TryParse(userID_str, out userID);
List<string> ids = new List<string>();
foreach (object key in requestData.Keys)
{
if (key is string && ((string)key).StartsWith("friend_") && requestData[key] != null)
ids.Add(requestData[key].ToString());
}
bool online = false;
bool.TryParse(requestData["online"].ToString(), out online);
hash["result"] = "true";
// let's spawn a thread for this, because it may take a long time...
Util.FireAndForget(delegate { m_HomeUsersService.StatusNotification(ids, userID, online); });
}
XmlRpcResponse response = new XmlRpcResponse();
response.Value = hash;
return response;
}
public XmlRpcResponse GetOnlineFriends(XmlRpcRequest request, IPEndPoint remoteClient)
{
Hashtable hash = new Hashtable();
Hashtable requestData = (Hashtable)request.Params[0];
//string host = (string)requestData["host"];
//string portstr = (string)requestData["port"];
if (requestData.ContainsKey("userID"))
{
string userID_str = (string)requestData["userID"];
UUID userID = UUID.Zero;
UUID.TryParse(userID_str, out userID);
List<string> ids = new List<string>();
foreach (object key in requestData.Keys)
{
if (key is string && ((string)key).StartsWith("friend_") && requestData[key] != null)
ids.Add(requestData[key].ToString());
}
// let's spawn a thread for this, because it may take a long time...
List<UUID> online = m_HomeUsersService.GetOnlineFriends(userID, ids);
if (online.Count > 0)
{
int i = 0;
foreach (UUID id in online)
{
hash["friend_" + i.ToString()] = id.ToString();
i++;
}
}
}
XmlRpcResponse response = new XmlRpcResponse();
response.Value = hash;
return response;
}
} }
} }

View File

@ -404,6 +404,97 @@ namespace OpenSim.Services.Connectors.Hypergrid
GetBoolResponse(request, out reason); GetBoolResponse(request, out reason);
} }
public void StatusNotification(List<string> 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<UUID> GetOnlineFriends(UUID userID, List<string> 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<UUID> online = new List<UUID>();
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) private bool GetBoolResponse(XmlRpcRequest request, out string reason)
{ {

View File

@ -31,10 +31,12 @@ using System.Net;
using System.Reflection; using System.Reflection;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Services.Connectors.Friends;
using OpenSim.Services.Connectors.Hypergrid; using OpenSim.Services.Connectors.Hypergrid;
using OpenSim.Services.Interfaces; using OpenSim.Services.Interfaces;
using GridRegion = OpenSim.Services.Interfaces.GridRegion; using GridRegion = OpenSim.Services.Interfaces.GridRegion;
using OpenSim.Server.Base; using OpenSim.Server.Base;
using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
using OpenMetaverse; using OpenMetaverse;
using log4net; using log4net;
@ -63,19 +65,34 @@ namespace OpenSim.Services.HypergridService
protected static IGridService m_GridService; protected static IGridService m_GridService;
protected static GatekeeperServiceConnector m_GatekeeperConnector; protected static GatekeeperServiceConnector m_GatekeeperConnector;
protected static IGatekeeperService m_GatekeeperService; 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 string m_GridName;
protected static bool m_BypassClientVerification; 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) if (!m_Initialized)
{ {
m_Initialized = true; m_Initialized = true;
m_log.DebugFormat("[HOME USERS SECURITY]: Starting..."); m_log.DebugFormat("[HOME USERS SECURITY]: Starting...");
m_FriendsSimConnector = new FriendsSimConnector();
IConfig serverConfig = config.Configs["UserAgentService"]; IConfig serverConfig = config.Configs["UserAgentService"];
if (serverConfig == null) if (serverConfig == null)
throw new Exception(String.Format("No section UserAgentService in config file")); 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 gridService = serverConfig.GetString("GridService", String.Empty);
string gridUserService = serverConfig.GetString("GridUserService", String.Empty); string gridUserService = serverConfig.GetString("GridUserService", String.Empty);
string gatekeeperService = serverConfig.GetString("GatekeeperService", 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); m_BypassClientVerification = serverConfig.GetBoolean("BypassClientVerification", false);
@ -94,6 +113,8 @@ namespace OpenSim.Services.HypergridService
m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args); m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
m_GatekeeperConnector = new GatekeeperServiceConnector(); m_GatekeeperConnector = new GatekeeperServiceConnector();
m_GatekeeperService = ServerUtils.LoadPlugin<IGatekeeperService>(gatekeeperService, args); m_GatekeeperService = ServerUtils.LoadPlugin<IGatekeeperService>(gatekeeperService, args);
m_FriendsService = ServerUtils.LoadPlugin<IFriendsService>(friendsService, args);
m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
m_GridName = serverConfig.GetString("ExternalName", string.Empty); m_GridName = serverConfig.GetString("ExternalName", string.Empty);
if (m_GridName == string.Empty) if (m_GridName == string.Empty)
@ -156,11 +177,16 @@ namespace OpenSim.Services.HypergridService
string gridName = gatekeeper.ServerURI; string gridName = gatekeeper.ServerURI;
m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}", m_GridName, gridName); m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}", m_GridName, gridName);
if (m_GridName == gridName) if (m_GridName == gridName)
success = m_GatekeeperService.LoginAgent(agentCircuit, finalDestination, out reason); success = m_GatekeeperService.LoginAgent(agentCircuit, finalDestination, out reason);
else else
{
success = m_GatekeeperConnector.CreateAgent(region, agentCircuit, (uint)Constants.TeleportFlags.ViaLogin, out myExternalIP, out reason); 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) if (!success)
{ {
@ -179,6 +205,7 @@ namespace OpenSim.Services.HypergridService
if (clientIP != null) if (clientIP != null)
m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress = clientIP.Address.ToString(); m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress = clientIP.Address.ToString();
m_TravelingAgents[agentCircuit.SessionID].MyIpAddress = myExternalIP; m_TravelingAgents[agentCircuit.SessionID].MyIpAddress = myExternalIP;
return true; return true;
} }
@ -291,6 +318,145 @@ namespace OpenSim.Services.HypergridService
return false; return false;
} }
public void StatusNotification(List<string> 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<string> usersToBeNotified = new List<string>();
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<UUID> GetOnlineFriends(UUID foreignUserID, List<string> friends)
{
List<UUID> online = new List<UUID>();
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<string> usersToBeNotified = new List<string>();
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 class TravelingAgentInfo

View File

@ -55,6 +55,9 @@ namespace OpenSim.Services.Interfaces
void LogoutAgent(UUID userID, UUID sessionID); void LogoutAgent(UUID userID, UUID sessionID);
GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt); GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt);
void StatusNotification(List<string> friends, UUID userID, bool online);
List<UUID> GetOnlineFriends(UUID userID, List<string> friends);
bool AgentIsComingHome(UUID sessionID, string thisGridExternalName); bool AgentIsComingHome(UUID sessionID, string thisGridExternalName);
bool VerifyAgent(UUID sessionID, string token); bool VerifyAgent(UUID sessionID, string token);
bool VerifyClient(UUID sessionID, string reportedIP); bool VerifyClient(UUID sessionID, string reportedIP);

View File

@ -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);
}
}

View File

@ -126,6 +126,9 @@
GridUserService = "OpenSim.Services.UserAccountService.dll:GridUserService" GridUserService = "OpenSim.Services.UserAccountService.dll:GridUserService"
GridService = "OpenSim.Services.GridService.dll:GridService" GridService = "OpenSim.Services.GridService.dll:GridService"
GatekeeperService = "OpenSim.Services.HypergridService.dll:GatekeeperService" GatekeeperService = "OpenSim.Services.HypergridService.dll:GatekeeperService"
PresenceService = "OpenSim.Services.PresenceService.dll:PresenceService"
FriendsService = "OpenSim.Services.FriendsService.dll:FriendsService"
;; The interface that local users get when they are in other grids ;; The interface that local users get when they are in other grids