clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
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 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Net;
32 using System.Reflection;
33 using System.Threading;
34 using log4net;
35 using Nini.Config;
36 using Mono.Addins;
37 using OpenMetaverse;
38 using OpenMetaverse.Messages.Linden;
39 using OpenMetaverse.Packets;
40 using OpenMetaverse.StructuredData;
41 using OpenSim.Framework;
42 using OpenSim.Framework.Console;
43 using OpenSim.Framework.Servers;
44 using OpenSim.Framework.Servers.HttpServer;
45 using OpenSim.Region.Framework.Interfaces;
46 using OpenSim.Region.Framework.Scenes;
47 using BlockingLLSDQueue = OpenSim.Framework.BlockingQueue<OpenMetaverse.StructuredData.OSD>;
48 using Caps=OpenSim.Framework.Capabilities.Caps;
49  
50 namespace OpenSim.Region.ClientStack.Linden
51 {
52 public struct QueueItem
53 {
54 public int id;
55 public OSDMap body;
56 }
57  
58 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EventQueueGetModule")]
59 public class EventQueueGetModule : IEventQueue, INonSharedRegionModule
60 {
61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62 private static string LogHeader = "[EVENT QUEUE GET MODULE]";
63  
64 /// <value>
65 /// Debug level.
66 /// </value>
67 public int DebugLevel { get; set; }
68  
69 // Viewer post requests timeout in 60 secs
70 // https://bitbucket.org/lindenlab/viewer-release/src/421c20423df93d650cc305dc115922bb30040999/indra/llmessage/llhttpclient.cpp?at=default#cl-44
71 //
72 private const int VIEWER_TIMEOUT = 60 * 1000;
73 // Just to be safe, we work on a 10 sec shorter cycle
74 private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000);
75  
76 protected Scene m_scene;
77  
78 private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>();
79  
80 private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>();
81 private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>();
82 private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>();
83  
84 #region INonSharedRegionModule methods
85 public virtual void Initialise(IConfigSource config)
86 {
87 }
88  
89 public void AddRegion(Scene scene)
90 {
91 m_scene = scene;
92 scene.RegisterModuleInterface<IEventQueue>(this);
93  
94 scene.EventManager.OnClientClosed += ClientClosed;
95 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
96  
97 MainConsole.Instance.Commands.AddCommand(
98 "Debug",
99 false,
100 "debug eq",
101 "debug eq [0|1|2]",
102 "Turn on event queue debugging\n"
103 + " <= 0 - turns off all event queue logging\n"
104 + " >= 1 - turns on event queue setup and outgoing event logging\n"
105 + " >= 2 - turns on poll notification",
106 HandleDebugEq);
107  
108 MainConsole.Instance.Commands.AddCommand(
109 "Debug",
110 false,
111 "show eq",
112 "show eq",
113 "Show contents of event queues for logged in avatars. Used for debugging.",
114 HandleShowEq);
115 }
116  
117 public void RemoveRegion(Scene scene)
118 {
119 if (m_scene != scene)
120 return;
121  
122 scene.EventManager.OnClientClosed -= ClientClosed;
123 scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
124  
125 scene.UnregisterModuleInterface<IEventQueue>(this);
126 m_scene = null;
127 }
128  
129 public void RegionLoaded(Scene scene)
130 {
131 }
132  
133 public virtual void Close()
134 {
135 }
136  
137 public virtual string Name
138 {
139 get { return "EventQueueGetModule"; }
140 }
141  
142 public Type ReplaceableInterface
143 {
144 get { return null; }
145 }
146  
147 #endregion
148  
149 protected void HandleDebugEq(string module, string[] args)
150 {
151 int debugLevel;
152  
153 if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel)))
154 {
155 MainConsole.Instance.OutputFormat("Usage: debug eq [0|1|2]");
156 }
157 else
158 {
159 DebugLevel = debugLevel;
160 MainConsole.Instance.OutputFormat(
161 "Set event queue debug level to {0} in {1}", DebugLevel, m_scene.RegionInfo.RegionName);
162 }
163 }
164  
165 protected void HandleShowEq(string module, string[] args)
166 {
167 MainConsole.Instance.OutputFormat("For scene {0}", m_scene.Name);
168  
169 lock (queues)
170 {
171 foreach (KeyValuePair<UUID, Queue<OSD>> kvp in queues)
172 {
173 MainConsole.Instance.OutputFormat(
174 "For agent {0} there are {1} messages queued for send.",
175 kvp.Key, kvp.Value.Count);
176 }
177 }
178 }
179  
180 /// <summary>
181 /// Always returns a valid queue
182 /// </summary>
183 /// <param name="agentId"></param>
184 /// <returns></returns>
185 private Queue<OSD> TryGetQueue(UUID agentId)
186 {
187 lock (queues)
188 {
189 if (!queues.ContainsKey(agentId))
190 {
191 if (DebugLevel > 0)
192 m_log.DebugFormat(
193 "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}",
194 agentId, m_scene.RegionInfo.RegionName);
195  
196 queues[agentId] = new Queue<OSD>();
197 }
198  
199 return queues[agentId];
200 }
201 }
202  
203 /// <summary>
204 /// May return a null queue
205 /// </summary>
206 /// <param name="agentId"></param>
207 /// <returns></returns>
208 private Queue<OSD> GetQueue(UUID agentId)
209 {
210 lock (queues)
211 {
212 if (queues.ContainsKey(agentId))
213 {
214 return queues[agentId];
215 }
216 else
217 return null;
218 }
219 }
220  
221 #region IEventQueue Members
222  
223 public bool Enqueue(OSD ev, UUID avatarID)
224 {
225 //m_log.DebugFormat("[EVENTQUEUE]: Enqueuing event for {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName);
226 try
227 {
228 Queue<OSD> queue = GetQueue(avatarID);
229 if (queue != null)
230 {
231 lock (queue)
232 queue.Enqueue(ev);
233 }
234 else if (DebugLevel > 0)
235 {
236 ScenePresence sp = m_scene.GetScenePresence(avatarID);
237  
238 // This assumes that an NPC should never have a queue.
239 if (sp != null && sp.PresenceType != PresenceType.Npc)
240 {
241 OSDMap evMap = (OSDMap)ev;
242 m_log.WarnFormat(
243 "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} {1} when placing message {2} in region {3}",
244 sp.Name, sp.UUID, evMap["message"], m_scene.Name);
245 }
246 }
247 }
248 catch (NullReferenceException e)
249 {
250 m_log.Error("[EVENTQUEUE] Caught exception: " + e);
251 return false;
252 }
253  
254 return true;
255 }
256  
257 #endregion
258  
259 private void ClientClosed(UUID agentID, Scene scene)
260 {
261 //m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
262  
263 lock (queues)
264 queues.Remove(agentID);
265  
266 List<UUID> removeitems = new List<UUID>();
267 lock (m_AvatarQueueUUIDMapping)
268 m_AvatarQueueUUIDMapping.Remove(agentID);
269  
270 UUID searchval = UUID.Zero;
271  
272 removeitems.Clear();
273  
274 lock (m_QueueUUIDAvatarMapping)
275 {
276 foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys)
277 {
278 searchval = m_QueueUUIDAvatarMapping[ky];
279  
280 if (searchval == agentID)
281 {
282 removeitems.Add(ky);
283 }
284 }
285  
286 foreach (UUID ky in removeitems)
287 m_QueueUUIDAvatarMapping.Remove(ky);
288 }
289  
290 // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
291  
292 }
293  
294 /// <summary>
295 /// Generate an Event Queue Get handler path for the given eqg uuid.
296 /// </summary>
297 /// <param name='eqgUuid'></param>
298 private string GenerateEqgCapPath(UUID eqgUuid)
299 {
300 return string.Format("/CAPS/EQG/{0}/", eqgUuid);
301 }
302  
303 public void OnRegisterCaps(UUID agentID, Caps caps)
304 {
305 // Register an event queue for the client
306  
307 if (DebugLevel > 0)
308 m_log.DebugFormat(
309 "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}",
310 agentID, caps, m_scene.RegionInfo.RegionName);
311  
312 // Let's instantiate a Queue for this agent right now
313 TryGetQueue(agentID);
314  
315 UUID eventQueueGetUUID;
316  
317 lock (m_AvatarQueueUUIDMapping)
318 {
319 // Reuse open queues. The client does!
320 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
321 {
322 //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!");
323 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
324 }
325 else
326 {
327 eventQueueGetUUID = UUID.Random();
328 //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!");
329 }
330 }
331  
332 lock (m_QueueUUIDAvatarMapping)
333 {
334 if (!m_QueueUUIDAvatarMapping.ContainsKey(eventQueueGetUUID))
335 m_QueueUUIDAvatarMapping.Add(eventQueueGetUUID, agentID);
336 }
337  
338 lock (m_AvatarQueueUUIDMapping)
339 {
340 if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID))
341 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
342 }
343  
344 caps.RegisterPollHandler(
345 "EventQueueGet",
346 new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS));
347  
348 Random rnd = new Random(Environment.TickCount);
349 lock (m_ids)
350 {
351 if (!m_ids.ContainsKey(agentID))
352 m_ids.Add(agentID, rnd.Next(30000000));
353 }
354 }
355  
356 public bool HasEvents(UUID requestID, UUID agentID)
357 {
358 // Don't use this, because of race conditions at agent closing time
359 //Queue<OSD> queue = TryGetQueue(agentID);
360  
361 Queue<OSD> queue = GetQueue(agentID);
362 if (queue != null)
363 lock (queue)
364 {
365 //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count);
366 return queue.Count > 0;
367 }
368  
369 return false;
370 }
371  
372 /// <summary>
373 /// Logs a debug line for an outbound event queue message if appropriate.
374 /// </summary>
375 /// <param name='element'>Element containing message</param>
376 private void LogOutboundDebugMessage(OSD element, UUID agentId)
377 {
378 if (element is OSDMap)
379 {
380 OSDMap ev = (OSDMap)element;
381 m_log.DebugFormat(
382 "Eq OUT {0,-30} to {1,-20} {2,-20}",
383 ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name);
384 }
385 }
386  
387 public Hashtable GetEvents(UUID requestID, UUID pAgentId)
388 {
389 if (DebugLevel >= 2)
390 m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.Name);
391  
392 Queue<OSD> queue = GetQueue(pAgentId);
393 if (queue == null)
394 {
395 return NoEvents(requestID, pAgentId);
396 }
397  
398 OSD element;
399 lock (queue)
400 {
401 if (queue.Count == 0)
402 return NoEvents(requestID, pAgentId);
403 element = queue.Dequeue(); // 15s timeout
404 }
405  
406 int thisID = 0;
407 lock (m_ids)
408 thisID = m_ids[pAgentId];
409  
410 OSDArray array = new OSDArray();
411 if (element == null) // didn't have an event in 15s
412 {
413 // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
414 array.Add(EventQueueHelper.KeepAliveEvent());
415 //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName);
416 }
417 else
418 {
419 if (DebugLevel > 0)
420 LogOutboundDebugMessage(element, pAgentId);
421  
422 array.Add(element);
423  
424 lock (queue)
425 {
426 while (queue.Count > 0)
427 {
428 element = queue.Dequeue();
429  
430 if (DebugLevel > 0)
431 LogOutboundDebugMessage(element, pAgentId);
432  
433 array.Add(element);
434 thisID++;
435 }
436 }
437 }
438  
439 OSDMap events = new OSDMap();
440 events.Add("events", array);
441  
442 events.Add("id", new OSDInteger(thisID));
443 lock (m_ids)
444 {
445 m_ids[pAgentId] = thisID + 1;
446 }
447 Hashtable responsedata = new Hashtable();
448 responsedata["int_response_code"] = 200;
449 responsedata["content_type"] = "application/xml";
450 responsedata["keepalive"] = false;
451 responsedata["reusecontext"] = false;
452 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
453 //m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", pAgentId, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
454 return responsedata;
455 }
456  
457 public Hashtable NoEvents(UUID requestID, UUID agentID)
458 {
459 Hashtable responsedata = new Hashtable();
460 responsedata["int_response_code"] = 502;
461 responsedata["content_type"] = "text/plain";
462 responsedata["keepalive"] = false;
463 responsedata["reusecontext"] = false;
464 responsedata["str_response_string"] = "Upstream error: ";
465 responsedata["error_status_text"] = "Upstream error:";
466 responsedata["http_protocol_version"] = "HTTP/1.0";
467 return responsedata;
468 }
469  
470 // public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps)
471 // {
472 // // TODO: this has to be redone to not busy-wait (and block the thread),
473 // // TODO: as soon as we have a non-blocking way to handle HTTP-requests.
474 //
475 //// if (m_log.IsDebugEnabled)
476 //// {
477 //// String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ ";
478 //// foreach (object key in request.Keys)
479 //// {
480 //// debug += key.ToString() + "=" + request[key].ToString() + " ";
481 //// }
482 //// m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name);
483 //// }
484 //
485 // Queue<OSD> queue = TryGetQueue(agentID);
486 // OSD element;
487 //
488 // lock (queue)
489 // element = queue.Dequeue(); // 15s timeout
490 //
491 // Hashtable responsedata = new Hashtable();
492 //
493 // int thisID = 0;
494 // lock (m_ids)
495 // thisID = m_ids[agentID];
496 //
497 // if (element == null)
498 // {
499 // //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName);
500 // if (thisID == -1) // close-request
501 // {
502 // m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName);
503 // responsedata["int_response_code"] = 404; //501; //410; //404;
504 // responsedata["content_type"] = "text/plain";
505 // responsedata["keepalive"] = false;
506 // responsedata["str_response_string"] = "Closed EQG";
507 // return responsedata;
508 // }
509 // responsedata["int_response_code"] = 502;
510 // responsedata["content_type"] = "text/plain";
511 // responsedata["keepalive"] = false;
512 // responsedata["str_response_string"] = "Upstream error: ";
513 // responsedata["error_status_text"] = "Upstream error:";
514 // responsedata["http_protocol_version"] = "HTTP/1.0";
515 // return responsedata;
516 // }
517 //
518 // OSDArray array = new OSDArray();
519 // if (element == null) // didn't have an event in 15s
520 // {
521 // // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
522 // array.Add(EventQueueHelper.KeepAliveEvent());
523 // //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
524 // }
525 // else
526 // {
527 // array.Add(element);
528 //
529 // if (element is OSDMap)
530 // {
531 // OSDMap ev = (OSDMap)element;
532 // m_log.DebugFormat(
533 // "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
534 // ev["message"], m_scene.GetScenePresence(agentID).Name);
535 // }
536 //
537 // lock (queue)
538 // {
539 // while (queue.Count > 0)
540 // {
541 // element = queue.Dequeue();
542 //
543 // if (element is OSDMap)
544 // {
545 // OSDMap ev = (OSDMap)element;
546 // m_log.DebugFormat(
547 // "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
548 // ev["message"], m_scene.GetScenePresence(agentID).Name);
549 // }
550 //
551 // array.Add(element);
552 // thisID++;
553 // }
554 // }
555 // }
556 //
557 // OSDMap events = new OSDMap();
558 // events.Add("events", array);
559 //
560 // events.Add("id", new OSDInteger(thisID));
561 // lock (m_ids)
562 // {
563 // m_ids[agentID] = thisID + 1;
564 // }
565 //
566 // responsedata["int_response_code"] = 200;
567 // responsedata["content_type"] = "application/xml";
568 // responsedata["keepalive"] = false;
569 // responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
570 //
571 // m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
572 //
573 // return responsedata;
574 // }
575  
576 // public Hashtable EventQueuePath2(Hashtable request)
577 // {
578 // string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/","");
579 // // pull off the last "/" in the path.
580 // Hashtable responsedata = new Hashtable();
581 // capuuid = capuuid.Substring(0, capuuid.Length - 1);
582 // capuuid = capuuid.Replace("/CAPS/EQG/", "");
583 // UUID AvatarID = UUID.Zero;
584 // UUID capUUID = UUID.Zero;
585 //
586 // // parse the path and search for the avatar with it registered
587 // if (UUID.TryParse(capuuid, out capUUID))
588 // {
589 // lock (m_QueueUUIDAvatarMapping)
590 // {
591 // if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID))
592 // {
593 // AvatarID = m_QueueUUIDAvatarMapping[capUUID];
594 // }
595 // }
596 //
597 // if (AvatarID != UUID.Zero)
598 // {
599 // return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID));
600 // }
601 // else
602 // {
603 // responsedata["int_response_code"] = 404;
604 // responsedata["content_type"] = "text/plain";
605 // responsedata["keepalive"] = false;
606 // responsedata["str_response_string"] = "Not Found";
607 // responsedata["error_status_text"] = "Not Found";
608 // responsedata["http_protocol_version"] = "HTTP/1.0";
609 // return responsedata;
610 // // return 404
611 // }
612 // }
613 // else
614 // {
615 // responsedata["int_response_code"] = 404;
616 // responsedata["content_type"] = "text/plain";
617 // responsedata["keepalive"] = false;
618 // responsedata["str_response_string"] = "Not Found";
619 // responsedata["error_status_text"] = "Not Found";
620 // responsedata["http_protocol_version"] = "HTTP/1.0";
621 // return responsedata;
622 // // return 404
623 // }
624 // }
625  
626 public OSD EventQueueFallBack(string path, OSD request, string endpoint)
627 {
628 // This is a fallback element to keep the client from loosing EventQueueGet
629 // Why does CAPS fail sometimes!?
630 m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!");
631 string capuuid = path.Replace("/CAPS/EQG/","");
632 capuuid = capuuid.Substring(0, capuuid.Length - 1);
633  
634 // UUID AvatarID = UUID.Zero;
635 UUID capUUID = UUID.Zero;
636 if (UUID.TryParse(capuuid, out capUUID))
637 {
638 /* Don't remove this yet code cleaners!
639 * Still testing this!
640 *
641 lock (m_QueueUUIDAvatarMapping)
642 {
643 if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID))
644 {
645 AvatarID = m_QueueUUIDAvatarMapping[capUUID];
646 }
647 }
648  
649  
650 if (AvatarID != UUID.Zero)
651 {
652 // Repair the CAP!
653 //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID);
654 //string capsBase = "/CAPS/EQG/";
655 //caps.RegisterHandler("EventQueueGet",
656 //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/",
657 //delegate(Hashtable m_dhttpMethod)
658 //{
659 // return ProcessQueue(m_dhttpMethod, AvatarID, caps);
660 //}));
661 // start new ID sequence.
662 Random rnd = new Random(System.Environment.TickCount);
663 lock (m_ids)
664 {
665 if (!m_ids.ContainsKey(AvatarID))
666 m_ids.Add(AvatarID, rnd.Next(30000000));
667 }
668  
669  
670 int thisID = 0;
671 lock (m_ids)
672 thisID = m_ids[AvatarID];
673  
674 BlockingLLSDQueue queue = GetQueue(AvatarID);
675 OSDArray array = new OSDArray();
676 LLSD element = queue.Dequeue(15000); // 15s timeout
677 if (element == null)
678 {
679  
680 array.Add(EventQueueHelper.KeepAliveEvent());
681 }
682 else
683 {
684 array.Add(element);
685 while (queue.Count() > 0)
686 {
687 array.Add(queue.Dequeue(1));
688 thisID++;
689 }
690 }
691 OSDMap events = new OSDMap();
692 events.Add("events", array);
693  
694 events.Add("id", new LLSDInteger(thisID));
695  
696 lock (m_ids)
697 {
698 m_ids[AvatarID] = thisID + 1;
699 }
700  
701 return events;
702 }
703 else
704 {
705 return new LLSD();
706 }
707 *
708 */
709 }
710 else
711 {
712 //return new LLSD();
713 }
714  
715 return new OSDString("shutdown404!");
716 }
717  
718 public void DisableSimulator(ulong handle, UUID avatarID)
719 {
720 OSD item = EventQueueHelper.DisableSimulator(handle);
721 Enqueue(item, avatarID);
722 }
723  
724 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY)
725 {
726 if (DebugLevel > 0)
727 m_log.DebugFormat("{0} EnableSimulator. handle={1}, endPoint={2}, avatarID={3}",
728 LogHeader, handle, endPoint, avatarID, regionSizeX, regionSizeY);
729  
730 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY);
731 Enqueue(item, avatarID);
732 }
733  
734 public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath,
735 ulong regionHandle, int regionSizeX, int regionSizeY)
736 {
737 if (DebugLevel > 0)
738 m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, endPoint={2}, avatarID={3}",
739 LogHeader, regionHandle, endPoint, avatarID, regionSizeX, regionSizeY);
740  
741 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY);
742 Enqueue(item, avatarID);
743 }
744  
745 public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess,
746 IPEndPoint regionExternalEndPoint,
747 uint locationID, uint flags, string capsURL,
748 UUID avatarID, int regionSizeX, int regionSizeY)
749 {
750 if (DebugLevel > 0)
751 m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, endPoint={2}, avatarID={3}",
752 LogHeader, regionHandle, regionExternalEndPoint, avatarID, regionSizeX, regionSizeY);
753  
754 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint,
755 locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY);
756 Enqueue(item, avatarID);
757 }
758  
759 public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
760 IPEndPoint newRegionExternalEndPoint,
761 string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY)
762 {
763 if (DebugLevel > 0)
764 m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>",
765 LogHeader, handle, avatarID, regionSizeX, regionSizeY);
766  
767 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint,
768 capsURL, avatarID, sessionID, regionSizeX, regionSizeY);
769 Enqueue(item, avatarID);
770 }
771  
772 public void ChatterboxInvitation(UUID sessionID, string sessionName,
773 UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog,
774 uint timeStamp, bool offline, int parentEstateID, Vector3 position,
775 uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
776 {
777 OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog,
778 timeStamp, offline, parentEstateID, position, ttl, transactionID,
779 fromGroup, binaryBucket);
780 Enqueue(item, toAgent);
781 //m_log.InfoFormat("########### eq ChatterboxInvitation #############\n{0}", item);
782  
783 }
784  
785 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat,
786 bool isModerator, bool textMute)
787 {
788 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat,
789 isModerator, textMute);
790 Enqueue(item, fromAgent);
791 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item);
792 }
793  
794 public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID)
795 {
796 OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage);
797 Enqueue(item, avatarID);
798 }
799  
800 public void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID)
801 {
802 OSD item = EventQueueHelper.GroupMembership(groupUpdate);
803 Enqueue(item, avatarID);
804 }
805  
806 public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID)
807 {
808 OSD item = EventQueueHelper.PlacesQuery(groupUpdate);
809 Enqueue(item, avatarID);
810 }
811  
812 public OSD ScriptRunningEvent(UUID objectID, UUID itemID, bool running, bool mono)
813 {
814 return EventQueueHelper.ScriptRunningReplyEvent(objectID, itemID, running, mono);
815 }
816  
817 public OSD BuildEvent(string eventName, OSD eventBody)
818 {
819 return EventQueueHelper.BuildEvent(eventName, eventBody);
820 }
821  
822 public void partPhysicsProperties(uint localID, byte physhapetype,
823 float density, float friction, float bounce, float gravmod,UUID avatarID)
824 {
825 OSD item = EventQueueHelper.partPhysicsProperties(localID, physhapetype,
826 density, friction, bounce, gravmod);
827 Enqueue(item, avatarID);
828 }
829 }
830 }