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.cs474
1 files changed, 128 insertions, 346 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index 9b9f6a7..feb3322 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -78,7 +78,6 @@ namespace OpenSim.Region.ClientStack.Linden
78 private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); 78 private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>();
79 79
80 private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); 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>(); 81 private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>();
83 82
84 #region INonSharedRegionModule methods 83 #region INonSharedRegionModule methods
@@ -201,6 +200,7 @@ namespace OpenSim.Region.ClientStack.Linden
201 } 200 }
202 201
203 /// <summary> 202 /// <summary>
203
204 /// May return a null queue 204 /// May return a null queue
205 /// </summary> 205 /// </summary>
206 /// <param name="agentId"></param> 206 /// <param name="agentId"></param>
@@ -231,18 +231,12 @@ namespace OpenSim.Region.ClientStack.Linden
231 lock (queue) 231 lock (queue)
232 queue.Enqueue(ev); 232 queue.Enqueue(ev);
233 } 233 }
234 else if (DebugLevel > 0) 234 else
235 { 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; 236 OSDMap evMap = (OSDMap)ev;
242 m_log.WarnFormat( 237 m_log.WarnFormat(
243 "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} {1} when placing message {2} in region {3}", 238 "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}",
244 sp.Name, sp.UUID, evMap["message"], m_scene.Name); 239 avatarID, evMap["message"], m_scene.Name);
245 }
246 } 240 }
247 } 241 }
248 catch (NullReferenceException e) 242 catch (NullReferenceException e)
@@ -263,28 +257,13 @@ namespace OpenSim.Region.ClientStack.Linden
263 lock (queues) 257 lock (queues)
264 queues.Remove(agentID); 258 queues.Remove(agentID);
265 259
266 List<UUID> removeitems = new List<UUID>();
267 lock (m_AvatarQueueUUIDMapping) 260 lock (m_AvatarQueueUUIDMapping)
268 m_AvatarQueueUUIDMapping.Remove(agentID); 261 m_AvatarQueueUUIDMapping.Remove(agentID);
269 262
270 UUID searchval = UUID.Zero; 263 lock (m_ids)
271
272 removeitems.Clear();
273
274 lock (m_QueueUUIDAvatarMapping)
275 { 264 {
276 foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys) 265 if (!m_ids.ContainsKey(agentID))
277 { 266 m_ids.Remove(agentID);
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 } 267 }
289 268
290 // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); 269 // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
@@ -309,55 +288,95 @@ namespace OpenSim.Region.ClientStack.Linden
309 "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", 288 "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}",
310 agentID, caps, m_scene.RegionInfo.RegionName); 289 agentID, caps, m_scene.RegionInfo.RegionName);
311 290
312 // Let's instantiate a Queue for this agent right now
313 TryGetQueue(agentID);
314
315 UUID eventQueueGetUUID; 291 UUID eventQueueGetUUID;
292 Queue<OSD> queue;
293 Random rnd = new Random(Environment.TickCount);
294 int nrnd = rnd.Next(30000000);
295 if (nrnd < 0)
296 nrnd = -nrnd;
316 297
317 lock (m_AvatarQueueUUIDMapping) 298 lock (queues)
318 { 299 {
319 // Reuse open queues. The client does! 300 if (queues.ContainsKey(agentID))
320 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) 301 queue = queues[agentID];
302 else
303 queue = null;
304
305 if (queue == null)
321 { 306 {
322 //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); 307 queue = new Queue<OSD>();
323 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; 308 queues[agentID] = queue;
309
310 // push markers to handle old responses still waiting
311 // this will cost at most viewer getting two forced noevents
312 // even being a new queue better be safe
313 queue.Enqueue(null);
314 queue.Enqueue(null); // one should be enough
315
316 lock (m_AvatarQueueUUIDMapping)
317 {
318 eventQueueGetUUID = UUID.Random();
319 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
320 {
321 // oops this should not happen ?
322 m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID without a queue");
323 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
324 }
325 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
326 }
327 lock (m_ids)
328 {
329 if (!m_ids.ContainsKey(agentID))
330 m_ids.Add(agentID, nrnd);
331 else
332 m_ids[agentID] = nrnd;
333 }
324 } 334 }
325 else 335 else
326 { 336 {
327 eventQueueGetUUID = UUID.Random(); 337 // push markers to handle old responses still waiting
328 //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); 338 // this will cost at most viewer getting two forced noevents
339 // even being a new queue better be safe
340 queue.Enqueue(null);
341 queue.Enqueue(null); // one should be enough
342
343 // reuse or not to reuse TODO FIX
344 lock (m_AvatarQueueUUIDMapping)
345 {
346 // Reuse open queues. The client does!
347 // Its reuse caps path not queues those are been reused already
348 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
349 {
350 m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!");
351 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
352 }
353 else
354 {
355 eventQueueGetUUID = UUID.Random();
356 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
357 m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!");
358 }
359 }
360 lock (m_ids)
361 {
362 // change to negative numbers so they are changed at end of sending first marker
363 // old data on a queue may be sent on a response for a new caps
364 // but at least will be sent with coerent IDs
365 if (!m_ids.ContainsKey(agentID))
366 m_ids.Add(agentID, -nrnd); // should not happen
367 else
368 m_ids[agentID] = -m_ids[agentID];
369 }
329 } 370 }
330 } 371 }
331 372
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( 373 caps.RegisterPollHandler(
345 "EventQueueGet", 374 "EventQueueGet",
346 new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS)); 375 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 } 376 }
355 377
356 public bool HasEvents(UUID requestID, UUID agentID) 378 public bool HasEvents(UUID requestID, UUID agentID)
357 { 379 {
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); 380 Queue<OSD> queue = GetQueue(agentID);
362 if (queue != null) 381 if (queue != null)
363 lock (queue) 382 lock (queue)
@@ -366,7 +385,8 @@ namespace OpenSim.Region.ClientStack.Linden
366 return queue.Count > 0; 385 return queue.Count > 0;
367 } 386 }
368 387
369 return false; 388 //m_log.WarnFormat("POLLED FOR EVENTS BY {0} unknown agent", agentID);
389 return true;
370 } 390 }
371 391
372 /// <summary> 392 /// <summary>
@@ -395,55 +415,65 @@ namespace OpenSim.Region.ClientStack.Linden
395 return NoEvents(requestID, pAgentId); 415 return NoEvents(requestID, pAgentId);
396 } 416 }
397 417
398 OSD element; 418 OSD element = null;;
419 OSDArray array = new OSDArray();
420 int thisID = 0;
421 bool negativeID = false;
422
399 lock (queue) 423 lock (queue)
400 { 424 {
401 if (queue.Count == 0) 425 if (queue.Count == 0)
402 return NoEvents(requestID, pAgentId); 426 return NoEvents(requestID, pAgentId);
403 element = queue.Dequeue(); // 15s timeout
404 }
405 427
406 int thisID = 0; 428 lock (m_ids)
407 lock (m_ids) 429 thisID = m_ids[pAgentId];
408 thisID = m_ids[pAgentId];
409 430
410 OSDArray array = new OSDArray(); 431 if (thisID < 0)
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 { 432 {
426 while (queue.Count > 0) 433 negativeID = true;
427 { 434 thisID = -thisID;
428 element = queue.Dequeue(); 435 }
436
437 while (queue.Count > 0)
438 {
439 element = queue.Dequeue();
440 // add elements until a marker is found
441 // so they get into a response
442 if (element == null)
443 break;
444 if (DebugLevel > 0)
445 LogOutboundDebugMessage(element, pAgentId);
446 array.Add(element);
447 thisID++;
448 }
449 }
429 450
430 if (DebugLevel > 0) 451 OSDMap events = null;
431 LogOutboundDebugMessage(element, pAgentId);
432 452
433 array.Add(element); 453 if (array.Count > 0)
434 thisID++; 454 {
435 } 455 events = new OSDMap();
436 } 456 events.Add("events", array);
457 events.Add("id", new OSDInteger(thisID));
437 } 458 }
438 459
439 OSDMap events = new OSDMap(); 460 if (negativeID && element == null)
440 events.Add("events", array); 461 {
462 Random rnd = new Random(Environment.TickCount);
463 thisID = rnd.Next(30000000);
464 if (thisID < 0)
465 thisID = -thisID;
466 }
441 467
442 events.Add("id", new OSDInteger(thisID));
443 lock (m_ids) 468 lock (m_ids)
444 { 469 {
445 m_ids[pAgentId] = thisID + 1; 470 m_ids[pAgentId] = thisID + 1;
446 } 471 }
472
473 // if there where no elements before a marker send a NoEvents
474 if (array.Count == 0)
475 return NoEvents(requestID, pAgentId);
476
447 Hashtable responsedata = new Hashtable(); 477 Hashtable responsedata = new Hashtable();
448 responsedata["int_response_code"] = 200; 478 responsedata["int_response_code"] = 200;
449 responsedata["content_type"] = "application/xml"; 479 responsedata["content_type"] = "application/xml";
@@ -461,260 +491,12 @@ namespace OpenSim.Region.ClientStack.Linden
461 responsedata["content_type"] = "text/plain"; 491 responsedata["content_type"] = "text/plain";
462 responsedata["keepalive"] = false; 492 responsedata["keepalive"] = false;
463 responsedata["reusecontext"] = false; 493 responsedata["reusecontext"] = false;
464 responsedata["str_response_string"] = "Upstream error: "; 494 responsedata["str_response_string"] = "<llsd></llsd>";
465 responsedata["error_status_text"] = "Upstream error:"; 495 responsedata["error_status_text"] = "<llsd></llsd>";
466 responsedata["http_protocol_version"] = "HTTP/1.0"; 496 responsedata["http_protocol_version"] = "HTTP/1.0";
467 return responsedata; 497 return responsedata;
468 } 498 }
469 499
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) 500 public void DisableSimulator(ulong handle, UUID avatarID)
719 { 501 {
720 OSD item = EventQueueHelper.DisableSimulator(handle); 502 OSD item = EventQueueHelper.DisableSimulator(handle);
@@ -827,4 +609,4 @@ namespace OpenSim.Region.ClientStack.Linden
827 Enqueue(item, avatarID); 609 Enqueue(item, avatarID);
828 } 610 }
829 } 611 }
830} \ No newline at end of file 612}