aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs313
1 files changed, 313 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs
new file mode 100644
index 0000000..5ec8f50
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs
@@ -0,0 +1,313 @@
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
29using System;
30using System.Collections.Generic;
31using System.Threading;
32using libsecondlife;
33using OpenSim.Region.Environment.Interfaces;
34using OpenSim.Region.Environment.Modules;
35
36namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
37{
38 /// <summary>
39 /// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
40 /// </summary>
41 public class AsyncLSLCommandManager : iScriptEngineFunctionModule
42 {
43 private Thread cmdHandlerThread;
44 private int cmdHandlerThreadCycleSleepms;
45
46 private ScriptEngine m_ScriptEngine;
47
48 public AsyncLSLCommandManager(ScriptEngine _ScriptEngine)
49 {
50 m_ScriptEngine = _ScriptEngine;
51 ReadConfig();
52
53 // Start the thread that will be doing the work
54 cmdHandlerThread = new Thread(CmdHandlerThreadLoop);
55 cmdHandlerThread.Name = "CmdHandlerThread";
56 cmdHandlerThread.Priority = ThreadPriority.BelowNormal;
57 cmdHandlerThread.IsBackground = true;
58 cmdHandlerThread.Start();
59 }
60
61 public void ReadConfig()
62 {
63 cmdHandlerThreadCycleSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("AsyncLLCommandLoopms", 50);
64 }
65
66
67 ~AsyncLSLCommandManager()
68 {
69 // Shut down thread
70 try
71 {
72 if (cmdHandlerThread != null)
73 {
74 if (cmdHandlerThread.IsAlive == true)
75 {
76 cmdHandlerThread.Abort();
77 cmdHandlerThread.Join();
78 }
79 }
80 }
81 catch
82 {
83 }
84 }
85
86 private void CmdHandlerThreadLoop()
87 {
88 while (true)
89 {
90 // Check timers
91 CheckTimerEvents();
92 Thread.Sleep(25);
93 // Check HttpRequests
94 CheckHttpRequests();
95 Thread.Sleep(25);
96 // Check XMLRPCRequests
97 CheckXMLRPCRequests();
98 Thread.Sleep(25);
99 // Check Listeners
100 CheckListeners();
101 Thread.Sleep(25);
102
103 // Sleep before next cycle
104 //Thread.Sleep(cmdHandlerThreadCycleSleepms);
105 }
106 }
107
108 /// <summary>
109 /// Remove a specific script (and all its pending commands)
110 /// </summary>
111 /// <param name="m_localID"></param>
112 /// <param name="m_itemID"></param>
113 public void RemoveScript(uint localID, LLUUID itemID)
114 {
115 // Remove a specific script
116
117 // Remove from: Timers
118 UnSetTimerEvents(localID, itemID);
119 // Remove from: HttpRequest
120 IHttpRequests iHttpReq =
121 m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
122 iHttpReq.StopHttpRequest(localID, itemID);
123 }
124
125 #region TIMER
126
127 //
128 // TIMER
129 //
130 private class TimerClass
131 {
132 public uint localID;
133 public LLUUID itemID;
134 public double interval;
135 public DateTime next;
136 }
137
138 private List<TimerClass> Timers = new List<TimerClass>();
139 private object TimerListLock = new object();
140
141 public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec)
142 {
143 Console.WriteLine("SetTimerEvent");
144
145 // Always remove first, in case this is a re-set
146 UnSetTimerEvents(m_localID, m_itemID);
147 if (sec == 0) // Disabling timer
148 return;
149
150 // Add to timer
151 TimerClass ts = new TimerClass();
152 ts.localID = m_localID;
153 ts.itemID = m_itemID;
154 ts.interval = sec;
155 ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
156 lock (TimerListLock)
157 {
158 Timers.Add(ts);
159 }
160 }
161
162 public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID)
163 {
164 // Remove from timer
165 lock (TimerListLock)
166 {
167 List<TimerClass> NewTimers = new List<TimerClass>();
168 foreach (TimerClass ts in Timers)
169 {
170 if (ts.localID != m_localID && ts.itemID != m_itemID)
171 {
172 NewTimers.Add(ts);
173 }
174 }
175 Timers.Clear();
176 Timers = NewTimers;
177 }
178 }
179
180 public void CheckTimerEvents()
181 {
182 // Nothing to do here?
183 if (Timers.Count == 0)
184 return;
185
186 lock (TimerListLock)
187 {
188 // Go through all timers
189 foreach (TimerClass ts in Timers)
190 {
191 // Time has passed?
192 if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
193 {
194 // Add it to queue
195 m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "timer", EventQueueManager.llDetectNull,
196 new object[] {});
197 // set next interval
198
199
200 ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
201 }
202 }
203 } // lock
204 }
205
206 #endregion
207
208 #region HTTP REQUEST
209
210 public void CheckHttpRequests()
211 {
212 if (m_ScriptEngine.World == null)
213 return;
214
215 IHttpRequests iHttpReq =
216 m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
217
218 HttpRequestClass httpInfo = null;
219
220 if (iHttpReq != null)
221 httpInfo = iHttpReq.GetNextCompletedRequest();
222
223 while (httpInfo != null)
224 {
225 //Console.WriteLine("PICKED HTTP REQ:" + httpInfo.response_body + httpInfo.status);
226
227 // Deliver data to prim's remote_data handler
228 //
229 // TODO: Returning null for metadata, since the lsl function
230 // only returns the byte for HTTP_BODY_TRUNCATED, which is not
231 // implemented here yet anyway. Should be fixed if/when maxsize
232 // is supported
233
234 object[] resobj = new object[]
235 {
236 httpInfo.reqID.ToString(), httpInfo.status, null, httpInfo.response_body
237 };
238
239 m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
240 httpInfo.localID, httpInfo.itemID, "http_response", EventQueueManager.llDetectNull, resobj
241 );
242
243 httpInfo.Stop();
244 httpInfo = null;
245
246 httpInfo = iHttpReq.GetNextCompletedRequest();
247 }
248 }
249
250 #endregion
251
252 public void CheckXMLRPCRequests()
253 {
254 if (m_ScriptEngine.World == null)
255 return;
256
257 IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
258
259 if (xmlrpc != null)
260 {
261 while (xmlrpc.hasRequests())
262 {
263 RPCRequestInfo rInfo = xmlrpc.GetNextRequest();
264 //Console.WriteLine("PICKED REQUEST");
265
266 //Deliver data to prim's remote_data handler
267 object[] resobj = new object[]
268 {
269 2, rInfo.GetChannelKey().ToString(), rInfo.GetMessageID().ToString(), String.Empty,
270 rInfo.GetIntValue(),
271 rInfo.GetStrVal()
272 };
273 m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
274 rInfo.GetLocalID(), rInfo.GetItemID(), "remote_data", EventQueueManager.llDetectNull, resobj
275 );
276 }
277 }
278 }
279
280 public void CheckListeners()
281 {
282 if (m_ScriptEngine.World == null)
283 return;
284 IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
285
286 while (comms.HasMessages())
287 {
288 ListenerInfo lInfo = comms.GetNextMessage();
289
290 //Deliver data to prim's listen handler
291 object[] resobj = new object[]
292 {
293 lInfo.GetChannel(), lInfo.GetName(), lInfo.GetID().ToString(), lInfo.GetMessage()
294 };
295
296 m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
297 lInfo.GetLocalID(), lInfo.GetItemID(), "listen", EventQueueManager.llDetectNull, resobj
298 );
299 }
300 }
301
302 /// <summary>
303 /// If set to true then threads and stuff should try to make a graceful exit
304 /// </summary>
305 public bool PleaseShutdown
306 {
307 get { return _PleaseShutdown; }
308 set { _PleaseShutdown = value; }
309 }
310 private bool _PleaseShutdown = false;
311
312 }
313} \ No newline at end of file