diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index ddae267a2d..b0d30b68e0 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -175,27 +175,6 @@ namespace OpenSim.Region.ClientStack.Linden } } - /// - /// Always returns a valid queue - /// - /// - /// - private Queue TryGetQueue(UUID agentId) - { - lock (queues) - { - if (!queues.ContainsKey(agentId)) - { - m_log.DebugFormat( - "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", - agentId, m_scene.RegionInfo.RegionName); - queues[agentId] = new Queue(); - } - - return queues[agentId]; - } - } - /// /// May return a null queue /// @@ -278,47 +257,95 @@ namespace OpenSim.Region.ClientStack.Linden public void OnRegisterCaps(UUID agentID, Caps caps) { // Register an event queue for the client - m_log.DebugFormat( "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", agentID, caps, m_scene.RegionInfo.RegionName); - // Let's instantiate a Queue for this agent right now - TryGetQueue(agentID); - UUID eventQueueGetUUID; + Queue queue; + Random rnd = new Random(Environment.TickCount); + int nrnd = rnd.Next(30000000); + if (nrnd < 0) + nrnd = -nrnd; - lock (m_AvatarQueueUUIDMapping) + lock (queues) { - // Reuse open queues. The client does! - // Its reuse caps path not queues those are been reused already - if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) + if (queues.ContainsKey(agentID)) + queue = queues[agentID]; + else + queue = null; + + if (queue == null) { - m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); - eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; + queue = new Queue(); + queues[agentID] = queue; + + // push markers to handle old responses still waiting + // this will cost at most viewer getting two forced noevents + // even being a new queue better be safe + queue.Enqueue(null); + queue.Enqueue(null); // one should be enough + + lock (m_AvatarQueueUUIDMapping) + { + eventQueueGetUUID = UUID.Random(); + if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) + { + // oops this should not happen ? + m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID without a queue"); + eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; + } + m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); + } + lock (m_ids) + { + if (!m_ids.ContainsKey(agentID)) + m_ids.Add(agentID, nrnd); + else + m_ids[agentID] = nrnd; + } } else { - eventQueueGetUUID = UUID.Random(); - m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); - m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); + // push markers to handle old responses still waiting + // this will cost at most viewer getting two forced noevents + // even being a new queue better be safe + queue.Enqueue(null); + queue.Enqueue(null); // one should be enough + + // reuse or not to reuse TODO FIX + lock (m_AvatarQueueUUIDMapping) + { + // Reuse open queues. The client does! + // Its reuse caps path not queues those are been reused already + if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) + { + m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); + eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; + } + else + { + eventQueueGetUUID = UUID.Random(); + m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); + m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); + } + } + lock (m_ids) + { + // change to negative numbers so they are changed at end of sending first marker + // old data on a queue may be sent on a response for a new caps + // but at least will be sent with coerent IDs + if (!m_ids.ContainsKey(agentID)) + m_ids.Add(agentID, -nrnd); // should not happen + else + m_ids[agentID] = -m_ids[agentID]; + } } } caps.RegisterPollHandler( "EventQueueGet", new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS)); - - Random rnd = new Random(Environment.TickCount); - int nrnd = rnd.Next(30000000); - - lock (m_ids) - { - if (!m_ids.ContainsKey(agentID)) - m_ids.Add(agentID, nrnd); - else - m_ids[agentID] = nrnd; - } } public bool HasEvents(UUID requestID, UUID agentID) @@ -361,55 +388,65 @@ namespace OpenSim.Region.ClientStack.Linden return NoEvents(requestID, pAgentId); } - OSD element; + OSD element = null;; + OSDArray array = new OSDArray(); + int thisID = 0; + bool negativeID = false; + lock (queue) { if (queue.Count == 0) return NoEvents(requestID, pAgentId); - element = queue.Dequeue(); // 15s timeout - } - int thisID = 0; - lock (m_ids) - thisID = m_ids[pAgentId]; + lock (m_ids) + thisID = m_ids[pAgentId]; - OSDArray array = new OSDArray(); - if (element == null) // didn't have an event in 15s - { - // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! - array.Add(EventQueueHelper.KeepAliveEvent()); - //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName); - } - else - { - if (DebugLevel > 0) - LogOutboundDebugMessage(element, pAgentId); - - array.Add(element); - - lock (queue) + if (thisID < 0) { - while (queue.Count > 0) - { - element = queue.Dequeue(); - - if (DebugLevel > 0) - LogOutboundDebugMessage(element, pAgentId); - - array.Add(element); - thisID++; - } + negativeID = true; + thisID = -thisID; + } + + while (queue.Count > 0) + { + element = queue.Dequeue(); + // add elements until a marker is found + // so they get into a response + if (element == null) + break; + if (DebugLevel > 0) + LogOutboundDebugMessage(element, pAgentId); + array.Add(element); + thisID++; } } - OSDMap events = new OSDMap(); - events.Add("events", array); + OSDMap events = null; + + if (array.Count > 0) + { + events = new OSDMap(); + events.Add("events", array); + events.Add("id", new OSDInteger(thisID)); + } + + if (negativeID && element == null) + { + Random rnd = new Random(Environment.TickCount); + thisID = rnd.Next(30000000); + if (thisID < 0) + thisID = -thisID; + } - events.Add("id", new OSDInteger(thisID)); lock (m_ids) { m_ids[pAgentId] = thisID + 1; } + + // if there where no elements before a marker send a NoEvents + if (array.Count == 0) + return NoEvents(requestID, pAgentId); + Hashtable responsedata = new Hashtable(); responsedata["int_response_code"] = 200; responsedata["content_type"] = "application/xml"; @@ -432,7 +469,6 @@ namespace OpenSim.Region.ClientStack.Linden responsedata["http_protocol_version"] = "HTTP/1.0"; return responsedata; } - public void DisableSimulator(ulong handle, UUID avatarID) {