OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
RestartModule.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.Linq;
30 using System.Reflection;
31 using System.Timers;
32 using System.IO;
33 using System.Diagnostics;
34 using System.Threading;
35 using System.Collections.Generic;
36 using log4net;
37 using Nini.Config;
38 using OpenMetaverse;
39 using OpenSim.Framework;
40 using OpenSim.Framework.Console;
41 using OpenSim.Region.Framework.Interfaces;
42 using OpenSim.Region.Framework.Scenes;
44 using Mono.Addins;
45 
46 namespace OpenSim.Region.CoreModules.World.Region
47 {
48  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RestartModule")]
50  {
51  private static readonly ILog m_log =
52  LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 
54  protected Scene m_Scene;
55  protected Timer m_CountdownTimer = null;
56  protected DateTime m_RestartBegin;
57  protected List<int> m_Alerts;
58  protected string m_Message;
59  protected UUID m_Initiator;
60  protected bool m_Notice = false;
61  protected IDialogModule m_DialogModule = null;
62  protected string m_MarkerPath = String.Empty;
63  private int[] m_CurrentAlerts = null;
64 
65  public void Initialise(IConfigSource config)
66  {
67  IConfig restartConfig = config.Configs["RestartModule"];
68  if (restartConfig != null)
69  {
70  m_MarkerPath = restartConfig.GetString("MarkerPath", String.Empty);
71  }
72  }
73 
74  public void AddRegion(Scene scene)
75  {
76  if (m_MarkerPath != String.Empty)
77  File.Delete(Path.Combine(m_MarkerPath,
78  scene.RegionInfo.RegionID.ToString()));
79 
80  m_Scene = scene;
81 
82  scene.RegisterModuleInterface<IRestartModule>(this);
83  MainConsole.Instance.Commands.AddCommand("Regions",
84  false, "region restart bluebox",
85  "region restart bluebox <message> <delta seconds>+",
86  "Schedule a region restart",
87  "Schedule a region restart after a given number of seconds. If one delta is given then the region is restarted in delta seconds time. A time to restart is sent to users in the region as a dismissable bluebox notice. If multiple deltas are given then a notice is sent when we reach each delta.",
88  HandleRegionRestart);
89 
90  MainConsole.Instance.Commands.AddCommand("Regions",
91  false, "region restart notice",
92  "region restart notice <message> <delta seconds>+",
93  "Schedule a region restart",
94  "Schedule a region restart after a given number of seconds. If one delta is given then the region is restarted in delta seconds time. A time to restart is sent to users in the region as a transient notice. If multiple deltas are given then a notice is sent when we reach each delta.",
95  HandleRegionRestart);
96 
97  MainConsole.Instance.Commands.AddCommand("Regions",
98  false, "region restart abort",
99  "region restart abort [<message>]",
100  "Abort a region restart", HandleRegionRestart);
101  }
102 
103  public void RegionLoaded(Scene scene)
104  {
105  m_DialogModule = m_Scene.RequestModuleInterface<IDialogModule>();
106  }
107 
108  public void RemoveRegion(Scene scene)
109  {
110  }
111 
112  public void Close()
113  {
114  }
115 
116  public string Name
117  {
118  get { return "RestartModule"; }
119  }
120 
121  public Type ReplaceableInterface
122  {
123  get { return typeof(IRestartModule); }
124  }
125 
126  public TimeSpan TimeUntilRestart
127  {
128  get { return DateTime.Now - m_RestartBegin; }
129  }
130 
131  public void ScheduleRestart(UUID initiator, string message, int[] alerts, bool notice)
132  {
133  if (m_CountdownTimer != null)
134  {
135  m_CountdownTimer.Stop();
136  m_CountdownTimer = null;
137  }
138 
139  if (alerts == null)
140  {
141  CreateMarkerFile();
142  m_Scene.RestartNow();
143  return;
144  }
145 
146  m_Message = message;
147  m_Initiator = initiator;
148  m_Notice = notice;
149  m_CurrentAlerts = alerts;
150  m_Alerts = new List<int>(alerts);
151  m_Alerts.Sort();
152  m_Alerts.Reverse();
153 
154  if (m_Alerts[0] == 0)
155  {
156  CreateMarkerFile();
157  m_Scene.RestartNow();
158  return;
159  }
160 
161  int nextInterval = DoOneNotice(true);
162 
163  SetTimer(nextInterval);
164  }
165 
166  public int DoOneNotice(bool sendOut)
167  {
168  if (m_Alerts.Count == 0 || m_Alerts[0] == 0)
169  {
170  CreateMarkerFile();
171  m_Scene.RestartNow();
172  return 0;
173  }
174 
175  int nextAlert = 0;
176  while (m_Alerts.Count > 1)
177  {
178  if (m_Alerts[1] == m_Alerts[0])
179  {
180  m_Alerts.RemoveAt(0);
181  continue;
182  }
183  nextAlert = m_Alerts[1];
184  break;
185  }
186 
187  int currentAlert = m_Alerts[0];
188 
189  m_Alerts.RemoveAt(0);
190 
191  if (sendOut)
192  {
193  int minutes = currentAlert / 60;
194  string currentAlertString = String.Empty;
195  if (minutes > 0)
196  {
197  if (minutes == 1)
198  currentAlertString += "1 minute";
199  else
200  currentAlertString += String.Format("{0} minutes", minutes);
201  if ((currentAlert % 60) != 0)
202  currentAlertString += " and ";
203  }
204  if ((currentAlert % 60) != 0)
205  {
206  int seconds = currentAlert % 60;
207  if (seconds == 1)
208  currentAlertString += "1 second";
209  else
210  currentAlertString += String.Format("{0} seconds", seconds);
211  }
212 
213  string msg = String.Format(m_Message, currentAlertString);
214 
215  if (m_DialogModule != null && msg != String.Empty)
216  {
217  if (m_Notice)
218  m_DialogModule.SendGeneralAlert(msg);
219  else
220  m_DialogModule.SendNotificationToUsersInRegion(m_Initiator, "System", msg);
221  }
222  }
223 
224  return currentAlert - nextAlert;
225  }
226 
227  public void SetTimer(int intervalSeconds)
228  {
229  if (intervalSeconds > 0)
230  {
231  m_CountdownTimer = new Timer();
232  m_CountdownTimer.AutoReset = false;
233  m_CountdownTimer.Interval = intervalSeconds * 1000;
234  m_CountdownTimer.Elapsed += OnTimer;
235  m_CountdownTimer.Start();
236  }
237  else if (m_CountdownTimer != null)
238  {
239  m_CountdownTimer.Stop();
240  m_CountdownTimer = null;
241  }
242  else
243  {
244  m_log.WarnFormat(
245  "[RESTART MODULE]: Tried to set restart timer to {0} in {1}, which is not a valid interval",
246  intervalSeconds, m_Scene.Name);
247  }
248  }
249 
250  private void OnTimer(object source, ElapsedEventArgs e)
251  {
252  int nextInterval = DoOneNotice(true);
253 
254  SetTimer(nextInterval);
255  }
256 
257  public void DelayRestart(int seconds, string message)
258  {
259  if (m_CountdownTimer == null)
260  return;
261 
262  m_CountdownTimer.Stop();
263  m_CountdownTimer = null;
264 
265  m_Alerts = new List<int>(m_CurrentAlerts);
266  m_Alerts.Add(seconds);
267  m_Alerts.Sort();
268  m_Alerts.Reverse();
269 
270  int nextInterval = DoOneNotice(false);
271 
272  SetTimer(nextInterval);
273  }
274 
275  public void AbortRestart(string message)
276  {
277  if (m_CountdownTimer != null)
278  {
279  m_CountdownTimer.Stop();
280  m_CountdownTimer = null;
281  if (m_DialogModule != null && message != String.Empty)
282  m_DialogModule.SendNotificationToUsersInRegion(UUID.Zero, "System", message);
283  //m_DialogModule.SendGeneralAlert(message);
284  }
285  if (m_MarkerPath != String.Empty)
286  File.Delete(Path.Combine(m_MarkerPath,
287  m_Scene.RegionInfo.RegionID.ToString()));
288  }
289 
290  private void HandleRegionRestart(string module, string[] args)
291  {
293  return;
294 
295  if (MainConsole.Instance.ConsoleScene != m_Scene)
296  return;
297 
298  if (args.Length < 5)
299  {
300  if (args.Length > 2)
301  {
302  if (args[2] == "abort")
303  {
304  string msg = String.Empty;
305  if (args.Length > 3)
306  msg = args[3];
307 
308  AbortRestart(msg);
309 
310  MainConsole.Instance.Output("Region restart aborted");
311  return;
312  }
313  }
314 
315  MainConsole.Instance.Output("Error: restart region <mode> <name> <delta seconds>+");
316  return;
317  }
318 
319  bool notice = false;
320  if (args[2] == "notice")
321  notice = true;
322 
323  List<int> times = new List<int>();
324  for (int i = 4 ; i < args.Length ; i++)
325  times.Add(Convert.ToInt32(args[i]));
326 
327  MainConsole.Instance.OutputFormat(
328  "Region {0} scheduled for restart in {1} seconds", m_Scene.Name, times.Sum());
329 
330  ScheduleRestart(UUID.Zero, args[3], times.ToArray(), notice);
331  }
332 
333  protected void CreateMarkerFile()
334  {
335  if (m_MarkerPath == String.Empty)
336  return;
337 
338  string path = Path.Combine(m_MarkerPath, m_Scene.RegionInfo.RegionID.ToString());
339  try
340  {
341  string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
342  FileStream fs = File.Create(path);
343  System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
344  Byte[] buf = enc.GetBytes(pidstring);
345  fs.Write(buf, 0, buf.Length);
346  fs.Close();
347  }
348  catch (Exception)
349  {
350  }
351  }
352  }
353 }
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
System.Timers.Timer Timer
System.Timers.Timer Timer
static ICommandConsole Instance
Definition: MainConsole.cs:35
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 RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
void DelayRestart(int seconds, string message)
void ScheduleRestart(UUID initiator, string message, int[] alerts, bool notice)
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...