diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs b/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs new file mode 100644 index 0000000000..7fc12671c9 --- /dev/null +++ b/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs @@ -0,0 +1,72 @@ +/* +* 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 OpenSim 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 libsecondlife; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Xml.Serialization; +using OpenSim.Framework; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.ApplicationPlugins.Rest.Regions +{ + [XmlRoot(ElementName="region")] + public class RegionDetails + { + public string region_name; + public string region_id; + public uint region_x; + public uint region_y; + public string region_owner; + public string region_owner_id; + public uint region_http_port; + public string region_server_uri; + public string region_external_hostname; + + public RegionDetails() + { + } + + public RegionDetails(RegionInfo regInfo) + { + region_name = regInfo.RegionName; + region_id = regInfo.RegionID.ToString(); + region_x = regInfo.RegionLocX; + region_y = regInfo.RegionLocY; + region_owner_id = regInfo.MasterAvatarAssignedUUID.ToString(); + region_http_port = regInfo.HttpPort; + region_server_uri = regInfo.ServerURI; + region_external_hostname = regInfo.ExternalHostName; + + if (!String.IsNullOrEmpty(regInfo.MasterAvatarFirstName)) + region_owner = String.Format("{0} {1}", regInfo.MasterAvatarFirstName, + regInfo.MasterAvatarLastName); + } + } +} \ No newline at end of file diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs b/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs new file mode 100644 index 0000000000..8a6fb092aa --- /dev/null +++ b/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs @@ -0,0 +1,162 @@ +/* +* 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 OpenSim 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 System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Timers; +using System.Xml; +using System.Xml.Serialization; +using libsecondlife; +using Mono.Addins; +using Nwc.XmlRpc; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Communications; +using OpenSim.Region.Environment.Scenes; +using OpenSim.ApplicationPlugins.Rest; + +[assembly : Addin] +[assembly : AddinDependency("OpenSim", "0.5")] + +namespace OpenSim.ApplicationPlugins.Rest.Regions +{ + + [Extension("/OpenSim/Startup")] + public class RestRegionPlugin : RestPlugin + { + private static readonly log4net.ILog _log = + log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + #region overriding properties + public override string Name + { + get { return "REGION"; } + } + + public override string ConfigName + { + get { return "RestRegionPlugin"; } + } + #endregion overriding properties + + #region overriding methods + /// + /// This method is called by OpenSimMain immediately after loading the + /// plugin and after basic server setup, but before running any server commands. + /// + /// + /// Note that entries MUST be added to the active configuration files before + /// the plugin can be enabled. + /// + public override void Initialise(OpenSimMain openSim) + { + try + { + base.Initialise(openSim); + if (IsEnabled) + m_log.InfoFormat("{0} Rest Plugins Enabled", MsgID); + else + m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID); + + // add REST method handlers + AddRestStreamHandler("GET", "/regions/", GetHandler); + } + catch (Exception e) + { + _log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message); + _log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString()); + } + } + + public override void Close() + { + } + #endregion overriding methods + + #region methods + public string GetHandler(string request, string path, string param) + { + m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param); + + // param empty: regions list + if (String.IsNullOrEmpty(param)) return GetHandlerRegions(); + + return GetHandlerRegion(param); + } + + public string GetHandlerRegions() + { + StringWriter sw = new StringWriter(); + XmlTextWriter xw = new XmlTextWriter(sw); + xw.Formatting = Formatting.Indented; + + xw.WriteStartElement(String.Empty, "regions", String.Empty); + foreach (Scene s in App.SceneManager.Scenes) + { + xw.WriteStartElement(String.Empty, "uuid", String.Empty); + xw.WriteString(s.RegionInfo.RegionID.ToString()); + xw.WriteEndElement(); + } + xw.WriteEndElement(); + xw.Close(); + + return sw.ToString(); + } + + public string GetHandlerRegion(string param) + { + string[] comps = param.Split('/'); + LLUUID regionID = (LLUUID)comps[0]; + _log.DebugFormat("{0} region UUID {1}", MsgID, regionID.ToString()); + + if (LLUUID.Zero == regionID) throw new Exception("missing region ID"); + + Scene scene = null; + App.SceneManager.TryGetScene(regionID, out scene); + + XmlSerializer xs = new XmlSerializer(typeof(RegionDetails)); + StringWriter sw = new StringWriter(); + XmlTextWriter xw = new XmlTextWriter(sw); + xw.Formatting = Formatting.Indented; + + xs.Serialize(xw, new RegionDetails(scene.RegionInfo)); + xw.Close(); + + return sw.ToString(); + } + #endregion methods + } +} diff --git a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs new file mode 100644 index 0000000000..0e54f4d9a3 --- /dev/null +++ b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs @@ -0,0 +1,246 @@ +/* +* 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 OpenSim 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 System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Reflection; +using System.Timers; +using libsecondlife; +using Mono.Addins; +using Nwc.XmlRpc; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Communications; +using OpenSim.Region.Environment.Scenes; + +// [assembly : Addin] +// [assembly : AddinDependency("OpenSim", "0.5")] + +namespace OpenSim.ApplicationPlugins.Rest +{ + + // [Extension("/OpenSim/Startup")] + public abstract class RestPlugin : IApplicationPlugin + { + #region properties + + protected static readonly log4net.ILog m_log = + log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IConfig _config; // Configuration source: Rest Plugins + private IConfig _pluginConfig; // Configuration source: Plugin specific + private OpenSimMain _app; // The 'server' + private BaseHttpServer _httpd; // The server's RPC interface + private string _prefix; // URL prefix below which all REST URLs are living + + private string _godkey; + private int _reqk; + + [ThreadStaticAttribute] + private static string _threadRequestID = String.Empty; + + /// + /// Return an ever increasing request ID for logging + /// + protected string RequestID + { + get { return _reqk++.ToString(); } + set { _reqk = Convert.ToInt32(value); } + } + + /// + /// Thread-constant message IDs for logging. + /// + protected string MsgID + { + get { return String.Format("[REST-{0}] #{1}", Name, _threadRequestID); } + set { _threadRequestID = value; } + } + + /// + /// Returns true if Rest Plugins are enabled. + /// + public bool PluginsAreEnabled + { + get { return null != _config; } + } + + /// + /// Returns true if specific Rest Plugin is enabled. + /// + public bool IsEnabled + { + get + { + return (null != _pluginConfig) && _pluginConfig.GetBoolean("enabled", false); + } + } + + /// + /// OpenSimMain application + /// + public OpenSimMain App + { + get { return _app; } + } + + /// + /// RPC server + /// + public BaseHttpServer HttpServer + { + get { return _httpd; } + } + + /// + /// URL prefix to use for all REST handlers + /// + public string Prefix + { + get { return _prefix; } + } + + /// + /// Configuration of the plugin + /// + public IConfig Config + { + get { return _pluginConfig; } + } + + /// + /// Name of the plugin + /// + public abstract string Name { get; } + + /// + /// Return the config section name + /// + public abstract string ConfigName { get; } + #endregion properties + + + #region methods + /// + /// This method is called by OpenSimMain immediately after loading the + /// plugin and after basic server setup, but before running any server commands. + /// + /// + /// Note that entries MUST be added to the active configuration files before + /// the plugin can be enabled. + /// + public virtual void Initialise(OpenSimMain openSim) + { + RequestID = "0"; + MsgID = RequestID; + + try + { + if ((_config = openSim.ConfigSource.Configs["RestPlugins"]) == null) { + m_log.WarnFormat("{0} Rest Plugins not configured", MsgID); + return; + } + + if (!_config.GetBoolean("enabled", false)) + { + m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID); + return; + } + + _app = openSim; + _httpd = openSim.HttpServer; + + // Retrieve GOD key value, if any. + _godkey = _config.GetString("god_key", String.Empty); + // Retrive prefix if any. + _prefix = _config.GetString("prefix", "/admin"); + + // Get plugin specific config + _pluginConfig = openSim.ConfigSource.Configs[ConfigName]; + + m_log.InfoFormat("{0} Rest Plugins Enabled", MsgID); + } + catch (Exception e) + { + // we can safely ignore this, as it just means that + // the key lookup in Configs failed, which signals to + // us that noone is interested in our services...they + // don't know what they are missing out on... + // NOTE: Under the present OpenSim implementation it is + // not possible for the openSim pointer to be null. However + // were the implementation to be changed, this could + // result in a silent initialization failure. Harmless + // except for lack of function and lack of any + // diagnostic indication as to why. The same is true if + // the HTTP server reference is bad. + // We should at least issue a message... + m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message); + m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString()); + } + } + + + private List _handlers = new List(); + + public void AddRestStreamHandler(string httpMethod, string path, RestMethod method) + { + if (!path.StartsWith(_prefix)) + { + path = String.Format("{0}{1}", _prefix, path); + } + + RestStreamHandler h = new RestStreamHandler(httpMethod, path, method); + _httpd.AddStreamHandler(h); + _handlers.Add(h); + + m_log.DebugFormat("{0} Added REST handler {1} {2}", MsgID, httpMethod, path); + } + + + public bool VerifyGod(string key) + { + if (String.IsNullOrEmpty(key)) return false; + return key == _godkey; + } + + public virtual void Close() + { + foreach (RestStreamHandler h in _handlers) + { + _httpd.RemoveStreamHandler(h.HttpMethod, h.Path); + } + _handlers = null; + } + #endregion methods + } +}