/* * Copyright (c) 2007-2008, openmetaverse.org * All rights reserved. * * - 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. * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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.Text; using System.Threading; using OpenMetaverse.Packets; namespace OpenMetaverse { /// /// 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 NetworkManager.PacketCallback Callback; /// Reference to the simulator that this packet came from public Simulator Simulator; /// The packet that needs to be processed public Packet Packet; } /// Reference to the GridClient object public GridClient Client; private Dictionary _EventTable = new Dictionary(); private WaitCallback _ThreadPoolCallback; /// /// Default constructor /// /// public PacketEventDictionary(GridClient client) { Client = client; _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, NetworkManager.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, NetworkManager.PacketCallback eventHandler) { lock (_EventTable) { if (_EventTable.ContainsKey(packetType) && _EventTable[packetType] != null) _EventTable[packetType] -= eventHandler; } } /// /// Fire the events registered for this packet type synchronously /// /// Incoming packet type /// Incoming packet /// Simulator this packet was received from internal void RaiseEvent(PacketType packetType, Packet packet, Simulator simulator) { NetworkManager.PacketCallback callback; // Default handler first, if one exists if (_EventTable.TryGetValue(PacketType.Default, out callback)) { try { callback(packet, simulator); } catch (Exception ex) { Logger.Log("Default packet event handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); } } if (_EventTable.TryGetValue(packetType, out callback)) { try { callback(packet, simulator); } catch (Exception ex) { Logger.Log("Packet event handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); } return; } if (packetType != PacketType.Default && packetType != PacketType.PacketAck) { Logger.DebugLog("No handler registered for packet event " + packetType, Client); } } /// /// Fire the events registered for this packet type asynchronously /// /// Incoming packet type /// Incoming packet /// Simulator this packet was received from internal void BeginRaiseEvent(PacketType packetType, Packet packet, Simulator simulator) { NetworkManager.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.Simulator = simulator; ThreadPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); } } if (_EventTable.TryGetValue(packetType, out callback)) { if (callback != null) { wrapper.Callback = callback; wrapper.Packet = packet; wrapper.Simulator = simulator; ThreadPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); return; } } if (packetType != PacketType.Default && packetType != PacketType.PacketAck) { Logger.DebugLog("No handler registered for packet event " + packetType, Client); } } private void ThreadPoolDelegate(Object state) { PacketCallbackWrapper wrapper = (PacketCallbackWrapper)state; try { wrapper.Callback(wrapper.Packet, wrapper.Simulator); } catch (Exception ex) { Logger.Log("Async Packet Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); } } } /// /// Registers, unregisters, and fires events generated by the Capabilities /// event queue /// public class CapsEventDictionary { /// /// Object that is passed to worker threads in the ThreadPool for /// firing CAPS callbacks /// private struct CapsCallbackWrapper { /// Callback to fire for this packet public Caps.EventQueueCallback Callback; /// Name of the CAPS event public string CapsEvent; /// Decoded body of the CAPS event public StructuredData.OSD Body; /// Reference to the simulator that generated this event public Simulator Simulator; } /// Reference to the GridClient object public GridClient Client; private Dictionary _EventTable = new Dictionary(); private WaitCallback _ThreadPoolCallback; /// /// Default constructor /// /// Reference to the GridClient object public CapsEventDictionary(GridClient client) { Client = client; _ThreadPoolCallback = new WaitCallback(ThreadPoolDelegate); } /// /// Register an event handler /// /// Use String.Empty to fire this event on every CAPS event /// Capability event name to register the /// handler for /// Callback to fire public void RegisterEvent(string capsEvent, Caps.EventQueueCallback eventHandler) { lock (_EventTable) { if (_EventTable.ContainsKey(capsEvent)) _EventTable[capsEvent] += eventHandler; else _EventTable[capsEvent] = eventHandler; } } /// /// /// /// Capability event name unregister the /// handler for /// Callback to unregister public void UnregisterEvent(string capsEvent, Caps.EventQueueCallback eventHandler) { lock (_EventTable) { if (_EventTable.ContainsKey(capsEvent) && _EventTable[capsEvent] != null) _EventTable[capsEvent] -= eventHandler; } } /// /// Fire the events registered for this event type synchronously /// /// Capability name /// Decoded event body /// Reference to the simulator that /// generated this event internal void RaiseEvent(string capsEvent, StructuredData.OSD body, Simulator simulator) { bool specialHandler = false; Caps.EventQueueCallback callback; // Default handler first, if one exists if (_EventTable.TryGetValue(capsEvent, out callback)) { if (callback != null) { try { callback(capsEvent, body, simulator); } catch (Exception ex) { Logger.Log("CAPS Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); } } } // Generic parser next if (body.Type == StructuredData.OSDType.Map) { StructuredData.OSDMap map = (StructuredData.OSDMap)body; Packet packet = Packet.BuildPacket(capsEvent, map); if (packet != null) { NetworkManager.IncomingPacket incomingPacket; incomingPacket.Simulator = simulator; incomingPacket.Packet = packet; Logger.DebugLog("Serializing " + packet.Type.ToString() + " capability with generic handler", Client); Client.Network.PacketInbox.Enqueue(incomingPacket); specialHandler = true; } } // Explicit handler next if (_EventTable.TryGetValue(capsEvent, out callback) && callback != null) { try { callback(capsEvent, body, simulator); } catch (Exception ex) { Logger.Log("CAPS Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); } specialHandler = true; } if (!specialHandler) Logger.Log("Unhandled CAPS event " + capsEvent, Helpers.LogLevel.Warning, Client); } /// /// Fire the events registered for this event type asynchronously /// /// Capability name /// Decoded event body /// Reference to the simulator that /// generated this event internal void BeginRaiseEvent(string capsEvent, StructuredData.OSD body, Simulator simulator) { bool specialHandler = false; Caps.EventQueueCallback callback; // Default handler first, if one exists if (_EventTable.TryGetValue(String.Empty, out callback)) { if (callback != null) { CapsCallbackWrapper wrapper; wrapper.Callback = callback; wrapper.CapsEvent = capsEvent; wrapper.Body = body; wrapper.Simulator = simulator; ThreadPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); } } // Generic parser next, don't generic parse events we've manually registered for if (body.Type == StructuredData.OSDType.Map && !_EventTable.ContainsKey(capsEvent)) { StructuredData.OSDMap map = (StructuredData.OSDMap)body; Packet packet = Packet.BuildPacket(capsEvent, map); if (packet != null) { NetworkManager.IncomingPacket incomingPacket; incomingPacket.Simulator = simulator; incomingPacket.Packet = packet; Logger.DebugLog("Serializing " + packet.Type.ToString() + " capability with generic handler", Client); Client.Network.PacketInbox.Enqueue(incomingPacket); specialHandler = true; } } // Explicit handler next if (_EventTable.TryGetValue(capsEvent, out callback) && callback != null) { CapsCallbackWrapper wrapper; wrapper.Callback = callback; wrapper.CapsEvent = capsEvent; wrapper.Body = body; wrapper.Simulator = simulator; ThreadPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper); specialHandler = true; } if (!specialHandler) Logger.Log("Unhandled CAPS event " + capsEvent, Helpers.LogLevel.Warning, Client); } private void ThreadPoolDelegate(Object state) { CapsCallbackWrapper wrapper = (CapsCallbackWrapper)state; try { wrapper.Callback(wrapper.CapsEvent, wrapper.Body, wrapper.Simulator); } catch (Exception ex) { Logger.Log("Async CAPS Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); } } } }