From d0ba9f84df1b4d290bdecea5e47e126488add358 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 4 Mar 2020 02:45:10 +0000 Subject: [PATCH] add some async work to profiles module, take profile out of groups v2, not its job --- OpenSim/Addons/Groups/GroupsModule.cs | 8 +- OpenSim/Framework/UserProfiles.cs | 1 + .../Avatar/UserProfiles/UserProfileModule.cs | 169 +++++++++++++++++- 3 files changed, 170 insertions(+), 8 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index 98264ad40a..390c723b98 100755 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -233,7 +233,7 @@ namespace OpenSim.Groups if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest; - client.OnRequestAvatarProperties += OnRequestAvatarProperties; + //client.OnRequestAvatarProperties += OnRequestAvatarProperties; } @@ -261,7 +261,7 @@ namespace OpenSim.Groups // Used for Notices and Group Invites/Accept/Reject sp.ControllingClient.OnInstantMessage -= OnInstantMessage; } - + /* private void OnRequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) { if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); @@ -269,7 +269,7 @@ namespace OpenSim.Groups GroupMembershipData[] avatarGroups = GetProfileListedGroupMemberships(remoteClient, avatarID); remoteClient.SendAvatarGroupsReply(avatarID, avatarGroups); } - + */ private void OnClientClosed(UUID AgentId, Scene scene) { if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); @@ -281,7 +281,7 @@ namespace OpenSim.Groups if (client != null) { client.OnAgentDataUpdateRequest -= OnAgentDataUpdateRequest; - client.OnRequestAvatarProperties -= OnRequestAvatarProperties; + //client.OnRequestAvatarProperties -= OnRequestAvatarProperties; // make child possible not called? client.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest; client.OnInstantMessage -= OnInstantMessage; diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs index 7c6a6feaae..a8a46832c3 100644 --- a/OpenSim/Framework/UserProfiles.cs +++ b/OpenSim/Framework/UserProfiles.cs @@ -132,6 +132,7 @@ namespace OpenSim.Framework public Dictionary classifiedsLists; public Dictionary classifieds; public UserProfileProperties props; + public GroupMembershipData[] avatarGroups; public string born; public byte[] membershipType; public uint flags; diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 22984ef40d..ef4c701eaf 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -30,17 +30,17 @@ using System.IO; using System.Text; using System.Collections; using System.Collections.Generic; +using System.Collections.Concurrent; using System.Globalization; using System.Linq; using System.Net; -using System.Net.Sockets; using System.Reflection; +using System.Threading; using System.Xml; using OpenMetaverse; using OpenMetaverse.StructuredData; using log4net; using Nini.Config; -using Nwc.XmlRpc; using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; @@ -70,6 +70,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles Dictionary m_classifiedInterest = new Dictionary(); ExpiringCache m_profilesCache = new ExpiringCache(); IAssetCache m_assetCache; + IGroupsModule m_groupsModule = null; static readonly UUID m_MrOpenSimID = new UUID("11111111-1111-0000-0000-000100bba000"); static readonly DateTime m_MrOpenSimBorn = new DateTime(2007,1,1,0,0,0,DateTimeKind.Utc); @@ -77,6 +78,143 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles private JsonRpcRequestManager rpc = new JsonRpcRequestManager(); private bool m_allowUserProfileWebURLs = true; + struct AsyncPropsRequest + { + public IClientAPI client; + public ScenePresence presence; + public UUID agent; + public int reqtype; + } + + private ConcurrentQueue m_asyncRequests = new ConcurrentQueue(); + private object m_asyncRequestsLock = new object(); + private bool m_asyncRequestsRunning = false; + + private void ProcessRequests() + { + lock(m_asyncRequestsLock) + { + try + { + while(m_asyncRequests.TryDequeue(out AsyncPropsRequest req)) + { + IClientAPI client = req.client; + if(!client.IsActive) + continue; + + if(req.reqtype == 0) + { + UUID avatarID = req.agent; + ScenePresence p = req.presence; + + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(avatarID, out serverURI); + + UserAccount account = null; + + if (!foreign) + account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, avatarID); + + Byte[] membershipType = new Byte[1]; + string born = string.Empty; + uint flags = 0x00; + + if (null != account) + { + if (account.UserTitle == "") + membershipType[0] = (Byte)((account.UserFlags & 0xf00) >> 8); + else + membershipType = Utils.StringToBytes(account.UserTitle); + + born = Util.ToDateTime(account.Created).ToString( + "M/d/yyyy", CultureInfo.InvariantCulture); + flags = (uint)(account.UserFlags & 0xff); + } + else + { + if (GetUserAccountData(avatarID, out Dictionary userInfo) == true) + { + if ((string)userInfo["user_title"] == "") + membershipType[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8); + else + membershipType = Utils.StringToBytes((string)userInfo["user_title"]); + + int val_born = (int)userInfo["user_created"]; + if (val_born != 0) + born = Util.ToDateTime(val_born).ToString( + "M/d/yyyy", CultureInfo.InvariantCulture); + + // picky, picky + int val_flags = (int)userInfo["user_flags"]; + flags = (uint)(val_flags & 0xff); + } + } + + UserProfileProperties props = new UserProfileProperties(); + props.UserId = avatarID; + + string result = string.Empty; + if (!GetProfileData(ref props, foreign, serverURI, out result)) + { + props.AboutText = "Profile not available at this time. User may still be unknown to this grid"; + } + + if (!m_allowUserProfileWebURLs) + props.WebUrl = ""; + + GroupMembershipData[] agentGroups = null; + if(m_groupsModule != null) + agentGroups = m_groupsModule.GetMembershipData(avatarID); + + HashSet clients; + lock (m_profilesCache) + { + if (!m_profilesCache.TryGetValue(props.UserId, out UserProfileCacheEntry uce) || uce == null) + uce = new UserProfileCacheEntry(); + uce.props = props; + uce.born = born; + uce.membershipType = membershipType; + uce.flags = flags; + clients = uce.ClientsWaitingProps; + uce.ClientsWaitingProps = null; + uce.avatarGroups = agentGroups; + m_profilesCache.AddOrUpdate(props.UserId, uce, PROFILECACHEEXPIRE); + } + + // if on same region force online + if (p != null && !p.IsDeleted) + flags |= 0x10; + + if(!clients.Contains(client) && client.IsActive) + { + client.SendAvatarProperties(props.UserId, props.AboutText, born, membershipType, props.FirstLifeText, flags, + props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); + + client.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, + (uint)props.SkillsMask, props.SkillsText, props.Language); + if (agentGroups != null) + client.SendAvatarGroupsReply(avatarID, agentGroups); + } + foreach (IClientAPI cli in clients) + { + if (!cli.IsActive) + continue; + cli.SendAvatarProperties(props.UserId, props.AboutText, born, membershipType, props.FirstLifeText, flags, + props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); + + cli.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, + (uint)props.SkillsMask, props.SkillsText, props.Language); + if (agentGroups != null) + cli.SendAvatarGroupsReply(avatarID, agentGroups); + } + } + } + m_asyncRequestsRunning = false; + } + catch { } + } + } + public Scene Scene { get; private set; @@ -225,6 +363,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles if(!Enabled) return; m_assetCache = Scene.RequestModuleInterface(); + m_groupsModule = Scene.RequestModuleInterface(); } /// @@ -1339,10 +1478,10 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) { - if (String.IsNullOrEmpty(avatarID.ToString()) || String.IsNullOrEmpty(remoteClient.AgentId.ToString())) + if (avatarID == UUID.Zero) { // Looking for a reason that some viewers are sending null Id's - m_log.DebugFormat("[PROFILES]: This should not happen remoteClient.AgentId {0} - avatarID {1}", remoteClient.AgentId, avatarID); + m_log.Debug("[PROFILES]: got request of null ID"); return; } @@ -1386,6 +1525,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask, props.SkillsText, props.Language); + if(uce.avatarGroups != null) + remoteClient.SendAvatarGroupsReply(avatarID, uce.avatarGroups); return; } else @@ -1406,6 +1547,25 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } } + AsyncPropsRequest req = new AsyncPropsRequest(); + req.client = remoteClient; + req.presence = p; + req.agent = avatarID; + req.reqtype = 0; + + m_asyncRequests.Enqueue(req); + if(Monitor.TryEnter(m_asyncRequestsLock)) + { + if (!m_asyncRequestsRunning) + { + m_asyncRequestsRunning = true; + Util.FireAndForget(x => ProcessRequests()); + } + Monitor.Exit(m_asyncRequestsLock); + + } + + /* string serverURI = string.Empty; bool foreign = GetUserProfileServerURI(avatarID, out serverURI); @@ -1510,6 +1670,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles } } + */ } ///