aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules/DataSnapshot
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
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')
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs99
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/DataSnapshotManager.cs486
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs149
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs36
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs46
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs44
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs433
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs264
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs337
9 files changed, 1894 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs b/OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs
new file mode 100644
index 0000000..50276ae
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs
@@ -0,0 +1,99 @@
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.Collections;
30using System.Reflection;
31using System.Xml;
32using log4net;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Framework.Capabilities;
36using OpenSim.Framework.Servers;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Scenes;
39using Caps = OpenSim.Framework.Capabilities.Caps;
40
41namespace OpenSim.Region.DataSnapshot
42{
43 public class DataRequestHandler
44 {
45// private Scene m_scene = null;
46 private DataSnapshotManager m_externalData = null;
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 public DataRequestHandler(Scene scene, DataSnapshotManager externalData)
50 {
51// m_scene = scene;
52 m_externalData = externalData;
53
54 //Register HTTP handler
55 if (MainServer.Instance.AddHTTPHandler("collector", OnGetSnapshot))
56 {
57 m_log.Info("[DATASNAPSHOT]: Set up snapshot service");
58 }
59 // Register validation callback handler
60 MainServer.Instance.AddHTTPHandler("validate", OnValidate);
61
62 }
63
64 public Hashtable OnGetSnapshot(Hashtable keysvals)
65 {
66 m_log.Debug("[DATASNAPSHOT] Received collection request");
67 Hashtable reply = new Hashtable();
68 int statuscode = 200;
69
70 string snapObj = (string)keysvals["region"];
71
72 XmlDocument response = m_externalData.GetSnapshot(snapObj);
73
74 reply["str_response_string"] = response.OuterXml;
75 reply["int_response_code"] = statuscode;
76 reply["content_type"] = "text/xml";
77
78 return reply;
79 }
80
81 public Hashtable OnValidate(Hashtable keysvals)
82 {
83 m_log.Debug("[DATASNAPSHOT] Received validation request");
84 Hashtable reply = new Hashtable();
85 int statuscode = 200;
86
87 string secret = (string)keysvals["secret"];
88 if (secret == m_externalData.Secret.ToString())
89 statuscode = 403;
90
91 reply["str_response_string"] = string.Empty;
92 reply["int_response_code"] = statuscode;
93 reply["content_type"] = "text/plain";
94
95 return reply;
96 }
97
98 }
99}
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}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs
new file mode 100644
index 0000000..8da9e8c
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs
@@ -0,0 +1,149 @@
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
28using System;
29using System.Xml;
30using OpenMetaverse;
31using OpenSim.Framework;
32
33using OpenSim.Region.DataSnapshot.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Services.Interfaces;
36
37namespace OpenSim.Region.DataSnapshot.Providers
38{
39 public class EstateSnapshot : IDataSnapshotProvider
40 {
41 /* This module doesn't check for changes, since it's *assumed* there are none.
42 * Nevertheless, it's possible to have changes, since all the fields are public.
43 * There's no event to subscribe to. :/
44 *
45 * I don't think anything changes the fields beyond RegionModule PostInit, however.
46 */
47 private Scene m_scene = null;
48 // private DataSnapshotManager m_parent = null;
49 private bool m_stale = true;
50
51 #region IDataSnapshotProvider Members
52
53 public XmlNode RequestSnapshotData(XmlDocument factory)
54 {
55 //Estate data section - contains who owns a set of sims and the name of the set.
56 //Now in DataSnapshotProvider module form!
57 XmlNode estatedata = factory.CreateNode(XmlNodeType.Element, "estate", "");
58
59 UUID ownerid = m_scene.RegionInfo.EstateSettings.EstateOwner;
60
61 UserAccount userInfo = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, ownerid);
62 //TODO: Change to query userserver about the master avatar UUID ?
63 String firstname;
64 String lastname;
65
66 if (userInfo != null)
67 {
68 firstname = userInfo.FirstName;
69 lastname = userInfo.LastName;
70
71 //TODO: Fix the marshalling system to have less copypasta gruntwork
72 XmlNode user = factory.CreateNode(XmlNodeType.Element, "user", "");
73// XmlAttribute type = (XmlAttribute)factory.CreateNode(XmlNodeType.Attribute, "type", "");
74// type.Value = "owner";
75// user.Attributes.Append(type);
76
77 //TODO: Create more TODOs
78 XmlNode username = factory.CreateNode(XmlNodeType.Element, "name", "");
79 username.InnerText = firstname + " " + lastname;
80 user.AppendChild(username);
81
82 XmlNode useruuid = factory.CreateNode(XmlNodeType.Element, "uuid", "");
83 useruuid.InnerText = ownerid.ToString();
84 user.AppendChild(useruuid);
85
86 estatedata.AppendChild(user);
87 }
88
89 XmlNode estatename = factory.CreateNode(XmlNodeType.Element, "name", "");
90 estatename.InnerText = m_scene.RegionInfo.EstateSettings.EstateName.ToString();
91 estatedata.AppendChild(estatename);
92
93 XmlNode estateid = factory.CreateNode(XmlNodeType.Element, "id", "");
94 estateid.InnerText = m_scene.RegionInfo.EstateSettings.EstateID.ToString();
95 estatedata.AppendChild(estateid);
96
97 XmlNode parentid = factory.CreateNode(XmlNodeType.Element, "parentid", "");
98 parentid.InnerText = m_scene.RegionInfo.EstateSettings.ParentEstateID.ToString();
99 estatedata.AppendChild(parentid);
100
101 XmlNode flags = factory.CreateNode(XmlNodeType.Element, "flags", "");
102
103 XmlAttribute teleport = (XmlAttribute)factory.CreateNode(XmlNodeType.Attribute, "teleport", "");
104 teleport.Value = m_scene.RegionInfo.EstateSettings.AllowDirectTeleport.ToString();
105 flags.Attributes.Append(teleport);
106
107 XmlAttribute publicaccess = (XmlAttribute)factory.CreateNode(XmlNodeType.Attribute, "public", "");
108 publicaccess.Value = m_scene.RegionInfo.EstateSettings.PublicAccess.ToString();
109 flags.Attributes.Append(publicaccess);
110
111 estatedata.AppendChild(flags);
112
113 this.Stale = false;
114 return estatedata;
115 }
116
117 public void Initialize(Scene scene, DataSnapshotManager parent)
118 {
119 m_scene = scene;
120 // m_parent = parent;
121 }
122
123 public Scene GetParentScene
124 {
125 get { return m_scene; }
126 }
127
128 public String Name {
129 get { return "EstateSnapshot"; }
130 }
131
132 public bool Stale
133 {
134 get {
135 return m_stale;
136 }
137 set {
138 m_stale = value;
139
140 if (m_stale)
141 OnStale(this);
142 }
143 }
144
145 public event ProviderStale OnStale;
146
147 #endregion
148 }
149}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs
new file mode 100644
index 0000000..3b3db65
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs
@@ -0,0 +1,36 @@
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
28using System.Xml;
29
30namespace OpenSim.Region.DataSnapshot.Interfaces
31{
32 public interface IDataSnapshot
33 {
34 XmlDocument GetSnapshot(string regionName);
35 }
36}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs b/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs
new file mode 100644
index 0000000..daea373
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs
@@ -0,0 +1,46 @@
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.Xml;
31using OpenSim.Region.Framework.Scenes;
32
33namespace OpenSim.Region.DataSnapshot.Interfaces
34{
35 public delegate void ProviderStale(IDataSnapshotProvider provider);
36
37 public interface IDataSnapshotProvider
38 {
39 XmlNode RequestSnapshotData(XmlDocument document);
40 void Initialize(Scene scene, DataSnapshotManager parent);
41 Scene GetParentScene { get; }
42 String Name { get; }
43 bool Stale { get; set; }
44 event ProviderStale OnStale;
45 }
46}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs b/OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs
new file mode 100644
index 0000000..54a87f9
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs
@@ -0,0 +1,44 @@
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
28using OpenSim.Framework.Capabilities;
29
30namespace OpenSim.Region.DataSnapshot
31{
32 [OSDMap]
33 public class LLSDDiscoveryResponse
34 {
35 public OSDArray snapshot_resources;
36 }
37
38 [OSDMap]
39 public class LLSDDiscoveryDataURL
40 {
41 public string snapshot_format;
42 public string snapshot_url;
43 }
44}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs
new file mode 100644
index 0000000..b8c90cd
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs
@@ -0,0 +1,433 @@
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
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Xml;
32using log4net;
33using OpenMetaverse;
34using OpenSim.Framework;
35
36using OpenSim.Region.CoreModules.World.Land;
37using OpenSim.Region.DataSnapshot.Interfaces;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41
42namespace OpenSim.Region.DataSnapshot.Providers
43{
44 public class LandSnapshot : IDataSnapshotProvider
45 {
46 private Scene m_scene = null;
47 private DataSnapshotManager m_parent = null;
48 //private Dictionary<int, Land> m_landIndexed = new Dictionary<int, Land>();
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 private bool m_stale = true;
51
52 #region Dead code
53
54 /*
55 * David, I don't think we need this at all. When we do the snapshot, we can
56 * simply look into the parcels that are marked for ShowDirectory -- see
57 * conditional in RequestSnapshotData
58 *
59 //Revise this, look for more direct way of checking for change in land
60 #region Client hooks
61
62 public void OnNewClient(IClientAPI client)
63 {
64 //Land hooks
65 client.OnParcelDivideRequest += ParcelSplitHook;
66 client.OnParcelJoinRequest += ParcelSplitHook;
67 client.OnParcelPropertiesUpdateRequest += ParcelPropsHook;
68 }
69
70 public void ParcelSplitHook(int west, int south, int east, int north, IClientAPI remote_client)
71 {
72 PrepareData();
73 }
74
75 public void ParcelPropsHook(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
76 {
77 PrepareData();
78 }
79
80 #endregion
81
82 public void PrepareData()
83 {
84 m_log.Info("[EXTERNALDATA]: Generating land data.");
85
86 m_landIndexed.Clear();
87
88 //Index sim land
89 foreach (KeyValuePair<int, Land> curLand in m_scene.LandManager.landList)
90 {
91 //if ((curLand.Value.LandData.landFlags & (uint)ParcelFlags.ShowDirectory) == (uint)ParcelFlags.ShowDirectory)
92 //{
93 m_landIndexed.Add(curLand.Key, curLand.Value.Copy());
94 //}
95 }
96 }
97
98 public Dictionary<int,Land> IndexedLand {
99 get { return m_landIndexed; }
100 }
101 */
102
103 #endregion
104
105 #region IDataSnapshotProvider members
106
107 public void Initialize(Scene scene, DataSnapshotManager parent)
108 {
109 m_scene = scene;
110 m_parent = parent;
111
112 //Brought back from the dead for staleness checks.
113 m_scene.EventManager.OnNewClient += OnNewClient;
114 }
115
116 public Scene GetParentScene
117 {
118 get { return m_scene; }
119 }
120
121 public XmlNode RequestSnapshotData(XmlDocument nodeFactory)
122 {
123 ILandChannel landChannel = m_scene.LandChannel;
124 List<ILandObject> parcels = landChannel.AllParcels();
125
126 IDwellModule dwellModule = m_scene.RequestModuleInterface<IDwellModule>();
127
128 XmlNode parent = nodeFactory.CreateNode(XmlNodeType.Element, "parceldata", "");
129 if (parcels != null)
130 {
131
132 //foreach (KeyValuePair<int, Land> curParcel in m_landIndexed)
133 foreach (ILandObject parcel_interface in parcels)
134 {
135 // Play it safe
136 if (!(parcel_interface is LandObject))
137 continue;
138
139 LandObject land = (LandObject)parcel_interface;
140
141 LandData parcel = land.LandData;
142 if (m_parent.ExposureLevel.Equals("all") ||
143 (m_parent.ExposureLevel.Equals("minimum") &&
144 (parcel.Flags & (uint)ParcelFlags.ShowDirectory) == (uint)ParcelFlags.ShowDirectory))
145 {
146
147 //TODO: make better method of marshalling data from LandData to XmlNode
148 XmlNode xmlparcel = nodeFactory.CreateNode(XmlNodeType.Element, "parcel", "");
149
150 // Attributes of the parcel node
151 XmlAttribute scripts_attr = nodeFactory.CreateAttribute("scripts");
152 scripts_attr.Value = GetScriptsPermissions(parcel);
153 XmlAttribute build_attr = nodeFactory.CreateAttribute("build");
154 build_attr.Value = GetBuildPermissions(parcel);
155 XmlAttribute public_attr = nodeFactory.CreateAttribute("public");
156 public_attr.Value = GetPublicPermissions(parcel);
157 // Check the category of the Parcel
158 XmlAttribute category_attr = nodeFactory.CreateAttribute("category");
159 category_attr.Value = ((int)parcel.Category).ToString();
160 // Check if the parcel is for sale
161 XmlAttribute forsale_attr = nodeFactory.CreateAttribute("forsale");
162 forsale_attr.Value = CheckForSale(parcel);
163 XmlAttribute sales_attr = nodeFactory.CreateAttribute("salesprice");
164 sales_attr.Value = parcel.SalePrice.ToString();
165
166 XmlAttribute directory_attr = nodeFactory.CreateAttribute("showinsearch");
167 directory_attr.Value = GetShowInSearch(parcel);
168 //XmlAttribute entities_attr = nodeFactory.CreateAttribute("entities");
169 //entities_attr.Value = land.primsOverMe.Count.ToString();
170 xmlparcel.Attributes.Append(directory_attr);
171 xmlparcel.Attributes.Append(scripts_attr);
172 xmlparcel.Attributes.Append(build_attr);
173 xmlparcel.Attributes.Append(public_attr);
174 xmlparcel.Attributes.Append(category_attr);
175 xmlparcel.Attributes.Append(forsale_attr);
176 xmlparcel.Attributes.Append(sales_attr);
177 //xmlparcel.Attributes.Append(entities_attr);
178
179
180 //name, description, area, and UUID
181 XmlNode name = nodeFactory.CreateNode(XmlNodeType.Element, "name", "");
182 name.InnerText = parcel.Name;
183 xmlparcel.AppendChild(name);
184
185 XmlNode desc = nodeFactory.CreateNode(XmlNodeType.Element, "description", "");
186 desc.InnerText = parcel.Description;
187 xmlparcel.AppendChild(desc);
188
189 XmlNode uuid = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", "");
190 uuid.InnerText = parcel.GlobalID.ToString();
191 xmlparcel.AppendChild(uuid);
192
193 XmlNode area = nodeFactory.CreateNode(XmlNodeType.Element, "area", "");
194 area.InnerText = parcel.Area.ToString();
195 xmlparcel.AppendChild(area);
196
197 //default location
198 XmlNode tpLocation = nodeFactory.CreateNode(XmlNodeType.Element, "location", "");
199 Vector3 loc = parcel.UserLocation;
200 if (loc.Equals(Vector3.Zero)) // This test is moot at this point: the location is wrong by default
201 loc = new Vector3((parcel.AABBMax.X + parcel.AABBMin.X) / 2, (parcel.AABBMax.Y + parcel.AABBMin.Y) / 2, (parcel.AABBMax.Z + parcel.AABBMin.Z) / 2);
202 tpLocation.InnerText = loc.X.ToString() + "/" + loc.Y.ToString() + "/" + loc.Z.ToString();
203 xmlparcel.AppendChild(tpLocation);
204
205 XmlNode infouuid = nodeFactory.CreateNode(XmlNodeType.Element, "infouuid", "");
206 uint x = (uint)loc.X, y = (uint)loc.Y;
207 findPointInParcel(land, ref x, ref y); // find a suitable spot
208 infouuid.InnerText = Util.BuildFakeParcelID(
209 m_scene.RegionInfo.RegionHandle, x, y).ToString();
210 xmlparcel.AppendChild(infouuid);
211
212 XmlNode dwell = nodeFactory.CreateNode(XmlNodeType.Element, "dwell", "");
213 if (dwellModule != null)
214 dwell.InnerText = dwellModule.GetDwell(parcel.GlobalID).ToString();
215 else
216 dwell.InnerText = "0";
217 xmlparcel.AppendChild(dwell);
218
219 //TODO: figure how to figure out teleport system landData.landingType
220
221 //land texture snapshot uuid
222 if (parcel.SnapshotID != UUID.Zero)
223 {
224 XmlNode textureuuid = nodeFactory.CreateNode(XmlNodeType.Element, "image", "");
225 textureuuid.InnerText = parcel.SnapshotID.ToString();
226 xmlparcel.AppendChild(textureuuid);
227 }
228
229 string groupName = String.Empty;
230
231 //attached user and group
232 if (parcel.GroupID != UUID.Zero)
233 {
234 XmlNode groupblock = nodeFactory.CreateNode(XmlNodeType.Element, "group", "");
235 XmlNode groupuuid = nodeFactory.CreateNode(XmlNodeType.Element, "groupuuid", "");
236 groupuuid.InnerText = parcel.GroupID.ToString();
237 groupblock.AppendChild(groupuuid);
238
239 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
240 if (gm != null)
241 {
242 GroupRecord g = gm.GetGroupRecord(parcel.GroupID);
243 if (g != null)
244 groupName = g.GroupName;
245 }
246
247 XmlNode groupname = nodeFactory.CreateNode(XmlNodeType.Element, "groupname", "");
248 groupname.InnerText = groupName;
249 groupblock.AppendChild(groupname);
250
251 xmlparcel.AppendChild(groupblock);
252 }
253
254 XmlNode userblock = nodeFactory.CreateNode(XmlNodeType.Element, "owner", "");
255
256 UUID userOwnerUUID = parcel.OwnerID;
257
258 XmlNode useruuid = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", "");
259 useruuid.InnerText = userOwnerUUID.ToString();
260 userblock.AppendChild(useruuid);
261
262 if (!parcel.IsGroupOwned)
263 {
264 try
265 {
266 XmlNode username = nodeFactory.CreateNode(XmlNodeType.Element, "name", "");
267 UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, userOwnerUUID);
268 username.InnerText = account.FirstName + " " + account.LastName;
269 userblock.AppendChild(username);
270 }
271 catch (Exception)
272 {
273 //m_log.Info("[DATASNAPSHOT]: Cannot find owner name; ignoring this parcel");
274 }
275
276 }
277 else
278 {
279 XmlNode username = nodeFactory.CreateNode(XmlNodeType.Element, "name", "");
280 username.InnerText = groupName;
281 userblock.AppendChild(username);
282 }
283
284 xmlparcel.AppendChild(userblock);
285
286 parent.AppendChild(xmlparcel);
287 }
288 }
289 //snap.AppendChild(parent);
290 }
291
292 this.Stale = false;
293 return parent;
294 }
295
296 public String Name
297 {
298 get { return "LandSnapshot"; }
299 }
300
301 public bool Stale
302 {
303 get
304 {
305 return m_stale;
306 }
307 set
308 {
309 m_stale = value;
310
311 if (m_stale)
312 OnStale(this);
313 }
314 }
315
316 public event ProviderStale OnStale;
317
318 #endregion
319
320 #region Helper functions
321
322 private string GetScriptsPermissions(LandData parcel)
323 {
324 if ((parcel.Flags & (uint)ParcelFlags.AllowOtherScripts) == (uint)ParcelFlags.AllowOtherScripts)
325 return "true";
326 else
327 return "false";
328
329 }
330
331 private string GetPublicPermissions(LandData parcel)
332 {
333 if ((parcel.Flags & (uint)ParcelFlags.UseAccessList) == (uint)ParcelFlags.UseAccessList)
334 return "false";
335 else
336 return "true";
337
338 }
339
340 private string GetBuildPermissions(LandData parcel)
341 {
342 if ((parcel.Flags & (uint)ParcelFlags.CreateObjects) == (uint)ParcelFlags.CreateObjects)
343 return "true";
344 else
345 return "false";
346
347 }
348
349 private string CheckForSale(LandData parcel)
350 {
351 if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale)
352 return "true";
353 else
354 return "false";
355 }
356
357 private string GetShowInSearch(LandData parcel)
358 {
359 if ((parcel.Flags & (uint)ParcelFlags.ShowDirectory) == (uint)ParcelFlags.ShowDirectory)
360 return "true";
361 else
362 return "false";
363
364 }
365
366 #endregion
367
368 #region Change detection hooks
369
370 public void OnNewClient(IClientAPI client)
371 {
372 //Land hooks
373 client.OnParcelDivideRequest += delegate(int west, int south, int east, int north,
374 IClientAPI remote_client) { this.Stale = true; };
375 client.OnParcelJoinRequest += delegate(int west, int south, int east, int north,
376 IClientAPI remote_client) { this.Stale = true; };
377 client.OnParcelPropertiesUpdateRequest += delegate(LandUpdateArgs args, int local_id,
378 IClientAPI remote_client) { this.Stale = true; };
379 client.OnParcelBuy += delegate(UUID agentId, UUID groupId, bool final, bool groupOwned,
380 bool removeContribution, int parcelLocalID, int parcelArea, int parcelPrice, bool authenticated)
381 { this.Stale = true; };
382 }
383
384 public void ParcelSplitHook(int west, int south, int east, int north, IClientAPI remote_client)
385 {
386 this.Stale = true;
387 }
388
389 public void ParcelPropsHook(LandUpdateArgs args, int local_id, IClientAPI remote_client)
390 {
391 this.Stale = true;
392 }
393
394 #endregion
395
396 // this is needed for non-convex parcels (example: rectangular parcel, and in the exact center
397 // another, smaller rectangular parcel). Both will have the same initial coordinates.
398 private void findPointInParcel(ILandObject land, ref uint refX, ref uint refY)
399 {
400 m_log.DebugFormat("[DATASNAPSHOT] trying {0}, {1}", refX, refY);
401 // the point we started with already is in the parcel
402 if (land.ContainsPoint((int)refX, (int)refY)) return;
403
404 // ... otherwise, we have to search for a point within the parcel
405 uint startX = (uint)land.LandData.AABBMin.X;
406 uint startY = (uint)land.LandData.AABBMin.Y;
407 uint endX = (uint)land.LandData.AABBMax.X;
408 uint endY = (uint)land.LandData.AABBMax.Y;
409
410 // default: center of the parcel
411 refX = (startX + endX) / 2;
412 refY = (startY + endY) / 2;
413 // If the center point is within the parcel, take that one
414 if (land.ContainsPoint((int)refX, (int)refY)) return;
415
416 // otherwise, go the long way.
417 for (uint y = startY; y <= endY; ++y)
418 {
419 for (uint x = startX; x <= endX; ++x)
420 {
421 if (land.ContainsPoint((int)x, (int)y))
422 {
423 // found a point
424 refX = x;
425 refY = y;
426 return;
427 }
428 }
429 }
430 }
431 }
432}
433
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs
new file mode 100644
index 0000000..0bb4044
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs
@@ -0,0 +1,264 @@
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
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Xml;
32using log4net;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.DataSnapshot.Interfaces;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.DataSnapshot.Providers
40{
41 public class ObjectSnapshot : IDataSnapshotProvider
42 {
43 private Scene m_scene = null;
44 // private DataSnapshotManager m_parent = null;
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 private bool m_stale = true;
47
48 private static UUID m_DefaultImage = new UUID("89556747-24cb-43ed-920b-47caed15465f");
49 private static UUID m_BlankImage = new UUID("5748decc-f629-461c-9a36-a35a221fe21f");
50
51
52 public void Initialize(Scene scene, DataSnapshotManager parent)
53 {
54 m_scene = scene;
55 // m_parent = parent;
56
57 //To check for staleness, we must catch all incoming client packets.
58 m_scene.EventManager.OnNewClient += OnNewClient;
59 m_scene.EventManager.OnParcelPrimCountAdd += delegate(SceneObjectGroup obj) { this.Stale = true; };
60 }
61
62 public void OnNewClient(IClientAPI client)
63 {
64 //Detect object data changes by hooking into the IClientAPI.
65 //Very dirty, and breaks whenever someone changes the client API.
66
67 client.OnAddPrim += delegate (UUID ownerID, UUID groupID, Vector3 RayEnd, Quaternion rot,
68 PrimitiveBaseShape shape, byte bypassRaycast, Vector3 RayStart, UUID RayTargetID,
69 byte RayEndIsIntersection) { this.Stale = true; };
70 client.OnLinkObjects += delegate (IClientAPI remoteClient, uint parent, List<uint> children)
71 { this.Stale = true; };
72 client.OnDelinkObjects += delegate(List<uint> primIds, IClientAPI clientApi) { this.Stale = true; };
73 client.OnGrabUpdate += delegate(UUID objectID, Vector3 offset, Vector3 grapPos,
74 IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs) { this.Stale = true; };
75 client.OnObjectAttach += delegate(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt,
76 bool silent) { this.Stale = true; };
77 client.OnObjectDuplicate += delegate(uint localID, Vector3 offset, uint dupeFlags, UUID AgentID,
78 UUID GroupID) { this.Stale = true; };
79 client.OnObjectDuplicateOnRay += delegate(uint localID, uint dupeFlags, UUID AgentID, UUID GroupID,
80 UUID RayTargetObj, Vector3 RayEnd, Vector3 RayStart, bool BypassRaycast,
81 bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates) { this.Stale = true; };
82 client.OnObjectIncludeInSearch += delegate(IClientAPI remoteClient, bool IncludeInSearch, uint localID)
83 { this.Stale = true; };
84 client.OnObjectPermissions += delegate(IClientAPI controller, UUID agentID, UUID sessionID,
85 byte field, uint localId, uint mask, byte set) { this.Stale = true; };
86 client.OnRezObject += delegate(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd,
87 Vector3 RayStart, UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
88 bool RezSelected,
89 bool RemoveItem, UUID fromTaskID) { this.Stale = true; };
90 }
91
92 public Scene GetParentScene
93 {
94 get { return m_scene; }
95 }
96
97 public XmlNode RequestSnapshotData(XmlDocument nodeFactory)
98 {
99 m_log.Debug("[DATASNAPSHOT]: Generating object data for scene " + m_scene.RegionInfo.RegionName);
100
101 XmlNode parent = nodeFactory.CreateNode(XmlNodeType.Element, "objectdata", "");
102 XmlNode node;
103
104 EntityBase[] entities = m_scene.Entities.GetEntities();
105 foreach (EntityBase entity in entities)
106 {
107 // only objects, not avatars
108 if (entity is SceneObjectGroup)
109 {
110 SceneObjectGroup obj = (SceneObjectGroup)entity;
111
112// m_log.Debug("[DATASNAPSHOT]: Found object " + obj.Name + " in scene");
113
114 // libomv will complain about PrimFlags.JointWheel
115 // being obsolete, so we...
116 #pragma warning disable 0612
117 if ((obj.RootPart.Flags & PrimFlags.JointWheel) == PrimFlags.JointWheel)
118 {
119 SceneObjectPart m_rootPart = obj.RootPart;
120
121 ILandObject land = m_scene.LandChannel.GetLandObject(m_rootPart.AbsolutePosition.X, m_rootPart.AbsolutePosition.Y);
122
123 XmlNode xmlobject = nodeFactory.CreateNode(XmlNodeType.Element, "object", "");
124 node = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", "");
125 node.InnerText = obj.UUID.ToString();
126 xmlobject.AppendChild(node);
127
128 node = nodeFactory.CreateNode(XmlNodeType.Element, "title", "");
129 node.InnerText = m_rootPart.Name;
130 xmlobject.AppendChild(node);
131
132 node = nodeFactory.CreateNode(XmlNodeType.Element, "description", "");
133 node.InnerText = m_rootPart.Description;
134 xmlobject.AppendChild(node);
135
136 node = nodeFactory.CreateNode(XmlNodeType.Element, "flags", "");
137 node.InnerText = String.Format("{0:x}", (uint)m_rootPart.Flags);
138 xmlobject.AppendChild(node);
139
140 node = nodeFactory.CreateNode(XmlNodeType.Element, "regionuuid", "");
141 node.InnerText = m_scene.RegionInfo.RegionSettings.RegionUUID.ToString();
142 xmlobject.AppendChild(node);
143
144 if (land != null && land.LandData != null)
145 {
146 node = nodeFactory.CreateNode(XmlNodeType.Element, "parceluuid", "");
147 node.InnerText = land.LandData.GlobalID.ToString();
148 xmlobject.AppendChild(node);
149 }
150 else
151 {
152 // Something is wrong with this object. Let's not list it.
153 m_log.WarnFormat("[DATASNAPSHOT]: Bad data for object {0} ({1}) in region {2}", obj.Name, obj.UUID, m_scene.RegionInfo.RegionName);
154 continue;
155 }
156
157 node = nodeFactory.CreateNode(XmlNodeType.Element, "location", "");
158 Vector3 loc = obj.AbsolutePosition;
159 node.InnerText = loc.X.ToString() + "/" + loc.Y.ToString() + "/" + loc.Z.ToString();
160 xmlobject.AppendChild(node);
161
162 string bestImage = GuessImage(obj);
163 if (bestImage != string.Empty)
164 {
165 node = nodeFactory.CreateNode(XmlNodeType.Element, "image", "");
166 node.InnerText = bestImage;
167 xmlobject.AppendChild(node);
168 }
169
170 parent.AppendChild(xmlobject);
171 }
172 #pragma warning disable 0612
173 }
174 }
175 this.Stale = false;
176 return parent;
177 }
178
179 public String Name
180 {
181 get { return "ObjectSnapshot"; }
182 }
183
184 public bool Stale
185 {
186 get
187 {
188 return m_stale;
189 }
190 set
191 {
192 m_stale = value;
193
194 if (m_stale)
195 OnStale(this);
196 }
197 }
198
199 public event ProviderStale OnStale;
200
201 /// <summary>
202 /// Guesses the best image, based on a simple heuristic. It guesses only for boxes.
203 /// We're optimizing for boxes, because those are the most common objects
204 /// marked "Show in search" -- boxes with content inside.For other shapes,
205 /// it's really hard to tell which texture should be grabbed.
206 /// </summary>
207 /// <param name="sog"></param>
208 /// <returns></returns>
209 private string GuessImage(SceneObjectGroup sog)
210 {
211 string bestguess = string.Empty;
212 Dictionary<UUID, int> counts = new Dictionary<UUID, int>();
213
214 PrimitiveBaseShape shape = sog.RootPart.Shape;
215 if (shape != null && shape.ProfileShape == ProfileShape.Square)
216 {
217 Primitive.TextureEntry textures = shape.Textures;
218 if (textures != null)
219 {
220 if (textures.DefaultTexture != null &&
221 textures.DefaultTexture.TextureID != UUID.Zero &&
222 textures.DefaultTexture.TextureID != m_DefaultImage &&
223 textures.DefaultTexture.TextureID != m_BlankImage &&
224 textures.DefaultTexture.RGBA.A < 50f)
225 {
226 counts[textures.DefaultTexture.TextureID] = 8;
227 }
228
229 if (textures.FaceTextures != null)
230 {
231 foreach (Primitive.TextureEntryFace tentry in textures.FaceTextures)
232 {
233 if (tentry != null)
234 {
235 if (tentry.TextureID != UUID.Zero && tentry.TextureID != m_DefaultImage && tentry.TextureID != m_BlankImage && tentry.RGBA.A < 50)
236 {
237 int c = 0;
238 counts.TryGetValue(tentry.TextureID, out c);
239 counts[tentry.TextureID] = c + 1;
240 // decrease the default texture count
241 if (counts.ContainsKey(textures.DefaultTexture.TextureID))
242 counts[textures.DefaultTexture.TextureID] = counts[textures.DefaultTexture.TextureID] - 1;
243 }
244 }
245 }
246 }
247
248 // Let's pick the most unique texture
249 int min = 9999;
250 foreach (KeyValuePair<UUID, int> kv in counts)
251 {
252 if (kv.Value < min && kv.Value >= 1)
253 {
254 bestguess = kv.Key.ToString();
255 min = kv.Value;
256 }
257 }
258 }
259 }
260
261 return bestguess;
262 }
263 }
264}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs b/OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs
new file mode 100644
index 0000000..480aaaf
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs
@@ -0,0 +1,337 @@
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
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Text;
33using System.Text.RegularExpressions;
34using System.Xml;
35using log4net;
36using OpenSim.Region.DataSnapshot.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.DataSnapshot
40{
41 public class SnapshotStore
42 {
43 #region Class Members
44 private String m_directory = "unyuu"; //not an attempt at adding RM references to core SVN, honest
45 private Dictionary<Scene, bool> m_scenes = null;
46 private List<IDataSnapshotProvider> m_providers = null;
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 private Dictionary<String, String> m_gridinfo = null;
49 private bool m_cacheEnabled = true;
50 private string m_listener_port = "9000"; //TODO: Set default port over 9000
51 private string m_hostname = "127.0.0.1";
52 #endregion
53
54 public SnapshotStore(string directory, Dictionary<String, String> gridinfo, string port, string hostname) {
55 m_directory = directory;
56 m_scenes = new Dictionary<Scene, bool>();
57 m_providers = new List<IDataSnapshotProvider>();
58 m_gridinfo = gridinfo;
59 m_listener_port = port;
60 m_hostname = hostname;
61
62 if (Directory.Exists(m_directory))
63 {
64 m_log.Info("[DATASNAPSHOT]: Response and fragment cache directory already exists.");
65 }
66 else
67 {
68 // Try to create the directory.
69 m_log.Info("[DATASNAPSHOT]: Creating directory " + m_directory);
70 try
71 {
72 Directory.CreateDirectory(m_directory);
73 }
74 catch (Exception e)
75 {
76 m_log.Error("[DATASNAPSHOT]: Failed to create directory " + m_directory, e);
77
78 //This isn't a horrible problem, just disable cacheing.
79 m_cacheEnabled = false;
80 m_log.Error("[DATASNAPSHOT]: Could not create directory, response cache has been disabled.");
81 }
82 }
83 }
84
85 public void ForceSceneStale(Scene scene) {
86 m_scenes[scene] = true;
87 }
88
89 #region Fragment storage
90 public XmlNode GetFragment(IDataSnapshotProvider provider, XmlDocument factory)
91 {
92 XmlNode data = null;
93
94 if (provider.Stale || !m_cacheEnabled)
95 {
96 data = provider.RequestSnapshotData(factory);
97
98 if (m_cacheEnabled)
99 {
100 String path = DataFileNameFragment(provider.GetParentScene, provider.Name);
101
102 try
103 {
104 using (XmlTextWriter snapXWriter = new XmlTextWriter(path, Encoding.Default))
105 {
106 snapXWriter.Formatting = Formatting.Indented;
107 snapXWriter.WriteStartDocument();
108 data.WriteTo(snapXWriter);
109 snapXWriter.WriteEndDocument();
110 }
111 }
112 catch (Exception e)
113 {
114 m_log.WarnFormat("[DATASNAPSHOT]: Exception on writing to file {0}: {1}", path, e.Message);
115 }
116
117 }
118
119 //mark provider as not stale, parent scene as stale
120 provider.Stale = false;
121 m_scenes[provider.GetParentScene] = true;
122
123 m_log.Debug("[DATASNAPSHOT]: Generated fragment response for provider type " + provider.Name);
124 }
125 else
126 {
127 String path = DataFileNameFragment(provider.GetParentScene, provider.Name);
128
129 XmlDocument fragDocument = new XmlDocument();
130 fragDocument.PreserveWhitespace = true;
131 fragDocument.Load(path);
132 foreach (XmlNode node in fragDocument)
133 {
134 data = factory.ImportNode(node, true);
135 }
136
137 m_log.Debug("[DATASNAPSHOT]: Retrieved fragment response for provider type " + provider.Name);
138 }
139
140 return data;
141 }
142 #endregion
143
144 #region Response storage
145 public XmlNode GetScene(Scene scene, XmlDocument factory)
146 {
147 m_log.Debug("[DATASNAPSHOT]: Data requested for scene " + scene.RegionInfo.RegionName);
148
149 if (!m_scenes.ContainsKey(scene)) {
150 m_scenes.Add(scene, true); //stale by default
151 }
152
153 XmlNode regionElement = null;
154
155 if (!m_scenes[scene])
156 {
157 m_log.Debug("[DATASNAPSHOT]: Attempting to retrieve snapshot from cache.");
158 //get snapshot from cache
159 String path = DataFileNameScene(scene);
160
161 XmlDocument fragDocument = new XmlDocument();
162 fragDocument.PreserveWhitespace = true;
163
164 fragDocument.Load(path);
165
166 foreach (XmlNode node in fragDocument)
167 {
168 regionElement = factory.ImportNode(node, true);
169 }
170
171 m_log.Debug("[DATASNAPSHOT]: Obtained snapshot from cache for " + scene.RegionInfo.RegionName);
172 }
173 else
174 {
175 m_log.Debug("[DATASNAPSHOT]: Attempting to generate snapshot.");
176 //make snapshot
177 regionElement = MakeRegionNode(scene, factory);
178
179 regionElement.AppendChild(GetGridSnapshotData(factory));
180 XmlNode regionData = factory.CreateNode(XmlNodeType.Element, "data", "");
181
182 foreach (IDataSnapshotProvider dataprovider in m_providers)
183 {
184 if (dataprovider.GetParentScene == scene)
185 {
186 regionData.AppendChild(GetFragment(dataprovider, factory));
187 }
188 }
189
190 regionElement.AppendChild(regionData);
191
192 factory.AppendChild(regionElement);
193
194 //save snapshot
195 String path = DataFileNameScene(scene);
196
197 try
198 {
199 using (XmlTextWriter snapXWriter = new XmlTextWriter(path, Encoding.Default))
200 {
201 snapXWriter.Formatting = Formatting.Indented;
202 snapXWriter.WriteStartDocument();
203 regionElement.WriteTo(snapXWriter);
204 snapXWriter.WriteEndDocument();
205 }
206 }
207 catch (Exception e)
208 {
209 m_log.WarnFormat("[DATASNAPSHOT]: Exception on writing to file {0}: {1}", path, e.Message);
210 }
211
212 m_scenes[scene] = false;
213
214 m_log.Debug("[DATASNAPSHOT]: Generated new snapshot for " + scene.RegionInfo.RegionName);
215 }
216
217 return regionElement;
218 }
219
220 #endregion
221
222 #region Helpers
223 private string DataFileNameFragment(Scene scene, String fragmentName)
224 {
225 return Path.Combine(m_directory, Path.ChangeExtension(Sanitize(scene.RegionInfo.RegionName + "_" + fragmentName), "xml"));
226 }
227
228 private string DataFileNameScene(Scene scene)
229 {
230 return Path.Combine(m_directory, Path.ChangeExtension(Sanitize(scene.RegionInfo.RegionName), "xml"));
231 //return (m_snapsDir + Path.DirectorySeparatorChar + scene.RegionInfo.RegionName + ".xml");
232 }
233
234 private static string Sanitize(string name)
235 {
236 string invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars()));
237 string invalidReStr = string.Format(@"[{0}]", invalidChars);
238 string newname = Regex.Replace(name, invalidReStr, "_");
239 return newname.Replace('.', '_');
240 }
241
242 private XmlNode MakeRegionNode(Scene scene, XmlDocument basedoc)
243 {
244 XmlNode docElement = basedoc.CreateNode(XmlNodeType.Element, "region", "");
245
246 XmlAttribute attr = basedoc.CreateAttribute("category");
247 attr.Value = GetRegionCategory(scene);
248 docElement.Attributes.Append(attr);
249
250 attr = basedoc.CreateAttribute("entities");
251 attr.Value = scene.Entities.Count.ToString();
252 docElement.Attributes.Append(attr);
253
254 //attr = basedoc.CreateAttribute("parcels");
255 //attr.Value = scene.LandManager.landList.Count.ToString();
256 //docElement.Attributes.Append(attr);
257
258
259 XmlNode infoblock = basedoc.CreateNode(XmlNodeType.Element, "info", "");
260
261 XmlNode infopiece = basedoc.CreateNode(XmlNodeType.Element, "uuid", "");
262 infopiece.InnerText = scene.RegionInfo.RegionID.ToString();
263 infoblock.AppendChild(infopiece);
264
265 infopiece = basedoc.CreateNode(XmlNodeType.Element, "url", "");
266 infopiece.InnerText = "http://" + m_hostname + ":" + m_listener_port;
267 infoblock.AppendChild(infopiece);
268
269 infopiece = basedoc.CreateNode(XmlNodeType.Element, "name", "");
270 infopiece.InnerText = scene.RegionInfo.RegionName;
271 infoblock.AppendChild(infopiece);
272
273 infopiece = basedoc.CreateNode(XmlNodeType.Element, "handle", "");
274 infopiece.InnerText = scene.RegionInfo.RegionHandle.ToString();
275 infoblock.AppendChild(infopiece);
276
277 docElement.AppendChild(infoblock);
278
279 m_log.Debug("[DATASNAPSHOT]: Generated region node");
280 return docElement;
281 }
282
283 private String GetRegionCategory(Scene scene)
284 {
285 if (scene.RegionInfo.RegionSettings.Maturity == 0)
286 return "PG";
287
288 if (scene.RegionInfo.RegionSettings.Maturity == 1)
289 return "Mature";
290
291 if (scene.RegionInfo.RegionSettings.Maturity == 2)
292 return "Adult";
293
294 return "Unknown";
295 }
296
297 private XmlNode GetGridSnapshotData(XmlDocument factory)
298 {
299 XmlNode griddata = factory.CreateNode(XmlNodeType.Element, "grid", "");
300
301 foreach (KeyValuePair<String, String> GridData in m_gridinfo)
302 {
303 //TODO: make it lowercase tag names for diva
304 XmlNode childnode = factory.CreateNode(XmlNodeType.Element, GridData.Key, "");
305 childnode.InnerText = GridData.Value;
306 griddata.AppendChild(childnode);
307 }
308
309 m_log.Debug("[DATASNAPSHOT]: Got grid snapshot data");
310
311 return griddata;
312 }
313 #endregion
314
315 #region Manage internal collections
316 public void AddScene(Scene newScene)
317 {
318 m_scenes.Add(newScene, true);
319 }
320
321 public void RemoveScene(Scene deadScene)
322 {
323 m_scenes.Remove(deadScene);
324 }
325
326 public void AddProvider(IDataSnapshotProvider newProvider)
327 {
328 m_providers.Add(newProvider);
329 }
330
331 public void RemoveProvider(IDataSnapshotProvider deadProvider)
332 {
333 m_providers.Remove(deadProvider);
334 }
335 #endregion
336 }
337}