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

View File

@ -46,7 +46,7 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion;
namespace OpenSim.Region.CoreModules.Avatar.Friends
{
[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);
@ -56,6 +56,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
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
protected override bool FetchFriendslist(IClientAPI client)
@ -103,6 +128,140 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
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)
{
first = "Unknown"; last = "User";
@ -172,7 +331,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
{
string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit);
m_log.DebugFormat("[XXX] GetFriendsFromService to {0}", agentUUI);
finfos = FriendsService.GetFriends(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>();
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 HGFriendsServerConnector(m_Config, MainServer.Instance, "HGFriendsService");
}

View File

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

View File

@ -54,13 +54,19 @@ namespace OpenSim.Server.Handlers.Hypergrid
private IUserAgentService m_HomeUsersService;
public UserAgentServerConnector(IConfigSource config, IHttpServer server) :
this(config, server, null)
{
}
public UserAgentServerConnector(IConfigSource config, IHttpServer server, IFriendsSimConnector friendsConnector) :
base(config, server, String.Empty)
{
IConfig gridConfig = config.Configs["UserAgentService"];
if (gridConfig != null)
{
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);
}
if (m_HomeUsersService == null)
@ -75,6 +81,9 @@ namespace OpenSim.Server.Handlers.Hypergrid
server.AddXmlRPCHandler("verify_client", VerifyClient, 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);
}
@ -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);
}
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)
{

View File

@ -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<IGridUserService>(gridUserService, args);
m_GatekeeperConnector = new GatekeeperServiceConnector();
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);
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<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

View File

@ -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<string> friends, UUID userID, bool online);
List<UUID> GetOnlineFriends(UUID userID, List<string> friends);
bool AgentIsComingHome(UUID sessionID, string thisGridExternalName);
bool VerifyAgent(UUID sessionID, string token);
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"
GridService = "OpenSim.Services.GridService.dll:GridService"
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