aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/Caps/EventQueue
diff options
context:
space:
mode:
authorUbitUmarov2015-09-01 11:43:07 +0100
committerUbitUmarov2015-09-01 11:43:07 +0100
commitfb78b182520fc9bb0f971afd0322029c70278ea6 (patch)
treeb4e30d383938fdeef8c92d1d1c2f44bb61d329bd /OpenSim/Region/ClientStack/Linden/Caps/EventQueue
parentlixo (diff)
parentMantis #7713: fixed bug introduced by 1st MOSES patch. (diff)
downloadopensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.zip
opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.gz
opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.bz2
opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.xz
Merge remote-tracking branch 'os/master'
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs830
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs433
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs190
3 files changed, 1453 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
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..384af74
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -0,0 +1,433 @@
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, int regionSizeX, int regionSizeY)
74 {
75 OSDMap llsdSimInfo = new OSDMap(5);
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 llsdSimInfo.Add("RegionSizeX", OSD.FromUInteger((uint) regionSizeX));
81 llsdSimInfo.Add("RegionSizeY", OSD.FromUInteger((uint) regionSizeY));
82
83 OSDArray arr = new OSDArray(1);
84 arr.Add(llsdSimInfo);
85
86 OSDMap llsdBody = new OSDMap(1);
87 llsdBody.Add("SimulatorInfo", arr);
88
89 return BuildEvent("EnableSimulator", llsdBody);
90 }
91
92 public static OSD DisableSimulator(ulong handle)
93 {
94 //OSDMap llsdSimInfo = new OSDMap(1);
95
96 //llsdSimInfo.Add("Handle", new OSDBinary(regionHandleToByteArray(handle)));
97
98 //OSDArray arr = new OSDArray(1);
99 //arr.Add(llsdSimInfo);
100
101 OSDMap llsdBody = new OSDMap(0);
102 //llsdBody.Add("SimulatorInfo", arr);
103
104 return BuildEvent("DisableSimulator", llsdBody);
105 }
106
107 public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
108 IPEndPoint newRegionExternalEndPoint,
109 string capsURL, UUID agentID, UUID sessionID,
110 int regionSizeX, int regionSizeY)
111 {
112 OSDArray lookAtArr = new OSDArray(3);
113 lookAtArr.Add(OSD.FromReal(lookAt.X));
114 lookAtArr.Add(OSD.FromReal(lookAt.Y));
115 lookAtArr.Add(OSD.FromReal(lookAt.Z));
116
117 OSDArray positionArr = new OSDArray(3);
118 positionArr.Add(OSD.FromReal(pos.X));
119 positionArr.Add(OSD.FromReal(pos.Y));
120 positionArr.Add(OSD.FromReal(pos.Z));
121
122 OSDMap infoMap = new OSDMap(2);
123 infoMap.Add("LookAt", lookAtArr);
124 infoMap.Add("Position", positionArr);
125
126 OSDArray infoArr = new OSDArray(1);
127 infoArr.Add(infoMap);
128
129 OSDMap agentDataMap = new OSDMap(2);
130 agentDataMap.Add("AgentID", OSD.FromUUID(agentID));
131 agentDataMap.Add("SessionID", OSD.FromUUID(sessionID));
132
133 OSDArray agentDataArr = new OSDArray(1);
134 agentDataArr.Add(agentDataMap);
135
136 OSDMap regionDataMap = new OSDMap(6);
137 regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle)));
138 regionDataMap.Add("SeedCapability", OSD.FromString(capsURL));
139 regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes()));
140 regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port));
141 regionDataMap.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX));
142 regionDataMap.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY));
143
144 OSDArray regionDataArr = new OSDArray(1);
145 regionDataArr.Add(regionDataMap);
146
147 OSDMap llsdBody = new OSDMap(3);
148 llsdBody.Add("Info", infoArr);
149 llsdBody.Add("AgentData", agentDataArr);
150 llsdBody.Add("RegionData", regionDataArr);
151
152 return BuildEvent("CrossedRegion", llsdBody);
153 }
154
155 public static OSD TeleportFinishEvent(
156 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
157 uint locationID, uint flags, string capsURL, UUID agentID,
158 int regionSizeX, int regionSizeY)
159 {
160 OSDMap info = new OSDMap();
161 info.Add("AgentID", OSD.FromUUID(agentID));
162 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this?
163 info.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(regionHandle)));
164 info.Add("SeedCapability", OSD.FromString(capsURL));
165 info.Add("SimAccess", OSD.FromInteger(simAccess));
166 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes()));
167 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
168 info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
169 info.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX));
170 info.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY));
171
172 OSDArray infoArr = new OSDArray();
173 infoArr.Add(info);
174
175 OSDMap body = new OSDMap();
176 body.Add("Info", infoArr);
177
178 return BuildEvent("TeleportFinish", body);
179 }
180
181 public static OSD ScriptRunningReplyEvent(UUID objectID, UUID itemID, bool running, bool mono)
182 {
183 OSDMap script = new OSDMap();
184 script.Add("ObjectID", OSD.FromUUID(objectID));
185 script.Add("ItemID", OSD.FromUUID(itemID));
186 script.Add("Running", OSD.FromBoolean(running));
187 script.Add("Mono", OSD.FromBoolean(mono));
188
189 OSDArray scriptArr = new OSDArray();
190 scriptArr.Add(script);
191
192 OSDMap body = new OSDMap();
193 body.Add("Script", scriptArr);
194
195 return BuildEvent("ScriptRunningReply", body);
196 }
197
198 public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap,
199 ulong regionHandle, int regionSizeX, int regionSizeY)
200 {
201 OSDMap body = new OSDMap(6)
202 {
203 {"agent-id", new OSDUUID(agentID)},
204 {"sim-ip-and-port", new OSDString(simIpAndPort)},
205 {"seed-capability", new OSDString(seedcap)},
206 {"region-handle", OSD.FromULong(regionHandle)},
207 {"region-size-x", OSD.FromInteger(regionSizeX)},
208 {"region-size-y", OSD.FromInteger(regionSizeY)}
209 };
210
211 return BuildEvent("EstablishAgentCommunication", body);
212 }
213
214 public static OSD KeepAliveEvent()
215 {
216 return BuildEvent("FAKEEVENT", new OSDMap());
217 }
218
219 public static OSD AgentParams(UUID agentID, bool checkEstate, int godLevel, bool limitedToEstate)
220 {
221 OSDMap body = new OSDMap(4);
222
223 body.Add("agent_id", new OSDUUID(agentID));
224 body.Add("check_estate", new OSDInteger(checkEstate ? 1 : 0));
225 body.Add("god_level", new OSDInteger(godLevel));
226 body.Add("limited_to_estate", new OSDInteger(limitedToEstate ? 1 : 0));
227
228 return body;
229 }
230
231 public static OSD InstantMessageParams(UUID fromAgent, string message, UUID toAgent,
232 string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID,
233 Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
234 {
235 OSDMap messageParams = new OSDMap(15);
236 messageParams.Add("type", new OSDInteger((int)dialog));
237
238 OSDArray positionArray = new OSDArray(3);
239 positionArray.Add(OSD.FromReal(position.X));
240 positionArray.Add(OSD.FromReal(position.Y));
241 positionArray.Add(OSD.FromReal(position.Z));
242 messageParams.Add("position", positionArray);
243
244 messageParams.Add("region_id", new OSDUUID(UUID.Zero));
245 messageParams.Add("to_id", new OSDUUID(toAgent));
246 messageParams.Add("source", new OSDInteger(0));
247
248 OSDMap data = new OSDMap(1);
249 data.Add("binary_bucket", OSD.FromBinary(binaryBucket));
250 messageParams.Add("data", data);
251 messageParams.Add("message", new OSDString(message));
252 messageParams.Add("id", new OSDUUID(transactionID));
253 messageParams.Add("from_name", new OSDString(fromName));
254 messageParams.Add("timestamp", new OSDInteger((int)timeStamp));
255 messageParams.Add("offline", new OSDInteger(offline ? 1 : 0));
256 messageParams.Add("parent_estate_id", new OSDInteger(parentEstateID));
257 messageParams.Add("ttl", new OSDInteger((int)ttl));
258 messageParams.Add("from_id", new OSDUUID(fromAgent));
259 messageParams.Add("from_group", new OSDInteger(fromGroup ? 1 : 0));
260
261 return messageParams;
262 }
263
264 public static OSD InstantMessage(UUID fromAgent, string message, UUID toAgent,
265 string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID,
266 Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket,
267 bool checkEstate, int godLevel, bool limitedToEstate)
268 {
269 OSDMap im = new OSDMap(2);
270 im.Add("message_params", InstantMessageParams(fromAgent, message, toAgent,
271 fromName, dialog, timeStamp, offline, parentEstateID,
272 position, ttl, transactionID, fromGroup, binaryBucket));
273
274 im.Add("agent_params", AgentParams(fromAgent, checkEstate, godLevel, limitedToEstate));
275
276 return im;
277 }
278
279
280 public static OSD ChatterboxInvitation(UUID sessionID, string sessionName,
281 UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog,
282 uint timeStamp, bool offline, int parentEstateID, Vector3 position,
283 uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
284 {
285 OSDMap body = new OSDMap(5);
286 body.Add("session_id", new OSDUUID(sessionID));
287 body.Add("from_name", new OSDString(fromName));
288 body.Add("session_name", new OSDString(sessionName));
289 body.Add("from_id", new OSDUUID(fromAgent));
290
291 body.Add("instantmessage", InstantMessage(fromAgent, message, toAgent,
292 fromName, dialog, timeStamp, offline, parentEstateID, position,
293 ttl, transactionID, fromGroup, binaryBucket, true, 0, true));
294
295 OSDMap chatterboxInvitation = new OSDMap(2);
296 chatterboxInvitation.Add("message", new OSDString("ChatterBoxInvitation"));
297 chatterboxInvitation.Add("body", body);
298 return chatterboxInvitation;
299 }
300
301 public static OSD ChatterBoxSessionAgentListUpdates(UUID sessionID,
302 UUID agentID, bool canVoiceChat, bool isModerator, bool textMute)
303 {
304 OSDMap body = new OSDMap();
305 OSDMap agentUpdates = new OSDMap();
306 OSDMap infoDetail = new OSDMap();
307 OSDMap mutes = new OSDMap();
308
309 mutes.Add("text", OSD.FromBoolean(textMute));
310 infoDetail.Add("can_voice_chat", OSD.FromBoolean(canVoiceChat));
311 infoDetail.Add("is_moderator", OSD.FromBoolean(isModerator));
312 infoDetail.Add("mutes", mutes);
313 OSDMap info = new OSDMap();
314 info.Add("info", infoDetail);
315 agentUpdates.Add(agentID.ToString(), info);
316 body.Add("agent_updates", agentUpdates);
317 body.Add("session_id", OSD.FromUUID(sessionID));
318 body.Add("updates", new OSD());
319
320 OSDMap chatterBoxSessionAgentListUpdates = new OSDMap();
321 chatterBoxSessionAgentListUpdates.Add("message", OSD.FromString("ChatterBoxSessionAgentListUpdates"));
322 chatterBoxSessionAgentListUpdates.Add("body", body);
323
324 return chatterBoxSessionAgentListUpdates;
325 }
326
327 public static OSD GroupMembership(AgentGroupDataUpdatePacket groupUpdatePacket)
328 {
329 OSDMap groupUpdate = new OSDMap();
330 groupUpdate.Add("message", OSD.FromString("AgentGroupDataUpdate"));
331
332 OSDMap body = new OSDMap();
333 OSDArray agentData = new OSDArray();
334 OSDMap agentDataMap = new OSDMap();
335 agentDataMap.Add("AgentID", OSD.FromUUID(groupUpdatePacket.AgentData.AgentID));
336 agentData.Add(agentDataMap);
337 body.Add("AgentData", agentData);
338
339 OSDArray groupData = new OSDArray();
340
341 foreach (AgentGroupDataUpdatePacket.GroupDataBlock groupDataBlock in groupUpdatePacket.GroupData)
342 {
343 OSDMap groupDataMap = new OSDMap();
344 groupDataMap.Add("ListInProfile", OSD.FromBoolean(false));
345 groupDataMap.Add("GroupID", OSD.FromUUID(groupDataBlock.GroupID));
346 groupDataMap.Add("GroupInsigniaID", OSD.FromUUID(groupDataBlock.GroupInsigniaID));
347 groupDataMap.Add("Contribution", OSD.FromInteger(groupDataBlock.Contribution));
348 groupDataMap.Add("GroupPowers", OSD.FromBinary(ulongToByteArray(groupDataBlock.GroupPowers)));
349 groupDataMap.Add("GroupName", OSD.FromString(Utils.BytesToString(groupDataBlock.GroupName)));
350 groupDataMap.Add("AcceptNotices", OSD.FromBoolean(groupDataBlock.AcceptNotices));
351
352 groupData.Add(groupDataMap);
353
354 }
355 body.Add("GroupData", groupData);
356 groupUpdate.Add("body", body);
357
358 return groupUpdate;
359 }
360
361 public static OSD PlacesQuery(PlacesReplyPacket PlacesReply)
362 {
363 OSDMap placesReply = new OSDMap();
364 placesReply.Add("message", OSD.FromString("PlacesReplyMessage"));
365
366 OSDMap body = new OSDMap();
367 OSDArray agentData = new OSDArray();
368 OSDMap agentDataMap = new OSDMap();
369 agentDataMap.Add("AgentID", OSD.FromUUID(PlacesReply.AgentData.AgentID));
370 agentDataMap.Add("QueryID", OSD.FromUUID(PlacesReply.AgentData.QueryID));
371 agentDataMap.Add("TransactionID", OSD.FromUUID(PlacesReply.TransactionData.TransactionID));
372 agentData.Add(agentDataMap);
373 body.Add("AgentData", agentData);
374
375 OSDArray QueryData = new OSDArray();
376
377 foreach (PlacesReplyPacket.QueryDataBlock groupDataBlock in PlacesReply.QueryData)
378 {
379 OSDMap QueryDataMap = new OSDMap();
380 QueryDataMap.Add("ActualArea", OSD.FromInteger(groupDataBlock.ActualArea));
381 QueryDataMap.Add("BillableArea", OSD.FromInteger(groupDataBlock.BillableArea));
382 QueryDataMap.Add("Description", OSD.FromBinary(groupDataBlock.Desc));
383 QueryDataMap.Add("Dwell", OSD.FromInteger((int)groupDataBlock.Dwell));
384 QueryDataMap.Add("Flags", OSD.FromString(Convert.ToString(groupDataBlock.Flags)));
385 QueryDataMap.Add("GlobalX", OSD.FromInteger((int)groupDataBlock.GlobalX));
386 QueryDataMap.Add("GlobalY", OSD.FromInteger((int)groupDataBlock.GlobalY));
387 QueryDataMap.Add("GlobalZ", OSD.FromInteger((int)groupDataBlock.GlobalZ));
388 QueryDataMap.Add("Name", OSD.FromBinary(groupDataBlock.Name));
389 QueryDataMap.Add("OwnerID", OSD.FromUUID(groupDataBlock.OwnerID));
390 QueryDataMap.Add("SimName", OSD.FromBinary(groupDataBlock.SimName));
391 QueryDataMap.Add("SnapShotID", OSD.FromUUID(groupDataBlock.SnapshotID));
392 QueryDataMap.Add("ProductSku", OSD.FromInteger(0));
393 QueryDataMap.Add("Price", OSD.FromInteger(groupDataBlock.Price));
394
395 QueryData.Add(QueryDataMap);
396 }
397 body.Add("QueryData", QueryData);
398 placesReply.Add("QueryData[]", body);
399
400 return placesReply;
401 }
402
403 public static OSD ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage)
404 {
405 OSDMap message = new OSDMap();
406 message.Add("message", OSD.FromString("ParcelProperties"));
407 OSD message_body = parcelPropertiesMessage.Serialize();
408 message.Add("body", message_body);
409 return message;
410 }
411
412 public static OSD partPhysicsProperties(uint localID, byte physhapetype,
413 float density, float friction, float bounce, float gravmod)
414 {
415
416 OSDMap physinfo = new OSDMap(6);
417 physinfo["LocalID"] = localID;
418 physinfo["Density"] = density;
419 physinfo["Friction"] = friction;
420 physinfo["GravityMultiplier"] = gravmod;
421 physinfo["Restitution"] = bounce;
422 physinfo["PhysicsShapeType"] = (int)physhapetype;
423
424 OSDArray array = new OSDArray(1);
425 array.Add(physinfo);
426
427 OSDMap llsdBody = new OSDMap(1);
428 llsdBody.Add("ObjectData", array);
429
430 return BuildEvent("ObjectPhysicsProperties", llsdBody);
431 }
432 }
433}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
new file mode 100644
index 0000000..16a902d
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
@@ -0,0 +1,190 @@
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 log4net.Config;
33using Nini.Config;
34using NUnit.Framework;
35using OpenMetaverse;
36using OpenMetaverse.Packets;
37using OpenMetaverse.StructuredData;
38using OpenSim.Framework;
39using OpenSim.Framework.Servers;
40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Region.ClientStack.Linden;
42using OpenSim.Region.CoreModules.Framework;
43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Region.OptionalModules.World.NPC;
45using OpenSim.Tests.Common;
46
47namespace OpenSim.Region.ClientStack.Linden.Tests
48{
49 [TestFixture]
50 public class EventQueueTests : OpenSimTestCase
51 {
52 private TestScene m_scene;
53 private EventQueueGetModule m_eqgMod;
54 private NPCModule m_npcMod;
55
56 [SetUp]
57 public override void SetUp()
58 {
59 base.SetUp();
60
61 uint port = 9999;
62 uint sslPort = 9998;
63
64 // This is an unfortunate bit of clean up we have to do because MainServer manages things through static
65 // variables and the VM is not restarted between tests.
66 MainServer.RemoveHttpServer(port);
67
68 BaseHttpServer server = new BaseHttpServer(port, false, sslPort, "");
69 MainServer.AddHttpServer(server);
70 MainServer.Instance = server;
71
72 IConfigSource config = new IniConfigSource();
73 config.AddConfig("Startup");
74 config.Configs["Startup"].Set("EventQueue", "true");
75
76 CapabilitiesModule capsModule = new CapabilitiesModule();
77 m_eqgMod = new EventQueueGetModule();
78
79 // For NPC test support
80 config.AddConfig("NPC");
81 config.Configs["NPC"].Set("Enabled", "true");
82 m_npcMod = new NPCModule();
83
84 m_scene = new SceneHelpers().SetupScene();
85 SceneHelpers.SetupSceneModules(m_scene, config, capsModule, m_eqgMod, m_npcMod);
86 }
87
88 [Test]
89 public void TestAddForClient()
90 {
91 TestHelpers.InMethod();
92// log4net.Config.XmlConfigurator.Configure();
93
94 SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
95
96 // TODO: Add more assertions for the other aspects of event queues
97 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(1));
98 }
99
100 [Test]
101 public void TestRemoveForClient()
102 {
103 TestHelpers.InMethod();
104// TestHelpers.EnableLogging();
105
106 UUID spId = TestHelpers.ParseTail(0x1);
107
108 SceneHelpers.AddScenePresence(m_scene, spId);
109 m_scene.CloseAgent(spId, false);
110
111 // TODO: Add more assertions for the other aspects of event queues
112 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));
113 }
114
115 [Test]
116 public void TestEnqueueMessage()
117 {
118 TestHelpers.InMethod();
119// log4net.Config.XmlConfigurator.Configure();
120
121 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
122
123 string messageName = "TestMessage";
124
125 m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), sp.UUID);
126
127 Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID);
128
129 Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK));
130
131// Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]);
132
133 OSDMap rawOsd = (OSDMap)OSDParser.DeserializeLLSDXml((string)eventsResponse["str_response_string"]);
134 OSDArray eventsOsd = (OSDArray)rawOsd["events"];
135
136 bool foundUpdate = false;
137 foreach (OSD osd in eventsOsd)
138 {
139 OSDMap eventOsd = (OSDMap)osd;
140
141 if (eventOsd["message"] == messageName)
142 foundUpdate = true;
143 }
144
145 Assert.That(foundUpdate, Is.True, string.Format("Did not find {0} in response", messageName));
146 }
147
148 /// <summary>
149 /// Test an attempt to put a message on the queue of a user that is not in the region.
150 /// </summary>
151 [Test]
152 public void TestEnqueueMessageNoUser()
153 {
154 TestHelpers.InMethod();
155 TestHelpers.EnableLogging();
156
157 string messageName = "TestMessage";
158
159 m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), TestHelpers.ParseTail(0x1));
160
161 Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, TestHelpers.ParseTail(0x1));
162
163 Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway));
164 }
165
166 /// <summary>
167 /// NPCs do not currently have an event queue but a caller may try to send a message anyway, so check behaviour.
168 /// </summary>
169 [Test]
170 public void TestEnqueueMessageToNpc()
171 {
172 TestHelpers.InMethod();
173// TestHelpers.EnableLogging();
174
175 UUID npcId
176 = m_npcMod.CreateNPC(
177 "John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, new AvatarAppearance());
178
179 ScenePresence npc = m_scene.GetScenePresence(npcId);
180
181 string messageName = "TestMessage";
182
183 m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), npc.UUID);
184
185 Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, npc.UUID);
186
187 Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway));
188 }
189 }
190} \ No newline at end of file