aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules/Scripting
diff options
context:
space:
mode:
authorMic Bowman2012-04-17 13:45:27 -0700
committerMic Bowman2012-04-17 13:45:27 -0700
commit5ff2bda587a50b73f470ba778348645953b6b4b0 (patch)
treeef2164de4447ca08b96f7e603b74763ea72ca2b0 /OpenSim/Region/OptionalModules/Scripting
parentmake the namespace for the ScriptModuleComms consistent with its file system ... (diff)
downloadopensim-SC_OLD-5ff2bda587a50b73f470ba778348645953b6b4b0.zip
opensim-SC_OLD-5ff2bda587a50b73f470ba778348645953b6b4b0.tar.gz
opensim-SC_OLD-5ff2bda587a50b73f470ba778348645953b6b4b0.tar.bz2
opensim-SC_OLD-5ff2bda587a50b73f470ba778348645953b6b4b0.tar.xz
This commit adds a new optional region module, JsonStore, that provides structured
storage (dictionaries and arrays of string values) for scripts and region modules. In addition, there are operations on the storage that enable "real" distributed computation between scripts through operations similar to those of a tuple space. Scripts can share task queues, implement shared locks or semaphores, etc. The structured store is limited to the current region and is not currently persisted. However, script operations are defined to initialize a store from a notecard and to serialize the store to a notecard. Documentation will be posted to the opensim wiki soon.
Diffstat (limited to 'OpenSim/Region/OptionalModules/Scripting')
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs498
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs429
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs489
3 files changed, 1416 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
new file mode 100644
index 0000000..49556b6
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
@@ -0,0 +1,498 @@
1/*
2 * Copyright (c) Contributors
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 */
27using Mono.Addins;
28
29using System;
30using System.Reflection;
31using System.Threading;
32using System.Text;
33using System.Net;
34using System.Net.Sockets;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42using System.Collections.Generic;
43using System.Text.RegularExpressions;
44
45namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
46{
47 public class JsonStore
48 {
49 private static readonly ILog m_log =
50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 private OSD m_ValueStore;
53
54 protected class TakeValueCallbackClass
55 {
56 public string Path { get; set; }
57 public bool UseJson { get; set; }
58 public TakeValueCallback Callback { get; set; }
59
60 public TakeValueCallbackClass(string spath, bool usejson, TakeValueCallback cback)
61 {
62 Path = spath;
63 UseJson = usejson;
64 Callback = cback;
65 }
66 }
67
68 protected List<TakeValueCallbackClass> m_TakeStore;
69 protected List<TakeValueCallbackClass> m_ReadStore;
70
71
72 // -----------------------------------------------------------------
73 /// <summary>
74 ///
75 /// </summary>
76 // -----------------------------------------------------------------
77 public JsonStore(string value = "")
78 {
79 m_TakeStore = new List<TakeValueCallbackClass>();
80 m_ReadStore = new List<TakeValueCallbackClass>();
81
82 if (String.IsNullOrEmpty(value))
83 m_ValueStore = new OSDMap();
84 else
85 m_ValueStore = OSDParser.DeserializeJson(value);
86 }
87
88 // -----------------------------------------------------------------
89 /// <summary>
90 ///
91 /// </summary>
92 // -----------------------------------------------------------------
93 public bool TestPath(string expr, bool useJson)
94 {
95 Stack<string> path = ParsePathExpression(expr);
96 OSD result = ProcessPathExpression(m_ValueStore,path);
97
98 if (result == null)
99 return false;
100
101 if (useJson || result.Type == OSDType.String)
102 return true;
103
104 return false;
105 }
106
107 // -----------------------------------------------------------------
108 /// <summary>
109 ///
110 /// </summary>
111 // -----------------------------------------------------------------
112 public bool GetValue(string expr, out string value, bool useJson)
113 {
114 Stack<string> path = ParsePathExpression(expr);
115 OSD result = ProcessPathExpression(m_ValueStore,path);
116 return ConvertOutputValue(result,out value,useJson);
117 }
118
119
120 // -----------------------------------------------------------------
121 /// <summary>
122 ///
123 /// </summary>
124 // -----------------------------------------------------------------
125 public bool RemoveValue(string expr)
126 {
127 return SetValueFromExpression(expr,null);
128 }
129
130 // -----------------------------------------------------------------
131 /// <summary>
132 ///
133 /// </summary>
134 // -----------------------------------------------------------------
135 public bool SetValue(string expr, string value, bool useJson)
136 {
137 OSD ovalue = useJson ? OSDParser.DeserializeJson(value) : new OSDString(value);
138 return SetValueFromExpression(expr,ovalue);
139 }
140
141 // -----------------------------------------------------------------
142 /// <summary>
143 ///
144 /// </summary>
145 // -----------------------------------------------------------------
146 public bool TakeValue(string expr, bool useJson, TakeValueCallback cback)
147 {
148 Stack<string> path = ParsePathExpression(expr);
149 string pexpr = PathExpressionToKey(path);
150
151 OSD result = ProcessPathExpression(m_ValueStore,path);
152 if (result == null)
153 {
154 m_TakeStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback));
155 return false;
156 }
157
158 string value = String.Empty;
159 if (! ConvertOutputValue(result,out value,useJson))
160 {
161 // the structure does not match the request so i guess we'll wait
162 m_TakeStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback));
163 return false;
164 }
165
166 SetValueFromExpression(expr,null);
167 cback(value);
168
169 return true;
170 }
171
172 // -----------------------------------------------------------------
173 /// <summary>
174 ///
175 /// </summary>
176 // -----------------------------------------------------------------
177 public bool ReadValue(string expr, bool useJson, TakeValueCallback cback)
178 {
179 Stack<string> path = ParsePathExpression(expr);
180 string pexpr = PathExpressionToKey(path);
181
182 OSD result = ProcessPathExpression(m_ValueStore,path);
183 if (result == null)
184 {
185 m_ReadStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback));
186 return false;
187 }
188
189 string value = String.Empty;
190 if (! ConvertOutputValue(result,out value,useJson))
191 {
192 // the structure does not match the request so i guess we'll wait
193 m_ReadStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback));
194 return false;
195 }
196
197 cback(value);
198
199 return true;
200 }
201
202 // -----------------------------------------------------------------
203 /// <summary>
204 ///
205 /// </summary>
206 // -----------------------------------------------------------------
207 protected bool SetValueFromExpression(string expr, OSD ovalue)
208 {
209 Stack<string> path = ParsePathExpression(expr);
210 if (path.Count == 0)
211 {
212 m_ValueStore = ovalue;
213 return true;
214 }
215
216 string pkey = path.Pop();
217 string pexpr = PathExpressionToKey(path);
218 if (pexpr != "")
219 pexpr += ".";
220
221 OSD result = ProcessPathExpression(m_ValueStore,path);
222 if (result == null)
223 return false;
224
225 Regex aPattern = new Regex("\\[([0-9]+|\\+)\\]");
226 MatchCollection amatches = aPattern.Matches(pkey,0);
227
228 if (amatches.Count > 0)
229 {
230 if (result.Type != OSDType.Array)
231 return false;
232
233 OSDArray amap = result as OSDArray;
234
235 Match match = amatches[0];
236 GroupCollection groups = match.Groups;
237 string akey = groups[1].Value;
238
239 if (akey == "+")
240 {
241 string npkey = String.Format("[{0}]",amap.Count);
242
243 amap.Add(ovalue);
244 InvokeNextCallback(pexpr + npkey);
245 return true;
246 }
247
248 int aval = Convert.ToInt32(akey);
249 if (0 <= aval && aval < amap.Count)
250 {
251 if (ovalue == null)
252 amap.RemoveAt(aval);
253 else
254 {
255 amap[aval] = ovalue;
256 InvokeNextCallback(pexpr + pkey);
257 }
258 return true;
259 }
260
261 return false;
262 }
263
264 Regex hPattern = new Regex("{([^}]+)}");
265 MatchCollection hmatches = hPattern.Matches(pkey,0);
266
267 if (hmatches.Count > 0)
268 {
269 Match match = hmatches[0];
270 GroupCollection groups = match.Groups;
271 string hkey = groups[1].Value;
272
273 if (result is OSDMap)
274 {
275 OSDMap hmap = result as OSDMap;
276 if (ovalue != null)
277 {
278 hmap[hkey] = ovalue;
279 InvokeNextCallback(pexpr + pkey);
280 }
281 else if (hmap.ContainsKey(hkey))
282 hmap.Remove(hkey);
283
284 return true;
285 }
286
287 return false;
288 }
289
290 // Shouldn't get here if the path was checked correctly
291 m_log.WarnFormat("[JsonStore] invalid path expression");
292 return false;
293 }
294
295 // -----------------------------------------------------------------
296 /// <summary>
297 ///
298 /// </summary>
299 // -----------------------------------------------------------------
300 protected bool InvokeNextCallback(string pexpr)
301 {
302 // Process all of the reads that match the expression first
303 List<TakeValueCallbackClass> reads =
304 m_ReadStore.FindAll(delegate(TakeValueCallbackClass tb) { return pexpr.StartsWith(tb.Path); });
305
306 foreach (TakeValueCallbackClass readcb in reads)
307 {
308 m_ReadStore.Remove(readcb);
309 ReadValue(readcb.Path,readcb.UseJson,readcb.Callback);
310 }
311
312 // Process one take next
313 TakeValueCallbackClass takecb =
314 m_TakeStore.Find(delegate(TakeValueCallbackClass tb) { return pexpr.StartsWith(tb.Path); });
315
316 if (takecb != null)
317 {
318 m_TakeStore.Remove(takecb);
319 TakeValue(takecb.Path,takecb.UseJson,takecb.Callback);
320
321 return true;
322 }
323
324 return false;
325 }
326
327 // -----------------------------------------------------------------
328 /// <summary>
329 /// Parse the path expression and put the components into a stack. We
330 /// use a stack because we process the path in inverse order later
331 /// </summary>
332 // -----------------------------------------------------------------
333 protected static Stack<string> ParsePathExpression(string path)
334 {
335 Stack<string> m_path = new Stack<string>();
336
337 // add front and rear separators
338 path = "." + path + ".";
339
340 // add separators for quoted paths
341 Regex pass1 = new Regex("{[^}]+}");
342 path = pass1.Replace(path,".$0.",-1,0);
343
344 // add separators for array references
345 Regex pass2 = new Regex("(\\[[0-9]+\\]|\\[\\+\\])");
346 path = pass2.Replace(path,".$0.",-1,0);
347
348 // add quotes to bare identifier
349 Regex pass3 = new Regex("\\.([a-zA-Z]+)");
350 path = pass3.Replace(path,".{$1}",-1,0);
351
352 // remove extra separators
353 Regex pass4 = new Regex("\\.+");
354 path = pass4.Replace(path,".",-1,0);
355
356 Regex validate = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)+$");
357 if (validate.IsMatch(path))
358 {
359 Regex parser = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\]+)");
360 MatchCollection matches = parser.Matches(path,0);
361 foreach (Match match in matches)
362 m_path.Push(match.Groups[1].Value);
363 }
364
365 return m_path;
366 }
367
368 // -----------------------------------------------------------------
369 /// <summary>
370 ///
371 /// </summary>
372 /// <param>path is a stack where the top level of the path is at the bottom of the stack</param>
373 // -----------------------------------------------------------------
374 protected static OSD ProcessPathExpression(OSD map, Stack<string> path)
375 {
376 if (path.Count == 0)
377 return map;
378
379 string pkey = path.Pop();
380
381 OSD rmap = ProcessPathExpression(map,path);
382 if (rmap == null)
383 return null;
384
385 // ---------- Check for an array index ----------
386 Regex aPattern = new Regex("\\[([0-9]+)\\]");
387 MatchCollection amatches = aPattern.Matches(pkey,0);
388
389 if (amatches.Count > 0)
390 {
391 if (rmap.Type != OSDType.Array)
392 {
393 m_log.WarnFormat("[JsonStore] wrong type for key {2}, expecting {0}, got {1}",OSDType.Array,rmap.Type,pkey);
394 return null;
395 }
396
397 OSDArray amap = rmap as OSDArray;
398
399 Match match = amatches[0];
400 GroupCollection groups = match.Groups;
401 string akey = groups[1].Value;
402 int aval = Convert.ToInt32(akey);
403
404 if (aval < amap.Count)
405 return (OSD) amap[aval];
406
407 return null;
408 }
409
410 // ---------- Check for a hash index ----------
411 Regex hPattern = new Regex("{([^}]+)}");
412 MatchCollection hmatches = hPattern.Matches(pkey,0);
413
414 if (hmatches.Count > 0)
415 {
416 if (rmap.Type != OSDType.Map)
417 {
418 m_log.WarnFormat("[JsonStore] wrong type for key {2}, expecting {0}, got {1}",OSDType.Map,rmap.Type,pkey);
419 return null;
420 }
421
422 OSDMap hmap = rmap as OSDMap;
423
424 Match match = hmatches[0];
425 GroupCollection groups = match.Groups;
426 string hkey = groups[1].Value;
427
428 if (hmap.ContainsKey(hkey))
429 return (OSD) hmap[hkey];
430
431 return null;
432 }
433
434 // Shouldn't get here if the path was checked correctly
435 m_log.WarnFormat("[JsonStore] Path type (unknown) does not match the structure");
436 return null;
437 }
438
439 // -----------------------------------------------------------------
440 /// <summary>
441 ///
442 /// </summary>
443 // -----------------------------------------------------------------
444 protected static bool ConvertOutputValue(OSD result, out string value, bool useJson)
445 {
446 value = String.Empty;
447
448 // If we couldn't process the path
449 if (result == null)
450 return false;
451
452 if (useJson)
453 {
454 // The path pointed to an intermediate hash structure
455 if (result.Type == OSDType.Map)
456 {
457 value = OSDParser.SerializeJsonString(result as OSDMap);
458 return true;
459 }
460
461 // The path pointed to an intermediate hash structure
462 if (result.Type == OSDType.Array)
463 {
464 value = OSDParser.SerializeJsonString(result as OSDArray);
465 return true;
466 }
467
468 value = "'" + result.AsString() + "'";
469 return true;
470 }
471
472 if (result.Type == OSDType.String)
473 {
474 value = result.AsString();
475 return true;
476 }
477
478 return false;
479 }
480
481 // -----------------------------------------------------------------
482 /// <summary>
483 ///
484 /// </summary>
485 // -----------------------------------------------------------------
486 protected static string PathExpressionToKey(Stack<string> path)
487 {
488 if (path.Count == 0)
489 return "";
490
491 string pkey = "";
492 foreach (string k in path)
493 pkey = (pkey == "") ? k : (k + "." + pkey);
494
495 return pkey;
496 }
497 }
498}
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
new file mode 100644
index 0000000..6dae956
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
@@ -0,0 +1,429 @@
1/*
2 * Copyright (c) Contributors
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 */
27using Mono.Addins;
28
29using System;
30using System.Reflection;
31using System.Threading;
32using System.Text;
33using System.Net;
34using System.Net.Sockets;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42using System.Collections.Generic;
43using System.Text.RegularExpressions;
44
45
46namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
47{
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "JsonStoreModule")]
49
50 public class JsonStoreModule : INonSharedRegionModule, IJsonStoreModule
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54
55 private IConfig m_config = null;
56 private bool m_enabled = false;
57 private Scene m_scene = null;
58
59 private Dictionary<UUID,JsonStore> m_JsonValueStore;
60 private UUID m_sharedStore;
61
62#region IRegionModule Members
63
64 // -----------------------------------------------------------------
65 /// <summary>
66 /// Name of this shared module is it's class name
67 /// </summary>
68 // -----------------------------------------------------------------
69 public string Name
70 {
71 get { return this.GetType().Name; }
72 }
73
74 // -----------------------------------------------------------------
75 /// <summary>
76 /// Initialise this shared module
77 /// </summary>
78 /// <param name="scene">this region is getting initialised</param>
79 /// <param name="source">nini config, we are not using this</param>
80 // -----------------------------------------------------------------
81 public void Initialise(IConfigSource config)
82 {
83 try
84 {
85 if ((m_config = config.Configs["JsonStore"]) == null)
86 {
87 // There is no configuration, the module is disabled
88 m_log.InfoFormat("[JsonStore] no configuration info");
89 return;
90 }
91
92 m_enabled = m_config.GetBoolean("Enabled", m_enabled);
93 }
94 catch (Exception e)
95 {
96 m_log.ErrorFormat("[JsonStore] initialization error: {0}",e.Message);
97 return;
98 }
99
100 m_log.InfoFormat("[JsonStore] module {0} enabled",(m_enabled ? "is" : "is not"));
101 }
102
103 // -----------------------------------------------------------------
104 /// <summary>
105 /// everything is loaded, perform post load configuration
106 /// </summary>
107 // -----------------------------------------------------------------
108 public void PostInitialise()
109 {
110 }
111
112 // -----------------------------------------------------------------
113 /// <summary>
114 /// Nothing to do on close
115 /// </summary>
116 // -----------------------------------------------------------------
117 public void Close()
118 {
119 }
120
121 // -----------------------------------------------------------------
122 /// <summary>
123 /// </summary>
124 // -----------------------------------------------------------------
125 public void AddRegion(Scene scene)
126 {
127 if (m_enabled)
128 {
129 m_scene = scene;
130 m_scene.RegisterModuleInterface<IJsonStoreModule>(this);
131
132 m_sharedStore = UUID.Zero;
133 m_JsonValueStore = new Dictionary<UUID,JsonStore>();
134 m_JsonValueStore.Add(m_sharedStore,new JsonStore(""));
135 }
136 }
137
138 // -----------------------------------------------------------------
139 /// <summary>
140 /// </summary>
141 // -----------------------------------------------------------------
142 public void RemoveRegion(Scene scene)
143 {
144 // need to remove all references to the scene in the subscription
145 // list to enable full garbage collection of the scene object
146 }
147
148 // -----------------------------------------------------------------
149 /// <summary>
150 /// Called when all modules have been added for a region. This is
151 /// where we hook up events
152 /// </summary>
153 // -----------------------------------------------------------------
154 public void RegionLoaded(Scene scene)
155 {
156 if (m_enabled) {}
157 }
158
159 /// -----------------------------------------------------------------
160 /// <summary>
161 /// </summary>
162 // -----------------------------------------------------------------
163 public Type ReplaceableInterface
164 {
165 get { return null; }
166 }
167
168#endregion
169
170#region ScriptInvocationInteface
171
172 // -----------------------------------------------------------------
173 /// <summary>
174 ///
175 /// </summary>
176 // -----------------------------------------------------------------
177 public bool CreateStore(string value, out UUID result)
178 {
179 result = UUID.Zero;
180
181 if (! m_enabled) return false;
182
183 UUID uuid = UUID.Random();
184 JsonStore map = null;
185
186 try
187 {
188 map = new JsonStore(value);
189 }
190 catch (Exception e)
191 {
192 m_log.InfoFormat("[JsonStore] Unable to initialize store from {0}; {1}",value,e.Message);
193 return false;
194 }
195
196 lock (m_JsonValueStore)
197 m_JsonValueStore.Add(uuid,map);
198
199 result = uuid;
200 return true;
201 }
202
203 // -----------------------------------------------------------------
204 /// <summary>
205 ///
206 /// </summary>
207 // -----------------------------------------------------------------
208 public bool DestroyStore(UUID storeID)
209 {
210 if (! m_enabled) return false;
211
212 lock (m_JsonValueStore)
213 m_JsonValueStore.Remove(storeID);
214
215 return true;
216 }
217
218 // -----------------------------------------------------------------
219 /// <summary>
220 ///
221 /// </summary>
222 // -----------------------------------------------------------------
223 public bool TestPath(UUID storeID, string path, bool useJson)
224 {
225 if (! m_enabled) return false;
226
227 JsonStore map = null;
228 lock (m_JsonValueStore)
229 {
230 if (! m_JsonValueStore.TryGetValue(storeID,out map))
231 {
232 m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
233 return true;
234 }
235 }
236
237 try
238 {
239 lock (map)
240 return map.TestPath(path,useJson);
241 }
242 catch (Exception e)
243 {
244 m_log.InfoFormat("[JsonStore] Path test failed for {0} in {1}; {2}",path,storeID,e.Message);
245 }
246
247 return false;
248 }
249
250 // -----------------------------------------------------------------
251 /// <summary>
252 ///
253 /// </summary>
254 // -----------------------------------------------------------------
255 public bool SetValue(UUID storeID, string path, string value, bool useJson)
256 {
257 if (! m_enabled) return false;
258
259 JsonStore map = null;
260 lock (m_JsonValueStore)
261 {
262 if (! m_JsonValueStore.TryGetValue(storeID,out map))
263 {
264 m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
265 return false;
266 }
267 }
268
269 try
270 {
271 lock (map)
272 if (map.SetValue(path,value,useJson))
273 return true;
274 }
275 catch (Exception e)
276 {
277 m_log.InfoFormat("[JsonStore] Unable to assign {0} to {1} in {2}; {3}",value,path,storeID,e.Message);
278 }
279
280 return false;
281 }
282
283 // -----------------------------------------------------------------
284 /// <summary>
285 ///
286 /// </summary>
287 // -----------------------------------------------------------------
288 public bool RemoveValue(UUID storeID, string path)
289 {
290 if (! m_enabled) return false;
291
292 JsonStore map = null;
293 lock (m_JsonValueStore)
294 {
295 if (! m_JsonValueStore.TryGetValue(storeID,out map))
296 {
297 m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
298 return false;
299 }
300 }
301
302 try
303 {
304 lock (map)
305 if (map.RemoveValue(path))
306 return true;
307 }
308 catch (Exception e)
309 {
310 m_log.InfoFormat("[JsonStore] Unable to remove {0} in {1}; {2}",path,storeID,e.Message);
311 }
312
313 return false;
314 }
315
316 // -----------------------------------------------------------------
317 /// <summary>
318 ///
319 /// </summary>
320 // -----------------------------------------------------------------
321 public bool GetValue(UUID storeID, string path, bool useJson, out string value)
322 {
323 value = String.Empty;
324
325 if (! m_enabled) return false;
326
327 JsonStore map = null;
328 lock (m_JsonValueStore)
329 {
330 if (! m_JsonValueStore.TryGetValue(storeID,out map))
331 return false;
332 }
333
334 try
335 {
336 lock (map)
337 {
338 return map.GetValue(path, out value, useJson);
339 }
340 }
341 catch (Exception e)
342 {
343 m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.Message);
344 }
345
346 return false;
347 }
348
349 // -----------------------------------------------------------------
350 /// <summary>
351 ///
352 /// </summary>
353 // -----------------------------------------------------------------
354 public void TakeValue(UUID storeID, string path, bool useJson, TakeValueCallback cback)
355 {
356 if (! m_enabled)
357 {
358 cback(String.Empty);
359 return;
360 }
361
362 JsonStore map = null;
363 lock (m_JsonValueStore)
364 {
365 if (! m_JsonValueStore.TryGetValue(storeID,out map))
366 {
367 cback(String.Empty);
368 return;
369 }
370 }
371
372 try
373 {
374 lock (map)
375 {
376 map.TakeValue(path, useJson, cback);
377 return;
378 }
379 }
380 catch (Exception e)
381 {
382 m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.ToString());
383 }
384
385 cback(String.Empty);
386 }
387
388 // -----------------------------------------------------------------
389 /// <summary>
390 ///
391 /// </summary>
392 // -----------------------------------------------------------------
393 public void ReadValue(UUID storeID, string path, bool useJson, TakeValueCallback cback)
394 {
395 if (! m_enabled)
396 {
397 cback(String.Empty);
398 return;
399 }
400
401 JsonStore map = null;
402 lock (m_JsonValueStore)
403 {
404 if (! m_JsonValueStore.TryGetValue(storeID,out map))
405 {
406 cback(String.Empty);
407 return;
408 }
409 }
410
411 try
412 {
413 lock (map)
414 {
415 map.ReadValue(path, useJson, cback);
416 return;
417 }
418 }
419 catch (Exception e)
420 {
421 m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.ToString());
422 }
423
424 cback(String.Empty);
425 }
426
427#endregion
428 }
429}
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
new file mode 100644
index 0000000..7aba860
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
@@ -0,0 +1,489 @@
1/*
2 * Copyright (c) Contributors
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 */
27using Mono.Addins;
28
29using System;
30using System.Reflection;
31using System.Threading;
32using System.Text;
33using System.Net;
34using System.Net.Sockets;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes;
42using System.Collections.Generic;
43using System.Text.RegularExpressions;
44
45namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
46{
47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "JsonStoreScriptModule")]
48
49 public class JsonStoreScriptModule : INonSharedRegionModule
50 {
51 private static readonly ILog m_log =
52 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 private IConfig m_config = null;
55 private bool m_enabled = false;
56 private Scene m_scene = null;
57
58 private IScriptModuleComms m_comms;
59 private IJsonStoreModule m_store;
60
61#region IRegionModule Members
62
63 // -----------------------------------------------------------------
64 /// <summary>
65 /// Name of this shared module is it's class name
66 /// </summary>
67 // -----------------------------------------------------------------
68 public string Name
69 {
70 get { return this.GetType().Name; }
71 }
72
73 // -----------------------------------------------------------------
74 /// <summary>
75 /// Initialise this shared module
76 /// </summary>
77 /// <param name="scene">this region is getting initialised</param>
78 /// <param name="source">nini config, we are not using this</param>
79 // -----------------------------------------------------------------
80 public void Initialise(IConfigSource config)
81 {
82 try
83 {
84 if ((m_config = config.Configs["JsonStore"]) == null)
85 {
86 // There is no configuration, the module is disabled
87 m_log.InfoFormat("[JsonStoreScripts] no configuration info");
88 return;
89 }
90
91 m_enabled = m_config.GetBoolean("Enabled", m_enabled);
92 }
93 catch (Exception e)
94 {
95 m_log.ErrorFormat("[JsonStoreScripts] initialization error: {0}",e.Message);
96 return;
97 }
98
99 m_log.InfoFormat("[JsonStoreScripts] module {0} enabled",(m_enabled ? "is" : "is not"));
100 }
101
102 // -----------------------------------------------------------------
103 /// <summary>
104 /// everything is loaded, perform post load configuration
105 /// </summary>
106 // -----------------------------------------------------------------
107 public void PostInitialise()
108 {
109 }
110
111 // -----------------------------------------------------------------
112 /// <summary>
113 /// Nothing to do on close
114 /// </summary>
115 // -----------------------------------------------------------------
116 public void Close()
117 {
118 }
119
120 // -----------------------------------------------------------------
121 /// <summary>
122 /// </summary>
123 // -----------------------------------------------------------------
124 public void AddRegion(Scene scene)
125 {
126 }
127
128 // -----------------------------------------------------------------
129 /// <summary>
130 /// </summary>
131 // -----------------------------------------------------------------
132 public void RemoveRegion(Scene scene)
133 {
134 // need to remove all references to the scene in the subscription
135 // list to enable full garbage collection of the scene object
136 }
137
138 // -----------------------------------------------------------------
139 /// <summary>
140 /// Called when all modules have been added for a region. This is
141 /// where we hook up events
142 /// </summary>
143 // -----------------------------------------------------------------
144 public void RegionLoaded(Scene scene)
145 {
146 if (m_enabled)
147 {
148 m_scene = scene;
149 m_comms = m_scene.RequestModuleInterface<IScriptModuleComms>();
150 if (m_comms == null)
151 {
152 m_log.ErrorFormat("[JsonStoreScripts] ScriptModuleComms interface not defined");
153 m_enabled = false;
154 return;
155 }
156
157 m_store = m_scene.RequestModuleInterface<IJsonStoreModule>();
158 if (m_store == null)
159 {
160 m_log.ErrorFormat("[JsonStoreScripts] JsonModule interface not defined");
161 m_enabled = false;
162 return;
163 }
164
165 m_comms.RegisterScriptInvocation(this,"JsonCreateStore");
166 m_comms.RegisterScriptInvocation(this,"JsonDestroyStore");
167
168 m_comms.RegisterScriptInvocation(this,"JsonReadNotecard");
169 m_comms.RegisterScriptInvocation(this,"JsonWriteNotecard");
170
171 m_comms.RegisterScriptInvocation(this,"JsonTestPath");
172 m_comms.RegisterScriptInvocation(this,"JsonTestPathJson");
173
174 m_comms.RegisterScriptInvocation(this,"JsonGetValue");
175 m_comms.RegisterScriptInvocation(this,"JsonGetValueJson");
176
177 m_comms.RegisterScriptInvocation(this,"JsonTakeValue");
178 m_comms.RegisterScriptInvocation(this,"JsonTakeValueJson");
179
180 m_comms.RegisterScriptInvocation(this,"JsonReadValue");
181 m_comms.RegisterScriptInvocation(this,"JsonReadValueJson");
182
183 m_comms.RegisterScriptInvocation(this,"JsonSetValue");
184 m_comms.RegisterScriptInvocation(this,"JsonSetValueJson");
185
186 m_comms.RegisterScriptInvocation(this,"JsonRemoveValue");
187 }
188 }
189
190 /// -----------------------------------------------------------------
191 /// <summary>
192 /// </summary>
193 // -----------------------------------------------------------------
194 public Type ReplaceableInterface
195 {
196 get { return null; }
197 }
198
199#endregion
200
201#region ScriptInvocationInteface
202 // -----------------------------------------------------------------
203 /// <summary>
204 ///
205 /// </summary>
206 // -----------------------------------------------------------------
207 protected void GenerateRuntimeError(string msg)
208 {
209 throw new Exception("JsonStore Runtime Error: " + msg);
210 }
211
212 // -----------------------------------------------------------------
213 /// <summary>
214 ///
215 /// </summary>
216 // -----------------------------------------------------------------
217 protected UUID JsonCreateStore(UUID hostID, UUID scriptID, string value)
218 {
219 UUID uuid = UUID.Zero;
220 if (! m_store.CreateStore(value, out uuid))
221 GenerateRuntimeError("Failed to create Json store");
222
223 return uuid;
224 }
225
226 // -----------------------------------------------------------------
227 /// <summary>
228 ///
229 /// </summary>
230 // -----------------------------------------------------------------
231 protected int JsonDestroyStore(UUID hostID, UUID scriptID, UUID storeID)
232 {
233 return m_store.DestroyStore(storeID) ? 1 : 0;
234 }
235
236 // -----------------------------------------------------------------
237 /// <summary>
238 ///
239 /// </summary>
240 // -----------------------------------------------------------------
241 protected UUID JsonReadNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, UUID assetID)
242 {
243 UUID reqID = UUID.Random();
244 Util.FireAndForget(delegate(object o) { DoJsonReadNotecard(reqID,hostID,scriptID,storeID,path,assetID); });
245 return reqID;
246 }
247
248 // -----------------------------------------------------------------
249 /// <summary>
250 ///
251 /// </summary>
252 // -----------------------------------------------------------------
253 protected UUID JsonWriteNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, string name)
254 {
255 UUID reqID = UUID.Random();
256 Util.FireAndForget(delegate(object o) { DoJsonWriteNotecard(reqID,hostID,scriptID,storeID,path,name); });
257 return reqID;
258 }
259
260 // -----------------------------------------------------------------
261 /// <summary>
262 ///
263 /// </summary>
264 // -----------------------------------------------------------------
265 protected int JsonTestPath(UUID hostID, UUID scriptID, UUID storeID, string path)
266 {
267 return m_store.TestPath(storeID,path,false) ? 1 : 0;
268 }
269
270 protected int JsonTestPathJson(UUID hostID, UUID scriptID, UUID storeID, string path)
271 {
272 return m_store.TestPath(storeID,path,true) ? 1 : 0;
273 }
274
275 // -----------------------------------------------------------------
276 /// <summary>
277 ///
278 /// </summary>
279 // -----------------------------------------------------------------
280 protected int JsonSetValue(UUID hostID, UUID scriptID, UUID storeID, string path, string value)
281 {
282 return m_store.SetValue(storeID,path,value,false) ? 1 : 0;
283 }
284
285 protected int JsonSetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value)
286 {
287 return m_store.SetValue(storeID,path,value,true) ? 1 : 0;
288 }
289
290 // -----------------------------------------------------------------
291 /// <summary>
292 ///
293 /// </summary>
294 // -----------------------------------------------------------------
295 protected int JsonRemoveValue(UUID hostID, UUID scriptID, UUID storeID, string path)
296 {
297 return m_store.RemoveValue(storeID,path) ? 1 : 0;
298 }
299
300 // -----------------------------------------------------------------
301 /// <summary>
302 ///
303 /// </summary>
304 // -----------------------------------------------------------------
305 protected string JsonGetValue(UUID hostID, UUID scriptID, UUID storeID, string path)
306 {
307 string value = String.Empty;
308 m_store.GetValue(storeID,path,false,out value);
309 return value;
310 }
311
312 protected string JsonGetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path)
313 {
314 string value = String.Empty;
315 m_store.GetValue(storeID,path,true, out value);
316 return value;
317 }
318
319 // -----------------------------------------------------------------
320 /// <summary>
321 ///
322 /// </summary>
323 // -----------------------------------------------------------------
324 protected UUID JsonTakeValue(UUID hostID, UUID scriptID, UUID storeID, string path)
325 {
326 UUID reqID = UUID.Random();
327 Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,false); });
328 return reqID;
329 }
330
331 protected UUID JsonTakeValueJson(UUID hostID, UUID scriptID, UUID storeID, string path)
332 {
333 UUID reqID = UUID.Random();
334 Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,true); });
335 return reqID;
336 }
337
338 private void DoJsonTakeValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson)
339 {
340 try
341 {
342 m_store.TakeValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); });
343 return;
344 }
345 catch (Exception e)
346 {
347 m_log.InfoFormat("[JsonStoreScripts] unable to retrieve value; {0}",e.ToString());
348 }
349
350 DispatchValue(scriptID,reqID,String.Empty);
351 }
352
353
354 // -----------------------------------------------------------------
355 /// <summary>
356 ///
357 /// </summary>
358 // -----------------------------------------------------------------
359 protected UUID JsonReadValue(UUID hostID, UUID scriptID, UUID storeID, string path)
360 {
361 UUID reqID = UUID.Random();
362 Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,false); });
363 return reqID;
364 }
365
366 protected UUID JsonReadValueJson(UUID hostID, UUID scriptID, UUID storeID, string path)
367 {
368 UUID reqID = UUID.Random();
369 Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,true); });
370 return reqID;
371 }
372
373 private void DoJsonReadValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson)
374 {
375 try
376 {
377 m_store.ReadValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); });
378 return;
379 }
380 catch (Exception e)
381 {
382 m_log.InfoFormat("[JsonStoreScripts] unable to retrieve value; {0}",e.ToString());
383 }
384
385 DispatchValue(scriptID,reqID,String.Empty);
386 }
387
388#endregion
389
390 // -----------------------------------------------------------------
391 /// <summary>
392 ///
393 /// </summary>
394 // -----------------------------------------------------------------
395 protected void DispatchValue(UUID scriptID, UUID reqID, string value)
396 {
397 m_comms.DispatchReply(scriptID,1,value,reqID.ToString());
398 }
399
400 // -----------------------------------------------------------------
401 /// <summary>
402 ///
403 /// </summary>
404 // -----------------------------------------------------------------
405 private void DoJsonReadNotecard(UUID reqID, UUID hostID, UUID scriptID, UUID storeID, string path, UUID assetID)
406 {
407 AssetBase a = m_scene.AssetService.Get(assetID.ToString());
408 if (a == null)
409 GenerateRuntimeError(String.Format("Unable to find notecard asset {0}",assetID));
410
411 if (a.Type != (sbyte)AssetType.Notecard)
412 GenerateRuntimeError(String.Format("Invalid notecard asset {0}",assetID));
413
414 m_log.DebugFormat("[JsonStoreScripts] read notecard in context {0}",storeID);
415
416 try
417 {
418 System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
419 string jsondata = SLUtil.ParseNotecardToString(enc.GetString(a.Data));
420 int result = m_store.SetValue(storeID,path,jsondata,true) ? 1 : 0;
421 m_comms.DispatchReply(scriptID,result,"",reqID.ToString());
422 return;
423 }
424 catch (Exception e)
425 {
426 m_log.WarnFormat("[JsonStoreScripts] Json parsing failed; {0}",e.Message);
427 }
428
429 GenerateRuntimeError(String.Format("Json parsing failed for {0}",assetID.ToString()));
430 m_comms.DispatchReply(scriptID,0,"",reqID.ToString());
431 }
432
433 // -----------------------------------------------------------------
434 /// <summary>
435 ///
436 /// </summary>
437 // -----------------------------------------------------------------
438 private void DoJsonWriteNotecard(UUID reqID, UUID hostID, UUID scriptID, UUID storeID, string path, string name)
439 {
440 string data;
441 if (! m_store.GetValue(storeID,path,true, out data))
442 {
443 m_comms.DispatchReply(scriptID,0,UUID.Zero.ToString(),reqID.ToString());
444 return;
445 }
446
447 SceneObjectPart host = m_scene.GetSceneObjectPart(hostID);
448
449 // Create new asset
450 UUID assetID = UUID.Random();
451 AssetBase asset = new AssetBase(assetID, name, (sbyte)AssetType.Notecard, host.OwnerID.ToString());
452 asset.Description = "Json store";
453
454 int textLength = data.Length;
455 data = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length "
456 + textLength.ToString() + "\n" + data + "}\n";
457
458 asset.Data = Util.UTF8.GetBytes(data);
459 m_scene.AssetService.Store(asset);
460
461 // Create Task Entry
462 TaskInventoryItem taskItem = new TaskInventoryItem();
463
464 taskItem.ResetIDs(host.UUID);
465 taskItem.ParentID = host.UUID;
466 taskItem.CreationDate = (uint)Util.UnixTimeSinceEpoch();
467 taskItem.Name = asset.Name;
468 taskItem.Description = asset.Description;
469 taskItem.Type = (int)AssetType.Notecard;
470 taskItem.InvType = (int)InventoryType.Notecard;
471 taskItem.OwnerID = host.OwnerID;
472 taskItem.CreatorID = host.OwnerID;
473 taskItem.BasePermissions = (uint)PermissionMask.All;
474 taskItem.CurrentPermissions = (uint)PermissionMask.All;
475 taskItem.EveryonePermissions = 0;
476 taskItem.NextPermissions = (uint)PermissionMask.All;
477 taskItem.GroupID = host.GroupID;
478 taskItem.GroupPermissions = 0;
479 taskItem.Flags = 0;
480 taskItem.PermsGranter = UUID.Zero;
481 taskItem.PermsMask = 0;
482 taskItem.AssetID = asset.FullID;
483
484 host.Inventory.AddInventoryItem(taskItem, false);
485
486 m_comms.DispatchReply(scriptID,1,assetID.ToString(),reqID.ToString());
487 }
488 }
489}