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