OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
RegionReadyModule.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Reflection;
31 using System.Net;
32 using System.IO;
33 using System.Text;
34 using log4net;
35 using Mono.Addins;
36 using Nini.Config;
37 using OpenMetaverse;
38 using OpenMetaverse.StructuredData;
39 using OpenSim.Framework;
40 using OpenSim.Region.Framework.Interfaces;
41 using OpenSim.Region.Framework.Scenes;
42 using OpenSim.Services.Interfaces;
43 
44 namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
45 {
46  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionReadyModule")]
48  {
49  private static readonly ILog m_log =
50  LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 
52  private IConfig m_config = null;
53  private bool m_firstEmptyCompileQueue;
54  private bool m_oarFileLoading;
55  private bool m_lastOarLoadedOk;
56  private int m_channelNotify = -1000;
57  private bool m_enabled = false;
58  private bool m_disable_logins;
59  private string m_uri = string.Empty;
60 
61  Scene m_scene;
62 
63  #region INonSharedRegionModule interface
64 
65  public Type ReplaceableInterface
66  {
67  get { return null; }
68  }
69 
70  public void Initialise(IConfigSource config)
71  {
72  m_config = config.Configs["RegionReady"];
73  if (m_config != null)
74  {
75  m_enabled = m_config.GetBoolean("enabled", false);
76 
77  if (m_enabled)
78  {
79  m_channelNotify = m_config.GetInt("channel_notify", m_channelNotify);
80  m_disable_logins = m_config.GetBoolean("login_disable", false);
81  m_uri = m_config.GetString("alert_uri",string.Empty);
82  }
83  }
84  }
85 
86  public void AddRegion(Scene scene)
87  {
88  if (!m_enabled)
89  return;
90 
91  m_scene = scene;
92 
93  m_scene.RegisterModuleInterface<IRegionReadyModule>(this);
94 
95  m_firstEmptyCompileQueue = true;
96  m_oarFileLoading = false;
97  m_lastOarLoadedOk = true;
98 
99  m_scene.EventManager.OnOarFileLoaded += OnOarFileLoaded;
100 
101  m_log.DebugFormat("[RegionReady]: Enabled for region {0}", scene.RegionInfo.RegionName);
102 
103  if (m_disable_logins)
104  {
105  m_scene.LoginLock = true;
106  m_scene.EventManager.OnEmptyScriptCompileQueue += OnEmptyScriptCompileQueue;
107 
108  // This should always show up to the user but should not trigger warn/errors as these messages are
109  // expected and are not simulator problems. Ideally, there would be a status level in log4net but
110  // failing that, we will print out to console instead.
111  MainConsole.Instance.OutputFormat("Region {0} - LOGINS DISABLED DURING INITIALIZATION.", m_scene.Name);
112 
113  if (m_uri != string.Empty)
114  {
115  RRAlert("disabled");
116  }
117  }
118  }
119 
120  public void RemoveRegion(Scene scene)
121  {
122  if (!m_enabled)
123  return;
124 
125  m_scene.EventManager.OnOarFileLoaded -= OnOarFileLoaded;
126 
127  if (m_disable_logins)
128  m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue;
129 
130  if (m_uri != string.Empty)
131  RRAlert("shutdown");
132 
133  m_scene = null;
134  }
135 
136  public void Close()
137  {
138  }
139 
140  public void RegionLoaded(Scene scene)
141  {
142  }
143 
144  public string Name
145  {
146  get { return "RegionReadyModule"; }
147  }
148 
149  #endregion
150 
151  void OnEmptyScriptCompileQueue(int numScriptsFailed, string message)
152  {
153  m_log.DebugFormat("[RegionReady]: Script compile queue empty!");
154 
155  if (m_firstEmptyCompileQueue || m_oarFileLoading)
156  {
157  OSChatMessage c = new OSChatMessage();
158  if (m_firstEmptyCompileQueue)
159  c.Message = "server_startup,";
160  else
161  c.Message = "oar_file_load,";
162  m_firstEmptyCompileQueue = false;
163  m_oarFileLoading = false;
164 
165  m_scene.Backup(false);
166 
167  c.From = "RegionReady";
168  if (m_lastOarLoadedOk)
169  c.Message += "1,";
170  else
171  c.Message += "0,";
172  c.Channel = m_channelNotify;
173  c.Message += numScriptsFailed.ToString() + "," + message;
174  c.Type = ChatTypeEnum.Region;
175  if (m_scene != null)
176  c.Position = new Vector3((m_scene.RegionInfo.RegionSizeX * 0.5f), (m_scene.RegionInfo.RegionSizeY * 0.5f), 30);
177  else
178  c.Position = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 30);
179  c.Sender = null;
180  c.SenderUUID = UUID.Zero;
181  c.Scene = m_scene;
182 
183  m_log.DebugFormat("[RegionReady]: Region \"{0}\" is ready: \"{1}\" on channel {2}",
184  m_scene.RegionInfo.RegionName, c.Message, m_channelNotify);
185 
186  m_scene.EventManager.TriggerOnChatBroadcast(this, c);
187 
188  TriggerRegionReady(m_scene);
189  }
190  }
191 
192  void OnOarFileLoaded(Guid requestId, List<UUID> loadedScenes, string message)
193  {
194  m_oarFileLoading = true;
195 
196  if (message==String.Empty)
197  {
198  m_lastOarLoadedOk = true;
199  }
200  else
201  {
202  m_log.WarnFormat("[RegionReady]: Oar file load errors: {0}", message);
203  m_lastOarLoadedOk = false;
204  }
205  }
206 
212  public void TriggerRegionReady(IScene scene)
213  {
214  m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue;
215  m_scene.LoginLock = false;
216 
217  if (!m_scene.StartDisabled)
218  {
219  m_scene.LoginsEnabled = true;
220 
221  // m_log.InfoFormat("[RegionReady]: Logins enabled for {0}, Oar {1}",
222  // m_scene.RegionInfo.RegionName, m_oarFileLoading.ToString());
223 
224  // Putting this out to console to make it eye-catching for people who are running OpenSimulator
225  // without info log messages enabled. Making this a warning is arguably misleading since it isn't a
226  // warning, and monitor scripts looking for warn/error/fatal messages will received false positives.
227  // Arguably, log4net needs a status log level (like Apache).
228  MainConsole.Instance.OutputFormat("INITIALIZATION COMPLETE FOR {0} - LOGINS ENABLED", m_scene.Name);
229  }
230 
231  m_scene.SceneGridService.InformNeighborsThatRegionisUp(
232  m_scene.RequestModuleInterface<INeighbourService>(), m_scene.RegionInfo);
233 
234  if (m_uri != string.Empty)
235  {
236  RRAlert("enabled");
237  }
238 
239  m_scene.Ready = true;
240  }
241 
242  public void OarLoadingAlert(string msg)
243  {
244  // Let's bypass this for now until some better feedback can be established
245  //
246 
247 // if (msg == "load")
248 // {
249 // m_scene.EventManager.OnEmptyScriptCompileQueue += OnEmptyScriptCompileQueue;
250 // m_scene.EventManager.OnOarFileLoaded += OnOarFileLoaded;
251 // m_scene.EventManager.OnLoginsEnabled += OnLoginsEnabled;
252 // m_scene.EventManager.OnRezScript += OnRezScript;
253 // m_oarFileLoading = true;
254 // m_firstEmptyCompileQueue = true;
255 //
256 // m_scene.LoginsDisabled = true;
257 // m_scene.LoginLock = true;
258 // if ( m_uri != string.Empty )
259 // {
260 // RRAlert("loading oar");
261 // RRAlert("disabled");
262 // }
263 // }
264  }
265 
266  public void RRAlert(string status)
267  {
268  string request_method = "POST";
269  string content_type = "application/json";
270  OSDMap RRAlert = new OSDMap();
271 
272  RRAlert["alert"] = "region_ready";
273  RRAlert["login"] = status;
274  RRAlert["region_name"] = m_scene.RegionInfo.RegionName;
275  RRAlert["region_id"] = m_scene.RegionInfo.RegionID;
276 
277  string strBuffer = "";
278  byte[] buffer = new byte[1];
279  try
280  {
281  strBuffer = OSDParser.SerializeJsonString(RRAlert);
282  Encoding str = Util.UTF8;
283  buffer = str.GetBytes(strBuffer);
284 
285  }
286  catch (Exception e)
287  {
288  m_log.WarnFormat("[RegionReady]: Exception thrown on alert: {0}", e.Message);
289  }
290 
291  WebRequest request = WebRequest.Create(m_uri);
292  request.Method = request_method;
293  request.ContentType = content_type;
294 
295  Stream os = null;
296  try
297  {
298  request.ContentLength = buffer.Length;
299  os = request.GetRequestStream();
300  os.Write(buffer, 0, strBuffer.Length);
301  }
302  catch(Exception e)
303  {
304  m_log.WarnFormat("[RegionReady]: Exception thrown sending alert: {0}", e.Message);
305  }
306  finally
307  {
308  if (os != null)
309  os.Dispose();
310  }
311  }
312  }
313 }
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
OpenMetaverse.StructuredData.OSDMap OSDMap
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
ChatFromViewer Arguments
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
Interactive OpenSim region server
Definition: OpenSim.cs:55
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
void TriggerRegionReady(IScene scene)
This will be triggered by Scene directly if it contains no scripts on startup. Otherwise it is trigge...