using System; using System.Collections.Generic; using System.Threading; using OpenMetaverse; using OpenMetaverse.Packets; namespace Simian { /// /// Registers, unregisters, and fires events generated by incoming packets /// public class PacketEventDictionary { /// /// Object that is passed to worker threads in the ThreadPool for /// firing packet callbacks /// private struct PacketCallbackWrapper { /// Callback to fire for this packet public UDPServer.PacketCallback Callback; /// Reference to the agent that this packet came from public Agent Agent; /// The packet that needs to be processed public Packet Packet; } private Dictionary _EventTable = new Dictionary(); private WaitCallback _ThreadPoolCallback; /// /// Default constructor /// public PacketEventDictionary() { _ThreadPoolCallback = new WaitCallback(ThreadPoolDelegate); } /// /// Register an event handler /// /// Use PacketType.Default to fire this event on every /// incoming packet /// Packet type to register the handler for /// Callback to be fired public void RegisterEvent(PacketType packetType, UDPServer.PacketCallback eventHandler) { lock (_EventTable) { if (_EventTable.ContainsKey(packetType)) _EventTable[packetType] += eventHandler; else _EventTable[packetType] = eventHandler; } } /// /// Unregister an event handler /// /// Packet type to unregister the handler for /// Callback to be unregistered public void UnregisterEvent(PacketType packetType, UDPServer.PacketCallback eventHandler) { lock (_EventTable) { if (_EventTable.ContainsKey(packetType) && _EventTable[packetType] != null) _EventTable[packetType] -= eventHandler; } } /// /// Fire the events registered for this packet type asynchronously /// /// Incoming packet type /// Incoming packet /// Agent this packet was received from internal void BeginRaiseEvent(PacketType packetType, Packet packet, Agent agent) { UDPServer.PacketCallback callback; PacketCallbackWrapper wrapper; // Default handler first, if one exists if (_EventTable.TryGetValue(PacketType.Default, out callback)) { if (callback != null) { wrapper.Callback = callback; wrapper.Packet = packet; wrapper.Agent = agent; ThreadPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); } } if (_EventTable.TryGetValue(packetType, out callback)) { if (callback != null) { wrapper.Callback = callback; wrapper.Packet = packet; wrapper.Agent = agent; ThreadPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); return; } } if (packetType != PacketType.Default && packetType != PacketType.PacketAck) { Logger.DebugLog("No handler registered for packet event " + packetType); } } private void ThreadPoolDelegate(Object state) { PacketCallbackWrapper wrapper = (PacketCallbackWrapper)state; try { wrapper.Callback(wrapper.Packet, wrapper.Agent); } catch (Exception ex) { Logger.Log("Async Packet Event Handler: " + ex.ToString(), Helpers.LogLevel.Error); } } } }