opensim-development – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | eva | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ |
||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
||
4 | * |
||
5 | * Redistribution and use in source and binary forms, with or without |
||
6 | * modification, are permitted provided that the following conditions are met: |
||
7 | * * Redistributions of source code must retain the above copyright |
||
8 | * notice, this list of conditions and the following disclaimer. |
||
9 | * * Redistributions in binary form must reproduce the above copyright |
||
10 | * notice, this list of conditions and the following disclaimer in the |
||
11 | * documentation and/or other materials provided with the distribution. |
||
12 | * * Neither the name of the OpenSimulator Project nor the |
||
13 | * names of its contributors may be used to endorse or promote products |
||
14 | * derived from this software without specific prior written permission. |
||
15 | * |
||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
26 | */ |
||
27 | |||
28 | using System; |
||
29 | using System.Collections.Generic; |
||
30 | using System.IO; |
||
31 | using System.Reflection; |
||
32 | using System.Text; |
||
33 | using System.Text.RegularExpressions; |
||
34 | using System.Xml; |
||
35 | using log4net; |
||
36 | using OpenSim.Region.DataSnapshot.Interfaces; |
||
37 | using OpenSim.Region.Framework.Scenes; |
||
38 | |||
39 | namespace 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 | } |