From 16d68749a457acf079a6737f4ca9a9adb9e53e2f Mon Sep 17 00:00:00 2001 From: Homer Horwitz Date: Fri, 3 Oct 2008 23:00:42 +0000 Subject: [PATCH] Add the missing bits for the new region-search: - Added lookup in the data-layer - MySQL works - SQLite doesn't have a grid-db, so it won't work there - I added MSSQL-code to the best of my knowledge; but I don't know MSSQL :-) - Added the plumbing up to OGS1GridServices. This speaks with the grid-server via XMLRPC. - Modified MapSearchModule to use the new data. It's backward compatible; if used with an old grid-server, it just returns one found region instead of a list. - Refactored a bit. Note: This updates data, grid-server and region code. No new files. --- OpenSim/Data/GridDataBase.cs | 3 + OpenSim/Data/IGridData.cs | 9 ++ OpenSim/Data/MSSQL/MSSQLGridData.cs | 27 ++++ OpenSim/Data/MySQL/MySQLGridData.cs | 46 +++++++ OpenSim/Data/SQLite/SQLiteGridData.cs | 12 ++ .../Framework/Communications/IGridServices.cs | 15 +++ OpenSim/Grid/GridServer/GridManager.cs | 70 +++++++++++ OpenSim/Grid/GridServer/GridServerBase.cs | 1 + .../Local/LocalBackEndServices.cs | 15 +++ .../Communications/OGS1/OGS1GridServices.cs | 119 +++++++++++------- .../Modules/World/WorldMap/MapSearchModule.cs | 57 +++++---- .../Scenes/SceneCommunicationService.cs | 6 +- 12 files changed, 312 insertions(+), 68 deletions(-) diff --git a/OpenSim/Data/GridDataBase.cs b/OpenSim/Data/GridDataBase.cs index e8dbc1144a..1e2b6fac62 100644 --- a/OpenSim/Data/GridDataBase.cs +++ b/OpenSim/Data/GridDataBase.cs @@ -25,6 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System.Collections.Generic; using OpenMetaverse; namespace OpenSim.Data @@ -35,6 +36,7 @@ namespace OpenSim.Data public abstract RegionProfileData GetProfileByUUID(UUID UUID); public abstract RegionProfileData GetProfileByString(string regionName); public abstract RegionProfileData[] GetProfilesInRange(uint Xmin, uint Ymin, uint Xmax, uint Ymax); + public abstract List GetRegionsByName(string namePrefix, uint maxNum); public abstract bool AuthenticateSim(UUID UUID, ulong regionHandle, string simrecvkey); public abstract DataResponse AddProfile(RegionProfileData profile); public abstract ReservationData GetReservationAtPoint(uint x, uint y); @@ -44,6 +46,7 @@ namespace OpenSim.Data public abstract void Initialise(); public abstract void Initialise(string connect); public abstract void Dispose(); + public abstract string Name { get; } public abstract string Version { get; } } diff --git a/OpenSim/Data/IGridData.cs b/OpenSim/Data/IGridData.cs index 132361ff1f..a42a7d8e7b 100644 --- a/OpenSim/Data/IGridData.cs +++ b/OpenSim/Data/IGridData.cs @@ -25,6 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System.Collections.Generic; using OpenMetaverse; using OpenSim.Framework; @@ -79,6 +80,14 @@ namespace OpenSim.Data /// An array containing all the sim profiles in the specified range RegionProfileData[] GetProfilesInRange(uint Xmin, uint Ymin, uint Xmax, uint Ymax); + /// + /// Returns up to maxNum profiles of regions that have a name starting with namePrefix + /// + /// The name to match against + /// Maximum number of profiles to return + /// A list of sim profiles + List GetRegionsByName(string namePrefix, uint maxNum); + /// /// Authenticates a sim by use of its recv key. /// WARNING: Insecure diff --git a/OpenSim/Data/MSSQL/MSSQLGridData.cs b/OpenSim/Data/MSSQL/MSSQLGridData.cs index 443116ad5d..6f94980e6a 100644 --- a/OpenSim/Data/MSSQL/MSSQLGridData.cs +++ b/OpenSim/Data/MSSQL/MSSQLGridData.cs @@ -216,6 +216,33 @@ namespace OpenSim.Data.MSSQL return null; } + + /// + /// Returns up to maxNum profiles of regions that have a name starting with namePrefix + /// + /// The name to match against + /// Maximum number of profiles to return + /// A list of sim profiles + override public List GetRegionsByName (string namePrefix, uint maxNum) + { + using (AutoClosingSqlCommand command = database.Query("SELECT * FROM regions WHERE regionName LIKE @name")) + { + command.Parameters.Add(database.CreateParameter("name", namePrefix + "%")); + + List rows = new List(); + + using (SqlDataReader reader = command.ExecuteReader()) + { + while (rows.Count < maxNum && reader.Read()) + { + rows.Add(ReadSimRow(reader)); + } + } + + return rows; + } + } + /// /// Returns a sim profile from its location /// diff --git a/OpenSim/Data/MySQL/MySQLGridData.cs b/OpenSim/Data/MySQL/MySQLGridData.cs index 1155ae3a9c..26a85918e5 100644 --- a/OpenSim/Data/MySQL/MySQLGridData.cs +++ b/OpenSim/Data/MySQL/MySQLGridData.cs @@ -282,6 +282,52 @@ namespace OpenSim.Data.MySQL } } + /// + /// Returns up to maxNum profiles of regions that have a name starting with namePrefix + /// + /// The name to match against + /// Maximum number of profiles to return + /// A list of sim profiles + override public List GetRegionsByName(string namePrefix, uint maxNum) + { + MySQLSuperManager dbm = GetLockedConnection(); + + try + { + Dictionary param = new Dictionary(); + param["?name"] = namePrefix + "%"; + + IDbCommand result = + dbm.Manager.Query( + "SELECT * FROM regions WHERE regionName LIKE ?name", + param); + IDataReader reader = result.ExecuteReader(); + + RegionProfileData row; + + List rows = new List(); + + while (rows.Count < maxNum && (row = dbm.Manager.readSimRow(reader)) != null) + { + rows.Add(row); + } + reader.Close(); + result.Dispose(); + + return rows; + } + catch (Exception e) + { + dbm.Manager.Reconnect(); + m_log.Error(e.ToString()); + return null; + } + finally + { + dbm.Release(); + } + } + /// /// Returns a sim profile from it's location /// diff --git a/OpenSim/Data/SQLite/SQLiteGridData.cs b/OpenSim/Data/SQLite/SQLiteGridData.cs index 3e1c67a002..5b0455d779 100644 --- a/OpenSim/Data/SQLite/SQLiteGridData.cs +++ b/OpenSim/Data/SQLite/SQLiteGridData.cs @@ -108,6 +108,18 @@ namespace OpenSim.Data.SQLite return null; } + + /// + /// Returns up to maxNum profiles of regions that have a name starting with namePrefix + /// + /// The name to match against + /// Maximum number of profiles to return + /// A list of sim profiles + override public List GetRegionsByName (string namePrefix, uint maxNum) + { + return null; + } + /// /// Returns a sim profile from it's handle /// diff --git a/OpenSim/Framework/Communications/IGridServices.cs b/OpenSim/Framework/Communications/IGridServices.cs index 177009d5be..69e875650e 100644 --- a/OpenSim/Framework/Communications/IGridServices.cs +++ b/OpenSim/Framework/Communications/IGridServices.cs @@ -70,5 +70,20 @@ namespace OpenSim.Framework.Communications List RequestNeighbourMapBlocks(int minX, int minY, int maxX, int maxY); // not complete yet, only contains the fields needed for ParcelInfoReqeust LandData RequestLandData(ulong regionHandle, uint x, uint y); + + /// + /// Get information about regions starting with the provided name. + /// + /// + /// The name to match against. + /// + /// + /// The maximum number of results to return. + /// + /// + /// A list of s of regions with matching name. If the + /// grid-server couldn't be contacted or returned an error, return null. + /// + List RequestNamedRegions(string name, int maxNumber); } } diff --git a/OpenSim/Grid/GridServer/GridManager.cs b/OpenSim/Grid/GridServer/GridManager.cs index ed474c5074..1e8ac000a2 100644 --- a/OpenSim/Grid/GridServer/GridManager.cs +++ b/OpenSim/Grid/GridServer/GridManager.cs @@ -188,6 +188,26 @@ namespace OpenSim.Grid.GridServer return regions; } + public List GetRegions(string name, int maxNum) + { + List regions = new List(); + foreach (IGridDataPlugin plugin in _plugins) + { + try + { + int num = maxNum - regions.Count; + List profiles = plugin.GetRegionsByName(name, (uint)num); + if (profiles != null) regions.AddRange(profiles); + } + catch + { + m_log.Warn("[storage]: Unable to query regionblock via " + plugin.Name); + } + } + + return regions; + } + /// /// Returns a XML String containing a list of the neighbouring regions /// @@ -876,6 +896,56 @@ namespace OpenSim.Grid.GridServer return response; } + /// + /// Returns up to maxNumber profiles of regions that have a name starting with name + /// + /// + /// + public XmlRpcResponse XmlRpcSearchForRegionMethod(XmlRpcRequest request) + { + Hashtable requestData = (Hashtable)request.Params[0]; + + if (!requestData.ContainsKey("name") || !requestData.Contains("maxNumber")) + { + m_log.Warn("[DATA] Invalid region-search request; missing name or maxNumber"); + return new XmlRpcResponse(500, "Missing name or maxNumber in region search request"); + } + + Hashtable responseData = new Hashtable(); + + string name = (string)requestData["name"]; + int maxNumber = Convert.ToInt32((string)requestData["maxNumber"]); + if (maxNumber == 0 || name.Length < 3) + { + // either we didn't want any, or we were too unspecific + responseData["numFound"] = 0; + } + else + { + List sims = GetRegions(name, maxNumber); + + responseData["numFound"] = sims.Count; + for (int i = 0; i < sims.Count; ++i) + { + RegionProfileData sim = sims[i]; + string prefix = "region" + i + "."; + responseData[prefix + "region_name"] = sim.regionName; + responseData[prefix + "region_UUID"] = sim.UUID.ToString(); + responseData[prefix + "region_locx"] = sim.regionLocX.ToString(); + responseData[prefix + "region_locy"] = sim.regionLocY.ToString(); + responseData[prefix + "sim_ip"] = sim.serverIP.ToString(); + responseData[prefix + "sim_port"] = sim.serverPort.ToString(); + responseData[prefix + "remoting_port"] = sim.remotingPort.ToString(); + responseData[prefix + "http_port"] = sim.httpPort.ToString(); + responseData[prefix + "map_UUID"] = sim.regionMapTextureID.ToString(); + } + } + + XmlRpcResponse response = new XmlRpcResponse(); + response.Value = responseData; + return response; + } + /// /// Performs a REST Get Operation /// diff --git a/OpenSim/Grid/GridServer/GridServerBase.cs b/OpenSim/Grid/GridServer/GridServerBase.cs index 875b4aca88..2ffeb576c7 100644 --- a/OpenSim/Grid/GridServer/GridServerBase.cs +++ b/OpenSim/Grid/GridServer/GridServerBase.cs @@ -101,6 +101,7 @@ namespace OpenSim.Grid.GridServer m_httpServer.AddXmlRPCHandler("simulator_data_request", m_gridManager.XmlRpcSimulatorDataRequestMethod); m_httpServer.AddXmlRPCHandler("simulator_after_region_moved", m_gridManager.XmlRpcDeleteRegionMethod); m_httpServer.AddXmlRPCHandler("map_block", m_gridManager.XmlRpcMapBlockMethod); + m_httpServer.AddXmlRPCHandler("search_for_region_by_name", m_gridManager.XmlRpcSearchForRegionMethod); // Message Server ---> Grid Server m_httpServer.AddXmlRPCHandler("register_messageserver", m_gridManager.XmlRPCRegisterMessageServer); diff --git a/OpenSim/Region/Communications/Local/LocalBackEndServices.cs b/OpenSim/Region/Communications/Local/LocalBackEndServices.cs index a861ceba7f..9034e49ed1 100644 --- a/OpenSim/Region/Communications/Local/LocalBackEndServices.cs +++ b/OpenSim/Region/Communications/Local/LocalBackEndServices.cs @@ -514,5 +514,20 @@ namespace OpenSim.Region.Communications.Local m_log.Debug("[INTERREGION STANDALONE] didn't find land data locally."); return null; } + + public List RequestNamedRegions (string name, int maxNumber) + { + List regions = new List(); + foreach (RegionInfo info in m_regions.Values) + { + if (info.RegionName.StartsWith(name)) + { + regions.Add(info); + if (regions.Count >= maxNumber) break; + } + } + + return regions; + } } } diff --git a/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs b/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs index a2d382336e..397062b7db 100644 --- a/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs +++ b/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs @@ -352,27 +352,7 @@ namespace OpenSim.Region.Communications.OGS1 return null; } - uint regX = Convert.ToUInt32((string) responseData["region_locx"]); - uint regY = Convert.ToUInt32((string) responseData["region_locy"]); - string internalIpStr = (string) responseData["sim_ip"]; - uint port = Convert.ToUInt32(responseData["sim_port"]); - // string externalUri = (string) responseData["sim_uri"]; - - IPEndPoint neighbourInternalEndPoint = new IPEndPoint(IPAddress.Parse(internalIpStr), (int) port); - // string neighbourExternalUri = externalUri; - regionInfo = new RegionInfo(regX, regY, neighbourInternalEndPoint, internalIpStr); - - regionInfo.RemotingPort = Convert.ToUInt32((string) responseData["remoting_port"]); - regionInfo.RemotingAddress = internalIpStr; - - if (responseData.ContainsKey("http_port")) - { - regionInfo.HttpPort = Convert.ToUInt32((string) responseData["http_port"]); - } - - regionInfo.RegionID = new UUID((string) responseData["region_UUID"]); - regionInfo.RegionName = (string) responseData["region_name"]; - + regionInfo = buildRegionInfo(responseData, String.Empty); if (requestData.ContainsKey("regionHandle")) { m_remoteRegionInfoCache.Add(Convert.ToUInt64((string) requestData["regionHandle"]), regionInfo); @@ -479,30 +459,11 @@ namespace OpenSim.Region.Communications.OGS1 if (responseData.ContainsKey("error")) { - m_log.Error("[OGS1 GRID SERVICES]: Error received from grid server" + responseData["error"]); + m_log.ErrorFormat("[OGS1 GRID SERVICES]: Error received from grid server: ", responseData["error"]); return null; } - uint regX = Convert.ToUInt32((string) responseData["region_locx"]); - uint regY = Convert.ToUInt32((string) responseData["region_locy"]); - string internalIpStr = (string) responseData["sim_ip"]; - uint port = Convert.ToUInt32(responseData["sim_port"]); - // string externalUri = (string) responseData["sim_uri"]; - - IPEndPoint neighbourInternalEndPoint = new IPEndPoint(IPAddress.Parse(internalIpStr), (int) port); - // string neighbourExternalUri = externalUri; - regionInfo = new RegionInfo(regX, regY, neighbourInternalEndPoint, internalIpStr); - - regionInfo.RemotingPort = Convert.ToUInt32((string) responseData["remoting_port"]); - regionInfo.RemotingAddress = internalIpStr; - - if (responseData.ContainsKey("http_port")) - { - regionInfo.HttpPort = Convert.ToUInt32((string) responseData["http_port"]); - } - - regionInfo.RegionID = new UUID((string) responseData["region_UUID"]); - regionInfo.RegionName = (string) responseData["region_name"]; + regionInfo = buildRegionInfo(responseData, ""); if (!m_remoteRegionInfoCache.ContainsKey(regionInfo.RegionHandle)) m_remoteRegionInfoCache.Add(regionInfo.RegionHandle, regionInfo); @@ -1676,7 +1637,8 @@ namespace OpenSim.Region.Communications.OGS1 else { hash = (Hashtable)response.Value; - try { + try + { landData = new LandData(); landData.AABBMax = Vector3.Parse((string)hash["AABBMax"]); landData.AABBMin = Vector3.Parse((string)hash["AABBMin"]); @@ -1745,5 +1707,76 @@ namespace OpenSim.Region.Communications.OGS1 response.Value = hash; return response; } + + public List RequestNamedRegions (string name, int maxNumber) + { + // no asking of the local backend first, here, as we have to ask the gridserver anyway. + Hashtable hash = new Hashtable(); + hash["name"] = name; + hash["maxNumber"] = maxNumber.ToString(); + + IList paramList = new ArrayList(); + paramList.Add(hash); + + Hashtable result = XmlRpcSearchForRegionByName(paramList); + if (result == null) return null; + + uint numberFound = Convert.ToUInt32(result["numFound"]); + List infos = new List(); + for (int i = 0; i < numberFound; ++i) + { + string prefix = "region" + i + "."; + RegionInfo info = buildRegionInfo(result, prefix); + infos.Add(info); + } + return infos; + } + + private RegionInfo buildRegionInfo(Hashtable responseData, string prefix) + { + uint regX = Convert.ToUInt32((string) responseData[prefix + "region_locx"]); + uint regY = Convert.ToUInt32((string) responseData[prefix + "region_locy"]); + string internalIpStr = (string) responseData[prefix + "sim_ip"]; + uint port = Convert.ToUInt32(responseData[prefix + "sim_port"]); + + IPEndPoint neighbourInternalEndPoint = new IPEndPoint(Util.GetHostFromDNS(internalIpStr), (int) port); + + RegionInfo regionInfo = new RegionInfo(regX, regY, neighbourInternalEndPoint, internalIpStr); + regionInfo.RemotingPort = Convert.ToUInt32((string) responseData[prefix + "remoting_port"]); + regionInfo.RemotingAddress = internalIpStr; + + if (responseData.ContainsKey(prefix + "http_port")) + { + regionInfo.HttpPort = Convert.ToUInt32((string) responseData[prefix + "http_port"]); + } + + regionInfo.RegionID = new UUID((string) responseData[prefix + "region_UUID"]); + regionInfo.RegionName = (string) responseData[prefix + "region_name"]; + + regionInfo.RegionSettings.TerrainImageID = new UUID((string) responseData[prefix + "map_UUID"]); + return regionInfo; + } + + private Hashtable XmlRpcSearchForRegionByName(IList parameters) + { + try + { + XmlRpcRequest request = new XmlRpcRequest("search_for_region_by_name", parameters); + XmlRpcResponse resp = request.Send(serversInfo.GridURL, 10000); + Hashtable respData = (Hashtable) resp.Value; + if (respData != null && respData.Contains("faultCode")) + { + m_log.WarnFormat("[OGS1 GRID SERVICES]: Got an error while contacting GridServer: {0}", respData["faultString"]); + return null; + } + + return respData; + } + catch (Exception e) + { + m_log.Error("[OGS1 GRID SERVICES]: MapBlockQuery XMLRPC failure: ", e); + return null; + } + } } } \ No newline at end of file diff --git a/OpenSim/Region/Environment/Modules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/Environment/Modules/World/WorldMap/MapSearchModule.cs index 1a15585951..8cc707cef6 100644 --- a/OpenSim/Region/Environment/Modules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/Environment/Modules/World/WorldMap/MapSearchModule.cs @@ -78,35 +78,44 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap private void OnMapNameRequest(IClientAPI remoteClient, string mapName) { - m_log.DebugFormat("[MAPSEARCH]: looking for region {0}", mapName); - - // TODO currently, this only returns one region per name. LL servers will return all starting with the provided name. - RegionInfo info = m_scene.SceneGridService.RequestClosestRegion(mapName); - // fetch the mapblock of the named sim. We need this anyway (we have the map open, and just jumped to the sim), - // so there shouldn't be any penalty for that. - if (info == null) - { - m_log.Warn("[MAPSEARCHMODULE]: Got Null Region Question!"); - return; + if (mapName.Length < 3) + { + remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); + return; + } + + // try to fetch from GridServer + List regionInfos = m_scene.SceneGridService.RequestNamedRegions(mapName, 20); + if (regionInfos == null) + { + m_log.Warn("[MAPSEARCHMODULE]: RequestNamedRegions returned null. Old gridserver?"); + // service wasn't available; maybe still an old GridServer. Try the old API, though it will return only one region + regionInfos = new List(); + RegionInfo info = m_scene.SceneGridService.RequestClosestRegion(mapName); + if (info != null) regionInfos.Add(info); } - List mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks((int)info.RegionLocX, - (int)info.RegionLocY, - (int)info.RegionLocX, - (int)info.RegionLocY); List blocks = new List(); - MapBlockData data = new MapBlockData(); - data.Agents = 3; // TODO set to number of agents in region - data.Access = 21; // TODO what's this? - data.MapImageId = mapBlocks.Count == 0 ? UUID.Zero : mapBlocks[0].MapImageId; - data.Name = info.RegionName; - data.RegionFlags = 0; // TODO fix this - data.WaterHeight = 0; // not used - data.X = (ushort)info.RegionLocX; - data.Y = (ushort)info.RegionLocY; - blocks.Add(data); + MapBlockData data; + if (regionInfos.Count > 0) + { + foreach (RegionInfo info in regionInfos) + { + data = new MapBlockData(); + data.Agents = 0; + data.Access = 21; // TODO what's this? + data.MapImageId = info.RegionSettings.TerrainImageID; + data.Name = info.RegionName; + data.RegionFlags = 0; // TODO not used? + data.WaterHeight = 0; // not used + data.X = (ushort)info.RegionLocX; + data.Y = (ushort)info.RegionLocY; + blocks.Add(data); + } + } + // final block, closing the search result data = new MapBlockData(); data.Agents = 0; data.Access = 255; diff --git a/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs index c33c777a48..08793d9750 100644 --- a/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs +++ b/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs @@ -806,6 +806,10 @@ namespace OpenSim.Region.Environment.Scenes { return m_commsProvider.GenerateAgentPickerRequestResponse(queryID, query); } - + + public List RequestNamedRegions(string name, int maxNumber) + { + return m_commsProvider.GridService.RequestNamedRegions(name, maxNumber); + } } }