aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/Caps/EventQueue
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps/EventQueue')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs731
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs399
2 files changed, 1130 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..4827baa
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -0,0 +1,731 @@
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.Servers;
43using OpenSim.Framework.Servers.HttpServer;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using BlockingLLSDQueue = OpenSim.Framework.BlockingQueue<OpenMetaverse.StructuredData.OSD>;
47using Caps=OpenSim.Framework.Capabilities.Caps;
48
49namespace OpenSim.Region.ClientStack.Linden
50{
51 public struct QueueItem
52 {
53 public int id;
54 public OSDMap body;
55 }
56
57 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
58 public class EventQueueGetModule : IEventQueue, IRegionModule
59 {
60 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61 protected Scene m_scene = null;
62 private IConfigSource m_gConfig;
63 bool enabledYN = false;
64
65 private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>();
66
67 private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>();
68 private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>();
69 private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>();
70
71 #region IRegionModule methods
72 public virtual void Initialise(Scene scene, IConfigSource config)
73 {
74 m_gConfig = config;
75
76 IConfig startupConfig = m_gConfig.Configs["Startup"];
77
78 ReadConfigAndPopulate(scene, startupConfig, "Startup");
79
80 if (enabledYN)
81 {
82 m_scene = scene;
83 scene.RegisterModuleInterface<IEventQueue>(this);
84
85 // Register fallback handler
86 // Why does EQG Fail on region crossings!
87
88 //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack);
89
90 scene.EventManager.OnNewClient += OnNewClient;
91
92 // TODO: Leaving these open, or closing them when we
93 // become a child is incorrect. It messes up TP in a big
94 // way. CAPS/EQ need to be active as long as the UDP
95 // circuit is there.
96
97 scene.EventManager.OnClientClosed += ClientClosed;
98 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
99 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
100 }
101 else
102 {
103 m_gConfig = null;
104 }
105
106 }
107
108 private void ReadConfigAndPopulate(Scene scene, IConfig startupConfig, string p)
109 {
110 enabledYN = startupConfig.GetBoolean("EventQueue", true);
111 }
112
113 public void PostInitialise()
114 {
115 }
116
117 public virtual void Close()
118 {
119 }
120
121 public virtual string Name
122 {
123 get { return "EventQueueGetModule"; }
124 }
125
126 public bool IsSharedModule
127 {
128 get { return false; }
129 }
130 #endregion
131
132 /// <summary>
133 /// Always returns a valid queue
134 /// </summary>
135 /// <param name="agentId"></param>
136 /// <returns></returns>
137 private Queue<OSD> TryGetQueue(UUID agentId)
138 {
139 lock (queues)
140 {
141 if (!queues.ContainsKey(agentId))
142 {
143 /*
144 m_log.DebugFormat(
145 "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}",
146 agentId, m_scene.RegionInfo.RegionName);
147 */
148 queues[agentId] = new Queue<OSD>();
149 }
150
151 return queues[agentId];
152 }
153 }
154
155 /// <summary>
156 /// May return a null queue
157 /// </summary>
158 /// <param name="agentId"></param>
159 /// <returns></returns>
160 private Queue<OSD> GetQueue(UUID agentId)
161 {
162 lock (queues)
163 {
164 if (queues.ContainsKey(agentId))
165 {
166 return queues[agentId];
167 }
168 else
169 return null;
170 }
171 }
172
173 #region IEventQueue Members
174
175 public bool Enqueue(OSD ev, UUID avatarID)
176 {
177 //m_log.DebugFormat("[EVENTQUEUE]: Enqueuing event for {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName);
178 try
179 {
180 Queue<OSD> queue = GetQueue(avatarID);
181 if (queue != null)
182 queue.Enqueue(ev);
183 }
184 catch(NullReferenceException e)
185 {
186 m_log.Error("[EVENTQUEUE] Caught exception: " + e);
187 return false;
188 }
189
190 return true;
191 }
192
193 #endregion
194
195 private void OnNewClient(IClientAPI client)
196 {
197 //client.OnLogout += ClientClosed;
198 }
199
200// private void ClientClosed(IClientAPI client)
201// {
202// ClientClosed(client.AgentId);
203// }
204
205 private void ClientClosed(UUID AgentID, Scene scene)
206 {
207 //m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", AgentID, m_scene.RegionInfo.RegionName);
208
209 int count = 0;
210 while (queues.ContainsKey(AgentID) && queues[AgentID].Count > 0 && count++ < 5)
211 {
212 Thread.Sleep(1000);
213 }
214
215 lock (queues)
216 {
217 queues.Remove(AgentID);
218 }
219 List<UUID> removeitems = new List<UUID>();
220 lock (m_AvatarQueueUUIDMapping)
221 {
222 foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys)
223 {
224 if (ky == AgentID)
225 {
226 removeitems.Add(ky);
227 }
228 }
229
230 foreach (UUID ky in removeitems)
231 {
232 m_AvatarQueueUUIDMapping.Remove(ky);
233 MainServer.Instance.RemovePollServiceHTTPHandler("","/CAPS/EQG/" + ky.ToString() + "/");
234 }
235
236 }
237 UUID searchval = UUID.Zero;
238
239 removeitems.Clear();
240
241 lock (m_QueueUUIDAvatarMapping)
242 {
243 foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys)
244 {
245 searchval = m_QueueUUIDAvatarMapping[ky];
246
247 if (searchval == AgentID)
248 {
249 removeitems.Add(ky);
250 }
251 }
252
253 foreach (UUID ky in removeitems)
254 m_QueueUUIDAvatarMapping.Remove(ky);
255
256 }
257 }
258
259 private void MakeChildAgent(ScenePresence avatar)
260 {
261 //m_log.DebugFormat("[EVENTQUEUE]: Make Child agent {0} in region {1}.", avatar.UUID, m_scene.RegionInfo.RegionName);
262 //lock (m_ids)
263 // {
264 //if (m_ids.ContainsKey(avatar.UUID))
265 //{
266 // close the event queue.
267 //m_ids[avatar.UUID] = -1;
268 //}
269 //}
270 }
271
272 public void OnRegisterCaps(UUID agentID, Caps caps)
273 {
274 // Register an event queue for the client
275
276 //m_log.DebugFormat(
277 // "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}",
278 // agentID, caps, m_scene.RegionInfo.RegionName);
279
280 // Let's instantiate a Queue for this agent right now
281 TryGetQueue(agentID);
282
283 string capsBase = "/CAPS/EQG/";
284 UUID EventQueueGetUUID = UUID.Zero;
285
286 lock (m_AvatarQueueUUIDMapping)
287 {
288 // Reuse open queues. The client does!
289 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
290 {
291 //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!");
292 EventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
293 }
294 else
295 {
296 EventQueueGetUUID = UUID.Random();
297 //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!");
298 }
299 }
300
301 lock (m_QueueUUIDAvatarMapping)
302 {
303 if (!m_QueueUUIDAvatarMapping.ContainsKey(EventQueueGetUUID))
304 m_QueueUUIDAvatarMapping.Add(EventQueueGetUUID, agentID);
305 }
306
307 lock (m_AvatarQueueUUIDMapping)
308 {
309 if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID))
310 m_AvatarQueueUUIDMapping.Add(agentID, EventQueueGetUUID);
311 }
312
313 // Register this as a caps handler
314 caps.RegisterHandler("EventQueueGet",
315 new RestHTTPHandler("POST", capsBase + EventQueueGetUUID.ToString() + "/",
316 delegate(Hashtable m_dhttpMethod)
317 {
318 return ProcessQueue(m_dhttpMethod, agentID, caps);
319 }));
320
321 // This will persist this beyond the expiry of the caps handlers
322 MainServer.Instance.AddPollServiceHTTPHandler(
323 capsBase + EventQueueGetUUID.ToString() + "/", EventQueuePoll, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID));
324
325 Random rnd = new Random(Environment.TickCount);
326 lock (m_ids)
327 {
328 if (!m_ids.ContainsKey(agentID))
329 m_ids.Add(agentID, rnd.Next(30000000));
330 }
331 }
332
333 public bool HasEvents(UUID requestID, UUID agentID)
334 {
335 // Don't use this, because of race conditions at agent closing time
336 //Queue<OSD> queue = TryGetQueue(agentID);
337
338 Queue<OSD> queue = GetQueue(agentID);
339 if (queue != null)
340 lock (queue)
341 {
342 if (queue.Count > 0)
343 return true;
344 else
345 return false;
346 }
347 return false;
348 }
349
350 public Hashtable GetEvents(UUID requestID, UUID pAgentId, string request)
351 {
352 Queue<OSD> queue = TryGetQueue(pAgentId);
353 OSD element;
354 lock (queue)
355 {
356 if (queue.Count == 0)
357 return NoEvents(requestID, pAgentId);
358 element = queue.Dequeue(); // 15s timeout
359 }
360
361
362
363 int thisID = 0;
364 lock (m_ids)
365 thisID = m_ids[pAgentId];
366
367 OSDArray array = new OSDArray();
368 if (element == null) // didn't have an event in 15s
369 {
370 // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
371 array.Add(EventQueueHelper.KeepAliveEvent());
372 //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName);
373 }
374 else
375 {
376 array.Add(element);
377 lock (queue)
378 {
379 while (queue.Count > 0)
380 {
381 array.Add(queue.Dequeue());
382 thisID++;
383 }
384 }
385 }
386
387 OSDMap events = new OSDMap();
388 events.Add("events", array);
389
390 events.Add("id", new OSDInteger(thisID));
391 lock (m_ids)
392 {
393 m_ids[pAgentId] = thisID + 1;
394 }
395 Hashtable responsedata = new Hashtable();
396 responsedata["int_response_code"] = 200;
397 responsedata["content_type"] = "application/xml";
398 responsedata["keepalive"] = false;
399 responsedata["reusecontext"] = false;
400 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
401 //m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", pAgentId, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
402 return responsedata;
403 }
404
405 public Hashtable NoEvents(UUID requestID, UUID agentID)
406 {
407 Hashtable responsedata = new Hashtable();
408 responsedata["int_response_code"] = 502;
409 responsedata["content_type"] = "text/plain";
410 responsedata["keepalive"] = false;
411 responsedata["reusecontext"] = false;
412 responsedata["str_response_string"] = "Upstream error: ";
413 responsedata["error_status_text"] = "Upstream error:";
414 responsedata["http_protocol_version"] = "HTTP/1.0";
415 return responsedata;
416 }
417
418 public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps)
419 {
420 // TODO: this has to be redone to not busy-wait (and block the thread),
421 // TODO: as soon as we have a non-blocking way to handle HTTP-requests.
422
423// if (m_log.IsDebugEnabled)
424// {
425// String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ ";
426// foreach (object key in request.Keys)
427// {
428// debug += key.ToString() + "=" + request[key].ToString() + " ";
429// }
430// m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name);
431// }
432
433 Queue<OSD> queue = TryGetQueue(agentID);
434 OSD element = queue.Dequeue(); // 15s timeout
435
436 Hashtable responsedata = new Hashtable();
437
438 int thisID = 0;
439 lock (m_ids)
440 thisID = m_ids[agentID];
441
442 if (element == null)
443 {
444 //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName);
445 if (thisID == -1) // close-request
446 {
447 m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName);
448 responsedata["int_response_code"] = 404; //501; //410; //404;
449 responsedata["content_type"] = "text/plain";
450 responsedata["keepalive"] = false;
451 responsedata["str_response_string"] = "Closed EQG";
452 return responsedata;
453 }
454 responsedata["int_response_code"] = 502;
455 responsedata["content_type"] = "text/plain";
456 responsedata["keepalive"] = false;
457 responsedata["str_response_string"] = "Upstream error: ";
458 responsedata["error_status_text"] = "Upstream error:";
459 responsedata["http_protocol_version"] = "HTTP/1.0";
460 return responsedata;
461 }
462
463 OSDArray array = new OSDArray();
464 if (element == null) // didn't have an event in 15s
465 {
466 // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
467 array.Add(EventQueueHelper.KeepAliveEvent());
468 //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
469 }
470 else
471 {
472 array.Add(element);
473 while (queue.Count > 0)
474 {
475 array.Add(queue.Dequeue());
476 thisID++;
477 }
478 }
479
480 OSDMap events = new OSDMap();
481 events.Add("events", array);
482
483 events.Add("id", new OSDInteger(thisID));
484 lock (m_ids)
485 {
486 m_ids[agentID] = thisID + 1;
487 }
488
489 responsedata["int_response_code"] = 200;
490 responsedata["content_type"] = "application/xml";
491 responsedata["keepalive"] = false;
492 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
493 //m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
494
495 return responsedata;
496 }
497
498 public Hashtable EventQueuePoll(Hashtable request)
499 {
500 return new Hashtable();
501 }
502
503 public Hashtable EventQueuePath2(Hashtable request)
504 {
505 string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/","");
506 // pull off the last "/" in the path.
507 Hashtable responsedata = new Hashtable();
508 capuuid = capuuid.Substring(0, capuuid.Length - 1);
509 capuuid = capuuid.Replace("/CAPS/EQG/", "");
510 UUID AvatarID = UUID.Zero;
511 UUID capUUID = UUID.Zero;
512
513 // parse the path and search for the avatar with it registered
514 if (UUID.TryParse(capuuid, out capUUID))
515 {
516 lock (m_QueueUUIDAvatarMapping)
517 {
518 if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID))
519 {
520 AvatarID = m_QueueUUIDAvatarMapping[capUUID];
521 }
522 }
523 if (AvatarID != UUID.Zero)
524 {
525 return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsHandlerForUser(AvatarID));
526 }
527 else
528 {
529 responsedata["int_response_code"] = 404;
530 responsedata["content_type"] = "text/plain";
531 responsedata["keepalive"] = false;
532 responsedata["str_response_string"] = "Not Found";
533 responsedata["error_status_text"] = "Not Found";
534 responsedata["http_protocol_version"] = "HTTP/1.0";
535 return responsedata;
536 // return 404
537 }
538 }
539 else
540 {
541 responsedata["int_response_code"] = 404;
542 responsedata["content_type"] = "text/plain";
543 responsedata["keepalive"] = false;
544 responsedata["str_response_string"] = "Not Found";
545 responsedata["error_status_text"] = "Not Found";
546 responsedata["http_protocol_version"] = "HTTP/1.0";
547 return responsedata;
548 // return 404
549 }
550
551 }
552
553 public OSD EventQueueFallBack(string path, OSD request, string endpoint)
554 {
555 // This is a fallback element to keep the client from loosing EventQueueGet
556 // Why does CAPS fail sometimes!?
557 m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!");
558 string capuuid = path.Replace("/CAPS/EQG/","");
559 capuuid = capuuid.Substring(0, capuuid.Length - 1);
560
561// UUID AvatarID = UUID.Zero;
562 UUID capUUID = UUID.Zero;
563 if (UUID.TryParse(capuuid, out capUUID))
564 {
565/* Don't remove this yet code cleaners!
566 * Still testing this!
567 *
568 lock (m_QueueUUIDAvatarMapping)
569 {
570 if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID))
571 {
572 AvatarID = m_QueueUUIDAvatarMapping[capUUID];
573 }
574 }
575
576
577 if (AvatarID != UUID.Zero)
578 {
579 // Repair the CAP!
580 //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID);
581 //string capsBase = "/CAPS/EQG/";
582 //caps.RegisterHandler("EventQueueGet",
583 //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/",
584 //delegate(Hashtable m_dhttpMethod)
585 //{
586 // return ProcessQueue(m_dhttpMethod, AvatarID, caps);
587 //}));
588 // start new ID sequence.
589 Random rnd = new Random(System.Environment.TickCount);
590 lock (m_ids)
591 {
592 if (!m_ids.ContainsKey(AvatarID))
593 m_ids.Add(AvatarID, rnd.Next(30000000));
594 }
595
596
597 int thisID = 0;
598 lock (m_ids)
599 thisID = m_ids[AvatarID];
600
601 BlockingLLSDQueue queue = GetQueue(AvatarID);
602 OSDArray array = new OSDArray();
603 LLSD element = queue.Dequeue(15000); // 15s timeout
604 if (element == null)
605 {
606
607 array.Add(EventQueueHelper.KeepAliveEvent());
608 }
609 else
610 {
611 array.Add(element);
612 while (queue.Count() > 0)
613 {
614 array.Add(queue.Dequeue(1));
615 thisID++;
616 }
617 }
618 OSDMap events = new OSDMap();
619 events.Add("events", array);
620
621 events.Add("id", new LLSDInteger(thisID));
622
623 lock (m_ids)
624 {
625 m_ids[AvatarID] = thisID + 1;
626 }
627
628 return events;
629 }
630 else
631 {
632 return new LLSD();
633 }
634*
635*/
636 }
637 else
638 {
639 //return new LLSD();
640 }
641
642 return new OSDString("shutdown404!");
643 }
644
645 public void DisableSimulator(ulong handle, UUID avatarID)
646 {
647 OSD item = EventQueueHelper.DisableSimulator(handle);
648 Enqueue(item, avatarID);
649 }
650
651 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID)
652 {
653 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint);
654 Enqueue(item, avatarID);
655 }
656
657 public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath)
658 {
659 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath);
660 Enqueue(item, avatarID);
661 }
662
663 public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess,
664 IPEndPoint regionExternalEndPoint,
665 uint locationID, uint flags, string capsURL,
666 UUID avatarID)
667 {
668 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint,
669 locationID, flags, capsURL, avatarID);
670 Enqueue(item, avatarID);
671 }
672
673 public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
674 IPEndPoint newRegionExternalEndPoint,
675 string capsURL, UUID avatarID, UUID sessionID)
676 {
677 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint,
678 capsURL, avatarID, sessionID);
679 Enqueue(item, avatarID);
680 }
681
682 public void ChatterboxInvitation(UUID sessionID, string sessionName,
683 UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog,
684 uint timeStamp, bool offline, int parentEstateID, Vector3 position,
685 uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
686 {
687 OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog,
688 timeStamp, offline, parentEstateID, position, ttl, transactionID,
689 fromGroup, binaryBucket);
690 Enqueue(item, toAgent);
691 //m_log.InfoFormat("########### eq ChatterboxInvitation #############\n{0}", item);
692
693 }
694
695 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat,
696 bool isModerator, bool textMute)
697 {
698 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat,
699 isModerator, textMute);
700 Enqueue(item, toAgent);
701 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item);
702 }
703
704 public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID)
705 {
706 OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage);
707 Enqueue(item, avatarID);
708 }
709
710 public void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID)
711 {
712 OSD item = EventQueueHelper.GroupMembership(groupUpdate);
713 Enqueue(item, avatarID);
714 }
715 public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID)
716 {
717 OSD item = EventQueueHelper.PlacesQuery(groupUpdate);
718 Enqueue(item, avatarID);
719 }
720
721 public OSD ScriptRunningEvent(UUID objectID, UUID itemID, bool running, bool mono)
722 {
723 return EventQueueHelper.ScriptRunningReplyEvent(objectID, itemID, running, mono);
724 }
725
726 public OSD BuildEvent(string eventName, OSD eventBody)
727 {
728 return EventQueueHelper.BuildEvent(eventName, eventBody);
729 }
730 }
731}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
new file mode 100644
index 0000000..3f49aba
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -0,0 +1,399 @@
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.Net;
30using OpenMetaverse;
31using OpenMetaverse.Packets;
32using OpenMetaverse.StructuredData;
33using OpenMetaverse.Messages.Linden;
34
35namespace OpenSim.Region.ClientStack.Linden
36{
37 public class EventQueueHelper
38 {
39 private EventQueueHelper() {} // no construction possible, it's an utility class
40
41 private static byte[] ulongToByteArray(ulong uLongValue)
42 {
43 // Reverse endianness of RegionHandle
44 return new byte[]
45 {
46 (byte)((uLongValue >> 56) % 256),
47 (byte)((uLongValue >> 48) % 256),
48 (byte)((uLongValue >> 40) % 256),
49 (byte)((uLongValue >> 32) % 256),
50 (byte)((uLongValue >> 24) % 256),
51 (byte)((uLongValue >> 16) % 256),
52 (byte)((uLongValue >> 8) % 256),
53 (byte)(uLongValue % 256)
54 };
55 }
56
57// private static byte[] uintToByteArray(uint uIntValue)
58// {
59// byte[] result = new byte[4];
60// Utils.UIntToBytesBig(uIntValue, result, 0);
61// return result;
62// }
63
64 public static OSD BuildEvent(string eventName, OSD eventBody)
65 {
66 OSDMap llsdEvent = new OSDMap(2);
67 llsdEvent.Add("message", new OSDString(eventName));
68 llsdEvent.Add("body", eventBody);
69
70 return llsdEvent;
71 }
72
73 public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint)
74 {
75 OSDMap llsdSimInfo = new OSDMap(3);
76
77 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle)));
78 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes()));
79 llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port));
80
81 OSDArray arr = new OSDArray(1);
82 arr.Add(llsdSimInfo);
83
84 OSDMap llsdBody = new OSDMap(1);
85 llsdBody.Add("SimulatorInfo", arr);
86
87 return BuildEvent("EnableSimulator", llsdBody);
88 }
89
90 public static OSD DisableSimulator(ulong handle)
91 {
92 //OSDMap llsdSimInfo = new OSDMap(1);
93
94 //llsdSimInfo.Add("Handle", new OSDBinary(regionHandleToByteArray(handle)));
95
96 //OSDArray arr = new OSDArray(1);
97 //arr.Add(llsdSimInfo);
98
99 OSDMap llsdBody = new OSDMap(0);
100 //llsdBody.Add("SimulatorInfo", arr);
101
102 return BuildEvent("DisableSimulator", llsdBody);
103 }
104
105 public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
106 IPEndPoint newRegionExternalEndPoint,
107 string capsURL, UUID agentID, UUID sessionID)
108 {
109 OSDArray lookAtArr = new OSDArray(3);
110 lookAtArr.Add(OSD.FromReal(lookAt.X));
111 lookAtArr.Add(OSD.FromReal(lookAt.Y));
112 lookAtArr.Add(OSD.FromReal(lookAt.Z));
113
114 OSDArray positionArr = new OSDArray(3);
115 positionArr.Add(OSD.FromReal(pos.X));
116 positionArr.Add(OSD.FromReal(pos.Y));
117 positionArr.Add(OSD.FromReal(pos.Z));
118
119 OSDMap infoMap = new OSDMap(2);
120 infoMap.Add("LookAt", lookAtArr);
121 infoMap.Add("Position", positionArr);
122
123 OSDArray infoArr = new OSDArray(1);
124 infoArr.Add(infoMap);
125
126 OSDMap agentDataMap = new OSDMap(2);
127 agentDataMap.Add("AgentID", OSD.FromUUID(agentID));
128 agentDataMap.Add("SessionID", OSD.FromUUID(sessionID));
129
130 OSDArray agentDataArr = new OSDArray(1);
131 agentDataArr.Add(agentDataMap);
132
133 OSDMap regionDataMap = new OSDMap(4);
134 regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle)));
135 regionDataMap.Add("SeedCapability", OSD.FromString(capsURL));
136 regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes()));
137 regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port));
138
139 OSDArray regionDataArr = new OSDArray(1);
140 regionDataArr.Add(regionDataMap);
141
142 OSDMap llsdBody = new OSDMap(3);
143 llsdBody.Add("Info", infoArr);
144 llsdBody.Add("AgentData", agentDataArr);
145 llsdBody.Add("RegionData", regionDataArr);
146
147 return BuildEvent("CrossedRegion", llsdBody);
148 }
149
150 public static OSD TeleportFinishEvent(
151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
152 uint locationID, uint flags, string capsURL, UUID agentID)
153 {
154 OSDMap info = new OSDMap();
155 info.Add("AgentID", OSD.FromUUID(agentID));
156 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this?
157 info.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(regionHandle)));
158 info.Add("SeedCapability", OSD.FromString(capsURL));
159 info.Add("SimAccess", OSD.FromInteger(simAccess));
160 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes()));
161 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
162 info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
163
164 OSDArray infoArr = new OSDArray();
165 infoArr.Add(info);
166
167 OSDMap body = new OSDMap();
168 body.Add("Info", infoArr);
169
170 return BuildEvent("TeleportFinish", body);
171 }
172
173 public static OSD ScriptRunningReplyEvent(UUID objectID, UUID itemID, bool running, bool mono)
174 {
175 OSDMap script = new OSDMap();
176 script.Add("ObjectID", OSD.FromUUID(objectID));
177 script.Add("ItemID", OSD.FromUUID(itemID));
178 script.Add("Running", OSD.FromBoolean(running));
179 script.Add("Mono", OSD.FromBoolean(mono));
180
181 OSDArray scriptArr = new OSDArray();
182 scriptArr.Add(script);
183
184 OSDMap body = new OSDMap();
185 body.Add("Script", scriptArr);
186
187 return BuildEvent("ScriptRunningReply", body);
188 }
189
190 public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap)
191 {
192 OSDMap body = new OSDMap(3);
193 body.Add("agent-id", new OSDUUID(agentID));
194 body.Add("sim-ip-and-port", new OSDString(simIpAndPort));
195 body.Add("seed-capability", new OSDString(seedcap));
196
197 return BuildEvent("EstablishAgentCommunication", body);
198 }
199
200 public static OSD KeepAliveEvent()
201 {
202 return BuildEvent("FAKEEVENT", new OSDMap());
203 }
204
205 public static OSD AgentParams(UUID agentID, bool checkEstate, int godLevel, bool limitedToEstate)
206 {
207 OSDMap body = new OSDMap(4);
208
209 body.Add("agent_id", new OSDUUID(agentID));
210 body.Add("check_estate", new OSDInteger(checkEstate ? 1 : 0));
211 body.Add("god_level", new OSDInteger(godLevel));
212 body.Add("limited_to_estate", new OSDInteger(limitedToEstate ? 1 : 0));
213
214 return body;
215 }
216
217 public static OSD InstantMessageParams(UUID fromAgent, string message, UUID toAgent,
218 string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID,
219 Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
220 {
221 OSDMap messageParams = new OSDMap(15);
222 messageParams.Add("type", new OSDInteger((int)dialog));
223
224 OSDArray positionArray = new OSDArray(3);
225 positionArray.Add(OSD.FromReal(position.X));
226 positionArray.Add(OSD.FromReal(position.Y));
227 positionArray.Add(OSD.FromReal(position.Z));
228 messageParams.Add("position", positionArray);
229
230 messageParams.Add("region_id", new OSDUUID(UUID.Zero));
231 messageParams.Add("to_id", new OSDUUID(toAgent));
232 messageParams.Add("source", new OSDInteger(0));
233
234 OSDMap data = new OSDMap(1);
235 data.Add("binary_bucket", OSD.FromBinary(binaryBucket));
236 messageParams.Add("data", data);
237 messageParams.Add("message", new OSDString(message));
238 messageParams.Add("id", new OSDUUID(transactionID));
239 messageParams.Add("from_name", new OSDString(fromName));
240 messageParams.Add("timestamp", new OSDInteger((int)timeStamp));
241 messageParams.Add("offline", new OSDInteger(offline ? 1 : 0));
242 messageParams.Add("parent_estate_id", new OSDInteger(parentEstateID));
243 messageParams.Add("ttl", new OSDInteger((int)ttl));
244 messageParams.Add("from_id", new OSDUUID(fromAgent));
245 messageParams.Add("from_group", new OSDInteger(fromGroup ? 1 : 0));
246
247 return messageParams;
248 }
249
250 public static OSD InstantMessage(UUID fromAgent, string message, UUID toAgent,
251 string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID,
252 Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket,
253 bool checkEstate, int godLevel, bool limitedToEstate)
254 {
255 OSDMap im = new OSDMap(2);
256 im.Add("message_params", InstantMessageParams(fromAgent, message, toAgent,
257 fromName, dialog, timeStamp, offline, parentEstateID,
258 position, ttl, transactionID, fromGroup, binaryBucket));
259
260 im.Add("agent_params", AgentParams(fromAgent, checkEstate, godLevel, limitedToEstate));
261
262 return im;
263 }
264
265
266 public static OSD ChatterboxInvitation(UUID sessionID, string sessionName,
267 UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog,
268 uint timeStamp, bool offline, int parentEstateID, Vector3 position,
269 uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
270 {
271 OSDMap body = new OSDMap(5);
272 body.Add("session_id", new OSDUUID(sessionID));
273 body.Add("from_name", new OSDString(fromName));
274 body.Add("session_name", new OSDString(sessionName));
275 body.Add("from_id", new OSDUUID(fromAgent));
276
277 body.Add("instantmessage", InstantMessage(fromAgent, message, toAgent,
278 fromName, dialog, timeStamp, offline, parentEstateID, position,
279 ttl, transactionID, fromGroup, binaryBucket, true, 0, true));
280
281 OSDMap chatterboxInvitation = new OSDMap(2);
282 chatterboxInvitation.Add("message", new OSDString("ChatterBoxInvitation"));
283 chatterboxInvitation.Add("body", body);
284 return chatterboxInvitation;
285 }
286
287 public static OSD ChatterBoxSessionAgentListUpdates(UUID sessionID,
288 UUID agentID, bool canVoiceChat, bool isModerator, bool textMute)
289 {
290 OSDMap body = new OSDMap();
291 OSDMap agentUpdates = new OSDMap();
292 OSDMap infoDetail = new OSDMap();
293 OSDMap mutes = new OSDMap();
294
295 mutes.Add("text", OSD.FromBoolean(textMute));
296 infoDetail.Add("can_voice_chat", OSD.FromBoolean(canVoiceChat));
297 infoDetail.Add("is_moderator", OSD.FromBoolean(isModerator));
298 infoDetail.Add("mutes", mutes);
299 OSDMap info = new OSDMap();
300 info.Add("info", infoDetail);
301 agentUpdates.Add(agentID.ToString(), info);
302 body.Add("agent_updates", agentUpdates);
303 body.Add("session_id", OSD.FromUUID(sessionID));
304 body.Add("updates", new OSD());
305
306 OSDMap chatterBoxSessionAgentListUpdates = new OSDMap();
307 chatterBoxSessionAgentListUpdates.Add("message", OSD.FromString("ChatterBoxSessionAgentListUpdates"));
308 chatterBoxSessionAgentListUpdates.Add("body", body);
309
310 return chatterBoxSessionAgentListUpdates;
311 }
312
313 public static OSD GroupMembership(AgentGroupDataUpdatePacket groupUpdatePacket)
314 {
315 OSDMap groupUpdate = new OSDMap();
316 groupUpdate.Add("message", OSD.FromString("AgentGroupDataUpdate"));
317
318 OSDMap body = new OSDMap();
319 OSDArray agentData = new OSDArray();
320 OSDMap agentDataMap = new OSDMap();
321 agentDataMap.Add("AgentID", OSD.FromUUID(groupUpdatePacket.AgentData.AgentID));
322 agentData.Add(agentDataMap);
323 body.Add("AgentData", agentData);
324
325 OSDArray groupData = new OSDArray();
326
327 foreach (AgentGroupDataUpdatePacket.GroupDataBlock groupDataBlock in groupUpdatePacket.GroupData)
328 {
329 OSDMap groupDataMap = new OSDMap();
330 groupDataMap.Add("ListInProfile", OSD.FromBoolean(false));
331 groupDataMap.Add("GroupID", OSD.FromUUID(groupDataBlock.GroupID));
332 groupDataMap.Add("GroupInsigniaID", OSD.FromUUID(groupDataBlock.GroupInsigniaID));
333 groupDataMap.Add("Contribution", OSD.FromInteger(groupDataBlock.Contribution));
334 groupDataMap.Add("GroupPowers", OSD.FromBinary(ulongToByteArray(groupDataBlock.GroupPowers)));
335 groupDataMap.Add("GroupName", OSD.FromString(Utils.BytesToString(groupDataBlock.GroupName)));
336 groupDataMap.Add("AcceptNotices", OSD.FromBoolean(groupDataBlock.AcceptNotices));
337
338 groupData.Add(groupDataMap);
339
340 }
341 body.Add("GroupData", groupData);
342 groupUpdate.Add("body", body);
343
344 return groupUpdate;
345 }
346
347 public static OSD PlacesQuery(PlacesReplyPacket PlacesReply)
348 {
349 OSDMap placesReply = new OSDMap();
350 placesReply.Add("message", OSD.FromString("PlacesReplyMessage"));
351
352 OSDMap body = new OSDMap();
353 OSDArray agentData = new OSDArray();
354 OSDMap agentDataMap = new OSDMap();
355 agentDataMap.Add("AgentID", OSD.FromUUID(PlacesReply.AgentData.AgentID));
356 agentDataMap.Add("QueryID", OSD.FromUUID(PlacesReply.AgentData.QueryID));
357 agentDataMap.Add("TransactionID", OSD.FromUUID(PlacesReply.TransactionData.TransactionID));
358 agentData.Add(agentDataMap);
359 body.Add("AgentData", agentData);
360
361 OSDArray QueryData = new OSDArray();
362
363 foreach (PlacesReplyPacket.QueryDataBlock groupDataBlock in PlacesReply.QueryData)
364 {
365 OSDMap QueryDataMap = new OSDMap();
366 QueryDataMap.Add("ActualArea", OSD.FromInteger(groupDataBlock.ActualArea));
367 QueryDataMap.Add("BillableArea", OSD.FromInteger(groupDataBlock.BillableArea));
368 QueryDataMap.Add("Description", OSD.FromBinary(groupDataBlock.Desc));
369 QueryDataMap.Add("Dwell", OSD.FromInteger((int)groupDataBlock.Dwell));
370 QueryDataMap.Add("Flags", OSD.FromString(Convert.ToString(groupDataBlock.Flags)));
371 QueryDataMap.Add("GlobalX", OSD.FromInteger((int)groupDataBlock.GlobalX));
372 QueryDataMap.Add("GlobalY", OSD.FromInteger((int)groupDataBlock.GlobalY));
373 QueryDataMap.Add("GlobalZ", OSD.FromInteger((int)groupDataBlock.GlobalZ));
374 QueryDataMap.Add("Name", OSD.FromBinary(groupDataBlock.Name));
375 QueryDataMap.Add("OwnerID", OSD.FromUUID(groupDataBlock.OwnerID));
376 QueryDataMap.Add("SimName", OSD.FromBinary(groupDataBlock.SimName));
377 QueryDataMap.Add("SnapShotID", OSD.FromUUID(groupDataBlock.SnapshotID));
378 QueryDataMap.Add("ProductSku", OSD.FromInteger(0));
379 QueryDataMap.Add("Price", OSD.FromInteger(groupDataBlock.Price));
380
381 QueryData.Add(QueryDataMap);
382 }
383 body.Add("QueryData", QueryData);
384 placesReply.Add("QueryData[]", body);
385
386 return placesReply;
387 }
388
389 public static OSD ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage)
390 {
391 OSDMap message = new OSDMap();
392 message.Add("message", OSD.FromString("ParcelProperties"));
393 OSD message_body = parcelPropertiesMessage.Serialize();
394 message.Add("body", message_body);
395 return message;
396 }
397
398 }
399}