diff --git a/OpenSim/Region/Environment/Interfaces/IWorldComm.cs b/OpenSim/Region/Environment/Interfaces/IWorldComm.cs new file mode 100644 index 0000000000..23bdbb6d46 --- /dev/null +++ b/OpenSim/Region/Environment/Interfaces/IWorldComm.cs @@ -0,0 +1,15 @@ +using libsecondlife; +using OpenSim.Region.Environment.Modules; + +namespace OpenSim.Region.Environment.Interfaces +{ + public interface IWorldComm + { + int Listen(uint LocalID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg); + void DeliverMessage(string sourceItemID, int type, int channel, string name, string msg); + bool HasMessages(); + ListenerInfo GetNextMessage(); + void ListenControl(int handle, int active); + void ListenRemove(int handle); + } +} \ No newline at end of file diff --git a/OpenSim/Region/Environment/Interfaces/IXMLRPC.cs b/OpenSim/Region/Environment/Interfaces/IXMLRPC.cs new file mode 100644 index 0000000000..dc44a8fa49 --- /dev/null +++ b/OpenSim/Region/Environment/Interfaces/IXMLRPC.cs @@ -0,0 +1,14 @@ +using libsecondlife; +using OpenSim.Region.Environment.Modules; + +namespace OpenSim.Region.Environment.Interfaces +{ + public interface IXMLRPC + { + LLUUID OpenXMLRPCChannel(uint localID, LLUUID itemID); + void CloseXMLRPCChannel(LLUUID channelKey); + bool hasRequests(); + RPCRequestInfo GetNextRequest(); + void RemoteDataReply(string channel, string message_id, string sdata, int idata); + } +} \ No newline at end of file diff --git a/OpenSim/Region/Environment/ModuleLoader.cs b/OpenSim/Region/Environment/ModuleLoader.cs index ce2a843348..43c1aaeca4 100644 --- a/OpenSim/Region/Environment/ModuleLoader.cs +++ b/OpenSim/Region/Environment/ModuleLoader.cs @@ -34,6 +34,12 @@ namespace OpenSim.Region.Environment module = new AvatarProfilesModule(); InitialiseModule(module, scene); + module = new XMLRPCModule(); + InitialiseModule(module, scene); + + module = new WorldCommModule(); + InitialiseModule(module, scene); + LoadRegionModule("OpenSim.Region.ExtensionsScriptModule.dll", "ExtensionsScriptingModule", scene); string lslPath = Path.Combine("ScriptEngines", "OpenSim.Region.ScriptEngine.DotNetEngine.dll"); @@ -153,4 +159,4 @@ namespace OpenSim.Region.Environment LoadedAssemblys.Clear(); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Environment/Modules/WorldCommModule.cs b/OpenSim/Region/Environment/Modules/WorldCommModule.cs new file mode 100644 index 0000000000..c2ec6995c6 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/WorldCommModule.cs @@ -0,0 +1,481 @@ +using System; +using System.IO; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using libsecondlife; +using OpenSim.Framework.Interfaces; +using OpenSim.Framework.Utilities; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Framework.Servers; +using Nwc.XmlRpc; +using System.Collections; +using System.Collections.Generic; + +/***************************************************** + * + * WorldCommModule + * + * + * Holding place for world comms - basically llListen + * function implementation. + * + * lLListen(integer channel, string name, key id, string msg) + * The name, id, and msg arguments specify the filtering + * criteria. You can pass the empty string + * (or NULL_KEY for id) for these to set a completely + * open filter; this causes the listen() event handler to be + * invoked for all chat on the channel. To listen only + * for chat spoken by a specific object or avatar, + * specify the name and/or id arguments. To listen + * only for a specific command, specify the + * (case-sensitive) msg argument. If msg is not empty, + * listener will only hear strings which are exactly equal + * to msg. You can also use all the arguments to establish + * the most restrictive filtering criteria. + * + * It might be useful for each listener to maintain a message + * digest, with a list of recent messages by UUID. This can + * be used to prevent in-world repeater loops. However, the + * linden functions do not have this capability, so for now + * thats the way it works. + * + * **************************************************/ +namespace OpenSim.Region.Environment.Modules +{ + public class WorldCommModule : IRegionModule, IWorldComm + { + private Scene m_scene; + private object CommListLock = new object(); + private string m_name = "WorldCommModule"; + private ListenerManager m_listenerManager; + private Queue m_pending; + + public WorldCommModule() + { + } + + public void Initialise(Scene scene) + { + + m_scene = scene; + m_scene.RegisterModuleInterface(this); + m_listenerManager = new ListenerManager(); + m_pending = new Queue(); + m_scene.EventManager.OnNewClient += NewClient; + + } + + public void PostInitialise() + { + } + + public void CloseDown() + { + } + + public string GetName() + { + return m_name; + } + + public bool IsSharedModule() + { + return false; + } + + public void NewClient(IClientAPI client) + { + client.OnChatFromViewer += DeliverClientMessage; + } + + private void DeliverClientMessage(byte[] message, byte type, int channel, LLVector3 fromPos, string fromName, + LLUUID fromAgentID) + { + ASCIIEncoding ae = new ASCIIEncoding(); + + DeliverMessage(fromAgentID.ToString(), type, channel, fromName, ae.GetString(message)); + + } + + public int Listen(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg) + { + return m_listenerManager.AddListener(localID, itemID, hostID, channel, name, id, msg); + } + + public void ListenControl(int handle, int active) + { + if ( active == 1 ) + m_listenerManager.Activate(handle); + else if ( active == 0 ) + m_listenerManager.Dectivate(handle); + + } + + public void ListenRemove(int handle) + { + m_listenerManager.Remove(handle); + } + + // This method scans nearby objects and determines if they are listeners, + // and if so if this message fits the filter. If it does, then + // enqueue the message for delivery to the objects listen event handler. + // Objects that do an llSay have their messages delivered here, and for + // nearby avatards, the SimChat function is used. + public void DeliverMessage(string sourceItemID, int type, int channel, string name, string msg) + { + + SceneObjectPart source = null; + ScenePresence avatar = null; + + source = m_scene.GetSceneObjectPart(new LLUUID(sourceItemID)); + if (source == null) + { + avatar = m_scene.GetScenePresence(new LLUUID(sourceItemID)); + } + if( (avatar != null) || (source != null) ) + { + // Loop through the objects in the scene + // If they are in proximity, then if they are + // listeners, if so add them to the pending queue + + foreach (LLUUID eb in m_scene.Entities.Keys) + { + EntityBase sPart; + + m_scene.Entities.TryGetValue(eb, out sPart); + + // Dont process if this message is from itself! + if (eb.ToString().Equals(sourceItemID) || + sPart.UUID.ToString().Equals(sourceItemID) ) + continue; + + double dis = 0; + + if (source != null) + dis = sPart.AbsolutePosition.GetDistanceTo(source.AbsolutePosition); + else + dis = sPart.AbsolutePosition.GetDistanceTo(avatar.AbsolutePosition); + + switch (type) + { + case 0: // Whisper + + if ((dis < 10) && (dis > -10)) + { + ListenerInfo isListener = m_listenerManager.IsListenerMatch( + sourceItemID, sPart.UUID, channel, name, msg + ); + if (isListener != null) + { + m_pending.Enqueue(isListener); + } + + } + break; + + case 1: // Say + + if ((dis < 30) && (dis > -30)) + { + ListenerInfo isListener = m_listenerManager.IsListenerMatch( + sourceItemID, sPart.UUID, channel, name, msg + ); + if (isListener != null) + { + m_pending.Enqueue(isListener); + } + + } + break; + + case 2: // Shout + if ((dis < 100) && (dis > -100)) + { + ListenerInfo isListener = m_listenerManager.IsListenerMatch( + sourceItemID, sPart.UUID, channel, name, msg + ); + if (isListener != null) + { + m_pending.Enqueue(isListener); + } + + } + break; + + case 0xff: // Broadcast + ListenerInfo isListen = m_listenerManager.IsListenerMatch(sourceItemID, eb, channel, name, msg); + if (isListen != null) + { + ListenerInfo isListener = m_listenerManager.IsListenerMatch( + sourceItemID, sPart.UUID, channel, name, msg + ); + if (isListener != null) + { + m_pending.Enqueue(isListener); + } + } + break; + } + }; + + } + + } + + public bool HasMessages() + { + return (m_pending.Count > 0); + } + + public ListenerInfo GetNextMessage() + { + + ListenerInfo li = null; + + lock (CommListLock) + { + li = m_pending.Dequeue(); + } + + return li; + + } + + } + + // hostID: the ID of the ScenePart + // itemID: the ID of the script host engine + // localID: local ID of host engine + public class ListenerManager + { + private Dictionary m_listeners; + private object ListenersLock = new object(); + private int m_MaxListeners = 100; + + public ListenerManager() + { + m_listeners = new Dictionary(); + } + + public int AddListener(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg) + { + + if ( m_listeners.Count < m_MaxListeners ) + { + ListenerInfo isListener = IsListenerMatch(LLUUID.Zero.ToString(), itemID, channel, name, msg); + + if(isListener == null) + { + int newHandle = GetNewHandle(); + + if (newHandle > -1) + { + + ListenerInfo li = new ListenerInfo(localID, newHandle, itemID, hostID, channel, name, id, msg); + + lock (ListenersLock) + { + m_listeners.Add(newHandle, li); + } + + return newHandle; + } + + } + + } + + return -1; + + } + + public void Remove(int handle) + { + m_listeners.Remove(handle); + } + + private int GetNewHandle() + { + + for (int i = 0; i < int.MaxValue - 1; i++) + { + if (!m_listeners.ContainsKey(i)) + return i; + } + + return -1; + + } + + public bool IsListener(LLUUID hostID) + { + + foreach (ListenerInfo li in m_listeners.Values) + { + if (li.GetHostID().Equals(hostID)) + return true; + } + + return false; + + } + + public void Activate(int handle) + { + + ListenerInfo li; + + if( m_listeners.TryGetValue(handle, out li) ) + { + li.Activate(); + } + } + + public void Dectivate(int handle) + { + + ListenerInfo li; + + if( m_listeners.TryGetValue(handle, out li) ) + { + li.Deactivate(); + } + } + + // Theres probably a more clever and efficient way to + // do this, maybe with regex. + public ListenerInfo IsListenerMatch(string sourceItemID, LLUUID listenerKey, int channel, string name, string msg) + { + + bool isMatch = true; + + foreach (ListenerInfo li in m_listeners.Values) + { + if (li.GetHostID().Equals(listenerKey)) + { + if ( li.IsActive() ) + { + if ( channel == li.GetChannel() ) + { + if ( (li.GetID().ToString().Length > 0) && + (!li.GetID().Equals(LLUUID.Zero)) ) + { + if (!li.GetID().ToString().Equals(sourceItemID)) + { + isMatch = false; + } + } + if ( isMatch && (li.GetName().Length > 0) ) + { + if ( li.GetName().Equals(name) ) + { + isMatch = false; + } + } + if ( isMatch ) + { + return new ListenerInfo( + li.GetLocalID(), li.GetHandle(), li.GetItemID(), li.GetHostID(), + li.GetChannel(), name, li.GetID(), msg, new LLUUID(sourceItemID) + ); + } + } + } + } + } + return null; + } + + } + + public class ListenerInfo + { + + private LLUUID m_itemID; // ID of the host script engine + private LLUUID m_hostID; // ID of the host/scene part + private LLUUID m_sourceItemID; // ID of the scenePart or avatar source of the message + private int m_channel; // Channel + private int m_handle; // Assigned handle of this listener + private uint m_localID; // Local ID from script engine + private string m_name; // Object name to filter messages from + private LLUUID m_id; // ID to filter messages from + private string m_message; // The message + private bool m_active; // Listener is active or not + + public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message) + { + Initialise(localID, handle, ItemID, hostID, channel, name, id, message); + } + + public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message, LLUUID sourceItemID) + { + Initialise(localID, handle, ItemID, hostID, channel, name, id, message); + m_sourceItemID = sourceItemID; + } + + private void Initialise(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message) + { + m_handle = handle; + m_channel = channel; + m_itemID = ItemID; + m_hostID = hostID; + m_name = name; + m_id = id; + m_message = message; + m_active = true; + m_localID = localID; + } + public LLUUID GetItemID() + { + return m_itemID; + } + public LLUUID GetHostID() + { + return m_hostID; + } + public LLUUID GetSourceItemID() + { + return m_sourceItemID; + } + public int GetChannel() + { + return m_channel; + } + public uint GetLocalID() + { + return m_localID; + } + public int GetHandle() + { + return m_handle; + } + public string GetMessage() + { + return m_message; + } + public string GetName() + { + return m_name; + } + public bool IsActive() + { + return m_active; + } + public void Deactivate() + { + m_active = false; + } + public void Activate() + { + m_active = true; + } + public LLUUID GetID() + { + return m_id; + } + + } + +} diff --git a/OpenSim/Region/Environment/Modules/XMLRPCModule.cs b/OpenSim/Region/Environment/Modules/XMLRPCModule.cs new file mode 100644 index 0000000000..50ed7760df --- /dev/null +++ b/OpenSim/Region/Environment/Modules/XMLRPCModule.cs @@ -0,0 +1,360 @@ +using System; +using System.IO; +using System.Net.Sockets; +using System.Threading; +using libsecondlife; +using OpenSim.Framework.Interfaces; +using OpenSim.Framework.Utilities; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Framework.Servers; +using Nwc.XmlRpc; +using System.Collections; +using System.Collections.Generic; + +/***************************************************** + * + * XMLRPCModule + * + * Module for accepting incoming communications from + * external XMLRPC client and calling a remote data + * procedure for a registered data channel/prim. + * + * + * 1. On module load, open a listener port + * 2. Attach an XMLRPC handler + * 3. When a request is received: + * 3.1 Parse into components: channel key, int, string + * 3.2 Look up registered channel listeners + * 3.3 Call the channel (prim) remote data method + * 3.4 Capture the response (llRemoteDataReply) + * 3.5 Return response to client caller + * 3.6 If no response from llRemoteDataReply within + * RemoteReplyScriptTimeout, generate script timeout fault + * + * Prims in script must: + * 1. Open a remote data channel + * 1.1 Generate a channel ID + * 1.2 Register primid,channelid pair with module + * 2. Implement the remote data procedure handler + * + * llOpenRemoteDataChannel + * llRemoteDataReply + * remote_data(integer type, key channel, key messageid, string sender, integer ival, string sval) + * llCloseRemoteDataChannel + * + * **************************************************/ +namespace OpenSim.Region.Environment.Modules +{ + public class XMLRPCModule : IRegionModule, IXMLRPC + { + private Scene m_scene; + private Queue rpcQueue = new Queue(); + private object XMLRPCListLock = new object(); + private string m_name = "XMLRPCModule"; + private int RemoteReplyScriptWait = 100; + private int RemoteReplyScriptTimeout = 300; + + // + private Dictionary m_openChannels; + + // + private Dictionary m_pendingResponse; + + public XMLRPCModule() + { + } + + public void Initialise(Scene scene) + { + m_scene = scene; + + m_scene.RegisterModuleInterface(this); + + m_openChannels = new Dictionary(); + m_pendingResponse = new Dictionary(); + + // Start http server + // Attach xmlrpc handlers + BaseHttpServer httpServer = new BaseHttpServer(20800); + httpServer.AddXmlRPCHandler("llRemoteData", this.XmlRpcRemoteData); + httpServer.Start(); + } + + public void PostInitialise() + { + } + + public void CloseDown() + { + } + + public string GetName() + { + return m_name; + } + + public bool IsSharedModule() + { + return false; + } + + /********************************************** + * OpenXMLRPCChannel + * + * Generate a LLUUID channel key and add it and + * the prim id to dictionary + * + * First check if there is a channel assigned for + * this itemID. If there is, then someone called + * llOpenRemoteDataChannel twice. Just return the + * original channel. Other option is to delete the + * current channel and assign a new one. + * + * ********************************************/ + public LLUUID OpenXMLRPCChannel(uint localID, LLUUID itemID) + { + LLUUID channel = null; + + //Is a dupe? + foreach (RPCChannelInfo ci in m_openChannels.Values) + { + if (ci.GetItemID().Equals(itemID)) + { + // return the original channel ID for this item + channel = ci.GetChannelID(); + break; + } + } + + if ( (channel == null) || (channel.Equals(LLUUID.Zero)) ) + { + channel = LLUUID.Random(); + RPCChannelInfo rpcChanInfo = new RPCChannelInfo(localID, itemID, channel); + lock (XMLRPCListLock) + { + m_openChannels.Add(channel, rpcChanInfo); + } + + } + + return channel; + } + + /********************************************** + * Remote Data Reply + * + * Response to RPC message + * + *********************************************/ + public void RemoteDataReply(string channel, string message_id, string sdata, int idata) + { + RPCRequestInfo rpcInfo; + LLUUID message_key = new LLUUID(message_id); + + if (m_pendingResponse.TryGetValue(message_key, out rpcInfo)) + { + rpcInfo.SetRetval(sdata); + rpcInfo.SetProcessed(true); + + lock (XMLRPCListLock) + { + m_pendingResponse.Remove(message_key); + } + } + + } + + /********************************************** + * CloseXMLRPCChannel + * + * Remove channel from dictionary + * + *********************************************/ + public void CloseXMLRPCChannel(LLUUID channelKey) + { + if(m_openChannels.ContainsKey(channelKey)) + m_openChannels.Remove(channelKey); + } + + + public XmlRpcResponse XmlRpcRemoteData(XmlRpcRequest request) + { + + XmlRpcResponse response = new XmlRpcResponse(); + + Hashtable requestData = (Hashtable)request.Params[0]; + bool GoodXML = (requestData.Contains("Channel") && requestData.Contains("IntValue") && requestData.Contains("StringValue")); + + if (GoodXML) + { + LLUUID channel = new LLUUID((string)requestData["Channel"]); + RPCChannelInfo rpcChanInfo; + if (m_openChannels.TryGetValue(channel, out rpcChanInfo)) + { + string intVal = (string)requestData["IntValue"]; + string strVal = (string)requestData["StringValue"]; + + RPCRequestInfo rpcInfo; + + lock (XMLRPCListLock) + { + rpcInfo = new RPCRequestInfo(rpcChanInfo.GetLocalID(), rpcChanInfo.GetItemID(), channel, strVal, intVal); + rpcQueue.Enqueue(rpcInfo); + } + + int timeoutCtr = 0; + + while(!rpcInfo.IsProcessed() && (timeoutCtr < RemoteReplyScriptTimeout)) + { + Thread.Sleep(RemoteReplyScriptWait); + timeoutCtr += RemoteReplyScriptWait; + } + if (rpcInfo.IsProcessed()) + { + response.Value = rpcInfo.GetRetval(); + rpcInfo = null; + } + else + { + response.SetFault(-1, "Script timeout"); + lock (XMLRPCListLock) + { + m_pendingResponse.Remove(rpcInfo.GetMessageID()); + } + } + + } + else + { + response.SetFault(-1, "Invalid channel"); + } + + } + + return response; + } + + public bool hasRequests() + { + return (rpcQueue.Count > 0); + } + + public RPCRequestInfo GetNextRequest() + { + lock (XMLRPCListLock) + { + RPCRequestInfo rpcInfo = rpcQueue.Dequeue(); + m_pendingResponse.Add(rpcInfo.GetMessageID(), rpcInfo); + return rpcInfo; + } + } + + } + + /************************************************************** + * + * Class RPCRequestInfo + * + * Holds details about incoming requests until they are picked + * from the queue by LSLLongCmdHandler + * ***********************************************************/ + public class RPCRequestInfo + { + private string m_StrVal; + private string m_IntVal; + private bool m_processed; + private string m_resp; + private uint m_localID; + private LLUUID m_ItemID; + private LLUUID m_MessageID; + private LLUUID m_ChannelKey; + + public RPCRequestInfo(uint localID, LLUUID itemID, LLUUID channelKey, string strVal, string intVal) + { + m_localID = localID; + m_StrVal = strVal; + m_IntVal = intVal; + m_ItemID = itemID; + m_ChannelKey = channelKey; + m_MessageID = LLUUID.Random(); + m_processed = false; + m_resp = ""; + } + + public bool IsProcessed() + { + return m_processed; + } + public LLUUID GetChannelKey() + { + return m_ChannelKey; + } + + public void SetProcessed(bool processed) + { + m_processed = processed; + } + public void SetRetval(string resp) + { + m_resp = resp; + } + public string GetRetval() + { + return m_resp; + } + public uint GetLocalID() + { + return m_localID; + } + public LLUUID GetItemID() + { + return m_ItemID; + } + public string GetStrVal() + { + return m_StrVal; + } + public int GetIntValue() + { + return int.Parse(m_IntVal); + } + public LLUUID GetMessageID() + { + return m_MessageID; + } + + + } + + public class RPCChannelInfo + { + private LLUUID m_itemID; + private uint m_localID; + private LLUUID m_ChannelKey; + + public RPCChannelInfo(uint localID, LLUUID itemID, LLUUID channelID) + { + m_ChannelKey = channelID; + m_localID = localID; + m_itemID = itemID; + } + + public LLUUID GetItemID() + { + return m_itemID; + } + + public LLUUID GetChannelID() + { + return m_ChannelKey; + } + + public uint GetLocalID() + { + return m_localID; + } + + } + +} diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index 579ec9062d..9e19a268e3 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs @@ -91,6 +91,8 @@ namespace OpenSim.Region.Environment.Scenes private IHttpRequests m_httpRequestModule = null; private ISimChat m_simChatModule = null; + private IXMLRPC m_xmlrpcModule = null; + private IWorldComm m_worldCommModule = null; // Central Update Loop @@ -210,6 +212,8 @@ namespace OpenSim.Region.Environment.Scenes { m_simChatModule = RequestModuleInterface(); m_httpRequestModule = RequestModuleInterface(); + m_xmlrpcModule = RequestModuleInterface(); + m_worldCommModule = RequestModuleInterface(); XferManager = RequestModuleInterface(); } diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/Server_API/LSL_BuiltIn_Commands.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/Server_API/LSL_BuiltIn_Commands.cs index 6838f470b1..3985273b0c 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/Server_API/LSL_BuiltIn_Commands.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/Compiler/Server_API/LSL_BuiltIn_Commands.cs @@ -177,14 +177,19 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler //type for whisper is 0 World.SimChat(Helpers.StringToField(text), 0, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID); + + IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); + wComm.DeliverMessage(m_host.UUID.ToString(), 0, channelID, m_host.Name, text); } public void llSay(int channelID, string text) { //type for say is 1 - World.SimChat(Helpers.StringToField(text), 1, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID); + + IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); + wComm.DeliverMessage(m_host.UUID.ToString(), 1, channelID, m_host.Name, text); } public void llShout(int channelID, string text) @@ -192,11 +197,32 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler //type for shout is 2 World.SimChat(Helpers.StringToField(text), 2, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID); + + IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); + wComm.DeliverMessage(m_host.UUID.ToString(), 2, channelID, m_host.Name, text); + } + + public int llListen(int channelID, string name, string ID, string msg) { + + IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); + return wComm.Listen(m_localID, m_itemID, m_host.UUID, channelID, name, ID, msg); + + } + + public void llListenControl(int number, int active) { + + IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); + wComm.ListenControl(number, active); + + } + + public void llListenRemove(int number) { + + IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); + wComm.ListenRemove(number); + } - public int llListen(int channelID, string name, string ID, string msg) { NotImplemented("llListen"); return 0; } - public void llListenControl(int number, int active) { NotImplemented("llListenControl"); return; } - public void llListenRemove(int number) { NotImplemented("llListenRemove"); return; } public void llSensor(string name, string id, int type, double range, double arc) { NotImplemented("llSensor"); return; } public void llSensorRepeat(string name, string id, int type, double range, double arc, double rate) { NotImplemented("llSensorRepeat"); return; } public void llSensorRemove() { NotImplemented("llSensorRemove"); return; } @@ -927,10 +953,37 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine.Compiler public void llRemoteLoadScript() { NotImplemented("llRemoteLoadScript"); } public void llSetRemoteScriptAccessPin(int pin) { NotImplemented("llSetRemoteScriptAccessPin"); } public void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param) { NotImplemented("llRemoteLoadScriptPin"); } - public void llOpenRemoteDataChannel() { NotImplemented("llOpenRemoteDataChannel"); } + + // remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval) + // Not sure where these constants should live: + // REMOTE_DATA_CHANNEL = 1 + // REMOTE_DATA_REQUEST = 2 + // REMOTE_DATA_REPLY = 3 + public void llOpenRemoteDataChannel() { + + IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); + LLUUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_localID, m_itemID); + object[] resobj = new object[] { 1, channelID.ToString(), LLUUID.Zero.ToString(), "", 0, "" }; + m_ScriptEngine.m_EventQueueManager.AddToScriptQueue(m_localID, m_itemID, "remote_data", resobj); + + } + public string llSendRemoteData(string channel, string dest, int idata, string sdata) { NotImplemented("llSendRemoteData"); return ""; } - public void llRemoteDataReply(string channel, string message_id, string sdata, int idata) { NotImplemented("llRemoteDataReply"); } - public void llCloseRemoteDataChannel(string channel) { NotImplemented("llCloseRemoteDataChannel"); } + + public void llRemoteDataReply(string channel, string message_id, string sdata, int idata) + { + + IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); + xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata); + + } + + public void llCloseRemoteDataChannel(string channel) { + + IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); + xmlrpcMod.CloseXMLRPCChannel(channel); + + } public string llMD5String(string src, int nonce) { diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/LSLLongCmdHandler.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/LSLLongCmdHandler.cs index 8ab0c306b7..5b92ff045e 100644 --- a/OpenSim/Region/ScriptEngine/DotNetEngine/LSLLongCmdHandler.cs +++ b/OpenSim/Region/ScriptEngine/DotNetEngine/LSLLongCmdHandler.cs @@ -4,6 +4,8 @@ using System.Text; using System.Threading; using libsecondlife; using OpenSim.Region.ScriptEngine.Common; +using OpenSim.Region.Environment.Modules; +using OpenSim.Region.Environment.Interfaces; namespace OpenSim.Region.ScriptEngine.DotNetEngine { @@ -26,6 +28,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine cmdHandlerThread.Priority = ThreadPriority.BelowNormal; cmdHandlerThread.IsBackground = true; cmdHandlerThread.Start(); + } ~LSLLongCmdHandler() { @@ -50,11 +53,19 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine { // 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); + //Thread.Sleep(cmdHandlerThreadCycleSleepms); } } @@ -258,5 +269,53 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine } #endregion + public void CheckXMLRPCRequests() + { + + IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface(); + + while (xmlrpc.hasRequests()) + { + RPCRequestInfo rInfo = xmlrpc.GetNextRequest(); + System.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(); + + while (comms.HasMessages()) + { + ListenerInfo lInfo = comms.GetNextMessage(); + System.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 + ); + + } + + } + + + + } } diff --git a/prebuild.xml b/prebuild.xml index 543f475eed..a551f1b0fb 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -474,6 +474,7 @@ +