From 78015bbbdc50d41cc002aab838487ab902750c4f Mon Sep 17 00:00:00 2001 From: Dev Random Date: Sat, 12 Apr 2014 17:33:45 -0400 Subject: Console commands for Estate Mgmt --- OpenSim/Region/Application/OpenSim.cs | 113 +++++++++++++++++++++ .../World/Estate/EstateManagementModule.cs | 63 ++++++++++++ .../Region/Framework/Interfaces/IEstateModule.cs | 3 + 3 files changed, 179 insertions(+) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index cc505f8..59b4614 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -402,6 +402,12 @@ namespace OpenSim "Delete a region from disk", RunCommand); + m_console.Commands.AddCommand("Estates", false, "estate create", + "estate create ", + "Creates a new estate with the specified name, owned by the specified user." + + " Estate name must be unique.", + CreateEstateCommand); + m_console.Commands.AddCommand("Estates", false, "estate set owner", "estate set owner [ | ]", "Sets the owner of the specified estate to the specified UUID or user. ", @@ -411,6 +417,11 @@ namespace OpenSim "estate set name ", "Sets the name of the specified estate to the specified value. New name must be unique.", SetEstateNameCommand); + + m_console.Commands.AddCommand("Estates", false, "estate link region", + "estate link region ", + "Attaches the specified region to the specified estate.", + EstateLinkRegionCommand); } protected override void ShutdownSpecific() @@ -1177,6 +1188,58 @@ namespace OpenSim SceneManager.SaveCurrentSceneToArchive(cmdparams); } + protected void CreateEstateCommand(string module, string[] args) + { + string response = null; + UUID userID; + + if (args.Length == 2) + { + response = "No user specified."; + } + else if (!UUID.TryParse(args[2], out userID)) + { + response = String.Format("{0} is not a valid UUID", args[2]); + } + else if (args.Length == 3) + { + response = "No estate name specified."; + } + else + { + Scene scene = SceneManager.CurrentOrFirstScene; + + // TODO: Is there a better choice here? + UUID scopeID = UUID.Zero; + UserAccount account = scene.UserAccountService.GetUserAccount(scopeID, userID); + if (account == null) + { + response = String.Format("Could not find user {0}", userID); + } + else + { + // concatenate it all to "name" + StringBuilder sb = new StringBuilder(args[3]); + for (int i = 4; i < args.Length; i++) + sb.Append (" " + args[i]); + string estateName = sb.ToString().Trim(); + + // send it off for processing. + IEstateModule estateModule = scene.RequestModuleInterface(); + response = estateModule.CreateEstate(estateName, userID); + if (response == String.Empty) + { + List estates = scene.EstateDataService.GetEstates(estateName); + response = String.Format("Estate {0} created as \"{1}\"", estates.ElementAt(0), estateName); + } + } + } + + // give the user some feedback + if (response != null) + MainConsole.Instance.Output(response); + } + protected void SetEstateOwnerCommand(string module, string[] args) { string response = null; @@ -1299,6 +1362,56 @@ namespace OpenSim MainConsole.Instance.Output(response); } + private void EstateLinkRegionCommand(string module, string[] args) + { + int estateId =-1; + UUID regionId = UUID.Zero; + Scene scene = null; + string response = null; + + if (args.Length == 3) + { + response = "No estate specified."; + } + else if (!int.TryParse(args [3], out estateId)) + { + response = String.Format("\"{0}\" is not a valid ID for an Estate", args [3]); + } + else if (args.Length == 4) + { + response = "No region specified."; + } + else if (!UUID.TryParse(args[4], out regionId)) + { + response = String.Format("\"{0}\" is not a valid UUID for a Region", args [4]); + } + else if (!SceneManager.TryGetScene(regionId, out scene)) + { + // region may exist, but on a different sim. + response = String.Format("No access to Region \"{0}\"", args [4]); + } + + if (response != null) + { + MainConsole.Instance.Output(response); + return; + } + + // send it off for processing. + IEstateModule estateModule = scene.RequestModuleInterface(); + response = estateModule.SetRegionEstate(scene.RegionInfo, estateId); + if (response == String.Empty) + { + estateModule.TriggerRegionInfoChange(); + estateModule.sendRegionHandshakeToAll(); + response = String.Format ("Region {0} is now attached to estate {1}", regionId, estateId); + } + + // give the user some feedback + if (response != null) + MainConsole.Instance.Output (response); + } + #endregion private static string CombineParams(string[] commandParams, int pos) diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 54a7302..a032bc7 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -313,6 +313,69 @@ namespace OpenSim.Region.CoreModules.World.Estate return response; } + public string SetRegionEstate(RegionInfo regionInfo, int estateID) + { + string response; + + if (regionInfo.EstateSettings.EstateID == estateID) + { + response = String.Format("\"{0}\" is already part of estate {1}", regionInfo.RegionName, estateID); + } + else + { + // get the current settings from DB + EstateSettings dbSettings = Scene.EstateDataService.LoadEstateSettings(estateID); + if (dbSettings.EstateID == 0) + { + response = String.Format("No estate found with ID {0}", estateID); + } + else if (Scene.EstateDataService.LinkRegion(regionInfo.RegionID, estateID)) + { + // make sure there's a log entry to document the change + m_log.InfoFormat("[ESTATE]: Region {0} ({1}) moved to Estate {2} ({3}).", regionInfo.RegionID, regionInfo.RegionName, estateID, dbSettings.EstateName); + + // propagate the change + ChangeDelegate change = OnEstateInfoChange; + + if (change != null) + change(regionInfo.RegionID); + + response = String.Empty; + } + else + { + response = String.Format("Could not move \"{0}\" to estate {1}", regionInfo.RegionName, estateID); + } + } + return response; + } + + public string CreateEstate(string estateName, UUID ownerID) + { + string response; + if (string.IsNullOrEmpty(estateName)) + { + response = "No estate name specified."; + } + else + { + List estates = Scene.EstateDataService.GetEstates(estateName); + if (estates.Count() > 0) + { + response = String.Format("An estate named \"{0}\" already exists.", estateName); + } + else + { + EstateSettings settings = Scene.EstateDataService.CreateNewEstate(); + settings.EstateOwner = ownerID; + settings.EstateName = estateName; + settings.Save(); + response = String.Empty; + } + } + return response; + } + #endregion #region Packet Data Responders diff --git a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs index 600ecfe..461c880 100644 --- a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs @@ -26,6 +26,7 @@ */ using OpenMetaverse; +using OpenSim.Framework; using OpenSim.Services.Interfaces; namespace OpenSim.Region.Framework.Interfaces @@ -44,6 +45,8 @@ namespace OpenSim.Region.Framework.Interfaces string SetEstateOwner(int estateID, UserAccount account); string SetEstateName(int estateID, string newName); + string SetRegionEstate(RegionInfo regionInfo, int estateID); + string CreateEstate(string estateName, UUID ownerID); /// /// Tell all clients about the current state of the region (terrain textures, water height, etc.). -- cgit v1.1 From e44450cce1cd3a9077aec5514a1b9e65b8cffa0a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 6 May 2014 19:53:35 +0100 Subject: Revert "fix infinite recursion loop in SendGridInstantMessageViaXMLRPCAsync()" There is a problem here with infinite recursion, but this patch loses the 'hunting' behaviour where the code will attempt multiple lookups if the avatar is teleporting rapidly around different simulators. This patch only does a single lookup before giving up. This reverts commit cecb446e0e91ede0b05ea9cf40c1313782241f3d. --- .../Avatar/InstantMessage/MessageTransferModule.cs | 178 ++++++++++++--------- 1 file changed, 99 insertions(+), 79 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index 4f8e2cd..40a400f 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs @@ -428,7 +428,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage /// /// delegate for sending a grid instant message asynchronously /// - public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result); + public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID); protected virtual void GridInstantMessageCompleted(IAsyncResult iar) { @@ -442,118 +442,138 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage { GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; - d.BeginInvoke(im, result, GridInstantMessageCompleted, d); + d.BeginInvoke(im, result, UUID.Zero, GridInstantMessageCompleted, d); } /// - /// Internal SendGridInstantMessage over XMLRPC method. + /// Recursive SendGridInstantMessage over XMLRPC method. /// This is called from within a dedicated thread. + /// The first time this is called, prevRegionHandle will be 0 Subsequent times this is called from + /// itself, prevRegionHandle will be the last region handle that we tried to send. + /// If the handles are the same, we look up the user's location using the grid. + /// If the handles are still the same, we end. The send failed. /// - private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result) + /// + /// Pass in 0 the first time this method is called. It will be called recursively with the last + /// regionhandle tried + /// + protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID) { UUID toAgentID = new UUID(im.toAgentID); - UUID regionID; - bool lookupAgent; - /* - * Try to get what region the agent is in from the cache. - */ + PresenceInfo upd = null; + + bool lookupAgent = false; + lock (m_UserRegionMap) { - lookupAgent = !m_UserRegionMap.TryGetValue(toAgentID, out regionID); + if (m_UserRegionMap.ContainsKey(toAgentID)) + { + upd = new PresenceInfo(); + upd.RegionID = m_UserRegionMap[toAgentID]; + + // We need to compare the current regionhandle with the previous region handle + // or the recursive loop will never end because it will never try to lookup the agent again + if (prevRegionID == upd.RegionID) + { + lookupAgent = true; + } + } + else + { + lookupAgent = true; + } } + - while (true) + // Are we needing to look-up an agent? + if (lookupAgent) { - - /* - * If not in cache, try to find out what region the agent is in. - * Also do this if we know the existing cache entry is bad. - */ - if (lookupAgent) + // Non-cached user agent lookup. + PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); + if (presences != null && presences.Length > 0) { - PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); - - regionID = UUID.Zero; - if (presences != null) + foreach (PresenceInfo p in presences) { - foreach (PresenceInfo p in presences) + if (p.RegionID != UUID.Zero) { - if (p.RegionID != UUID.Zero) - { - regionID = p.RegionID; - break; - } + upd = p; + break; } } + } - // If not found, message is undeliverable - if (regionID == UUID.Zero) + if (upd != null) + { + // check if we've tried this before.. + // This is one way to end the recursive loop + // + if (upd.RegionID == prevRegionID) { - break; + // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); + HandleUndeliveredMessage(im, result); + return; } } - - /* - * Try to find out about region. - * If unable, message is undeliverable. - */ - GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, regionID); - if (reginfo == null) + else { - m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", regionID); - break; + // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); + HandleUndeliveredMessage(im, result); + return; } + } - /* - * Try to send message to agent in the region. - */ - Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); - msgdata["region_handle"] = 0; - bool imresult = doIMSending(reginfo, msgdata); - - /* - * If message delivery successful, save cache entry because we know it is good. - * Then tell caller message has been delivered and we are done. - */ - if (imresult) + if (upd != null) + { + GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, + upd.RegionID); + if (reginfo != null) { - lock (m_UserRegionMap) + Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); + // Not actually used anymore, left in for compatibility + // Remove at next interface change + // + msgdata["region_handle"] = 0; + bool imresult = doIMSending(reginfo, msgdata); + if (imresult) + { + // IM delivery successful, so store the Agent's location in our local cache. + lock (m_UserRegionMap) + { + if (m_UserRegionMap.ContainsKey(toAgentID)) + { + m_UserRegionMap[toAgentID] = upd.RegionID; + } + else + { + m_UserRegionMap.Add(toAgentID, upd.RegionID); + } + } + result(true); + } + else { - m_UserRegionMap[toAgentID] = regionID; + // try again, but lookup user this time. + // Warning, this must call the Async version + // of this method or we'll be making thousands of threads + // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync + // The version that spawns the thread is SendGridInstantMessageViaXMLRPC + + // This is recursive!!!!! + SendGridInstantMessageViaXMLRPCAsync(im, result, + upd.RegionID); } - result(true); - return; } - - /* - * Message delivery failed. - * If we just looked up what region the agent is in, message is undeliverable. - */ - if (lookupAgent) + else { - break; + m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.RegionID); + HandleUndeliveredMessage(im, result); } - - /* - * We used a cached entry that we now know is bad. - * Try again by searching the grid for the user. - */ - lookupAgent = true; } - - /* - * Message is undeliverable for one reason or another. - * Remove possible bad entry from cache. - * Then inform caller that the message is undeliverable. - */ - lock (m_UserRegionMap) + else { - m_UserRegionMap.Remove(toAgentID); + HandleUndeliveredMessage(im, result); } - - // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); - HandleUndeliveredMessage(im, result); } /// -- cgit v1.1