aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs (renamed from OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/LSLLongCmdHandler.cs)606
1 files changed, 312 insertions, 294 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/LSLLongCmdHandler.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs
index 7d66638..5ec8f50 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/LSLLongCmdHandler.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/AsyncLSLCommandManager.cs
@@ -1,295 +1,313 @@
1/* 1/*
2* Copyright (c) Contributors, http://opensimulator.org/ 2* Copyright (c) Contributors, http://opensimulator.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders. 3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4* 4*
5* Redistribution and use in source and binary forms, with or without 5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met: 6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright 7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer. 8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright 9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the 10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution. 11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the 12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products 13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission. 14* derived from this software without specific prior written permission.
15* 15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY 16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 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 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 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
29using System; 29using System;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Threading; 31using System.Threading;
32using libsecondlife; 32using libsecondlife;
33using OpenSim.Region.Environment.Interfaces; 33using OpenSim.Region.Environment.Interfaces;
34using OpenSim.Region.Environment.Modules; 34using OpenSim.Region.Environment.Modules;
35 35
36namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase 36namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
37{ 37{
38 /// <summary> 38 /// <summary>
39 /// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc. 39 /// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
40 /// </summary> 40 /// </summary>
41 public class LSLLongCmdHandler 41 public class AsyncLSLCommandManager : iScriptEngineFunctionModule
42 { 42 {
43 private Thread cmdHandlerThread; 43 private Thread cmdHandlerThread;
44 private int cmdHandlerThreadCycleSleepms = 100; 44 private int cmdHandlerThreadCycleSleepms;
45 45
46 private ScriptEngine m_ScriptEngine; 46 private ScriptEngine m_ScriptEngine;
47 47
48 public LSLLongCmdHandler(ScriptEngine _ScriptEngine) 48 public AsyncLSLCommandManager(ScriptEngine _ScriptEngine)
49 { 49 {
50 m_ScriptEngine = _ScriptEngine; 50 m_ScriptEngine = _ScriptEngine;
51 51 ReadConfig();
52 // Start the thread that will be doing the work 52
53 cmdHandlerThread = new Thread(CmdHandlerThreadLoop); 53 // Start the thread that will be doing the work
54 cmdHandlerThread.Name = "CmdHandlerThread"; 54 cmdHandlerThread = new Thread(CmdHandlerThreadLoop);
55 cmdHandlerThread.Priority = ThreadPriority.BelowNormal; 55 cmdHandlerThread.Name = "CmdHandlerThread";
56 cmdHandlerThread.IsBackground = true; 56 cmdHandlerThread.Priority = ThreadPriority.BelowNormal;
57 cmdHandlerThread.Start(); 57 cmdHandlerThread.IsBackground = true;
58 } 58 cmdHandlerThread.Start();
59 59 }
60 ~LSLLongCmdHandler() 60
61 { 61 public void ReadConfig()
62 // Shut down thread 62 {
63 try 63 cmdHandlerThreadCycleSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("AsyncLLCommandLoopms", 50);
64 { 64 }
65 if (cmdHandlerThread != null) 65
66 { 66
67 if (cmdHandlerThread.IsAlive == true) 67 ~AsyncLSLCommandManager()
68 { 68 {
69 cmdHandlerThread.Abort(); 69 // Shut down thread
70 cmdHandlerThread.Join(); 70 try
71 } 71 {
72 } 72 if (cmdHandlerThread != null)
73 } 73 {
74 catch 74 if (cmdHandlerThread.IsAlive == true)
75 { 75 {
76 } 76 cmdHandlerThread.Abort();
77 } 77 cmdHandlerThread.Join();
78 78 }
79 private void CmdHandlerThreadLoop() 79 }
80 { 80 }
81 while (true) 81 catch
82 { 82 {
83 // Check timers 83 }
84 CheckTimerEvents(); 84 }
85 Thread.Sleep(25); 85
86 // Check HttpRequests 86 private void CmdHandlerThreadLoop()
87 CheckHttpRequests(); 87 {
88 Thread.Sleep(25); 88 while (true)
89 // Check XMLRPCRequests 89 {
90 CheckXMLRPCRequests(); 90 // Check timers
91 Thread.Sleep(25); 91 CheckTimerEvents();
92 // Check Listeners 92 Thread.Sleep(25);
93 CheckListeners(); 93 // Check HttpRequests
94 Thread.Sleep(25); 94 CheckHttpRequests();
95 95 Thread.Sleep(25);
96 // Sleep before next cycle 96 // Check XMLRPCRequests
97 //Thread.Sleep(cmdHandlerThreadCycleSleepms); 97 CheckXMLRPCRequests();
98 } 98 Thread.Sleep(25);
99 } 99 // Check Listeners
100 100 CheckListeners();
101 /// <summary> 101 Thread.Sleep(25);
102 /// Remove a specific script (and all its pending commands) 102
103 /// </summary> 103 // Sleep before next cycle
104 /// <param name="m_localID"></param> 104 //Thread.Sleep(cmdHandlerThreadCycleSleepms);
105 /// <param name="m_itemID"></param> 105 }
106 public void RemoveScript(uint localID, LLUUID itemID) 106 }
107 { 107
108 // Remove a specific script 108 /// <summary>
109 109 /// Remove a specific script (and all its pending commands)
110 // Remove from: Timers 110 /// </summary>
111 UnSetTimerEvents(localID, itemID); 111 /// <param name="m_localID"></param>
112 // Remove from: HttpRequest 112 /// <param name="m_itemID"></param>
113 IHttpRequests iHttpReq = 113 public void RemoveScript(uint localID, LLUUID itemID)
114 m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>(); 114 {
115 iHttpReq.StopHttpRequest(localID, itemID); 115 // Remove a specific script
116 } 116
117 117 // Remove from: Timers
118 #region TIMER 118 UnSetTimerEvents(localID, itemID);
119 119 // Remove from: HttpRequest
120 // 120 IHttpRequests iHttpReq =
121 // TIMER 121 m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
122 // 122 iHttpReq.StopHttpRequest(localID, itemID);
123 private class TimerClass 123 }
124 { 124
125 public uint localID; 125 #region TIMER
126 public LLUUID itemID; 126
127 public double interval; 127 //
128 public DateTime next; 128 // TIMER
129 } 129 //
130 130 private class TimerClass
131 private List<TimerClass> Timers = new List<TimerClass>(); 131 {
132 private object TimerListLock = new object(); 132 public uint localID;
133 133 public LLUUID itemID;
134 public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec) 134 public double interval;
135 { 135 public DateTime next;
136 Console.WriteLine("SetTimerEvent"); 136 }
137 137
138 // Always remove first, in case this is a re-set 138 private List<TimerClass> Timers = new List<TimerClass>();
139 UnSetTimerEvents(m_localID, m_itemID); 139 private object TimerListLock = new object();
140 if (sec == 0) // Disabling timer 140
141 return; 141 public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec)
142 142 {
143 // Add to timer 143 Console.WriteLine("SetTimerEvent");
144 TimerClass ts = new TimerClass(); 144
145 ts.localID = m_localID; 145 // Always remove first, in case this is a re-set
146 ts.itemID = m_itemID; 146 UnSetTimerEvents(m_localID, m_itemID);
147 ts.interval = sec; 147 if (sec == 0) // Disabling timer
148 ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); 148 return;
149 lock (TimerListLock) 149
150 { 150 // Add to timer
151 Timers.Add(ts); 151 TimerClass ts = new TimerClass();
152 } 152 ts.localID = m_localID;
153 } 153 ts.itemID = m_itemID;
154 154 ts.interval = sec;
155 public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID) 155 ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
156 { 156 lock (TimerListLock)
157 // Remove from timer 157 {
158 lock (TimerListLock) 158 Timers.Add(ts);
159 { 159 }
160 List<TimerClass> NewTimers = new List<TimerClass>(); 160 }
161 foreach (TimerClass ts in Timers) 161
162 { 162 public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID)
163 if (ts.localID != m_localID && ts.itemID != m_itemID) 163 {
164 { 164 // Remove from timer
165 NewTimers.Add(ts); 165 lock (TimerListLock)
166 } 166 {
167 } 167 List<TimerClass> NewTimers = new List<TimerClass>();
168 Timers.Clear(); 168 foreach (TimerClass ts in Timers)
169 Timers = NewTimers; 169 {
170 } 170 if (ts.localID != m_localID && ts.itemID != m_itemID)
171 } 171 {
172 172 NewTimers.Add(ts);
173 public void CheckTimerEvents() 173 }
174 { 174 }
175 // Nothing to do here? 175 Timers.Clear();
176 if (Timers.Count == 0) 176 Timers = NewTimers;
177 return; 177 }
178 178 }
179 lock (TimerListLock) 179
180 { 180 public void CheckTimerEvents()
181 // Go through all timers 181 {
182 foreach (TimerClass ts in Timers) 182 // Nothing to do here?
183 { 183 if (Timers.Count == 0)
184 // Time has passed? 184 return;
185 if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime()) 185
186 { 186 lock (TimerListLock)
187 // Add it to queue 187 {
188 m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "timer", EventQueueManager.llDetectNull, 188 // Go through all timers
189 new object[] {}); 189 foreach (TimerClass ts in Timers)
190 // set next interval 190 {
191 191 // Time has passed?
192 192 if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
193 ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); 193 {
194 } 194 // Add it to queue
195 } 195 m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "timer", EventQueueManager.llDetectNull,
196 } // lock 196 new object[] {});
197 } 197 // set next interval
198 198
199 #endregion 199
200 200 ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
201 #region HTTP REQUEST 201 }
202 202 }
203 public void CheckHttpRequests() 203 } // lock
204 { 204 }
205 if (m_ScriptEngine.World == null) 205
206 return; 206 #endregion
207 207
208 IHttpRequests iHttpReq = 208 #region HTTP REQUEST
209 m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>(); 209
210 210 public void CheckHttpRequests()
211 HttpRequestClass httpInfo = null; 211 {
212 212 if (m_ScriptEngine.World == null)
213 if (iHttpReq != null) 213 return;
214 httpInfo = iHttpReq.GetNextCompletedRequest(); 214
215 215 IHttpRequests iHttpReq =
216 while (httpInfo != null) 216 m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
217 { 217
218 //Console.WriteLine("PICKED HTTP REQ:" + httpInfo.response_body + httpInfo.status); 218 HttpRequestClass httpInfo = null;
219 219
220 // Deliver data to prim's remote_data handler 220 if (iHttpReq != null)
221 // 221 httpInfo = iHttpReq.GetNextCompletedRequest();
222 // TODO: Returning null for metadata, since the lsl function 222
223 // only returns the byte for HTTP_BODY_TRUNCATED, which is not 223 while (httpInfo != null)
224 // implemented here yet anyway. Should be fixed if/when maxsize 224 {
225 // is supported 225 //Console.WriteLine("PICKED HTTP REQ:" + httpInfo.response_body + httpInfo.status);
226 226
227 object[] resobj = new object[] 227 // Deliver data to prim's remote_data handler
228 { 228 //
229 httpInfo.reqID.ToString(), httpInfo.status, null, httpInfo.response_body 229 // TODO: Returning null for metadata, since the lsl function
230 }; 230 // only returns the byte for HTTP_BODY_TRUNCATED, which is not
231 231 // implemented here yet anyway. Should be fixed if/when maxsize
232 m_ScriptEngine.m_EventQueueManager.AddToScriptQueue( 232 // is supported
233 httpInfo.localID, httpInfo.itemID, "http_response", EventQueueManager.llDetectNull, resobj 233
234 ); 234 object[] resobj = new object[]
235 235 {
236 httpInfo.Stop(); 236 httpInfo.reqID.ToString(), httpInfo.status, null, httpInfo.response_body
237 httpInfo = null; 237 };
238 238
239 httpInfo = iHttpReq.GetNextCompletedRequest(); 239 m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
240 } 240 httpInfo.localID, httpInfo.itemID, "http_response", EventQueueManager.llDetectNull, resobj
241 } 241 );
242 242
243 #endregion 243 httpInfo.Stop();
244 244 httpInfo = null;
245 public void CheckXMLRPCRequests() 245
246 { 246 httpInfo = iHttpReq.GetNextCompletedRequest();
247 if (m_ScriptEngine.World == null) 247 }
248 return; 248 }
249 249
250 IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); 250 #endregion
251 251
252 if (xmlrpc != null) 252 public void CheckXMLRPCRequests()
253 { 253 {
254 while (xmlrpc.hasRequests()) 254 if (m_ScriptEngine.World == null)
255 { 255 return;
256 RPCRequestInfo rInfo = xmlrpc.GetNextRequest(); 256
257 //Console.WriteLine("PICKED REQUEST"); 257 IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
258 258
259 //Deliver data to prim's remote_data handler 259 if (xmlrpc != null)
260 object[] resobj = new object[] 260 {
261 { 261 while (xmlrpc.hasRequests())
262 2, rInfo.GetChannelKey().ToString(), rInfo.GetMessageID().ToString(), String.Empty, 262 {
263 rInfo.GetIntValue(), 263 RPCRequestInfo rInfo = xmlrpc.GetNextRequest();
264 rInfo.GetStrVal() 264 //Console.WriteLine("PICKED REQUEST");
265 }; 265
266 m_ScriptEngine.m_EventQueueManager.AddToScriptQueue( 266 //Deliver data to prim's remote_data handler
267 rInfo.GetLocalID(), rInfo.GetItemID(), "remote_data", EventQueueManager.llDetectNull, resobj 267 object[] resobj = new object[]
268 ); 268 {
269 } 269 2, rInfo.GetChannelKey().ToString(), rInfo.GetMessageID().ToString(), String.Empty,
270 } 270 rInfo.GetIntValue(),
271 } 271 rInfo.GetStrVal()
272 272 };
273 public void CheckListeners() 273 m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
274 { 274 rInfo.GetLocalID(), rInfo.GetItemID(), "remote_data", EventQueueManager.llDetectNull, resobj
275 if (m_ScriptEngine.World == null) 275 );
276 return; 276 }
277 IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>(); 277 }
278 278 }
279 while (comms.HasMessages()) 279
280 { 280 public void CheckListeners()
281 ListenerInfo lInfo = comms.GetNextMessage(); 281 {
282 282 if (m_ScriptEngine.World == null)
283 //Deliver data to prim's listen handler 283 return;
284 object[] resobj = new object[] 284 IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
285 { 285
286 lInfo.GetChannel(), lInfo.GetName(), lInfo.GetID().ToString(), lInfo.GetMessage() 286 while (comms.HasMessages())
287 }; 287 {
288 288 ListenerInfo lInfo = comms.GetNextMessage();
289 m_ScriptEngine.m_EventQueueManager.AddToScriptQueue( 289
290 lInfo.GetLocalID(), lInfo.GetItemID(), "listen", EventQueueManager.llDetectNull, resobj 290 //Deliver data to prim's listen handler
291 ); 291 object[] resobj = new object[]
292 } 292 {
293 } 293 lInfo.GetChannel(), lInfo.GetName(), lInfo.GetID().ToString(), lInfo.GetMessage()
294 } 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 }
295} \ No newline at end of file 313} \ No newline at end of file