AsyncCommandManager.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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. using System;
  28. using System.Collections;
  29. using System.Collections.Generic;
  30. using System.Threading;
  31. using OpenMetaverse;
  32. using OpenSim.Framework;
  33. using OpenSim.Framework.Monitoring;
  34. using OpenSim.Region.Framework.Interfaces;
  35. using OpenSim.Region.ScriptEngine.Interfaces;
  36. using OpenSim.Region.ScriptEngine.Shared;
  37. using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
  38. using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer;
  39. namespace OpenSim.Region.ScriptEngine.Shared.Api
  40. {
  41. /// <summary>
  42. /// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
  43. /// </summary>
  44. public class AsyncCommandManager
  45. {
  46. private static Thread cmdHandlerThread;
  47. private static int cmdHandlerThreadCycleSleepms;
  48. private static List<IScene> m_Scenes = new List<IScene>();
  49. private static List<IScriptEngine> m_ScriptEngines =
  50. new List<IScriptEngine>();
  51. public IScriptEngine m_ScriptEngine;
  52. private IScene m_Scene;
  53. private static Dictionary<IScriptEngine, Dataserver> m_Dataserver =
  54. new Dictionary<IScriptEngine, Dataserver>();
  55. private static Dictionary<IScriptEngine, Timer> m_Timer =
  56. new Dictionary<IScriptEngine, Timer>();
  57. private static Dictionary<IScriptEngine, Listener> m_Listener =
  58. new Dictionary<IScriptEngine, Listener>();
  59. private static Dictionary<IScriptEngine, HttpRequest> m_HttpRequest =
  60. new Dictionary<IScriptEngine, HttpRequest>();
  61. private static Dictionary<IScriptEngine, SensorRepeat> m_SensorRepeat =
  62. new Dictionary<IScriptEngine, SensorRepeat>();
  63. private static Dictionary<IScriptEngine, XmlRequest> m_XmlRequest =
  64. new Dictionary<IScriptEngine, XmlRequest>();
  65. public Dataserver DataserverPlugin
  66. {
  67. get { return m_Dataserver[m_ScriptEngine]; }
  68. }
  69. public Timer TimerPlugin
  70. {
  71. get { return m_Timer[m_ScriptEngine]; }
  72. }
  73. public HttpRequest HttpRequestPlugin
  74. {
  75. get { return m_HttpRequest[m_ScriptEngine]; }
  76. }
  77. public Listener ListenerPlugin
  78. {
  79. get { return m_Listener[m_ScriptEngine]; }
  80. }
  81. public SensorRepeat SensorRepeatPlugin
  82. {
  83. get { return m_SensorRepeat[m_ScriptEngine]; }
  84. }
  85. public XmlRequest XmlRequestPlugin
  86. {
  87. get { return m_XmlRequest[m_ScriptEngine]; }
  88. }
  89. public IScriptEngine[] ScriptEngines
  90. {
  91. get { return m_ScriptEngines.ToArray(); }
  92. }
  93. public AsyncCommandManager(IScriptEngine _ScriptEngine)
  94. {
  95. m_ScriptEngine = _ScriptEngine;
  96. m_Scene = m_ScriptEngine.World;
  97. if (m_Scenes.Count == 0)
  98. ReadConfig();
  99. if (!m_Scenes.Contains(m_Scene))
  100. m_Scenes.Add(m_Scene);
  101. if (!m_ScriptEngines.Contains(m_ScriptEngine))
  102. m_ScriptEngines.Add(m_ScriptEngine);
  103. // Create instances of all plugins
  104. if (!m_Dataserver.ContainsKey(m_ScriptEngine))
  105. m_Dataserver[m_ScriptEngine] = new Dataserver(this);
  106. if (!m_Timer.ContainsKey(m_ScriptEngine))
  107. m_Timer[m_ScriptEngine] = new Timer(this);
  108. if (!m_HttpRequest.ContainsKey(m_ScriptEngine))
  109. m_HttpRequest[m_ScriptEngine] = new HttpRequest(this);
  110. if (!m_Listener.ContainsKey(m_ScriptEngine))
  111. m_Listener[m_ScriptEngine] = new Listener(this);
  112. if (!m_SensorRepeat.ContainsKey(m_ScriptEngine))
  113. m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this);
  114. if (!m_XmlRequest.ContainsKey(m_ScriptEngine))
  115. m_XmlRequest[m_ScriptEngine] = new XmlRequest(this);
  116. StartThread();
  117. }
  118. private static void StartThread()
  119. {
  120. if (cmdHandlerThread == null)
  121. {
  122. // Start the thread that will be doing the work
  123. cmdHandlerThread
  124. = Watchdog.StartThread(
  125. CmdHandlerThreadLoop, "AsyncLSLCmdHandlerThread", ThreadPriority.Normal, true, true);
  126. }
  127. }
  128. private void ReadConfig()
  129. {
  130. // cmdHandlerThreadCycleSleepms = m_ScriptEngine.Config.GetInt("AsyncLLCommandLoopms", 100);
  131. // TODO: Make this sane again
  132. cmdHandlerThreadCycleSleepms = 100;
  133. }
  134. ~AsyncCommandManager()
  135. {
  136. // Shut down thread
  137. // try
  138. // {
  139. // if (cmdHandlerThread != null)
  140. // {
  141. // if (cmdHandlerThread.IsAlive == true)
  142. // {
  143. // cmdHandlerThread.Abort();
  144. // //cmdHandlerThread.Join();
  145. // }
  146. // }
  147. // }
  148. // catch
  149. // {
  150. // }
  151. }
  152. /// <summary>
  153. /// Main loop for the manager thread
  154. /// </summary>
  155. private static void CmdHandlerThreadLoop()
  156. {
  157. while (true)
  158. {
  159. try
  160. {
  161. while (true)
  162. {
  163. Thread.Sleep(cmdHandlerThreadCycleSleepms);
  164. DoOneCmdHandlerPass();
  165. Watchdog.UpdateThread();
  166. }
  167. }
  168. catch
  169. {
  170. }
  171. }
  172. }
  173. private static void DoOneCmdHandlerPass()
  174. {
  175. // Check HttpRequests
  176. m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests();
  177. // Check XMLRPCRequests
  178. m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests();
  179. foreach (IScriptEngine s in m_ScriptEngines)
  180. {
  181. // Check Listeners
  182. m_Listener[s].CheckListeners();
  183. // Check timers
  184. m_Timer[s].CheckTimerEvents();
  185. // Check Sensors
  186. m_SensorRepeat[s].CheckSenseRepeaterEvents();
  187. // Check dataserver
  188. m_Dataserver[s].ExpireRequests();
  189. }
  190. }
  191. /// <summary>
  192. /// Remove a specific script (and all its pending commands)
  193. /// </summary>
  194. /// <param name="localID"></param>
  195. /// <param name="itemID"></param>
  196. public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID)
  197. {
  198. // Remove a specific script
  199. // Remove dataserver events
  200. m_Dataserver[engine].RemoveEvents(localID, itemID);
  201. // Remove from: Timers
  202. m_Timer[engine].UnSetTimerEvents(localID, itemID);
  203. // Remove from: HttpRequest
  204. IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>();
  205. if (iHttpReq != null)
  206. iHttpReq.StopHttpRequest(localID, itemID);
  207. IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
  208. if (comms != null)
  209. comms.DeleteListener(itemID);
  210. IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
  211. if (xmlrpc != null)
  212. {
  213. xmlrpc.DeleteChannels(itemID);
  214. xmlrpc.CancelSRDRequests(itemID);
  215. }
  216. // Remove Sensors
  217. m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
  218. }
  219. /// <summary>
  220. /// Get the sensor repeat plugin for this script engine.
  221. /// </summary>
  222. /// <param name="engine"></param>
  223. /// <returns></returns>
  224. public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine)
  225. {
  226. if (m_SensorRepeat.ContainsKey(engine))
  227. return m_SensorRepeat[engine];
  228. else
  229. return null;
  230. }
  231. /// <summary>
  232. /// Get the dataserver plugin for this script engine.
  233. /// </summary>
  234. /// <param name="engine"></param>
  235. /// <returns></returns>
  236. public static Dataserver GetDataserverPlugin(IScriptEngine engine)
  237. {
  238. if (m_Dataserver.ContainsKey(engine))
  239. return m_Dataserver[engine];
  240. else
  241. return null;
  242. }
  243. /// <summary>
  244. /// Get the timer plugin for this script engine.
  245. /// </summary>
  246. /// <param name="engine"></param>
  247. /// <returns></returns>
  248. public static Timer GetTimerPlugin(IScriptEngine engine)
  249. {
  250. if (m_Timer.ContainsKey(engine))
  251. return m_Timer[engine];
  252. else
  253. return null;
  254. }
  255. /// <summary>
  256. /// Get the listener plugin for this script engine.
  257. /// </summary>
  258. /// <param name="engine"></param>
  259. /// <returns></returns>
  260. public static Listener GetListenerPlugin(IScriptEngine engine)
  261. {
  262. if (m_Listener.ContainsKey(engine))
  263. return m_Listener[engine];
  264. else
  265. return null;
  266. }
  267. public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID)
  268. {
  269. List<Object> data = new List<Object>();
  270. Object[] listeners = m_Listener[engine].GetSerializationData(itemID);
  271. if (listeners.Length > 0)
  272. {
  273. data.Add("listener");
  274. data.Add(listeners.Length);
  275. data.AddRange(listeners);
  276. }
  277. Object[] timers=m_Timer[engine].GetSerializationData(itemID);
  278. if (timers.Length > 0)
  279. {
  280. data.Add("timer");
  281. data.Add(timers.Length);
  282. data.AddRange(timers);
  283. }
  284. Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID);
  285. if (sensors.Length > 0)
  286. {
  287. data.Add("sensor");
  288. data.Add(sensors.Length);
  289. data.AddRange(sensors);
  290. }
  291. return data.ToArray();
  292. }
  293. public static void CreateFromData(IScriptEngine engine, uint localID,
  294. UUID itemID, UUID hostID, Object[] data)
  295. {
  296. int idx = 0;
  297. int len;
  298. while (idx < data.Length)
  299. {
  300. string type = data[idx].ToString();
  301. len = (int)data[idx+1];
  302. idx+=2;
  303. if (len > 0)
  304. {
  305. Object[] item = new Object[len];
  306. Array.Copy(data, idx, item, 0, len);
  307. idx+=len;
  308. switch (type)
  309. {
  310. case "listener":
  311. m_Listener[engine].CreateFromData(localID, itemID,
  312. hostID, item);
  313. break;
  314. case "timer":
  315. m_Timer[engine].CreateFromData(localID, itemID,
  316. hostID, item);
  317. break;
  318. case "sensor":
  319. m_SensorRepeat[engine].CreateFromData(localID,
  320. itemID, hostID, item);
  321. break;
  322. }
  323. }
  324. }
  325. }
  326. #region Check llRemoteData channels
  327. #endregion
  328. #region Check llListeners
  329. #endregion
  330. /// <summary>
  331. /// If set to true then threads and stuff should try to make a graceful exit
  332. /// </summary>
  333. public bool PleaseShutdown
  334. {
  335. get { return _PleaseShutdown; }
  336. set { _PleaseShutdown = value; }
  337. }
  338. private bool _PleaseShutdown = false;
  339. }
  340. }