LSLLongCmdHandler.cs 12 KB

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