355 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			355 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
| /*
 | |
| * 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
 | |
|                     );
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| } |