123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- /*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSim Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- using System;
- using System.Collections.Generic;
- using System.Threading;
- using libsecondlife;
- using OpenSim.Region.Environment.Interfaces;
- using OpenSim.Region.Environment.Modules;
- namespace OpenSim.Grid.ScriptEngine.DotNetEngine
- {
- /// <summary>
- /// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
- /// </summary>
- internal class LSLLongCmdHandler
- {
- private Thread cmdHandlerThread;
- private int cmdHandlerThreadCycleSleepms = 100;
- private ScriptEngine m_ScriptEngine;
- public LSLLongCmdHandler(ScriptEngine _ScriptEngine)
- {
- m_ScriptEngine = _ScriptEngine;
- // Start the thread that will be doing the work
- cmdHandlerThread = new Thread(CmdHandlerThreadLoop);
- cmdHandlerThread.Name = "CmdHandlerThread";
- cmdHandlerThread.Priority = ThreadPriority.BelowNormal;
- cmdHandlerThread.IsBackground = true;
- cmdHandlerThread.Start();
- }
- ~LSLLongCmdHandler()
- {
- // Shut down thread
- try
- {
- if (cmdHandlerThread != null)
- {
- if (cmdHandlerThread.IsAlive == true)
- {
- cmdHandlerThread.Abort();
- cmdHandlerThread.Join();
- }
- }
- }
- catch
- {
- }
- }
- private void CmdHandlerThreadLoop()
- {
- while (true)
- {
- // Check timers
- CheckTimerEvents();
- Thread.Sleep(25);
- // Check HttpRequests
- CheckHttpRequests();
- Thread.Sleep(25);
- // Check XMLRPCRequests
- CheckXMLRPCRequests();
- Thread.Sleep(25);
- // Check Listeners
- CheckListeners();
- Thread.Sleep(25);
- // Sleep before next cycle
- //Thread.Sleep(cmdHandlerThreadCycleSleepms);
- }
- }
- /// <summary>
- /// Remove a specific script (and all its pending commands)
- /// </summary>
- /// <param name="m_localID"></param>
- /// <param name="m_itemID"></param>
- public void RemoveScript(uint localID, LLUUID itemID)
- {
- // Remove a specific script
- // Remove from: Timers
- UnSetTimerEvents(localID, itemID);
- // Remove from: HttpRequest
- StopHttpRequest(localID, itemID);
- }
- #region TIMER
- //
- // TIMER
- //
- private class TimerClass
- {
- public uint localID;
- public LLUUID itemID;
- public double interval;
- public DateTime next;
- }
- private List<TimerClass> Timers = new List<TimerClass>();
- private object TimerListLock = new object();
- public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec)
- {
- Console.WriteLine("SetTimerEvent");
- // Always remove first, in case this is a re-set
- UnSetTimerEvents(m_localID, m_itemID);
- if (sec == 0) // Disabling timer
- return;
- // Add to timer
- TimerClass ts = new TimerClass();
- ts.localID = m_localID;
- ts.itemID = m_itemID;
- ts.interval = sec;
- ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
- lock (TimerListLock)
- {
- Timers.Add(ts);
- }
- }
- public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID)
- {
- // Remove from timer
- lock (TimerListLock)
- {
- List<TimerClass> NewTimers = new List<TimerClass>();
- foreach (TimerClass ts in Timers)
- {
- if (ts.localID != m_localID && ts.itemID != m_itemID)
- {
- NewTimers.Add(ts);
- }
- }
- Timers.Clear();
- Timers = NewTimers;
- }
- }
- public void CheckTimerEvents()
- {
- // Nothing to do here?
- if (Timers.Count == 0)
- return;
- lock (TimerListLock)
- {
- // Go through all timers
- foreach (TimerClass ts in Timers)
- {
- // Time has passed?
- if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
- {
- // Add it to queue
- m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "timer",
- new object[] {});
- // set next interval
- ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
- }
- }
- }
- }
- #endregion
- #region HTTP REQUEST
- //
- // HTTP REAQUEST
- //
- private class HttpClass
- {
- public uint localID;
- public LLUUID itemID;
- public string url;
- public List<string> parameters;
- public string body;
- public DateTime next;
- public string response_request_id;
- public int response_status;
- public List<string> response_metadata;
- public string response_body;
- public void SendRequest()
- {
- // TODO: SEND REQUEST!!!
- }
- public void Stop()
- {
- // TODO: Cancel any ongoing request
- }
- public bool CheckResponse()
- {
- // TODO: Check if we got a response yet, return true if so -- false if not
- return true;
- // TODO: If we got a response, set the following then return true
- //response_request_id
- //response_status
- //response_metadata
- //response_body
- }
- }
- private List<HttpClass> HttpRequests = new List<HttpClass>();
- private object HttpListLock = new object();
- public void StartHttpRequest(uint localID, LLUUID itemID, string url, List<string> parameters, string body)
- {
- Console.WriteLine("StartHttpRequest");
- HttpClass htc = new HttpClass();
- htc.localID = localID;
- htc.itemID = itemID;
- htc.url = url;
- htc.parameters = parameters;
- htc.body = body;
- lock (HttpListLock)
- {
- //ADD REQUEST
- HttpRequests.Add(htc);
- }
- }
- public void StopHttpRequest(uint m_localID, LLUUID m_itemID)
- {
- // Remove from list
- lock (HttpListLock)
- {
- List<HttpClass> NewHttpList = new List<HttpClass>();
- foreach (HttpClass ts in HttpRequests)
- {
- if (ts.localID != m_localID && ts.itemID != m_itemID)
- {
- // Keeping this one
- NewHttpList.Add(ts);
- }
- else
- {
- // Shutting this one down
- ts.Stop();
- }
- }
- HttpRequests.Clear();
- HttpRequests = NewHttpList;
- }
- }
- public void CheckHttpRequests()
- {
- // Nothing to do here?
- if (HttpRequests.Count == 0)
- return;
- lock (HttpListLock)
- {
- foreach (HttpClass ts in HttpRequests)
- {
- if (ts.CheckResponse() == true)
- {
- // Add it to event queue
- //key request_id, integer status, list metadata, string body
- object[] resobj =
- new object[]
- {ts.response_request_id, ts.response_status, ts.response_metadata, ts.response_body};
- m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(ts.localID, ts.itemID, "http_response",
- resobj);
- // Now stop it
- StopHttpRequest(ts.localID, ts.itemID);
- }
- }
- }
- }
- #endregion
- public void CheckXMLRPCRequests()
- {
- IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
- while (xmlrpc.hasRequests())
- {
- RPCRequestInfo rInfo = xmlrpc.GetNextRequest();
- Console.WriteLine("PICKED REQUEST");
- //Deliver data to prim's remote_data handler
- object[] resobj = new object[]
- {
- 2, rInfo.GetChannelKey().ToString(), rInfo.GetMessageID().ToString(), "", rInfo.GetIntValue(),
- rInfo.GetStrVal()
- };
- m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
- rInfo.GetLocalID(), rInfo.GetItemID(), "remote_data", resobj
- );
- }
- }
- public void CheckListeners()
- {
- IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
- while (comms.HasMessages())
- {
- ListenerInfo lInfo = comms.GetNextMessage();
- Console.WriteLine("PICKED LISTENER");
- //Deliver data to prim's listen handler
- object[] resobj = new object[]
- {
- lInfo.GetChannel(), lInfo.GetName(), lInfo.GetID().ToString(), lInfo.GetMessage()
- };
- m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(
- lInfo.GetLocalID(), lInfo.GetItemID(), "listen", resobj
- );
- }
- }
- }
- }
|