diff options
author | Charles Krinke | 2008-05-17 15:47:08 +0000 |
---|---|---|
committer | Charles Krinke | 2008-05-17 15:47:08 +0000 |
commit | f6a4f8844f01fb756bbc26d65c252fc07ab8c2bf (patch) | |
tree | da27e199a03ec4afd829a3ab9b06deab47cd02a3 | |
parent | while this doesn't fix the initial no pants issue in grid (which still baffle... (diff) | |
download | opensim-SC-f6a4f8844f01fb756bbc26d65c252fc07ab8c2bf.zip opensim-SC-f6a4f8844f01fb756bbc26d65c252fc07ab8c2bf.tar.gz opensim-SC-f6a4f8844f01fb756bbc26d65c252fc07ab8c2bf.tar.bz2 opensim-SC-f6a4f8844f01fb756bbc26d65c252fc07ab8c2bf.tar.xz |
Thank you very much KMeisthax for DataSnapshot 1.1
to enhance search capability on OpenSim sims using
external search engines such as Metaversink.com and
others.
-rw-r--r-- | OpenSim/Region/DataSnapshot/DataRequestHandler.cs | 37 | ||||
-rw-r--r-- | OpenSim/Region/DataSnapshot/DataSnapshotManager.cs | 451 | ||||
-rw-r--r-- | OpenSim/Region/DataSnapshot/EstateSnapshot.cs | 31 | ||||
-rw-r--r-- | OpenSim/Region/DataSnapshot/Interfaces/IDataSnapshot.cs | 13 | ||||
-rw-r--r-- | OpenSim/Region/DataSnapshot/Interfaces/IDataSnapshotProvider.cs | 12 | ||||
-rw-r--r-- | OpenSim/Region/DataSnapshot/LLSDDiscovery.cs | 46 | ||||
-rw-r--r-- | OpenSim/Region/DataSnapshot/LandSnapshot.cs | 71 | ||||
-rw-r--r-- | OpenSim/Region/DataSnapshot/ObjectSnapshot.cs | 134 | ||||
-rw-r--r-- | OpenSim/Region/DataSnapshot/SnapshotStore.cs | 316 |
9 files changed, 785 insertions, 326 deletions
diff --git a/OpenSim/Region/DataSnapshot/DataRequestHandler.cs b/OpenSim/Region/DataSnapshot/DataRequestHandler.cs index e08934b..abf2c1a 100644 --- a/OpenSim/Region/DataSnapshot/DataRequestHandler.cs +++ b/OpenSim/Region/DataSnapshot/DataRequestHandler.cs | |||
@@ -26,11 +26,16 @@ | |||
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | 28 | ||
29 | using System; | ||
29 | using System.Collections; | 30 | using System.Collections; |
30 | using System.Reflection; | 31 | using System.Reflection; |
31 | using System.Xml; | 32 | using System.Xml; |
32 | using log4net; | 33 | using log4net; |
33 | using OpenSim.Region.Environment.Scenes; | 34 | using OpenSim.Region.Environment.Scenes; |
35 | using OpenSim.Framework.Communications.Capabilities; | ||
36 | using Caps = OpenSim.Framework.Communications.Capabilities.Caps; | ||
37 | using libsecondlife; | ||
38 | using OpenSim.Framework.Servers; | ||
34 | 39 | ||
35 | namespace OpenSim.Region.DataSnapshot | 40 | namespace OpenSim.Region.DataSnapshot |
36 | { | 41 | { |
@@ -40,18 +45,50 @@ namespace OpenSim.Region.DataSnapshot | |||
40 | private DataSnapshotManager m_externalData = null; | 45 | private DataSnapshotManager m_externalData = null; |
41 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 46 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
42 | 47 | ||
48 | private readonly string m_discoveryPath = "DS0001/"; | ||
49 | |||
43 | public DataRequestHandler(Scene scene, DataSnapshotManager externalData) | 50 | public DataRequestHandler(Scene scene, DataSnapshotManager externalData) |
44 | { | 51 | { |
45 | m_scene = scene; | 52 | m_scene = scene; |
46 | m_externalData = externalData; | 53 | m_externalData = externalData; |
47 | 54 | ||
55 | //Register HTTP handler | ||
48 | if (m_scene.AddHTTPHandler("collector", OnGetSnapshot)) | 56 | if (m_scene.AddHTTPHandler("collector", OnGetSnapshot)) |
49 | { | 57 | { |
50 | m_log.Info("[DATASNAPSHOT]: Set up snapshot service"); | 58 | m_log.Info("[DATASNAPSHOT]: Set up snapshot service"); |
51 | } | 59 | } |
60 | |||
61 | //Register CAPS handler event | ||
62 | m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
63 | |||
52 | //harbl | 64 | //harbl |
53 | } | 65 | } |
54 | 66 | ||
67 | public void OnRegisterCaps(LLUUID agentID, Caps caps) | ||
68 | { | ||
69 | m_log.Info("[DATASNAPSHOT]: Registering service discovery capability for " + agentID); | ||
70 | string capsBase = "/CAPS/" + caps.CapsObjectPath; | ||
71 | caps.RegisterHandler("PublicSnapshotDataInfo", | ||
72 | new RestStreamHandler("POST", capsBase + m_discoveryPath, OnDiscoveryAttempt)); | ||
73 | } | ||
74 | |||
75 | public string OnDiscoveryAttempt(string request, string path, string param) | ||
76 | { | ||
77 | //Very static for now, flexible enough to add new formats | ||
78 | LLSDDiscoveryResponse llsd_response = new LLSDDiscoveryResponse(); | ||
79 | llsd_response.snapshot_resources = new LLSDArray(); | ||
80 | |||
81 | LLSDDiscoveryDataURL llsd_dataurl = new LLSDDiscoveryDataURL(); | ||
82 | llsd_dataurl.snapshot_format = "os-datasnapshot-v1"; | ||
83 | llsd_dataurl.snapshot_url = "http://" + m_externalData.m_hostname + ":" + m_externalData.m_listener_port + "/?method=collector"; | ||
84 | |||
85 | llsd_response.snapshot_resources.Array.Add(llsd_dataurl); | ||
86 | |||
87 | string response = LLSDHelpers.SerialiseLLSDReply(llsd_response); | ||
88 | |||
89 | return response; | ||
90 | } | ||
91 | |||
55 | public Hashtable OnGetSnapshot(Hashtable keysvals) | 92 | public Hashtable OnGetSnapshot(Hashtable keysvals) |
56 | { | 93 | { |
57 | m_log.Info("[DATASNAPSHOT] Received collection request"); | 94 | m_log.Info("[DATASNAPSHOT] Received collection request"); |
diff --git a/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs b/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs index af3e547..6fdedb4 100644 --- a/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs +++ b/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs | |||
@@ -37,49 +37,62 @@ using System.Xml; | |||
37 | using libsecondlife; | 37 | using libsecondlife; |
38 | using log4net; | 38 | using log4net; |
39 | using Nini.Config; | 39 | using Nini.Config; |
40 | using OpenSim.Framework; | ||
40 | using OpenSim.Framework.Communications; | 41 | using OpenSim.Framework.Communications; |
41 | using OpenSim.Region.DataSnapshot.Interfaces; | 42 | using OpenSim.Region.DataSnapshot.Interfaces; |
42 | using OpenSim.Region.Environment.Interfaces; | 43 | using OpenSim.Region.Environment.Interfaces; |
43 | using OpenSim.Region.Environment.Scenes; | 44 | using OpenSim.Region.Environment.Scenes; |
45 | using libsecondlife.Packets; | ||
44 | 46 | ||
45 | namespace OpenSim.Region.DataSnapshot | 47 | namespace OpenSim.Region.DataSnapshot |
46 | { | 48 | { |
47 | public class DataSnapshotManager : IRegionModule | 49 | public class DataSnapshotManager : IRegionModule, IDataSnapshot |
48 | { | 50 | { |
49 | #region Class members | 51 | #region Class members |
50 | private List<Scene> m_scenes = new List<Scene>(); | 52 | //Information from config |
51 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
52 | private bool m_enabled = false; | 53 | private bool m_enabled = false; |
53 | private bool m_configLoaded = false; | 54 | private bool m_configLoaded = false; |
54 | internal object m_syncInit = new object(); | 55 | private List<String> m_disabledModules = new List<String>(); |
55 | private DataRequestHandler m_requests = null; | ||
56 | private Dictionary<Scene, List<IDataSnapshotProvider>> m_dataproviders = new Dictionary<Scene, List<IDataSnapshotProvider>>(); | ||
57 | private Dictionary<string, string> m_gridinfo = new Dictionary<string, string>(); | 56 | private Dictionary<string, string> m_gridinfo = new Dictionary<string, string>(); |
58 | //private int m_oldestSnapshot = 0; | ||
59 | private int m_maxSnapshots = 500; | ||
60 | private int m_lastSnapshot = 0; | ||
61 | private string m_snapsDir = "DataSnapshot"; | 57 | private string m_snapsDir = "DataSnapshot"; |
58 | |||
59 | //Lists of stuff we need | ||
60 | private List<Scene> m_scenes = new List<Scene>(); | ||
61 | private List<IDataSnapshotProvider> m_dataproviders = new List<IDataSnapshotProvider>(); | ||
62 | |||
63 | //Various internal objects | ||
64 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
65 | internal object m_syncInit = new object(); | ||
66 | |||
67 | //DataServices and networking | ||
62 | private string m_dataServices = "noservices"; | 68 | private string m_dataServices = "noservices"; |
63 | private string m_listener_port = "9000"; //TODO: Set default port over 9000 | 69 | public string m_listener_port = "9000"; //TODO: Set default port over 9000 |
64 | private string m_hostname = "127.0.0.1"; | 70 | public string m_hostname = "127.0.0.1"; |
71 | |||
72 | //Update timers | ||
65 | private Timer m_periodic = null; | 73 | private Timer m_periodic = null; |
66 | private int m_period = 60; // in seconds | 74 | private int m_period = 20; // in seconds |
67 | private List<string> m_disabledModules = new List<string>(); | 75 | private int m_maxStales = 500; |
76 | private int m_stales = 0; | ||
77 | private Timer m_passedCheck = null; | ||
78 | private bool m_periodPassed = false; | ||
79 | |||
80 | //Program objects | ||
81 | private SnapshotStore m_snapStore = null; | ||
82 | private DataRequestHandler m_requests = null; | ||
83 | |||
68 | #endregion | 84 | #endregion |
69 | 85 | ||
70 | #region IRegionModule | 86 | #region IRegionModule |
87 | |||
71 | public void Close() | 88 | public void Close() |
72 | { | 89 | { |
73 | 90 | m_log.Info("[DATASNAPSHOT]: Close called"); | |
74 | } | 91 | } |
75 | 92 | ||
76 | public void Initialise(Scene scene, IConfigSource config) | 93 | public void Initialise(Scene scene, IConfigSource config) |
77 | { | 94 | { |
78 | if (!m_scenes.Contains(scene)) | 95 | if (!m_configLoaded) { |
79 | m_scenes.Add(scene); | ||
80 | |||
81 | if (!m_configLoaded) | ||
82 | { | ||
83 | m_configLoaded = true; | 96 | m_configLoaded = true; |
84 | m_log.Info("[DATASNAPSHOT]: Loading configuration"); | 97 | m_log.Info("[DATASNAPSHOT]: Loading configuration"); |
85 | //Read from the config for options | 98 | //Read from the config for options |
@@ -99,49 +112,59 @@ namespace OpenSim.Region.DataSnapshot | |||
99 | //Non gridmode stuff | 112 | //Non gridmode stuff |
100 | } | 113 | } |
101 | 114 | ||
102 | m_gridinfo.Add("Name", config.Configs["DataSnapshot"].GetString("gridname", "harbl")); | 115 | m_gridinfo.Add("Name", config.Configs["DataSnapshot"].GetString("gridname", "harbl")); |
103 | m_maxSnapshots = config.Configs["DataSnapshot"].GetInt("max_snapshots", m_maxSnapshots); | 116 | m_period = config.Configs["DataSnapshot"].GetInt("default_snapshot_period", m_period); |
104 | m_period = config.Configs["DataSnapshot"].GetInt("default_snapshot_period", m_period); | 117 | m_maxStales = config.Configs["DataSnapshot"].GetInt("max_changes_before_update", m_maxStales); |
105 | m_snapsDir = config.Configs["DataSnapshot"].GetString("snapshot_cache_directory", m_snapsDir); | 118 | m_snapsDir = config.Configs["DataSnapshot"].GetString("snapshot_cache_directory", m_snapsDir); |
106 | m_dataServices = config.Configs["DataSnapshot"].GetString("data_services", m_dataServices); | 119 | m_dataServices = config.Configs["DataSnapshot"].GetString("data_services", m_dataServices); |
107 | m_listener_port = config.Configs["Network"].GetString("http_listener_port", m_listener_port); | 120 | m_listener_port = config.Configs["Network"].GetString("http_listener_port", m_listener_port); |
108 | //BUG: Naming a search data module "DESUDESUDESU" will cause it to not get loaded by default. | 121 | |
109 | //RESOLUTION: Wontfix, there are no Suiseiseki-loving developers | 122 | String[] annoying_string_array = config.Configs["DataSnapshot"].GetString("disable_modules", "").Split(".".ToCharArray()); |
110 | String[] annoying_string_array = config.Configs["DataSnapshot"].GetString("disable_modules", "DESUDESUDESU").Split(".".ToCharArray()); | 123 | foreach (String bloody_wanker in annoying_string_array) { |
111 | foreach (String bloody_wanker in annoying_string_array) | 124 | m_disabledModules.Add(bloody_wanker); |
112 | { | 125 | } |
113 | m_disabledModules.Add(bloody_wanker); | 126 | } catch (Exception) { |
114 | } | ||
115 | } | ||
116 | catch (Exception) | ||
117 | { | ||
118 | m_log.Info("[DATASNAPSHOT]: Could not load configuration. DataSnapshot will be disabled."); | 127 | m_log.Info("[DATASNAPSHOT]: Could not load configuration. DataSnapshot will be disabled."); |
119 | m_enabled = false; | 128 | m_enabled = false; |
120 | return; | 129 | return; |
121 | } | 130 | } |
122 | } | 131 | } |
123 | } | 132 | |
124 | if (Directory.Exists(m_snapsDir)) | 133 | m_snapStore = new SnapshotStore(m_snapsDir, m_gridinfo, m_listener_port, m_hostname); |
125 | { | ||
126 | m_log.Info("[DATASNAPSHOT] DataSnapshot directory already exists."); | ||
127 | } | ||
128 | else | ||
129 | { | ||
130 | // Try to create the directory. | ||
131 | m_log.Info("[DATASNAPSHOT] Creating " + m_snapsDir + " directory."); | ||
132 | try | ||
133 | { | ||
134 | Directory.CreateDirectory(m_snapsDir); | ||
135 | } | ||
136 | catch (Exception) | ||
137 | { | ||
138 | m_log.Error("[DATASNAPSHOT] Failed to create " + m_snapsDir + " directory."); | ||
139 | } | ||
140 | } | 134 | } |
141 | 135 | ||
142 | if (m_enabled) | 136 | if (m_enabled) |
143 | { | 137 | { |
144 | m_log.Info("[DATASNAPSHOT]: Scene added to module."); | 138 | m_log.Info("[DATASNAPSHOT]: Scene added to module."); |
139 | |||
140 | m_snapStore.AddScene(scene); | ||
141 | m_scenes.Add(scene); | ||
142 | |||
143 | Assembly currentasm = Assembly.GetExecutingAssembly(); | ||
144 | |||
145 | foreach (Type pluginType in currentasm.GetTypes()) | ||
146 | { | ||
147 | if (pluginType.IsPublic) | ||
148 | { | ||
149 | if (!pluginType.IsAbstract) | ||
150 | { | ||
151 | if (pluginType.GetInterface("IDataSnapshotProvider") != null) | ||
152 | { | ||
153 | IDataSnapshotProvider module = (IDataSnapshotProvider)Activator.CreateInstance(pluginType); | ||
154 | module.Initialize(scene, this); | ||
155 | module.OnStale += MarkDataStale; | ||
156 | |||
157 | m_dataproviders.Add(module); | ||
158 | m_snapStore.AddProvider(module); | ||
159 | |||
160 | m_log.Info("[DATASNAPSHOT]: Added new data provider type: " + pluginType.Name); | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | //scene.OnRestart += OnSimRestart; | ||
167 | scene.EventManager.OnShutdown += delegate() { OnSimRestart(scene.RegionInfo); }; | ||
145 | } | 168 | } |
146 | else | 169 | else |
147 | { | 170 | { |
@@ -163,68 +186,35 @@ namespace OpenSim.Region.DataSnapshot | |||
163 | { | 186 | { |
164 | if (m_enabled) | 187 | if (m_enabled) |
165 | { | 188 | { |
166 | //Right now, only load ISearchData objects in the current assembly. | ||
167 | //Eventually allow it to load ISearchData objects from all assemblies. | ||
168 | Assembly currentasm = Assembly.GetExecutingAssembly(); | ||
169 | |||
170 | //Stolen from ModuleLoader.cs | ||
171 | foreach (Type pluginType in currentasm.GetTypes()) | ||
172 | { | ||
173 | if (pluginType.IsPublic) | ||
174 | { | ||
175 | if (!pluginType.IsAbstract) | ||
176 | { | ||
177 | if (pluginType.GetInterface("IDataSnapshotProvider") != null) | ||
178 | { | ||
179 | foreach (Scene scene in m_scenes) | ||
180 | { | ||
181 | IDataSnapshotProvider module = (IDataSnapshotProvider)Activator.CreateInstance(pluginType); | ||
182 | module.Initialize(scene, this); | ||
183 | //module.PrepareData(); | ||
184 | List<IDataSnapshotProvider> providerlist = null; | ||
185 | m_dataproviders.TryGetValue(scene, out providerlist); | ||
186 | if (providerlist == null) | ||
187 | { | ||
188 | providerlist = new List<IDataSnapshotProvider>(); | ||
189 | m_dataproviders.Add(scene, providerlist); | ||
190 | } | ||
191 | providerlist.Add(module); | ||
192 | |||
193 | } | ||
194 | m_log.Info("[DATASNAPSHOT]: Added new data provider type: " + pluginType.Name); | ||
195 | } | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | |||
200 | //Hand it the first scene, assuming that all scenes have the same BaseHTTPServer | 189 | //Hand it the first scene, assuming that all scenes have the same BaseHTTPServer |
201 | m_requests = new DataRequestHandler(m_scenes[0], this); | 190 | m_requests = new DataRequestHandler(m_scenes[0], this); |
202 | 191 | ||
203 | //Create timer | 192 | //Create update timer |
204 | m_periodic = new Timer(); | 193 | m_periodic = new Timer(); |
205 | m_periodic.Interval = m_period * 1000; | 194 | m_periodic.Interval = m_period * 1000; |
206 | m_periodic.Elapsed += SnapshotTimerCallback; | 195 | m_periodic.Elapsed += SnapshotTimerCallback; |
207 | m_periodic.Enabled = true; | 196 | |
197 | //Create update eligibility timer | ||
198 | m_passedCheck = new Timer(); | ||
199 | m_passedCheck.Interval = m_period * 1000; | ||
200 | m_passedCheck.Elapsed += UpdateEligibilityCallback; | ||
201 | m_passedCheck.Start(); | ||
208 | 202 | ||
209 | m_hostname = m_scenes[0].RegionInfo.ExternalHostName; | 203 | m_hostname = m_scenes[0].RegionInfo.ExternalHostName; |
210 | 204 | ||
211 | MakeNewSnapshot(); //Make the initial snapshot | 205 | //m_snapStore = new SnapshotStore(m_snapsDir, m_dataproviders, m_gridinfo, m_listener_port, m_hostname); |
206 | MakeEverythingStale(); | ||
212 | 207 | ||
213 | if (m_dataServices != "noservices") | 208 | if (m_dataServices != "noservices") |
214 | NotifyDataServices(m_dataServices); | 209 | NotifyDataServices(m_dataServices); |
215 | } | 210 | } |
216 | } | 211 | } |
212 | |||
217 | #endregion | 213 | #endregion |
218 | 214 | ||
219 | #region Associated helper functions | 215 | #region Associated helper functions |
220 | 216 | ||
221 | string DataFileName(Scene scene) | 217 | public Scene SceneForName(string name) |
222 | { | ||
223 | return Path.Combine(m_snapsDir, Path.ChangeExtension(scene.RegionInfo.RegionName, "xml")); | ||
224 | //return (m_snapsDir + Path.DirectorySeparatorChar + scene.RegionInfo.RegionName + ".xml"); | ||
225 | } | ||
226 | |||
227 | Scene SceneForName(string name) | ||
228 | { | 218 | { |
229 | foreach (Scene scene in m_scenes) | 219 | foreach (Scene scene in m_scenes) |
230 | if (scene.RegionInfo.RegionName == name) | 220 | if (scene.RegionInfo.RegionName == name) |
@@ -233,168 +223,19 @@ namespace OpenSim.Region.DataSnapshot | |||
233 | return null; | 223 | return null; |
234 | } | 224 | } |
235 | 225 | ||
236 | #endregion | 226 | public Scene SceneForUUID(LLUUID id) |
237 | |||
238 | #region [Private] XML snapshot generator | ||
239 | |||
240 | private XmlDocument Snapshot(Scene scene) | ||
241 | { | ||
242 | XmlDocument basedoc = new XmlDocument(); | ||
243 | XmlNode regionElement = MakeRegionNode(scene, basedoc); | ||
244 | |||
245 | regionElement.AppendChild(GetGridSnapshotData(basedoc)); | ||
246 | XmlNode regionData = basedoc.CreateNode(XmlNodeType.Element, "data", ""); | ||
247 | |||
248 | foreach (KeyValuePair<Scene, List<IDataSnapshotProvider>> dataprovider in m_dataproviders) | ||
249 | { | ||
250 | if (dataprovider.Key == scene) | ||
251 | { | ||
252 | foreach (IDataSnapshotProvider provider in dataprovider.Value) | ||
253 | { | ||
254 | XmlNode data = provider.RequestSnapshotData(basedoc); | ||
255 | regionData.AppendChild(data); | ||
256 | } | ||
257 | } | ||
258 | } | ||
259 | |||
260 | regionElement.AppendChild(regionData); | ||
261 | |||
262 | basedoc.AppendChild(regionElement); | ||
263 | |||
264 | return basedoc; | ||
265 | } | ||
266 | |||
267 | private XmlNode MakeRegionNode(Scene scene, XmlDocument basedoc) | ||
268 | { | ||
269 | XmlNode docElement = basedoc.CreateNode(XmlNodeType.Element, "region", ""); | ||
270 | |||
271 | XmlAttribute attr = basedoc.CreateAttribute("category"); | ||
272 | attr.Value = GetRegionCategory(scene); | ||
273 | docElement.Attributes.Append(attr); | ||
274 | |||
275 | attr = basedoc.CreateAttribute("entities"); | ||
276 | attr.Value = scene.Entities.Count.ToString(); | ||
277 | docElement.Attributes.Append(attr); | ||
278 | |||
279 | //attr = basedoc.CreateAttribute("parcels"); | ||
280 | //attr.Value = scene.LandManager.landList.Count.ToString(); | ||
281 | //docElement.Attributes.Append(attr); | ||
282 | |||
283 | |||
284 | XmlNode infoblock = basedoc.CreateNode(XmlNodeType.Element, "info", ""); | ||
285 | |||
286 | XmlNode infopiece = basedoc.CreateNode(XmlNodeType.Element, "uuid", ""); | ||
287 | infopiece.InnerText = scene.RegionInfo.RegionID.ToString(); | ||
288 | infoblock.AppendChild(infopiece); | ||
289 | |||
290 | infopiece = basedoc.CreateNode(XmlNodeType.Element, "url", ""); | ||
291 | infopiece.InnerText = "http://" + m_hostname + ":" + m_listener_port; | ||
292 | infoblock.AppendChild(infopiece); | ||
293 | |||
294 | infopiece = basedoc.CreateNode(XmlNodeType.Element, "name", ""); | ||
295 | infopiece.InnerText = scene.RegionInfo.RegionName; | ||
296 | infoblock.AppendChild(infopiece); | ||
297 | |||
298 | docElement.AppendChild(infoblock); | ||
299 | |||
300 | return docElement; | ||
301 | } | ||
302 | |||
303 | private XmlNode GetGridSnapshotData(XmlDocument factory) | ||
304 | { | ||
305 | XmlNode griddata = factory.CreateNode(XmlNodeType.Element, "grid", ""); | ||
306 | |||
307 | foreach (KeyValuePair<String, String> GridData in m_gridinfo) | ||
308 | { | ||
309 | //TODO: make it lowercase tag names for diva | ||
310 | XmlNode childnode = factory.CreateNode(XmlNodeType.Element, GridData.Key, ""); | ||
311 | childnode.InnerText = GridData.Value; | ||
312 | griddata.AppendChild(childnode); | ||
313 | } | ||
314 | |||
315 | return griddata; | ||
316 | } | ||
317 | |||
318 | private String GetRegionCategory(Scene scene) | ||
319 | { | 227 | { |
228 | foreach (Scene scene in m_scenes) | ||
229 | if (scene.RegionInfo.RegionID == id) | ||
230 | return scene; | ||
320 | 231 | ||
321 | //Boolean choice between: | 232 | return null; |
322 | // "PG" - Mormontown | ||
323 | // "Mature" - Sodom and Gomorrah | ||
324 | // (Depreciated) "Patriotic Nigra Testing Sandbox" - Abandon Hope All Ye Who Enter Here | ||
325 | if ((scene.RegionInfo.EstateSettings.simAccess & Simulator.SimAccess.Mature) == Simulator.SimAccess.Mature) | ||
326 | { | ||
327 | return "Mature"; | ||
328 | } | ||
329 | else if ((scene.RegionInfo.EstateSettings.simAccess & Simulator.SimAccess.PG) == Simulator.SimAccess.PG) | ||
330 | { | ||
331 | return "PG"; | ||
332 | } | ||
333 | else | ||
334 | { | ||
335 | return "Unknown"; | ||
336 | } | ||
337 | } | 233 | } |
338 | 234 | ||
339 | /* Code's closed due to AIDS, See EstateSnapshot.cs for CURE | ||
340 | private XmlNode GetEstateSnapshotData(Scene scene, XmlDocument factory) | ||
341 | { | ||
342 | //Estate data section - contains who owns a set of sims and the name of the set. | ||
343 | //In Opensim all the estate names are the same as the Master Avatar (owner of the sim) | ||
344 | XmlNode estatedata = factory.CreateNode(XmlNodeType.Element, "estate", ""); | ||
345 | |||
346 | LLUUID ownerid = scene.RegionInfo.MasterAvatarAssignedUUID; | ||
347 | String firstname = scene.RegionInfo.MasterAvatarFirstName; | ||
348 | String lastname = scene.RegionInfo.MasterAvatarLastName; | ||
349 | String hostname = scene.RegionInfo.ExternalHostName; | ||
350 | |||
351 | XmlNode user = factory.CreateNode(XmlNodeType.Element, "owner", ""); | ||
352 | |||
353 | XmlNode username = factory.CreateNode(XmlNodeType.Element, "name", ""); | ||
354 | username.InnerText = firstname + " " + lastname; | ||
355 | user.AppendChild(username); | ||
356 | |||
357 | XmlNode useruuid = factory.CreateNode(XmlNodeType.Element, "uuid", ""); | ||
358 | useruuid.InnerText = ownerid.ToString(); | ||
359 | user.AppendChild(useruuid); | ||
360 | |||
361 | estatedata.AppendChild(user); | ||
362 | |||
363 | return estatedata; | ||
364 | } */ | ||
365 | |||
366 | #endregion | 235 | #endregion |
367 | 236 | ||
368 | #region [Public] Snapshot storage functions | 237 | #region [Public] Snapshot storage functions |
369 | 238 | ||
370 | public void MakeNewSnapshot() | ||
371 | { | ||
372 | foreach (Scene scene in m_scenes) | ||
373 | { | ||
374 | XmlDocument snapshot = Snapshot(scene); | ||
375 | |||
376 | string path = DataFileName(scene); | ||
377 | |||
378 | try | ||
379 | { | ||
380 | using (XmlTextWriter snapXWriter = new XmlTextWriter(path, Encoding.Default)) | ||
381 | { | ||
382 | snapXWriter.Formatting = Formatting.Indented; | ||
383 | snapXWriter.WriteStartDocument(); | ||
384 | snapshot.WriteTo(snapXWriter); | ||
385 | snapXWriter.WriteEndDocument(); | ||
386 | |||
387 | m_lastSnapshot++; | ||
388 | } | ||
389 | } | ||
390 | catch (Exception e) | ||
391 | { | ||
392 | m_log.Warn("[DATASNAPSHOT]: Caught unknown exception while trying to save snapshot: " + path + "\n" + e.ToString()); | ||
393 | } | ||
394 | m_log.Info("[DATASNAPSHOT]: Made external data snapshot " + path); | ||
395 | } | ||
396 | } | ||
397 | |||
398 | /** | 239 | /** |
399 | * Reply to the http request | 240 | * Reply to the http request |
400 | */ | 241 | */ |
@@ -410,30 +251,16 @@ namespace OpenSim.Region.DataSnapshot | |||
410 | { | 251 | { |
411 | foreach (Scene scene in m_scenes) | 252 | foreach (Scene scene in m_scenes) |
412 | { | 253 | { |
413 | string path = DataFileName(scene); | 254 | regiondata.AppendChild(m_snapStore.GetScene(scene, requestedSnap)); |
414 | XmlDocument regionSnap = new XmlDocument(); | ||
415 | regionSnap.PreserveWhitespace = true; | ||
416 | |||
417 | regionSnap.Load(path); | ||
418 | XmlNode nodeOrig = regionSnap["region"]; | ||
419 | XmlNode nodeDest = requestedSnap.ImportNode(nodeOrig, true); | ||
420 | //requestedSnap.AppendChild(nodeDest); | ||
421 | |||
422 | regiondata.AppendChild(requestedSnap.CreateWhitespace("\r\n")); | ||
423 | regiondata.AppendChild(nodeDest); | ||
424 | } | 255 | } |
425 | } | 256 | } |
426 | else | 257 | else |
427 | { | 258 | { |
428 | Scene scene = SceneForName(regionName); | 259 | Scene scene = SceneForName(regionName); |
429 | requestedSnap.Load(DataFileName(scene)); | 260 | regiondata.AppendChild(m_snapStore.GetScene(scene, requestedSnap)); |
430 | } | 261 | } |
431 | // requestedSnap.InsertBefore(requestedSnap.CreateXmlDeclaration("1.0", null, null), | ||
432 | // requestedSnap.DocumentElement); | ||
433 | requestedSnap.AppendChild(regiondata); | 262 | requestedSnap.AppendChild(regiondata); |
434 | regiondata.AppendChild(requestedSnap.CreateWhitespace("\r\n")); | 263 | regiondata.AppendChild(requestedSnap.CreateWhitespace("\r\n")); |
435 | |||
436 | |||
437 | } | 264 | } |
438 | catch (XmlException e) | 265 | catch (XmlException e) |
439 | { | 266 | { |
@@ -469,16 +296,6 @@ namespace OpenSim.Region.DataSnapshot | |||
469 | 296 | ||
470 | #endregion | 297 | #endregion |
471 | 298 | ||
472 | #region Event callbacks | ||
473 | |||
474 | private void SnapshotTimerCallback(object timer, ElapsedEventArgs args) | ||
475 | { | ||
476 | MakeNewSnapshot(); | ||
477 | //Add extra calls here | ||
478 | } | ||
479 | |||
480 | #endregion | ||
481 | |||
482 | #region External data services | 299 | #region External data services |
483 | private void NotifyDataServices(string servicesStr) | 300 | private void NotifyDataServices(string servicesStr) |
484 | { | 301 | { |
@@ -524,5 +341,85 @@ namespace OpenSim.Region.DataSnapshot | |||
524 | 341 | ||
525 | } | 342 | } |
526 | #endregion | 343 | #endregion |
344 | |||
345 | #region Latency-based update functions | ||
346 | |||
347 | public void MarkDataStale(IDataSnapshotProvider provider) | ||
348 | { | ||
349 | //Behavior here: Wait m_period seconds, then update if there has not been a request in m_period seconds | ||
350 | //or m_maxStales has been exceeded | ||
351 | m_stales++; | ||
352 | |||
353 | if ((m_stales >= m_maxStales) && m_periodPassed) | ||
354 | SnapshotTimerCallback(m_periodic, null); | ||
355 | else if (m_periodic.Enabled == false) | ||
356 | m_periodic.Start(); | ||
357 | else | ||
358 | { | ||
359 | m_periodic.Stop(); | ||
360 | m_periodic.Start(); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | private void SnapshotTimerCallback(object timer, ElapsedEventArgs args) | ||
365 | { | ||
366 | m_log.Debug("[DATASNAPSHOT]: Marking scenes for snapshot updates."); | ||
367 | |||
368 | //Finally generate those snapshot updates | ||
369 | MakeEverythingStale(); | ||
370 | |||
371 | //Stop the update delay timer | ||
372 | m_periodic.Stop(); | ||
373 | |||
374 | //Reset the eligibility flag and timer | ||
375 | m_periodPassed = false; | ||
376 | m_passedCheck.Stop(); | ||
377 | m_passedCheck.Start(); | ||
378 | } | ||
379 | |||
380 | private void UpdateEligibilityCallback(object timer, ElapsedEventArgs args) | ||
381 | { | ||
382 | //Set eligibility, so we can start making updates | ||
383 | m_periodPassed = true; | ||
384 | } | ||
385 | |||
386 | public void MakeEverythingStale() | ||
387 | { | ||
388 | m_log.Debug("[DATASNAPSHOT]: Marking all scenes as stale."); | ||
389 | foreach (Scene scene in m_scenes) | ||
390 | { | ||
391 | m_snapStore.ForceSceneStale(scene); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | #endregion | ||
396 | |||
397 | public void OnSimRestart(RegionInfo thisRegion) | ||
398 | { | ||
399 | m_log.Info("[DATASNAPSHOT]: Region " + thisRegion.RegionName + " is restarting, removing from indexing"); | ||
400 | Scene restartedScene = SceneForUUID(thisRegion.RegionID); | ||
401 | |||
402 | m_scenes.Remove(restartedScene); | ||
403 | m_snapStore.RemoveScene(restartedScene); | ||
404 | |||
405 | //Getting around the fact that we can't remove objects from a collection we are enumerating over | ||
406 | List<IDataSnapshotProvider> providersToRemove = new List<IDataSnapshotProvider>(); | ||
407 | |||
408 | foreach (IDataSnapshotProvider provider in m_dataproviders) | ||
409 | { | ||
410 | if (provider.GetParentScene == restartedScene) | ||
411 | { | ||
412 | providersToRemove.Add(provider); | ||
413 | } | ||
414 | } | ||
415 | |||
416 | foreach (IDataSnapshotProvider provider in providersToRemove) | ||
417 | { | ||
418 | m_dataproviders.Remove(provider); | ||
419 | m_snapStore.RemoveProvider(provider); | ||
420 | } | ||
421 | |||
422 | m_snapStore.RemoveScene(restartedScene); | ||
423 | } | ||
527 | } | 424 | } |
528 | } | 425 | } |
diff --git a/OpenSim/Region/DataSnapshot/EstateSnapshot.cs b/OpenSim/Region/DataSnapshot/EstateSnapshot.cs index 8020713..40b96d5 100644 --- a/OpenSim/Region/DataSnapshot/EstateSnapshot.cs +++ b/OpenSim/Region/DataSnapshot/EstateSnapshot.cs | |||
@@ -31,12 +31,19 @@ using libsecondlife; | |||
31 | using OpenSim.Region.DataSnapshot.Interfaces; | 31 | using OpenSim.Region.DataSnapshot.Interfaces; |
32 | using OpenSim.Region.Environment.Scenes; | 32 | using OpenSim.Region.Environment.Scenes; |
33 | 33 | ||
34 | namespace OpenSim.Region.DataSnapshot | 34 | namespace OpenSim.Region.DataSnapshot.Providers |
35 | { | 35 | { |
36 | public class EstateSnapshot : IDataSnapshotProvider | 36 | public class EstateSnapshot : IDataSnapshotProvider |
37 | { | 37 | { |
38 | /* This module doesn't check for changes, since it's *assumed* there are none. | ||
39 | * Nevertheless, it's possible to have changes, since all the fields are public. | ||
40 | * There's no event to subscribe to. :/ | ||
41 | * | ||
42 | * I don't think anything changes the fields beyond RegionModule PostInit, however. | ||
43 | */ | ||
38 | private Scene m_scene = null; | 44 | private Scene m_scene = null; |
39 | private DataSnapshotManager m_parent = null; | 45 | private DataSnapshotManager m_parent = null; |
46 | private bool m_stale = true; | ||
40 | 47 | ||
41 | #region IDataSnapshotProvider Members | 48 | #region IDataSnapshotProvider Members |
42 | 49 | ||
@@ -70,6 +77,7 @@ namespace OpenSim.Region.DataSnapshot | |||
70 | 77 | ||
71 | estatedata.AppendChild(user); | 78 | estatedata.AppendChild(user); |
72 | 79 | ||
80 | this.Stale = false; | ||
73 | return estatedata; | 81 | return estatedata; |
74 | } | 82 | } |
75 | 83 | ||
@@ -84,6 +92,25 @@ namespace OpenSim.Region.DataSnapshot | |||
84 | get { return m_scene; } | 92 | get { return m_scene; } |
85 | } | 93 | } |
86 | 94 | ||
95 | public String Name { | ||
96 | get { return "EstateSnapshot"; } | ||
97 | } | ||
98 | |||
99 | public bool Stale | ||
100 | { | ||
101 | get { | ||
102 | return m_stale; | ||
103 | } | ||
104 | set { | ||
105 | m_stale = value; | ||
106 | |||
107 | if (m_stale) | ||
108 | OnStale(this); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | public event ProviderStale OnStale; | ||
113 | |||
87 | #endregion | 114 | #endregion |
88 | } | 115 | } |
89 | } | 116 | } \ No newline at end of file |
diff --git a/OpenSim/Region/DataSnapshot/Interfaces/IDataSnapshot.cs b/OpenSim/Region/DataSnapshot/Interfaces/IDataSnapshot.cs new file mode 100644 index 0000000..697d313 --- /dev/null +++ b/OpenSim/Region/DataSnapshot/Interfaces/IDataSnapshot.cs | |||
@@ -0,0 +1,13 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using System.Xml; | ||
5 | |||
6 | namespace OpenSim.Region.DataSnapshot.Interfaces | ||
7 | { | ||
8 | public interface IDataSnapshot | ||
9 | { | ||
10 | XmlDocument GetSnapshot(string regionName); | ||
11 | void MakeEverythingStale(); | ||
12 | } | ||
13 | } | ||
diff --git a/OpenSim/Region/DataSnapshot/Interfaces/IDataSnapshotProvider.cs b/OpenSim/Region/DataSnapshot/Interfaces/IDataSnapshotProvider.cs index fb9c51a..1519355 100644 --- a/OpenSim/Region/DataSnapshot/Interfaces/IDataSnapshotProvider.cs +++ b/OpenSim/Region/DataSnapshot/Interfaces/IDataSnapshotProvider.cs | |||
@@ -26,19 +26,21 @@ | |||
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | 28 | ||
29 | using System; | ||
29 | using System.Xml; | 30 | using System.Xml; |
30 | using OpenSim.Region.Environment.Scenes; | 31 | using OpenSim.Region.Environment.Scenes; |
31 | 32 | ||
32 | namespace OpenSim.Region.DataSnapshot.Interfaces | 33 | namespace OpenSim.Region.DataSnapshot.Interfaces |
33 | { | 34 | { |
35 | public delegate void ProviderStale(IDataSnapshotProvider provider); | ||
36 | |||
34 | public interface IDataSnapshotProvider | 37 | public interface IDataSnapshotProvider |
35 | { | 38 | { |
36 | XmlNode RequestSnapshotData(XmlDocument document); | 39 | XmlNode RequestSnapshotData(XmlDocument document); |
37 | |||
38 | //void PrepareData(); | ||
39 | |||
40 | void Initialize(Scene scene, DataSnapshotManager parent); | 40 | void Initialize(Scene scene, DataSnapshotManager parent); |
41 | |||
42 | Scene GetParentScene { get; } | 41 | Scene GetParentScene { get; } |
42 | String Name { get; } | ||
43 | bool Stale { get; set; } | ||
44 | event ProviderStale OnStale; | ||
43 | } | 45 | } |
44 | } \ No newline at end of file | 46 | } |
diff --git a/OpenSim/Region/DataSnapshot/LLSDDiscovery.cs b/OpenSim/Region/DataSnapshot/LLSDDiscovery.cs new file mode 100644 index 0000000..7b4f4ec --- /dev/null +++ b/OpenSim/Region/DataSnapshot/LLSDDiscovery.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 OpenSim 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 | |||
29 | using System; | ||
30 | using OpenSim.Framework.Communications.Capabilities; | ||
31 | |||
32 | namespace OpenSim.Region.DataSnapshot | ||
33 | { | ||
34 | [LLSDMap] | ||
35 | public class LLSDDiscoveryResponse | ||
36 | { | ||
37 | public LLSDArray snapshot_resources; | ||
38 | } | ||
39 | |||
40 | [LLSDMap] | ||
41 | public class LLSDDiscoveryDataURL | ||
42 | { | ||
43 | public string snapshot_format; | ||
44 | public string snapshot_url; | ||
45 | } | ||
46 | } | ||
diff --git a/OpenSim/Region/DataSnapshot/LandSnapshot.cs b/OpenSim/Region/DataSnapshot/LandSnapshot.cs index 183c2a3..4bfa87a 100644 --- a/OpenSim/Region/DataSnapshot/LandSnapshot.cs +++ b/OpenSim/Region/DataSnapshot/LandSnapshot.cs | |||
@@ -23,7 +23,7 @@ | |||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 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 | 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. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | 28 | ||
29 | using System; | 29 | using System; |
@@ -37,8 +37,9 @@ using OpenSim.Region.DataSnapshot.Interfaces; | |||
37 | using OpenSim.Region.Environment.Interfaces; | 37 | using OpenSim.Region.Environment.Interfaces; |
38 | using OpenSim.Region.Environment.Modules.World.Land; | 38 | using OpenSim.Region.Environment.Modules.World.Land; |
39 | using OpenSim.Region.Environment.Scenes; | 39 | using OpenSim.Region.Environment.Scenes; |
40 | using libsecondlife.Packets; | ||
40 | 41 | ||
41 | namespace OpenSim.Region.DataSnapshot | 42 | namespace OpenSim.Region.DataSnapshot.Providers |
42 | { | 43 | { |
43 | public class LandSnapshot : IDataSnapshotProvider | 44 | public class LandSnapshot : IDataSnapshotProvider |
44 | { | 45 | { |
@@ -46,14 +47,15 @@ namespace OpenSim.Region.DataSnapshot | |||
46 | private DataSnapshotManager m_parent = null; | 47 | private DataSnapshotManager m_parent = null; |
47 | //private Dictionary<int, Land> m_landIndexed = new Dictionary<int, Land>(); | 48 | //private Dictionary<int, Land> m_landIndexed = new Dictionary<int, Land>(); |
48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
50 | private bool m_stale = true; | ||
49 | 51 | ||
50 | #region Dead code | 52 | #region Dead code |
51 | 53 | ||
52 | /* | 54 | /* |
53 | * David, I don't think we need this at all. When we do the snapshot, we can | 55 | * David, I don't think we need this at all. When we do the snapshot, we can |
54 | * simply look into the parcels that are marked for ShowDirectory -- see | 56 | * simply look into the parcels that are marked for ShowDirectory -- see |
55 | * conditional in RequestSnapshotData | 57 | * conditional in RequestSnapshotData |
56 | * | 58 | * |
57 | //Revise this, look for more direct way of checking for change in land | 59 | //Revise this, look for more direct way of checking for change in land |
58 | #region Client hooks | 60 | #region Client hooks |
59 | 61 | ||
@@ -106,7 +108,9 @@ namespace OpenSim.Region.DataSnapshot | |||
106 | { | 108 | { |
107 | m_scene = scene; | 109 | m_scene = scene; |
108 | m_parent = parent; | 110 | m_parent = parent; |
109 | //m_scene.EventManager.OnNewClient += OnNewClient; | 111 | |
112 | //Brought back from the dead for staleness checks. | ||
113 | m_scene.EventManager.OnNewClient += OnNewClient; | ||
110 | } | 114 | } |
111 | 115 | ||
112 | public Scene GetParentScene | 116 | public Scene GetParentScene |
@@ -115,7 +119,7 @@ namespace OpenSim.Region.DataSnapshot | |||
115 | } | 119 | } |
116 | 120 | ||
117 | public XmlNode RequestSnapshotData(XmlDocument nodeFactory) | 121 | public XmlNode RequestSnapshotData(XmlDocument nodeFactory) |
118 | { | 122 | { |
119 | ILandChannel landChannel = (LandChannel)m_scene.LandChannel; | 123 | ILandChannel landChannel = (LandChannel)m_scene.LandChannel; |
120 | Dictionary<int, ILandObject> landList = null; | 124 | Dictionary<int, ILandObject> landList = null; |
121 | try | 125 | try |
@@ -129,7 +133,7 @@ namespace OpenSim.Region.DataSnapshot | |||
129 | } | 133 | } |
130 | catch (Exception e) | 134 | catch (Exception e) |
131 | { | 135 | { |
132 | Console.WriteLine("[DATASNAPSHOT] couldn't access field reflectively\n" + e.ToString()); | 136 | m_log.Error("[DATASNAPSHOT] couldn't access field reflectively\n" + e.ToString()); |
133 | } | 137 | } |
134 | XmlNode parent = nodeFactory.CreateNode(XmlNodeType.Element, "parceldata", ""); | 138 | XmlNode parent = nodeFactory.CreateNode(XmlNodeType.Element, "parceldata", ""); |
135 | if (landList != null) | 139 | if (landList != null) |
@@ -243,9 +247,32 @@ namespace OpenSim.Region.DataSnapshot | |||
243 | //snap.AppendChild(parent); | 247 | //snap.AppendChild(parent); |
244 | } | 248 | } |
245 | 249 | ||
250 | this.Stale = false; | ||
246 | return parent; | 251 | return parent; |
247 | } | 252 | } |
248 | 253 | ||
254 | public String Name | ||
255 | { | ||
256 | get { return "LandSnapshot"; } | ||
257 | } | ||
258 | |||
259 | public bool Stale | ||
260 | { | ||
261 | get | ||
262 | { | ||
263 | return m_stale; | ||
264 | } | ||
265 | set | ||
266 | { | ||
267 | m_stale = value; | ||
268 | |||
269 | if (m_stale) | ||
270 | OnStale(this); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | public event ProviderStale OnStale; | ||
275 | |||
249 | #endregion | 276 | #endregion |
250 | 277 | ||
251 | #region Helper functions | 278 | #region Helper functions |
@@ -260,5 +287,33 @@ namespace OpenSim.Region.DataSnapshot | |||
260 | } | 287 | } |
261 | 288 | ||
262 | #endregion | 289 | #endregion |
290 | |||
291 | #region Change detection hooks | ||
292 | |||
293 | public void OnNewClient(IClientAPI client) | ||
294 | { | ||
295 | //Land hooks | ||
296 | client.OnParcelDivideRequest += delegate (int west, int south, int east, int north, | ||
297 | IClientAPI remote_client) { this.Stale = true; }; | ||
298 | client.OnParcelJoinRequest += delegate (int west, int south, int east, int north, | ||
299 | IClientAPI remote_client) { this.Stale = true; }; | ||
300 | client.OnParcelPropertiesUpdateRequest += delegate(LandUpdateArgs args, int local_id, | ||
301 | IClientAPI remote_client) { this.Stale = true; }; | ||
302 | client.OnParcelBuy += delegate (LLUUID agentId, LLUUID groupId, bool final, bool groupOwned, | ||
303 | bool removeContribution, int parcelLocalID, int parcelArea, int parcelPrice, bool authenticated) | ||
304 | { this.Stale = true; }; | ||
305 | } | ||
306 | |||
307 | public void ParcelSplitHook(int west, int south, int east, int north, IClientAPI remote_client) | ||
308 | { | ||
309 | this.Stale = true; | ||
310 | } | ||
311 | |||
312 | public void ParcelPropsHook(LandUpdateArgs args, int local_id, IClientAPI remote_client) | ||
313 | { | ||
314 | this.Stale = true; | ||
315 | } | ||
316 | |||
317 | #endregion | ||
263 | } | 318 | } |
264 | } | 319 | } \ No newline at end of file |
diff --git a/OpenSim/Region/DataSnapshot/ObjectSnapshot.cs b/OpenSim/Region/DataSnapshot/ObjectSnapshot.cs index 3270c3a..af73ba0 100644 --- a/OpenSim/Region/DataSnapshot/ObjectSnapshot.cs +++ b/OpenSim/Region/DataSnapshot/ObjectSnapshot.cs | |||
@@ -25,24 +25,63 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
28 | using System.Reflection; | 30 | using System.Reflection; |
29 | using System.Xml; | 31 | using System.Xml; |
30 | using log4net; | 32 | using log4net; |
31 | using OpenSim.Region.DataSnapshot.Interfaces; | 33 | using OpenSim.Region.DataSnapshot.Interfaces; |
32 | using OpenSim.Region.Environment.Scenes; | 34 | using OpenSim.Region.Environment.Scenes; |
35 | using OpenSim.Framework; | ||
36 | using libsecondlife; | ||
33 | 37 | ||
34 | namespace OpenSim.Region.DataSnapshot | 38 | namespace OpenSim.Region.DataSnapshot.Providers |
35 | { | 39 | { |
36 | public class ObjectSnapshot : IDataSnapshotProvider | 40 | public class ObjectSnapshot : IDataSnapshotProvider |
37 | { | 41 | { |
38 | private Scene m_scene = null; | 42 | private Scene m_scene = null; |
39 | private DataSnapshotManager m_parent = null; | 43 | private DataSnapshotManager m_parent = null; |
40 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
45 | private bool m_stale = true; | ||
41 | 46 | ||
42 | public void Initialize(Scene scene, DataSnapshotManager parent) | 47 | public void Initialize(Scene scene, DataSnapshotManager parent) |
43 | { | 48 | { |
44 | m_scene = scene; | 49 | m_scene = scene; |
45 | m_parent = parent; | 50 | m_parent = parent; |
51 | |||
52 | //To check for staleness, we must catch all incoming client packets. | ||
53 | m_scene.EventManager.OnNewClient += OnNewClient; | ||
54 | m_scene.EventManager.OnParcelPrimCountAdd += delegate(SceneObjectGroup obj) { this.Stale = true; }; | ||
55 | } | ||
56 | |||
57 | public void OnNewClient(IClientAPI client) | ||
58 | { | ||
59 | //Detect object data changes by hooking into the IClientAPI. | ||
60 | //Very dirty, and breaks whenever someone changes the client API. | ||
61 | |||
62 | client.OnAddPrim += delegate (LLUUID ownerID, LLVector3 RayEnd, LLQuaternion rot, | ||
63 | PrimitiveBaseShape shape, byte bypassRaycast, LLVector3 RayStart, LLUUID RayTargetID, | ||
64 | byte RayEndIsIntersection) { this.Stale = true; }; | ||
65 | client.OnLinkObjects += delegate (IClientAPI remoteClient, uint parent, List<uint> children) | ||
66 | { this.Stale = true; }; | ||
67 | client.OnDelinkObjects += delegate(List<uint> primIds) { this.Stale = true; }; | ||
68 | client.OnGrabUpdate += delegate(LLUUID objectID, LLVector3 offset, LLVector3 grapPos, | ||
69 | IClientAPI remoteClient) { this.Stale = true; }; | ||
70 | client.OnObjectAttach += delegate(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, | ||
71 | LLQuaternion rot) { this.Stale = true; }; | ||
72 | client.OnObjectDuplicate += delegate(uint localID, LLVector3 offset, uint dupeFlags, LLUUID AgentID, | ||
73 | LLUUID GroupID) { this.Stale = true; }; | ||
74 | client.OnObjectDuplicateOnRay += delegate(uint localID, uint dupeFlags, LLUUID AgentID, LLUUID GroupID, | ||
75 | LLUUID RayTargetObj, LLVector3 RayEnd, LLVector3 RayStart, bool BypassRaycast, | ||
76 | bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates) { this.Stale = true; }; | ||
77 | client.OnObjectIncludeInSearch += delegate(IClientAPI remoteClient, bool IncludeInSearch, uint localID) | ||
78 | { this.Stale = true; }; | ||
79 | client.OnObjectPermissions += delegate(IClientAPI controller, LLUUID agentID, LLUUID sessionID, | ||
80 | byte field, uint localId, uint mask, byte set) { this.Stale = true; }; | ||
81 | client.OnRezObject += delegate(IClientAPI remoteClient, LLUUID itemID, LLVector3 RayEnd, | ||
82 | LLVector3 RayStart, LLUUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, | ||
83 | uint EveryoneMask, uint GroupMask, uint NextOwnerMask, uint ItemFlags, bool RezSelected, | ||
84 | bool RemoveItem, LLUUID fromTaskID) { this.Stale = true; }; | ||
46 | } | 85 | } |
47 | 86 | ||
48 | public Scene GetParentScene | 87 | public Scene GetParentScene |
@@ -52,56 +91,83 @@ namespace OpenSim.Region.DataSnapshot | |||
52 | 91 | ||
53 | public XmlNode RequestSnapshotData(XmlDocument nodeFactory) | 92 | public XmlNode RequestSnapshotData(XmlDocument nodeFactory) |
54 | { | 93 | { |
94 | m_log.Debug("[DATASNAPSHOT]: Generating object data for scene " + m_scene.RegionInfo.RegionName); | ||
95 | |||
55 | XmlNode parent = nodeFactory.CreateNode(XmlNodeType.Element, "objectdata", ""); | 96 | XmlNode parent = nodeFactory.CreateNode(XmlNodeType.Element, "objectdata", ""); |
56 | XmlNode node; | 97 | XmlNode node; |
57 | #if LIBSL_IS_FIXED | 98 | |
58 | foreach (EntityBase entity in m_scene.Entities.Values) | 99 | foreach (EntityBase entity in m_scene.Entities.Values) |
59 | { | 100 | { |
60 | // only objects, not avatars | 101 | // only objects, not avatars |
61 | if (entity is SceneObjectGroup) | 102 | if (entity is SceneObjectGroup) |
62 | { | 103 | { |
63 | SceneObjectGroup obj = (SceneObjectGroup)entity; | 104 | SceneObjectGroup obj = (SceneObjectGroup)entity; |
64 | 105 | ||
65 | XmlNode xmlobject = nodeFactory.CreateNode(XmlNodeType.Element, "object", ""); | 106 | m_log.Debug("[DATASNAPSHOT]: Found object " + obj.Name + " in scene"); |
66 | 107 | ||
67 | node = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", ""); | 108 | if ((obj.RootPart.Flags & LLObject.ObjectFlags.JointWheel) == LLObject.ObjectFlags.JointWheel) { |
68 | node.InnerText = obj.UUID.ToString(); | 109 | XmlNode xmlobject = nodeFactory.CreateNode(XmlNodeType.Element, "object", ""); |
69 | xmlobject.AppendChild(node); | ||
70 | 110 | ||
71 | SceneObjectPart m_rootPart = null; | 111 | node = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", ""); |
72 | try | 112 | node.InnerText = obj.UUID.ToString(); |
73 | { | ||
74 | Type sog = typeof(SceneObjectGroup); | ||
75 | FieldInfo rootField = sog.GetField("m_rootPart", BindingFlags.NonPublic | BindingFlags.Instance); | ||
76 | if (rootField != null) | ||
77 | { | ||
78 | m_rootPart = (SceneObjectPart)rootField.GetValue(obj); | ||
79 | } | ||
80 | } | ||
81 | catch (Exception e) | ||
82 | { | ||
83 | Console.WriteLine("[DATASNAPSHOT] couldn't access field reflectively\n" + e.ToString()); | ||
84 | } | ||
85 | if (m_rootPart != null) | ||
86 | { | ||
87 | node = nodeFactory.CreateNode(XmlNodeType.Element, "title", ""); | ||
88 | node.InnerText = m_rootPart.Name; | ||
89 | xmlobject.AppendChild(node); | 113 | xmlobject.AppendChild(node); |
90 | 114 | ||
91 | node = nodeFactory.CreateNode(XmlNodeType.Element, "description", ""); | 115 | SceneObjectPart m_rootPart = null; |
92 | node.InnerText = m_rootPart.Description; | 116 | try |
93 | xmlobject.AppendChild(node); | 117 | { |
118 | Type sog = typeof(SceneObjectGroup); | ||
119 | FieldInfo rootField = sog.GetField("m_rootPart", BindingFlags.NonPublic | BindingFlags.Instance); | ||
120 | if (rootField != null) | ||
121 | { | ||
122 | m_rootPart = (SceneObjectPart)rootField.GetValue(obj); | ||
123 | } | ||
124 | } | ||
125 | catch (Exception e) | ||
126 | { | ||
127 | Console.WriteLine("[DATASNAPSHOT] couldn't access field reflectively\n" + e.ToString()); | ||
128 | } | ||
129 | if (m_rootPart != null) | ||
130 | { | ||
131 | node = nodeFactory.CreateNode(XmlNodeType.Element, "title", ""); | ||
132 | node.InnerText = m_rootPart.Name; | ||
133 | xmlobject.AppendChild(node); | ||
94 | 134 | ||
95 | node = nodeFactory.CreateNode(XmlNodeType.Element, "flags", ""); | 135 | node = nodeFactory.CreateNode(XmlNodeType.Element, "description", ""); |
96 | node.InnerText = String.Format("{0:x}", m_rootPart.ObjectFlags); | 136 | node.InnerText = m_rootPart.Description; |
97 | xmlobject.AppendChild(node); | 137 | xmlobject.AppendChild(node); |
138 | |||
139 | node = nodeFactory.CreateNode(XmlNodeType.Element, "flags", ""); | ||
140 | node.InnerText = String.Format("{0:x}", m_rootPart.ObjectFlags); | ||
141 | xmlobject.AppendChild(node); | ||
142 | } | ||
143 | parent.AppendChild(xmlobject); | ||
98 | } | 144 | } |
99 | parent.AppendChild(xmlobject); | ||
100 | } | 145 | } |
101 | } | 146 | } |
102 | #endif | 147 | this.Stale = false; |
103 | return parent; | 148 | return parent; |
149 | } | ||
104 | 150 | ||
151 | public String Name | ||
152 | { | ||
153 | get { return "ObjectSnapshot"; } | ||
105 | } | 154 | } |
155 | |||
156 | public bool Stale | ||
157 | { | ||
158 | get | ||
159 | { | ||
160 | return m_stale; | ||
161 | } | ||
162 | set | ||
163 | { | ||
164 | m_stale = value; | ||
165 | |||
166 | if (m_stale) | ||
167 | OnStale(this); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | public event ProviderStale OnStale; | ||
106 | } | 172 | } |
107 | } | 173 | } \ No newline at end of file |
diff --git a/OpenSim/Region/DataSnapshot/SnapshotStore.cs b/OpenSim/Region/DataSnapshot/SnapshotStore.cs new file mode 100644 index 0000000..05d5640 --- /dev/null +++ b/OpenSim/Region/DataSnapshot/SnapshotStore.cs | |||
@@ -0,0 +1,316 @@ | |||
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 OpenSim 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 | |||
29 | using System; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Text; | ||
32 | using System.Xml; | ||
33 | using System.IO; | ||
34 | using OpenSim.Region.Environment.Scenes; | ||
35 | using OpenSim.Region.DataSnapshot.Interfaces; | ||
36 | using libsecondlife; | ||
37 | |||
38 | namespace OpenSim.Region.DataSnapshot | ||
39 | { | ||
40 | public class SnapshotStore | ||
41 | { | ||
42 | #region Class Members | ||
43 | private String m_directory = "unyuu"; //not an attempt at adding RM references to core SVN, honest | ||
44 | private Dictionary<Scene, bool> m_scenes = null; | ||
45 | private List<IDataSnapshotProvider> m_providers = null; | ||
46 | private log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | private Dictionary<String, String> m_gridinfo = null; | ||
48 | private bool m_cacheEnabled = true; | ||
49 | private string m_listener_port = "9000"; //TODO: Set default port over 9000 | ||
50 | private string m_hostname = "127.0.0.1"; | ||
51 | #endregion | ||
52 | |||
53 | public SnapshotStore(string directory, Dictionary<String, String> gridinfo, string port, string hostname) { | ||
54 | m_directory = directory; | ||
55 | m_scenes = new Dictionary<Scene, bool>(); | ||
56 | m_providers = new List<IDataSnapshotProvider>(); | ||
57 | m_gridinfo = gridinfo; | ||
58 | m_listener_port = port; | ||
59 | m_hostname = hostname; | ||
60 | |||
61 | if (Directory.Exists(m_directory)) | ||
62 | { | ||
63 | m_log.Info("[DATASNAPSHOT]: Repsonse and fragment cache directory already exists."); | ||
64 | } | ||
65 | else | ||
66 | { | ||
67 | // Try to create the directory. | ||
68 | m_log.Info("[DATASNAPSHOT]: Creating directory " + m_directory); | ||
69 | try | ||
70 | { | ||
71 | Directory.CreateDirectory(m_directory); | ||
72 | } | ||
73 | catch (Exception e) | ||
74 | { | ||
75 | m_log.Error("[DATASNAPSHOT]: Failed to create directory " + m_directory, e); | ||
76 | |||
77 | //This isn't a horrible problem, just disable cacheing. | ||
78 | m_cacheEnabled = false; | ||
79 | m_log.Error("[DATASNAPSHOT]: Could not create directory, response cache has been disabled."); | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | public void ForceSceneStale(Scene scene) { | ||
85 | m_scenes[scene] = true; | ||
86 | } | ||
87 | |||
88 | #region Fragment storage | ||
89 | public XmlNode GetFragment(IDataSnapshotProvider provider, XmlDocument factory) | ||
90 | { | ||
91 | XmlNode data = null; | ||
92 | |||
93 | if (provider.Stale || !m_cacheEnabled) | ||
94 | { | ||
95 | data = provider.RequestSnapshotData(factory); | ||
96 | |||
97 | if (m_cacheEnabled) | ||
98 | { | ||
99 | String path = DataFileNameFragment(provider.GetParentScene, provider.Name); | ||
100 | |||
101 | using (XmlTextWriter snapXWriter = new XmlTextWriter(path, Encoding.Default)) | ||
102 | { | ||
103 | snapXWriter.Formatting = Formatting.Indented; | ||
104 | snapXWriter.WriteStartDocument(); | ||
105 | data.WriteTo(snapXWriter); | ||
106 | snapXWriter.WriteEndDocument(); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | //mark provider as not stale, parent scene as stale | ||
111 | provider.Stale = false; | ||
112 | m_scenes[provider.GetParentScene] = true; | ||
113 | |||
114 | m_log.Info("[DATASNAPSHOT]: Generated fragment response for provider type " + provider.Name); | ||
115 | } | ||
116 | else | ||
117 | { | ||
118 | String path = DataFileNameFragment(provider.GetParentScene, provider.Name); | ||
119 | |||
120 | XmlDocument fragDocument = new XmlDocument(); | ||
121 | fragDocument.PreserveWhitespace = true; | ||
122 | fragDocument.Load(path); | ||
123 | foreach (XmlNode node in fragDocument) | ||
124 | { | ||
125 | data = factory.ImportNode(node, true); | ||
126 | } | ||
127 | |||
128 | m_log.Info("[DATASNAPSHOT]: Retrieved fragment response for provider type " + provider.Name); | ||
129 | } | ||
130 | |||
131 | return data; | ||
132 | } | ||
133 | #endregion | ||
134 | |||
135 | #region Response storage | ||
136 | public XmlNode GetScene(Scene scene, XmlDocument factory) | ||
137 | { | ||
138 | m_log.Debug("[DATASNAPSHOT]: Data requested for scene " + scene.RegionInfo.RegionName); | ||
139 | |||
140 | if (!m_scenes.ContainsKey(scene)) { | ||
141 | m_scenes.Add(scene, true); //stale by default | ||
142 | } | ||
143 | |||
144 | XmlNode regionElement = null; | ||
145 | |||
146 | if (!m_scenes[scene]) | ||
147 | { | ||
148 | m_log.Info("[DATASNAPSHOT]: Attempting to retrieve snapshot from cache."); | ||
149 | //get snapshot from cache | ||
150 | String path = DataFileNameScene(scene); | ||
151 | |||
152 | XmlDocument fragDocument = new XmlDocument(); | ||
153 | fragDocument.PreserveWhitespace = true; | ||
154 | |||
155 | fragDocument.Load(path); | ||
156 | |||
157 | foreach (XmlNode node in fragDocument) | ||
158 | { | ||
159 | regionElement = factory.ImportNode(node, true); | ||
160 | } | ||
161 | |||
162 | m_log.Info("[DATASNAPSHOT]: Obtained snapshot from cache for " + scene.RegionInfo.RegionName); | ||
163 | } | ||
164 | else | ||
165 | { | ||
166 | m_log.Info("[DATASNAPSHOT]: Attempting to generate snapshot."); | ||
167 | //make snapshot | ||
168 | regionElement = MakeRegionNode(scene, factory); | ||
169 | |||
170 | regionElement.AppendChild(GetGridSnapshotData(factory)); | ||
171 | XmlNode regionData = factory.CreateNode(XmlNodeType.Element, "data", ""); | ||
172 | |||
173 | foreach (IDataSnapshotProvider dataprovider in m_providers) | ||
174 | { | ||
175 | if (dataprovider.GetParentScene == scene) | ||
176 | { | ||
177 | regionData.AppendChild(GetFragment(dataprovider, factory)); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | regionElement.AppendChild(regionData); | ||
182 | |||
183 | factory.AppendChild(regionElement); | ||
184 | |||
185 | //save snapshot | ||
186 | String path = DataFileNameScene(scene); | ||
187 | |||
188 | using (XmlTextWriter snapXWriter = new XmlTextWriter(path, Encoding.Default)) | ||
189 | { | ||
190 | snapXWriter.Formatting = Formatting.Indented; | ||
191 | snapXWriter.WriteStartDocument(); | ||
192 | regionElement.WriteTo(snapXWriter); | ||
193 | snapXWriter.WriteEndDocument(); | ||
194 | } | ||
195 | |||
196 | m_scenes[scene] = false; | ||
197 | |||
198 | m_log.Info("[DATASNAPSHOT]: Generated new snapshot for " + scene.RegionInfo.RegionName); | ||
199 | } | ||
200 | |||
201 | return regionElement; | ||
202 | } | ||
203 | |||
204 | #endregion | ||
205 | |||
206 | #region Helpers | ||
207 | private string DataFileNameFragment(Scene scene, String fragmentName) | ||
208 | { | ||
209 | return Path.Combine(m_directory, Path.ChangeExtension(scene.RegionInfo.RegionName + "_" + fragmentName, "xml")); | ||
210 | } | ||
211 | |||
212 | private string DataFileNameScene(Scene scene) | ||
213 | { | ||
214 | return Path.Combine(m_directory, Path.ChangeExtension(scene.RegionInfo.RegionName, "xml")); | ||
215 | //return (m_snapsDir + Path.DirectorySeparatorChar + scene.RegionInfo.RegionName + ".xml"); | ||
216 | } | ||
217 | |||
218 | private XmlNode MakeRegionNode(Scene scene, XmlDocument basedoc) | ||
219 | { | ||
220 | XmlNode docElement = basedoc.CreateNode(XmlNodeType.Element, "region", ""); | ||
221 | |||
222 | XmlAttribute attr = basedoc.CreateAttribute("category"); | ||
223 | attr.Value = GetRegionCategory(scene); | ||
224 | docElement.Attributes.Append(attr); | ||
225 | |||
226 | attr = basedoc.CreateAttribute("entities"); | ||
227 | attr.Value = scene.Entities.Count.ToString(); | ||
228 | docElement.Attributes.Append(attr); | ||
229 | |||
230 | //attr = basedoc.CreateAttribute("parcels"); | ||
231 | //attr.Value = scene.LandManager.landList.Count.ToString(); | ||
232 | //docElement.Attributes.Append(attr); | ||
233 | |||
234 | |||
235 | XmlNode infoblock = basedoc.CreateNode(XmlNodeType.Element, "info", ""); | ||
236 | |||
237 | XmlNode infopiece = basedoc.CreateNode(XmlNodeType.Element, "uuid", ""); | ||
238 | infopiece.InnerText = scene.RegionInfo.RegionID.ToString(); | ||
239 | infoblock.AppendChild(infopiece); | ||
240 | |||
241 | infopiece = basedoc.CreateNode(XmlNodeType.Element, "url", ""); | ||
242 | infopiece.InnerText = "http://" + m_hostname + ":" + m_listener_port; | ||
243 | infoblock.AppendChild(infopiece); | ||
244 | |||
245 | infopiece = basedoc.CreateNode(XmlNodeType.Element, "name", ""); | ||
246 | infopiece.InnerText = scene.RegionInfo.RegionName; | ||
247 | infoblock.AppendChild(infopiece); | ||
248 | |||
249 | docElement.AppendChild(infoblock); | ||
250 | |||
251 | m_log.Debug("[DATASNAPSHOT]: Generated region node"); | ||
252 | return docElement; | ||
253 | } | ||
254 | |||
255 | private String GetRegionCategory(Scene scene) | ||
256 | { | ||
257 | |||
258 | //Boolean choice between: | ||
259 | // "PG" - Mormontown | ||
260 | // "Mature" - Sodom and Gomorrah | ||
261 | // (Depreciated) "Patriotic Nigra Testing Sandbox" - Abandon Hope All Ye Who Enter Here | ||
262 | if ((scene.RegionInfo.EstateSettings.simAccess & Simulator.SimAccess.Mature) == Simulator.SimAccess.Mature) | ||
263 | { | ||
264 | return "Mature"; | ||
265 | } | ||
266 | else if ((scene.RegionInfo.EstateSettings.simAccess & Simulator.SimAccess.PG) == Simulator.SimAccess.PG) | ||
267 | { | ||
268 | return "PG"; | ||
269 | } | ||
270 | else | ||
271 | { | ||
272 | return "Unknown"; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | private XmlNode GetGridSnapshotData(XmlDocument factory) | ||
277 | { | ||
278 | XmlNode griddata = factory.CreateNode(XmlNodeType.Element, "grid", ""); | ||
279 | |||
280 | foreach (KeyValuePair<String, String> GridData in m_gridinfo) | ||
281 | { | ||
282 | //TODO: make it lowercase tag names for diva | ||
283 | XmlNode childnode = factory.CreateNode(XmlNodeType.Element, GridData.Key, ""); | ||
284 | childnode.InnerText = GridData.Value; | ||
285 | griddata.AppendChild(childnode); | ||
286 | } | ||
287 | |||
288 | m_log.Debug("[DATASNAPSHOT]: Got grid snapshot data"); | ||
289 | |||
290 | return griddata; | ||
291 | } | ||
292 | #endregion | ||
293 | |||
294 | #region Manage internal collections | ||
295 | public void AddScene(Scene newScene) | ||
296 | { | ||
297 | m_scenes.Add(newScene, true); | ||
298 | } | ||
299 | |||
300 | public void RemoveScene(Scene deadScene) | ||
301 | { | ||
302 | m_scenes.Remove(deadScene); | ||
303 | } | ||
304 | |||
305 | public void AddProvider(IDataSnapshotProvider newProvider) | ||
306 | { | ||
307 | m_providers.Add(newProvider); | ||
308 | } | ||
309 | |||
310 | public void RemoveProvider(IDataSnapshotProvider deadProvider) | ||
311 | { | ||
312 | m_providers.Remove(deadProvider); | ||
313 | } | ||
314 | #endregion | ||
315 | } | ||
316 | } | ||