aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs830
1 files changed, 830 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
new file mode 100644
index 0000000..9b9f6a7
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -0,0 +1,830 @@
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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
32using System.Reflection;
33using System.Threading;
34using log4net;
35using Nini.Config;
36using Mono.Addins;
37using OpenMetaverse;
38using OpenMetaverse.Messages.Linden;
39using OpenMetaverse.Packets;
40using OpenMetaverse.StructuredData;
41using OpenSim.Framework;
42using OpenSim.Framework.Console;
43using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Region.Framework.Scenes;
47using BlockingLLSDQueue = OpenSim.Framework.BlockingQueue<OpenMetaverse.StructuredData.OSD>;
48using Caps=OpenSim.Framework.Capabilities.Caps;
49
50namespace 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} \ No newline at end of file