corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Collections.Generic;
29 using System.Text;
30 using System.Threading;
31 using OpenMetaverse.Packets;
32 using OpenMetaverse.Messages.Linden;
33 using OpenMetaverse.Interfaces;
34  
35 namespace OpenMetaverse
36 {
37 /// <summary>
38 /// Registers, unregisters, and fires events generated by incoming packets
39 /// </summary>
40 public class PacketEventDictionary
41 {
42 private sealed class PacketCallback
43 {
44 public EventHandler<PacketReceivedEventArgs> Callback;
45 public bool IsAsync;
46  
47 public PacketCallback(EventHandler<PacketReceivedEventArgs> callback, bool isAsync)
48 {
49 Callback = callback;
50 IsAsync = isAsync;
51 }
52 }
53  
54 /// <summary>
55 /// Object that is passed to worker threads in the ThreadPool for
56 /// firing packet callbacks
57 /// </summary>
58 private struct PacketCallbackWrapper
59 {
60 /// <summary>Callback to fire for this packet</summary>
61 public EventHandler<PacketReceivedEventArgs> Callback;
62 /// <summary>Reference to the simulator that this packet came from</summary>
63 public Simulator Simulator;
64 /// <summary>The packet that needs to be processed</summary>
65 public Packet Packet;
66 }
67  
68 /// <summary>Reference to the GridClient object</summary>
69 public GridClient Client;
70  
71 private Dictionary<PacketType, PacketCallback> _EventTable = new Dictionary<PacketType, PacketCallback>();
72  
73 /// <summary>
74 /// Default constructor
75 /// </summary>
76 /// <param name="client"></param>
77 public PacketEventDictionary(GridClient client)
78 {
79 Client = client;
80 }
81  
82 /// <summary>
83 /// Register an event handler
84 /// </summary>
85 /// <remarks>Use PacketType.Default to fire this event on every
86 /// incoming packet</remarks>
87 /// <param name="packetType">Packet type to register the handler for</param>
88 /// <param name="eventHandler">Callback to be fired</param>
89 /// <param name="isAsync">True if this callback should be ran
90 /// asynchronously, false to run it synchronous</param>
91 public void RegisterEvent(PacketType packetType, EventHandler<PacketReceivedEventArgs> eventHandler, bool isAsync)
92 {
93 lock (_EventTable)
94 {
95 PacketCallback callback;
96 if (_EventTable.TryGetValue(packetType, out callback))
97 {
98 callback.Callback += eventHandler;
99 callback.IsAsync = callback.IsAsync || isAsync;
100 }
101 else
102 {
103 callback = new PacketCallback(eventHandler, isAsync);
104 _EventTable[packetType] = callback;
105 }
106 }
107 }
108  
109 /// <summary>
110 /// Unregister an event handler
111 /// </summary>
112 /// <param name="packetType">Packet type to unregister the handler for</param>
113 /// <param name="eventHandler">Callback to be unregistered</param>
114 public void UnregisterEvent(PacketType packetType, EventHandler<PacketReceivedEventArgs> eventHandler)
115 {
116 lock (_EventTable)
117 {
118 PacketCallback callback;
119 if (_EventTable.TryGetValue(packetType, out callback))
120 {
121 callback.Callback -= eventHandler;
122 if (callback.Callback == null || callback.Callback.GetInvocationList().Length == 0)
123 _EventTable.Remove(packetType);
124 }
125 }
126 }
127  
128 /// <summary>
129 /// Fire the events registered for this packet type
130 /// </summary>
131 /// <param name="packetType">Incoming packet type</param>
132 /// <param name="packet">Incoming packet</param>
133 /// <param name="simulator">Simulator this packet was received from</param>
134 internal void RaiseEvent(PacketType packetType, Packet packet, Simulator simulator)
135 {
136 PacketCallback callback;
137  
138 // Default handler first, if one exists
139 if (_EventTable.TryGetValue(PacketType.Default, out callback) && callback.Callback != null)
140 {
141 if (callback.IsAsync)
142 {
143 PacketCallbackWrapper wrapper;
144 wrapper.Callback = callback.Callback;
145 wrapper.Packet = packet;
146 wrapper.Simulator = simulator;
147 WorkPool.QueueUserWorkItem(ThreadPoolDelegate, wrapper);
148 }
149 else
150 {
151 try { callback.Callback(this, new PacketReceivedEventArgs(packet, simulator)); }
152 catch (Exception ex)
153 {
154 Logger.Log("Default packet event handler: " + ex.ToString(), Helpers.LogLevel.Error, Client);
155 }
156 }
157 }
158  
159 if (_EventTable.TryGetValue(packetType, out callback) && callback.Callback != null)
160 {
161 if (callback.IsAsync)
162 {
163 PacketCallbackWrapper wrapper;
164 wrapper.Callback = callback.Callback;
165 wrapper.Packet = packet;
166 wrapper.Simulator = simulator;
167 WorkPool.QueueUserWorkItem(ThreadPoolDelegate, wrapper);
168 }
169 else
170 {
171 try { callback.Callback(this, new PacketReceivedEventArgs(packet, simulator)); }
172 catch (Exception ex)
173 {
174 Logger.Log("Packet event handler: " + ex.ToString(), Helpers.LogLevel.Error, Client);
175 }
176 }
177  
178 return;
179 }
180  
181 if (packetType != PacketType.Default && packetType != PacketType.PacketAck)
182 {
183 Logger.DebugLog("No handler registered for packet event " + packetType, Client);
184 }
185 }
186  
187 private void ThreadPoolDelegate(Object state)
188 {
189 PacketCallbackWrapper wrapper = (PacketCallbackWrapper)state;
190  
191 try
192 {
193 wrapper.Callback(this, new PacketReceivedEventArgs(wrapper.Packet, wrapper.Simulator));
194 }
195 catch (Exception ex)
196 {
197 Logger.Log("Async Packet Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client);
198 }
199 }
200 }
201  
202 /// <summary>
203 /// Registers, unregisters, and fires events generated by the Capabilities
204 /// event queue
205 /// </summary>
206 public class CapsEventDictionary
207 {
208 /// <summary>
209 /// Object that is passed to worker threads in the ThreadPool for
210 /// firing CAPS callbacks
211 /// </summary>
212 private struct CapsCallbackWrapper
213 {
214 /// <summary>Callback to fire for this packet</summary>
215 public Caps.EventQueueCallback Callback;
216 /// <summary>Name of the CAPS event</summary>
217 public string CapsEvent;
218 /// <summary>Strongly typed decoded data</summary>
219 public IMessage Message;
220 /// <summary>Reference to the simulator that generated this event</summary>
221 public Simulator Simulator;
222 }
223  
224 /// <summary>Reference to the GridClient object</summary>
225 public GridClient Client;
226  
227 private Dictionary<string, Caps.EventQueueCallback> _EventTable =
228 new Dictionary<string, Caps.EventQueueCallback>();
229 private WaitCallback _ThreadPoolCallback;
230  
231 /// <summary>
232 /// Default constructor
233 /// </summary>
234 /// <param name="client">Reference to the GridClient object</param>
235 public CapsEventDictionary(GridClient client)
236 {
237 Client = client;
238 _ThreadPoolCallback = new WaitCallback(ThreadPoolDelegate);
239 }
240  
241 /// <summary>
242 /// Register an new event handler for a capabilities event sent via the EventQueue
243 /// </summary>
244 /// <remarks>Use String.Empty to fire this event on every CAPS event</remarks>
245 /// <param name="capsEvent">Capability event name to register the
246 /// handler for</param>
247 /// <param name="eventHandler">Callback to fire</param>
248 public void RegisterEvent(string capsEvent, Caps.EventQueueCallback eventHandler)
249 {
250 // TODO: Should we add support for synchronous CAPS handlers?
251 lock (_EventTable)
252 {
253 if (_EventTable.ContainsKey(capsEvent))
254 _EventTable[capsEvent] += eventHandler;
255 else
256 _EventTable[capsEvent] = eventHandler;
257 }
258 }
259  
260 /// <summary>
261 /// Unregister a previously registered capabilities handler
262 /// </summary>
263 /// <param name="capsEvent">Capability event name unregister the
264 /// handler for</param>
265 /// <param name="eventHandler">Callback to unregister</param>
266 public void UnregisterEvent(string capsEvent, Caps.EventQueueCallback eventHandler)
267 {
268 lock (_EventTable)
269 {
270 if (_EventTable.ContainsKey(capsEvent) && _EventTable[capsEvent] != null)
271 _EventTable[capsEvent] -= eventHandler;
272 }
273 }
274  
275 /// <summary>
276 /// Fire the events registered for this event type synchronously
277 /// </summary>
278 /// <param name="capsEvent">Capability name</param>
279 /// <param name="message">Decoded event body</param>
280 /// <param name="simulator">Reference to the simulator that
281 /// generated this event</param>
282 internal void RaiseEvent(string capsEvent, IMessage message, Simulator simulator)
283 {
284 bool specialHandler = false;
285 Caps.EventQueueCallback callback;
286  
287 // Default handler first, if one exists
288 if (_EventTable.TryGetValue(capsEvent, out callback))
289 {
290 if (callback != null)
291 {
292 try { callback(capsEvent, message, simulator); }
293 catch (Exception ex) { Logger.Log("CAPS Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); }
294 }
295 }
296  
297 // Explicit handler next
298 if (_EventTable.TryGetValue(capsEvent, out callback) && callback != null)
299 {
300 try { callback(capsEvent, message, simulator); }
301 catch (Exception ex) { Logger.Log("CAPS Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); }
302  
303 specialHandler = true;
304 }
305  
306 if (!specialHandler)
307 Logger.Log("Unhandled CAPS event " + capsEvent, Helpers.LogLevel.Warning, Client);
308 }
309  
310 /// <summary>
311 /// Fire the events registered for this event type asynchronously
312 /// </summary>
313 /// <param name="capsEvent">Capability name</param>
314 /// <param name="message">Decoded event body</param>
315 /// <param name="simulator">Reference to the simulator that
316 /// generated this event</param>
317 internal void BeginRaiseEvent(string capsEvent, IMessage message, Simulator simulator)
318 {
319 bool specialHandler = false;
320 Caps.EventQueueCallback callback;
321  
322 // Default handler first, if one exists
323 if (_EventTable.TryGetValue(String.Empty, out callback))
324 {
325 if (callback != null)
326 {
327 callback(capsEvent, message, simulator);
328 // CapsCallbackWrapper wrapper;
329 // wrapper.Callback = callback;
330 // wrapper.CapsEvent = capsEvent;
331 // wrapper.Message = message;
332 // wrapper.Simulator = simulator;
333 // WorkPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper);
334 }
335 }
336  
337 // Explicit handler next
338 if (_EventTable.TryGetValue(capsEvent, out callback) && callback != null)
339 {
340 callback(capsEvent, message, simulator);
341  
342 // CapsCallbackWrapper wrapper;
343 // wrapper.Callback = callback;
344 // wrapper.CapsEvent = capsEvent;
345 // wrapper.Message = message;
346 // wrapper.Simulator = simulator;
347 // WorkPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper);
348  
349 specialHandler = true;
350 }
351  
352 if (!specialHandler)
353 Logger.Log("Unhandled CAPS event " + capsEvent, Helpers.LogLevel.Warning, Client);
354 }
355  
356 private void ThreadPoolDelegate(Object state)
357 {
358 CapsCallbackWrapper wrapper = (CapsCallbackWrapper)state;
359  
360 try
361 {
362 wrapper.Callback(wrapper.CapsEvent, wrapper.Message, wrapper.Simulator);
363 }
364 catch (Exception ex)
365 {
366 Logger.Log("Async CAPS Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client);
367 }
368 }
369 }
370 }