29 using System.Collections;
30 using System.Collections.Generic;
32 using System.Reflection;
33 using System.Threading;
38 using OpenMetaverse.Messages.Linden;
39 using OpenMetaverse.Packets;
40 using OpenMetaverse.StructuredData;
41 using OpenSim.Framework;
42 using OpenSim.Framework.Console;
43 using OpenSim.Framework.Servers;
44 using OpenSim.Framework.Servers.HttpServer;
45 using OpenSim.Region.Framework.Interfaces;
46 using OpenSim.Region.Framework.Scenes;
47 using BlockingLLSDQueue = OpenSim.Framework.BlockingQueue<OpenMetaverse.StructuredData.OSD>;
50 namespace OpenSim.
Region.ClientStack.Linden
58 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"EventQueueGetModule")]
61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62 private static string LogHeader =
"[EVENT QUEUE GET MODULE]";
67 public int DebugLevel {
get; set; }
72 private const int VIEWER_TIMEOUT = 60 * 1000;
74 private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000);
78 private Dictionary<UUID, int> m_ids =
new Dictionary<UUID, int>();
80 private Dictionary<UUID, Queue<OSD>> queues =
new Dictionary<UUID, Queue<OSD>>();
81 private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping =
new Dictionary<UUID, UUID>();
83 #region INonSharedRegionModule methods
93 scene.EventManager.OnClientClosed += ClientClosed;
94 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
96 MainConsole.Instance.Commands.AddCommand(
101 "Turn on event queue debugging\n"
102 +
" <= 0 - turns off all event queue logging\n"
103 +
" >= 1 - turns on event queue setup and outgoing event logging\n"
104 +
" >= 2 - turns on poll notification",
107 MainConsole.Instance.Commands.AddCommand(
112 "Show contents of event queues for logged in avatars. Used for debugging.",
118 if (m_scene != scene)
121 scene.EventManager.OnClientClosed -= ClientClosed;
122 scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
124 scene.UnregisterModuleInterface<
IEventQueue>(
this);
136 public virtual string Name
138 get {
return "EventQueueGetModule"; }
141 public Type ReplaceableInterface
152 if (!(args.Length == 3 &&
int.TryParse(args[2], out debugLevel)))
154 MainConsole.Instance.OutputFormat(
"Usage: debug eq [0|1|2]");
158 DebugLevel = debugLevel;
159 MainConsole.Instance.OutputFormat(
160 "Set event queue debug level to {0} in {1}", DebugLevel, m_scene.RegionInfo.RegionName);
166 MainConsole.Instance.OutputFormat(
"For scene {0}", m_scene.Name);
170 foreach (KeyValuePair<
UUID, Queue<OSD>> kvp
in queues)
172 MainConsole.Instance.OutputFormat(
173 "For agent {0} there are {1} messages queued for send.",
174 kvp.Key, kvp.Value.Count);
184 private Queue<OSD> TryGetQueue(UUID agentId)
188 if (!queues.ContainsKey(agentId))
192 "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}",
193 agentId, m_scene.RegionInfo.RegionName);
195 queues[agentId] =
new Queue<OSD>();
198 return queues[agentId];
208 private Queue<OSD> GetQueue(UUID agentId)
212 if (queues.ContainsKey(agentId))
214 return queues[agentId];
221 #region IEventQueue Members
228 Queue<OSD> queue = GetQueue(avatarID);
238 "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}",
239 avatarID, evMap[
"message"], m_scene.Name);
242 catch (NullReferenceException e)
244 m_log.Error(
"[EVENTQUEUE] Caught exception: " + e);
253 private void ClientClosed(UUID agentID,
Scene scene)
258 queues.Remove(agentID);
260 lock (m_AvatarQueueUUIDMapping)
261 m_AvatarQueueUUIDMapping.Remove(agentID);
265 if (!m_ids.ContainsKey(agentID))
266 m_ids.Remove(agentID);
277 private string GenerateEqgCapPath(UUID eqgUuid)
279 return string.Format(
"/CAPS/EQG/{0}/", eqgUuid);
288 "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}",
289 agentID, caps, m_scene.RegionInfo.RegionName);
291 UUID eventQueueGetUUID;
293 Random rnd =
new Random(Environment.TickCount);
294 int nrnd = rnd.Next(30000000);
300 if (queues.ContainsKey(agentID))
301 queue = queues[agentID];
307 queue =
new Queue<OSD>();
308 queues[agentID] = queue;
316 lock (m_AvatarQueueUUIDMapping)
318 eventQueueGetUUID = UUID.Random();
319 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
322 m_log.DebugFormat(
"[EVENTQUEUE]: Found Existing UUID without a queue");
323 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
325 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
329 if (!m_ids.ContainsKey(agentID))
330 m_ids.Add(agentID, nrnd);
332 m_ids[agentID] = nrnd;
344 lock (m_AvatarQueueUUIDMapping)
348 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
350 m_log.DebugFormat(
"[EVENTQUEUE]: Found Existing UUID!");
351 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
355 eventQueueGetUUID = UUID.Random();
356 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
357 m_log.DebugFormat(
"[EVENTQUEUE]: Using random UUID!");
365 if (!m_ids.ContainsKey(agentID))
366 m_ids.Add(agentID, -nrnd);
368 m_ids[agentID] = -m_ids[agentID];
373 caps.RegisterPollHandler(
375 new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS));
380 Queue<OSD> queue = GetQueue(agentID);
385 return queue.Count > 0;
396 private void LogOutboundDebugMessage(
OSD element, UUID agentId)
400 OSDMap ev = (
OSDMap)element;
402 "Eq OUT {0,-30} to {1,-20} {2,-20}",
403 ev[
"message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name);
407 public Hashtable
GetEvents(UUID requestID, UUID pAgentId)
410 m_log.WarnFormat(
"POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.Name);
412 Queue<OSD> queue = GetQueue(pAgentId);
415 return NoEvents(requestID, pAgentId);
421 bool negativeID =
false;
425 if (queue.Count == 0)
426 return NoEvents(requestID, pAgentId);
429 thisID = m_ids[pAgentId];
437 while (queue.Count > 0)
439 element = queue.Dequeue();
445 LogOutboundDebugMessage(element, pAgentId);
456 events.Add(
"events", array);
457 events.Add(
"id",
new OSDInteger(thisID));
460 if (negativeID && element == null)
462 Random rnd =
new Random(Environment.TickCount);
463 thisID = rnd.Next(30000000);
470 m_ids[pAgentId] = thisID + 1;
474 if (array.Count == 0)
475 return NoEvents(requestID, pAgentId);
477 Hashtable responsedata =
new Hashtable();
478 responsedata[
"int_response_code"] = 200;
479 responsedata[
"content_type"] =
"application/xml";
480 responsedata[
"keepalive"] =
false;
481 responsedata[
"reusecontext"] =
false;
482 responsedata[
"str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
487 public Hashtable
NoEvents(UUID requestID, UUID agentID)
489 Hashtable responsedata =
new Hashtable();
490 responsedata[
"int_response_code"] = 502;
491 responsedata[
"content_type"] =
"text/plain";
492 responsedata[
"keepalive"] =
false;
493 responsedata[
"reusecontext"] =
false;
494 responsedata[
"str_response_string"] =
"<llsd></llsd>";
495 responsedata[
"error_status_text"] =
"<llsd></llsd>";
496 responsedata[
"http_protocol_version"] =
"HTTP/1.0";
502 OSD item = EventQueueHelper.DisableSimulator(handle);
503 Enqueue(item, avatarID);
506 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID,
int regionSizeX,
int regionSizeY)
509 m_log.DebugFormat(
"{0} EnableSimulator. handle={1}, endPoint={2}, avatarID={3}",
510 LogHeader, handle, endPoint, avatarID, regionSizeX, regionSizeY);
512 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY);
513 Enqueue(item, avatarID);
517 ulong regionHandle,
int regionSizeX,
int regionSizeY)
520 m_log.DebugFormat(
"{0} EstablishAgentCommunication. handle={1}, endPoint={2}, avatarID={3}",
521 LogHeader, regionHandle, endPoint, avatarID, regionSizeX, regionSizeY);
523 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY);
524 Enqueue(item, avatarID);
528 IPEndPoint regionExternalEndPoint,
529 uint locationID, uint flags,
string capsURL,
530 UUID avatarID,
int regionSizeX,
int regionSizeY)
533 m_log.DebugFormat(
"{0} TeleportFinishEvent. handle={1}, endPoint={2}, avatarID={3}",
534 LogHeader, regionHandle, regionExternalEndPoint, avatarID, regionSizeX, regionSizeY);
536 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint,
537 locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY);
538 Enqueue(item, avatarID);
541 public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
542 IPEndPoint newRegionExternalEndPoint,
543 string capsURL, UUID avatarID, UUID sessionID,
int regionSizeX,
int regionSizeY)
546 m_log.DebugFormat(
"{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>",
547 LogHeader, handle, avatarID, regionSizeX, regionSizeY);
549 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint,
550 capsURL, avatarID, sessionID, regionSizeX, regionSizeY);
551 Enqueue(item, avatarID);
555 UUID fromAgent,
string message, UUID toAgent,
string fromName, byte dialog,
556 uint timeStamp,
bool offline,
int parentEstateID, Vector3 position,
557 uint ttl, UUID transactionID,
bool fromGroup, byte[] binaryBucket)
559 OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog,
560 timeStamp, offline, parentEstateID, position, ttl, transactionID,
561 fromGroup, binaryBucket);
562 Enqueue(item, toAgent);
568 bool isModerator,
bool textMute)
570 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat,
571 isModerator, textMute);
572 Enqueue(item, fromAgent);
576 public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID)
578 OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage);
579 Enqueue(item, avatarID);
584 OSD item = EventQueueHelper.GroupMembership(groupUpdate);
585 Enqueue(item, avatarID);
588 public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID)
590 OSD item = EventQueueHelper.PlacesQuery(groupUpdate);
591 Enqueue(item, avatarID);
596 return EventQueueHelper.ScriptRunningReplyEvent(objectID, itemID, running, mono);
601 return EventQueueHelper.BuildEvent(eventName, eventBody);
605 float density,
float friction,
float bounce,
float gravmod,UUID avatarID)
607 OSD item = EventQueueHelper.partPhysicsProperties(localID, physhapetype,
608 density, friction, bounce, gravmod);
609 Enqueue(item, avatarID);
void partPhysicsProperties(uint localID, byte physhapetype, float density, float friction, float bounce, float gravmod, UUID avatarID)
OpenMetaverse.StructuredData.OSDArray OSDArray
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
OSD ScriptRunningEvent(UUID objectID, UUID itemID, bool running, bool mono)
OpenMetaverse.StructuredData.OSDMap OSDMap
bool HasEvents(UUID requestID, UUID agentID)
OSD BuildEvent(string eventName, OSD eventBody)
OpenSim.Framework.Capabilities.Caps Caps
virtual void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID)
Hashtable GetEvents(UUID requestID, UUID pAgentId)
virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, IPEndPoint newRegionExternalEndPoint, string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY)
void ChatterboxInvitation(UUID sessionID, string sessionName, UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID, Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat, bool isModerator, bool textMute)
bool Enqueue(OSD ev, UUID avatarID)
void HandleShowEq(string module, string[] args)
void OnRegisterCaps(UUID agentID, Caps caps)
virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY)
OpenSim.Framework.Capabilities.Caps Caps
OpenMetaverse.StructuredData.OSD OSD
Hashtable NoEvents(UUID requestID, UUID agentID)
void DisableSimulator(ulong handle, UUID avatarID)
void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID)
virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, uint locationID, uint flags, string capsURL, UUID avatarID, int regionSizeX, int regionSizeY)
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
OpenSim.Framework.BlockingQueue< OpenMetaverse.StructuredData.OSD > BlockingLLSDQueue
virtual void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID)
virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath, ulong regionHandle, int regionSizeX, int regionSizeY)
void HandleDebugEq(string module, string[] args)