aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/DataSnapshot/DataSnapshotManager.cs')
-rw-r--r--OpenSim/Region/DataSnapshot/DataSnapshotManager.cs490
1 files changed, 0 insertions, 490 deletions
diff --git a/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs b/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs
deleted file mode 100644
index d5ae83e..0000000
--- a/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs
+++ /dev/null
@@ -1,490 +0,0 @@
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
29using System;
30using System.Collections.Generic;
31using System.IO;
32using System.Linq;
33using System.Net;
34using System.Reflection;
35using System.Text;
36using System.Xml;
37using log4net;
38using Nini.Config;
39using OpenMetaverse;
40using Mono.Addins;
41using OpenSim.Framework;
42using OpenSim.Region.DataSnapshot.Interfaces;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45
46[assembly: Addin("DataSnapshot", OpenSim.VersionInfo.VersionNumber)]
47[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
48
49namespace OpenSim.Region.DataSnapshot
50{
51 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DataSnapshotManager")]
52 public class DataSnapshotManager : ISharedRegionModule, IDataSnapshot
53 {
54 #region Class members
55 //Information from config
56 private bool m_enabled = false;
57 private bool m_configLoaded = false;
58 private List<string> m_disabledModules = new List<string>();
59 private Dictionary<string, string> m_gridinfo = new Dictionary<string, string>();
60 private string m_snapsDir = "DataSnapshot";
61 private string m_exposure_level = "minimum";
62
63 //Lists of stuff we need
64 private List<Scene> m_scenes = new List<Scene>();
65 private List<IDataSnapshotProvider> m_dataproviders = new List<IDataSnapshotProvider>();
66
67 //Various internal objects
68 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
69 internal object m_syncInit = new object();
70
71 //DataServices and networking
72 private string m_dataServices = "noservices";
73 public string m_listener_port = ConfigSettings.DefaultRegionHttpPort.ToString();
74 public string m_hostname = "127.0.0.1";
75 private UUID m_Secret = UUID.Random();
76 private bool m_servicesNotified = false;
77
78 //Update timers
79 private int m_period = 20; // in seconds
80 private int m_maxStales = 500;
81 private int m_stales = 0;
82 private int m_lastUpdate = 0;
83
84 //Program objects
85 private SnapshotStore m_snapStore = null;
86
87 #endregion
88
89 #region Properties
90
91 public string ExposureLevel
92 {
93 get { return m_exposure_level; }
94 }
95
96 public UUID Secret
97 {
98 get { return m_Secret; }
99 }
100
101 #endregion
102
103 #region Region Module interface
104
105 public void Initialise(IConfigSource config)
106 {
107 if (!m_configLoaded)
108 {
109 m_configLoaded = true;
110 //m_log.Debug("[DATASNAPSHOT]: Loading configuration");
111 //Read from the config for options
112 lock (m_syncInit)
113 {
114 try
115 {
116 m_enabled = config.Configs["DataSnapshot"].GetBoolean("index_sims", m_enabled);
117 string gatekeeper = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
118 new string[] { "Startup", "Hypergrid", "GridService" }, String.Empty);
119 // Legacy. Remove soon!
120 if (string.IsNullOrEmpty(gatekeeper))
121 {
122 IConfig conf = config.Configs["GridService"];
123 if (conf != null)
124 gatekeeper = conf.GetString("Gatekeeper", gatekeeper);
125 }
126 if (!string.IsNullOrEmpty(gatekeeper))
127 m_gridinfo.Add("gatekeeperURL", gatekeeper);
128
129 m_gridinfo.Add(
130 "name", config.Configs["DataSnapshot"].GetString("gridname", "the lost continent of hippo"));
131 m_exposure_level = config.Configs["DataSnapshot"].GetString("data_exposure", m_exposure_level);
132 m_period = config.Configs["DataSnapshot"].GetInt("default_snapshot_period", m_period);
133 m_maxStales = config.Configs["DataSnapshot"].GetInt("max_changes_before_update", m_maxStales);
134 m_snapsDir = config.Configs["DataSnapshot"].GetString("snapshot_cache_directory", m_snapsDir);
135 m_listener_port = config.Configs["Network"].GetString("http_listener_port", m_listener_port);
136
137 m_dataServices = config.Configs["DataSnapshot"].GetString("data_services", m_dataServices);
138 // New way of spec'ing data services, one per line
139 AddDataServicesVars(config.Configs["DataSnapshot"]);
140
141 String[] annoying_string_array = config.Configs["DataSnapshot"].GetString("disable_modules", "").Split(".".ToCharArray());
142 foreach (String bloody_wanker in annoying_string_array)
143 {
144 m_disabledModules.Add(bloody_wanker);
145 }
146 m_lastUpdate = Environment.TickCount;
147 }
148 catch (Exception)
149 {
150 m_log.Warn("[DATASNAPSHOT]: Could not load configuration. DataSnapshot will be disabled.");
151 m_enabled = false;
152 return;
153 }
154
155 }
156
157 }
158
159 }
160
161 public void AddRegion(Scene scene)
162 {
163 if (!m_enabled)
164 return;
165
166 m_log.DebugFormat("[DATASNAPSHOT]: Module added to Scene {0}.", scene.RegionInfo.RegionName);
167
168 if (!m_servicesNotified)
169 {
170 m_hostname = scene.RegionInfo.ExternalHostName;
171 m_snapStore = new SnapshotStore(m_snapsDir, m_gridinfo, m_listener_port, m_hostname);
172
173 //Hand it the first scene, assuming that all scenes have the same BaseHTTPServer
174 new DataRequestHandler(scene, this);
175
176 if (m_dataServices != "" && m_dataServices != "noservices")
177 NotifyDataServices(m_dataServices, "online");
178
179 m_servicesNotified = true;
180 }
181
182 m_scenes.Add(scene);
183 m_snapStore.AddScene(scene);
184
185 Assembly currentasm = Assembly.GetExecutingAssembly();
186
187 foreach (Type pluginType in currentasm.GetTypes())
188 {
189 if (pluginType.IsPublic)
190 {
191 if (!pluginType.IsAbstract)
192 {
193 if (pluginType.GetInterface("IDataSnapshotProvider") != null)
194 {
195 IDataSnapshotProvider module = (IDataSnapshotProvider)Activator.CreateInstance(pluginType);
196 module.Initialize(scene, this);
197 module.OnStale += MarkDataStale;
198
199 m_dataproviders.Add(module);
200 m_snapStore.AddProvider(module);
201
202 m_log.Debug("[DATASNAPSHOT]: Added new data provider type: " + pluginType.Name);
203 }
204 }
205 }
206 }
207
208 }
209
210 public void RemoveRegion(Scene scene)
211 {
212 if (!m_enabled)
213 return;
214
215 m_log.Info("[DATASNAPSHOT]: Region " + scene.RegionInfo.RegionName + " is being removed, removing from indexing");
216 Scene restartedScene = SceneForUUID(scene.RegionInfo.RegionID);
217
218 m_scenes.Remove(restartedScene);
219 m_snapStore.RemoveScene(restartedScene);
220
221 //Getting around the fact that we can't remove objects from a collection we are enumerating over
222 List<IDataSnapshotProvider> providersToRemove = new List<IDataSnapshotProvider>();
223
224 foreach (IDataSnapshotProvider provider in m_dataproviders)
225 {
226 if (provider.GetParentScene == restartedScene)
227 {
228 providersToRemove.Add(provider);
229 }
230 }
231
232 foreach (IDataSnapshotProvider provider in providersToRemove)
233 {
234 m_dataproviders.Remove(provider);
235 m_snapStore.RemoveProvider(provider);
236 }
237
238 m_snapStore.RemoveScene(restartedScene);
239 }
240
241 public void PostInitialise()
242 {
243 }
244
245 public void RegionLoaded(Scene scene)
246 {
247 if (!m_enabled)
248 return;
249
250 m_log.DebugFormat("[DATASNAPSHOT]: Marking scene {0} as stale.", scene.RegionInfo.RegionName);
251 m_snapStore.ForceSceneStale(scene);
252 }
253
254 public void Close()
255 {
256 if (!m_enabled)
257 return;
258
259 if (m_enabled && m_dataServices != "" && m_dataServices != "noservices")
260 NotifyDataServices(m_dataServices, "offline");
261 }
262
263
264 public string Name
265 {
266 get { return "External Data Generator"; }
267 }
268
269 public Type ReplaceableInterface
270 {
271 get { return null; }
272 }
273
274 #endregion
275
276 #region Associated helper functions
277
278 public Scene SceneForName(string name)
279 {
280 foreach (Scene scene in m_scenes)
281 if (scene.RegionInfo.RegionName == name)
282 return scene;
283
284 return null;
285 }
286
287 public Scene SceneForUUID(UUID id)
288 {
289 foreach (Scene scene in m_scenes)
290 if (scene.RegionInfo.RegionID == id)
291 return scene;
292
293 return null;
294 }
295
296 private void AddDataServicesVars(IConfig config)
297 {
298 // Make sure the services given this way aren't in m_dataServices already
299 List<string> servs = new List<string>(m_dataServices.Split(new char[] { ';' }));
300
301 StringBuilder sb = new StringBuilder();
302 string[] keys = config.GetKeys();
303
304 if (keys.Length > 0)
305 {
306 IEnumerable<string> serviceKeys = keys.Where(value => value.StartsWith("DATA_SRV_"));
307 foreach (string serviceKey in serviceKeys)
308 {
309 string keyValue = config.GetString(serviceKey, string.Empty).Trim();
310 if (!servs.Contains(keyValue))
311 sb.Append(keyValue).Append(";");
312 }
313 }
314
315 m_dataServices = (m_dataServices == "noservices") ? sb.ToString() : sb.Append(m_dataServices).ToString();
316 }
317
318 #endregion
319
320 #region [Public] Snapshot storage functions
321
322 /**
323 * Reply to the http request
324 */
325 public XmlDocument GetSnapshot(string regionName)
326 {
327 CheckStale();
328
329 XmlDocument requestedSnap = new XmlDocument();
330 requestedSnap.AppendChild(requestedSnap.CreateXmlDeclaration("1.0", null, null));
331 requestedSnap.AppendChild(requestedSnap.CreateWhitespace("\r\n"));
332
333 XmlNode regiondata = requestedSnap.CreateNode(XmlNodeType.Element, "regiondata", "");
334 try
335 {
336 if (string.IsNullOrEmpty(regionName))
337 {
338 XmlNode timerblock = requestedSnap.CreateNode(XmlNodeType.Element, "expire", "");
339 timerblock.InnerText = m_period.ToString();
340 regiondata.AppendChild(timerblock);
341
342 regiondata.AppendChild(requestedSnap.CreateWhitespace("\r\n"));
343 foreach (Scene scene in m_scenes)
344 {
345 regiondata.AppendChild(m_snapStore.GetScene(scene, requestedSnap));
346 }
347 }
348 else
349 {
350 Scene scene = SceneForName(regionName);
351 regiondata.AppendChild(m_snapStore.GetScene(scene, requestedSnap));
352 }
353 requestedSnap.AppendChild(regiondata);
354 regiondata.AppendChild(requestedSnap.CreateWhitespace("\r\n"));
355 }
356 catch (XmlException e)
357 {
358 m_log.Warn("[DATASNAPSHOT]: XmlException while trying to load snapshot: " + e.ToString());
359 requestedSnap = GetErrorMessage(regionName, e);
360 }
361 catch (Exception e)
362 {
363 m_log.Warn("[DATASNAPSHOT]: Caught unknown exception while trying to load snapshot: " + e.StackTrace);
364 requestedSnap = GetErrorMessage(regionName, e);
365 }
366
367
368 return requestedSnap;
369 }
370
371 private XmlDocument GetErrorMessage(string regionName, Exception e)
372 {
373 XmlDocument errorMessage = new XmlDocument();
374 XmlNode error = errorMessage.CreateNode(XmlNodeType.Element, "error", "");
375 XmlNode region = errorMessage.CreateNode(XmlNodeType.Element, "region", "");
376 region.InnerText = regionName;
377
378 XmlNode exception = errorMessage.CreateNode(XmlNodeType.Element, "exception", "");
379 exception.InnerText = e.ToString();
380
381 error.AppendChild(region);
382 error.AppendChild(exception);
383 errorMessage.AppendChild(error);
384
385 return errorMessage;
386 }
387
388 #endregion
389
390 #region External data services
391 private void NotifyDataServices(string servicesStr, string serviceName)
392 {
393 Stream reply = null;
394 string delimStr = ";";
395 char [] delimiter = delimStr.ToCharArray();
396
397 string[] services = servicesStr.Split(delimiter, StringSplitOptions.RemoveEmptyEntries);
398
399 for (int i = 0; i < services.Length; i++)
400 {
401 string url = services[i].Trim();
402 using (RestClient cli = new RestClient(url))
403 {
404 cli.AddQueryParameter("service", serviceName);
405 cli.AddQueryParameter("host", m_hostname);
406 cli.AddQueryParameter("port", m_listener_port);
407 cli.AddQueryParameter("secret", m_Secret.ToString());
408 cli.RequestMethod = "GET";
409 try
410 {
411 reply = cli.Request(null);
412 }
413 catch (WebException)
414 {
415 m_log.Warn("[DATASNAPSHOT]: Unable to notify " + url);
416 }
417 catch (Exception e)
418 {
419 m_log.Warn("[DATASNAPSHOT]: Ignoring unknown exception " + e.ToString());
420 }
421
422 byte[] response = new byte[1024];
423 // int n = 0;
424 try
425 {
426 // n = reply.Read(response, 0, 1024);
427 reply.Read(response, 0, 1024);
428 }
429 catch (Exception e)
430 {
431 m_log.WarnFormat("[DATASNAPSHOT]: Unable to decode reply from data service. Ignoring. {0}", e.StackTrace);
432 }
433 // This is not quite working, so...
434 // string responseStr = Util.UTF8.GetString(response);
435 m_log.Info("[DATASNAPSHOT]: data service " + url + " notified. Secret: " + m_Secret);
436 }
437 }
438
439 }
440 #endregion
441
442 #region Latency-based update functions
443
444 public void MarkDataStale(IDataSnapshotProvider provider)
445 {
446 //Behavior here: Wait m_period seconds, then update if there has not been a request in m_period seconds
447 //or m_maxStales has been exceeded
448 m_stales++;
449 }
450
451 private void CheckStale()
452 {
453 // Wrap check
454 if (Environment.TickCount < m_lastUpdate)
455 {
456 m_lastUpdate = Environment.TickCount;
457 }
458
459 if (m_stales >= m_maxStales)
460 {
461 if (Environment.TickCount - m_lastUpdate >= 20000)
462 {
463 m_stales = 0;
464 m_lastUpdate = Environment.TickCount;
465 MakeEverythingStale();
466 }
467 }
468 else
469 {
470 if (m_lastUpdate + 1000 * m_period < Environment.TickCount)
471 {
472 m_stales = 0;
473 m_lastUpdate = Environment.TickCount;
474 MakeEverythingStale();
475 }
476 }
477 }
478
479 public void MakeEverythingStale()
480 {
481 m_log.Debug("[DATASNAPSHOT]: Marking all scenes as stale.");
482 foreach (Scene scene in m_scenes)
483 {
484 m_snapStore.ForceSceneStale(scene);
485 }
486 }
487 #endregion
488
489 }
490}