aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs81
1 files changed, 53 insertions, 28 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index 0c81bb2..5d94ff7 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -29,6 +29,7 @@ using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Reflection; 31using System.Reflection;
32using System.Threading;
32using log4net; 33using log4net;
33using Nini.Config; 34using Nini.Config;
34using Nwc.XmlRpc; 35using Nwc.XmlRpc;
@@ -79,10 +80,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
79 protected IFriendsService m_FriendsService = null; 80 protected IFriendsService m_FriendsService = null;
80 protected FriendsSimConnector m_FriendsSimConnector; 81 protected FriendsSimConnector m_FriendsSimConnector;
81 82
82 protected Dictionary<UUID, UserFriendData> m_Friends = 83 /// <summary>
83 new Dictionary<UUID, UserFriendData>(); 84 /// Cache friends lists for users.
85 /// </summary>
86 /// <remarks>
87 /// This is a complex and error-prone thing to do. At the moment, we assume that the efficiency gained in
88 /// permissions checks outweighs the disadvantages of that complexity.
89 /// </remarks>
90 protected Dictionary<UUID, UserFriendData> m_Friends = new Dictionary<UUID, UserFriendData>();
84 91
85 protected HashSet<UUID> m_NeedsListOfFriends = new HashSet<UUID>(); 92 /// <summary>
93 /// Maintain a record of viewers that need to be sent notifications for friends that are online. This only
94 /// needs to be done on login. Subsequent online/offline friend changes are sent by a different mechanism.
95 /// </summary>
96 protected HashSet<UUID> m_NeedsListOfOnlineFriends = new HashSet<UUID>();
86 97
87 protected IPresenceService PresenceService 98 protected IPresenceService PresenceService
88 { 99 {
@@ -189,6 +200,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
189 { 200 {
190 if (!m_Enabled) 201 if (!m_Enabled)
191 return; 202 return;
203
192 m_log.DebugFormat("[FRIENDS MODULE]: AddRegion on {0}", Name); 204 m_log.DebugFormat("[FRIENDS MODULE]: AddRegion on {0}", Name);
193 205
194 m_Scenes.Add(scene); 206 m_Scenes.Add(scene);
@@ -241,16 +253,25 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
241 client.OnInstantMessage += OnInstantMessage; 253 client.OnInstantMessage += OnInstantMessage;
242 client.OnApproveFriendRequest += OnApproveFriendRequest; 254 client.OnApproveFriendRequest += OnApproveFriendRequest;
243 client.OnDenyFriendRequest += OnDenyFriendRequest; 255 client.OnDenyFriendRequest += OnDenyFriendRequest;
244 client.OnTerminateFriendship += OnTerminateFriendship; 256 client.OnTerminateFriendship += (thisClient, agentID, exfriendID) => RemoveFriendship(thisClient, exfriendID);
245 client.OnGrantUserRights += OnGrantUserRights; 257 client.OnGrantUserRights += OnGrantUserRights;
246 258
247 Util.FireAndForget(delegate { FetchFriendslist(client); }); 259 // Do not do this asynchronously. If we do, then subsequent code can outrace CacheFriends() and
260 // return misleading results from the still empty friends cache.
261 // If we absolutely need to do this asynchronously, then a signalling mechanism is needed so that calls
262 // to GetFriends() will wait until CacheFriends() completes. Locks are insufficient.
263 CacheFriends(client);
248 } 264 }
249 265
250 /// Fetch the friends list or increment the refcount for the existing 266 /// <summary>
251 /// friends list 267 /// Cache the friends list or increment the refcount for the existing friends list.
268 /// </summary>
269 /// <param name="client">
270 /// </param>
271 /// <returns>
252 /// Returns true if the list was fetched, false if it wasn't 272 /// Returns true if the list was fetched, false if it wasn't
253 protected virtual bool FetchFriendslist(IClientAPI client) 273 /// </returns>
274 protected virtual bool CacheFriends(IClientAPI client)
254 { 275 {
255 UUID agentID = client.AgentId; 276 UUID agentID = client.AgentId;
256 lock (m_Friends) 277 lock (m_Friends)
@@ -297,7 +318,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
297 318
298 private void OnMakeRootAgent(ScenePresence sp) 319 private void OnMakeRootAgent(ScenePresence sp)
299 { 320 {
300 RefetchFriends(sp.ControllingClient); 321 RecacheFriends(sp.ControllingClient);
301 } 322 }
302 323
303 private void OnClientLogin(IClientAPI client) 324 private void OnClientLogin(IClientAPI client)
@@ -309,8 +330,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
309 StatusChange(agentID, true); 330 StatusChange(agentID, true);
310 331
311 // Register that we need to send the list of online friends to this user 332 // Register that we need to send the list of online friends to this user
312 lock (m_NeedsListOfFriends) 333 lock (m_NeedsListOfOnlineFriends)
313 m_NeedsListOfFriends.Add(agentID); 334 m_NeedsListOfOnlineFriends.Add(agentID);
314 } 335 }
315 336
316 public virtual bool SendFriendsOnlineIfNeeded(IClientAPI client) 337 public virtual bool SendFriendsOnlineIfNeeded(IClientAPI client)
@@ -318,9 +339,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
318 UUID agentID = client.AgentId; 339 UUID agentID = client.AgentId;
319 340
320 // Check if the online friends list is needed 341 // Check if the online friends list is needed
321 lock (m_NeedsListOfFriends) 342 lock (m_NeedsListOfOnlineFriends)
322 { 343 {
323 if (!m_NeedsListOfFriends.Remove(agentID)) 344 if (!m_NeedsListOfOnlineFriends.Remove(agentID))
324 return false; 345 return false;
325 } 346 }
326 347
@@ -328,7 +349,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
328 List<UUID> online = GetOnlineFriends(agentID); 349 List<UUID> online = GetOnlineFriends(agentID);
329 if (online.Count > 0) 350 if (online.Count > 0)
330 { 351 {
331 m_log.DebugFormat("[FRIENDS MODULE]: User {0} in region {1} has {2} friends online", client.AgentId, client.Scene.RegionInfo.RegionName, online.Count); 352 m_log.DebugFormat(
353 "[FRIENDS MODULE]: User {0} in region {1} has {2} friends online",
354 client.Name, client.Scene.RegionInfo.RegionName, online.Count);
355
332 client.SendAgentOnline(online.ToArray()); 356 client.SendAgentOnline(online.ToArray());
333 } 357 }
334 358
@@ -586,7 +610,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
586 } 610 }
587 611
588 // Update the local cache 612 // Update the local cache
589 RefetchFriends(client); 613 RecacheFriends(client);
590 614
591 // 615 //
592 // Notify the friend 616 // Notify the friend
@@ -641,14 +665,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
641 } 665 }
642 } 666 }
643 } 667 }
644 668
645 private void OnTerminateFriendship(IClientAPI client, UUID agentID, UUID exfriendID) 669 public void RemoveFriendship(IClientAPI client, UUID exfriendID)
646 { 670 {
647 if (!DeleteFriendship(agentID, exfriendID)) 671 if (!DeleteFriendship(client.AgentId, exfriendID))
648 client.SendAlertMessage("Unable to terminate friendship on this sim."); 672 client.SendAlertMessage("Unable to terminate friendship on this sim.");
649 673
650 // Update local cache 674 // Update local cache
651 RefetchFriends(client); 675 RecacheFriends(client);
652 676
653 client.SendTerminateFriend(exfriendID); 677 client.SendTerminateFriend(exfriendID);
654 678
@@ -667,9 +691,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
667 if (friendSession != null) 691 if (friendSession != null)
668 { 692 {
669 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); 693 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
670 m_FriendsSimConnector.FriendshipTerminated(region, agentID, exfriendID); 694 m_FriendsSimConnector.FriendshipTerminated(region, client.AgentId, exfriendID);
671 } 695 }
672 } 696 }
673 } 697 }
674 698
675 private void OnGrantUserRights(IClientAPI remoteClient, UUID requester, UUID target, int rights) 699 private void OnGrantUserRights(IClientAPI remoteClient, UUID requester, UUID target, int rights)
@@ -769,7 +793,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
769 793
770 794
771 // Update the local cache 795 // Update the local cache
772 RefetchFriends(friendClient); 796 RecacheFriends(friendClient);
773 797
774 // we're done 798 // we're done
775 return true; 799 return true;
@@ -802,7 +826,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
802 // the friend in this sim as root agent 826 // the friend in this sim as root agent
803 friendClient.SendTerminateFriend(exfriendID); 827 friendClient.SendTerminateFriend(exfriendID);
804 // update local cache 828 // update local cache
805 RefetchFriends(friendClient); 829 RecacheFriends(friendClient);
806 // we're done 830 // we're done
807 return true; 831 return true;
808 } 832 }
@@ -819,16 +843,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
819 if (onlineBitChanged) 843 if (onlineBitChanged)
820 { 844 {
821 if ((rights & (int)FriendRights.CanSeeOnline) == 1) 845 if ((rights & (int)FriendRights.CanSeeOnline) == 1)
822 friendClient.SendAgentOnline(new UUID[] { new UUID(userID) }); 846 friendClient.SendAgentOnline(new UUID[] { userID });
823 else 847 else
824 friendClient.SendAgentOffline(new UUID[] { new UUID(userID) }); 848 friendClient.SendAgentOffline(new UUID[] { userID });
825 } 849 }
826 else 850 else
827 { 851 {
828 bool canEditObjectsChanged = ((rights ^ userFlags) & (int)FriendRights.CanModifyObjects) != 0; 852 bool canEditObjectsChanged = ((rights ^ userFlags) & (int)FriendRights.CanModifyObjects) != 0;
829 if (canEditObjectsChanged) 853 if (canEditObjectsChanged)
830 friendClient.SendChangeUserRights(userID, friendID, rights); 854 friendClient.SendChangeUserRights(userID, friendID, rights);
831
832 } 855 }
833 856
834 // Update local cache 857 // Update local cache
@@ -847,7 +870,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
847 IClientAPI friendClient = LocateClientObject(friendID); 870 IClientAPI friendClient = LocateClientObject(friendID);
848 if (friendClient != null) 871 if (friendClient != null)
849 { 872 {
850 // the friend in this sim as root agent 873 // the friend in this sim as root agent
851 if (online) 874 if (online)
852 friendClient.SendAgentOnline(new UUID[] { userID }); 875 friendClient.SendAgentOnline(new UUID[] { userID });
853 else 876 else
@@ -902,8 +925,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
902 return FriendsService.GetFriends(client.AgentId); 925 return FriendsService.GetFriends(client.AgentId);
903 } 926 }
904 927
905 private void RefetchFriends(IClientAPI client) 928 private void RecacheFriends(IClientAPI client)
906 { 929 {
930 // FIXME: Ideally, we want to avoid doing this here since it sits the EventManager.OnMakeRootAgent event
931 // is on the critical path for transferring an avatar from one region to another.
907 UUID agentID = client.AgentId; 932 UUID agentID = client.AgentId;
908 lock (m_Friends) 933 lock (m_Friends)
909 { 934 {