diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | 618 |
1 files changed, 178 insertions, 440 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index eb40eb1..ca6c3ca 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | |||
@@ -65,12 +65,18 @@ namespace OpenSim.Region.ClientStack.Linden | |||
65 | /// </value> | 65 | /// </value> |
66 | public int DebugLevel { get; set; } | 66 | public int DebugLevel { get; set; } |
67 | 67 | ||
68 | // Viewer post requests timeout in 60 secs | ||
69 | // https://bitbucket.org/lindenlab/viewer-release/src/421c20423df93d650cc305dc115922bb30040999/indra/llmessage/llhttpclient.cpp?at=default#cl-44 | ||
70 | // | ||
71 | private const int VIEWER_TIMEOUT = 60 * 1000; | ||
72 | // Just to be safe, we work on a 10 sec shorter cycle | ||
73 | private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000); | ||
74 | |||
68 | protected Scene m_scene; | 75 | protected Scene m_scene; |
69 | 76 | ||
70 | private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); | 77 | private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); |
71 | 78 | ||
72 | private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); | 79 | private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); |
73 | private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>(); | ||
74 | private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); | 80 | private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); |
75 | 81 | ||
76 | #region INonSharedRegionModule methods | 82 | #region INonSharedRegionModule methods |
@@ -84,7 +90,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
84 | scene.RegisterModuleInterface<IEventQueue>(this); | 90 | scene.RegisterModuleInterface<IEventQueue>(this); |
85 | 91 | ||
86 | scene.EventManager.OnClientClosed += ClientClosed; | 92 | scene.EventManager.OnClientClosed += ClientClosed; |
87 | scene.EventManager.OnMakeChildAgent += MakeChildAgent; | ||
88 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | 93 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; |
89 | 94 | ||
90 | MainConsole.Instance.Commands.AddCommand( | 95 | MainConsole.Instance.Commands.AddCommand( |
@@ -113,7 +118,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
113 | return; | 118 | return; |
114 | 119 | ||
115 | scene.EventManager.OnClientClosed -= ClientClosed; | 120 | scene.EventManager.OnClientClosed -= ClientClosed; |
116 | scene.EventManager.OnMakeChildAgent -= MakeChildAgent; | ||
117 | scene.EventManager.OnRegisterCaps -= OnRegisterCaps; | 121 | scene.EventManager.OnRegisterCaps -= OnRegisterCaps; |
118 | 122 | ||
119 | scene.UnregisterModuleInterface<IEventQueue>(this); | 123 | scene.UnregisterModuleInterface<IEventQueue>(this); |
@@ -172,29 +176,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
172 | } | 176 | } |
173 | 177 | ||
174 | /// <summary> | 178 | /// <summary> |
175 | /// Always returns a valid queue | ||
176 | /// </summary> | ||
177 | /// <param name="agentId"></param> | ||
178 | /// <returns></returns> | ||
179 | private Queue<OSD> TryGetQueue(UUID agentId) | ||
180 | { | ||
181 | lock (queues) | ||
182 | { | ||
183 | if (!queues.ContainsKey(agentId)) | ||
184 | { | ||
185 | /* | ||
186 | m_log.DebugFormat( | ||
187 | "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", | ||
188 | agentId, m_scene.RegionInfo.RegionName); | ||
189 | */ | ||
190 | queues[agentId] = new Queue<OSD>(); | ||
191 | } | ||
192 | |||
193 | return queues[agentId]; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /// <summary> | ||
198 | /// May return a null queue | 179 | /// May return a null queue |
199 | /// </summary> | 180 | /// </summary> |
200 | /// <param name="agentId"></param> | 181 | /// <param name="agentId"></param> |
@@ -221,8 +202,17 @@ namespace OpenSim.Region.ClientStack.Linden | |||
221 | { | 202 | { |
222 | Queue<OSD> queue = GetQueue(avatarID); | 203 | Queue<OSD> queue = GetQueue(avatarID); |
223 | if (queue != null) | 204 | if (queue != null) |
205 | { | ||
224 | lock (queue) | 206 | lock (queue) |
225 | queue.Enqueue(ev); | 207 | queue.Enqueue(ev); |
208 | } | ||
209 | else | ||
210 | { | ||
211 | OSDMap evMap = (OSDMap)ev; | ||
212 | m_log.WarnFormat( | ||
213 | "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}", | ||
214 | avatarID, evMap["message"], m_scene.Name); | ||
215 | } | ||
226 | } | 216 | } |
227 | catch (NullReferenceException e) | 217 | catch (NullReferenceException e) |
228 | { | 218 | { |
@@ -237,77 +227,22 @@ namespace OpenSim.Region.ClientStack.Linden | |||
237 | 227 | ||
238 | private void ClientClosed(UUID agentID, Scene scene) | 228 | private void ClientClosed(UUID agentID, Scene scene) |
239 | { | 229 | { |
240 | // m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | 230 | //m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); |
241 | |||
242 | int count = 0; | ||
243 | while (queues.ContainsKey(agentID) && queues[agentID].Count > 0 && count++ < 5) | ||
244 | { | ||
245 | Thread.Sleep(1000); | ||
246 | } | ||
247 | 231 | ||
248 | lock (queues) | 232 | lock (queues) |
249 | { | ||
250 | queues.Remove(agentID); | 233 | queues.Remove(agentID); |
251 | } | ||
252 | 234 | ||
253 | List<UUID> removeitems = new List<UUID>(); | ||
254 | lock (m_AvatarQueueUUIDMapping) | 235 | lock (m_AvatarQueueUUIDMapping) |
255 | { | 236 | m_AvatarQueueUUIDMapping.Remove(agentID); |
256 | foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys) | ||
257 | { | ||
258 | // m_log.DebugFormat("[EVENTQUEUE]: Found key {0} in m_AvatarQueueUUIDMapping while looking for {1}", ky, AgentID); | ||
259 | if (ky == agentID) | ||
260 | { | ||
261 | removeitems.Add(ky); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | foreach (UUID ky in removeitems) | ||
266 | { | ||
267 | UUID eventQueueGetUuid = m_AvatarQueueUUIDMapping[ky]; | ||
268 | m_AvatarQueueUUIDMapping.Remove(ky); | ||
269 | 237 | ||
270 | string eqgPath = GenerateEqgCapPath(eventQueueGetUuid); | 238 | lock (m_ids) |
271 | MainServer.Instance.RemovePollServiceHTTPHandler("", eqgPath); | ||
272 | |||
273 | // m_log.DebugFormat( | ||
274 | // "[EVENT QUEUE GET MODULE]: Removed EQG handler {0} for {1} in {2}", | ||
275 | // eqgPath, agentID, m_scene.RegionInfo.RegionName); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | UUID searchval = UUID.Zero; | ||
280 | |||
281 | removeitems.Clear(); | ||
282 | |||
283 | lock (m_QueueUUIDAvatarMapping) | ||
284 | { | 239 | { |
285 | foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys) | 240 | if (!m_ids.ContainsKey(agentID)) |
286 | { | 241 | m_ids.Remove(agentID); |
287 | searchval = m_QueueUUIDAvatarMapping[ky]; | ||
288 | |||
289 | if (searchval == agentID) | ||
290 | { | ||
291 | removeitems.Add(ky); | ||
292 | } | ||
293 | } | ||
294 | |||
295 | foreach (UUID ky in removeitems) | ||
296 | m_QueueUUIDAvatarMapping.Remove(ky); | ||
297 | } | 242 | } |
298 | } | ||
299 | 243 | ||
300 | private void MakeChildAgent(ScenePresence avatar) | 244 | // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); |
301 | { | 245 | |
302 | //m_log.DebugFormat("[EVENTQUEUE]: Make Child agent {0} in region {1}.", avatar.UUID, m_scene.RegionInfo.RegionName); | ||
303 | //lock (m_ids) | ||
304 | // { | ||
305 | //if (m_ids.ContainsKey(avatar.UUID)) | ||
306 | //{ | ||
307 | // close the event queue. | ||
308 | //m_ids[avatar.UUID] = -1; | ||
309 | //} | ||
310 | //} | ||
311 | } | 246 | } |
312 | 247 | ||
313 | /// <summary> | 248 | /// <summary> |
@@ -322,85 +257,109 @@ namespace OpenSim.Region.ClientStack.Linden | |||
322 | public void OnRegisterCaps(UUID agentID, Caps caps) | 257 | public void OnRegisterCaps(UUID agentID, Caps caps) |
323 | { | 258 | { |
324 | // Register an event queue for the client | 259 | // Register an event queue for the client |
325 | 260 | m_log.DebugFormat( | |
326 | //m_log.DebugFormat( | 261 | "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", |
327 | // "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", | 262 | agentID, caps, m_scene.RegionInfo.RegionName); |
328 | // agentID, caps, m_scene.RegionInfo.RegionName); | ||
329 | |||
330 | // Let's instantiate a Queue for this agent right now | ||
331 | TryGetQueue(agentID); | ||
332 | 263 | ||
333 | UUID eventQueueGetUUID; | 264 | UUID eventQueueGetUUID; |
265 | Queue<OSD> queue; | ||
266 | Random rnd = new Random(Environment.TickCount); | ||
267 | int nrnd = rnd.Next(30000000); | ||
268 | if (nrnd < 0) | ||
269 | nrnd = -nrnd; | ||
334 | 270 | ||
335 | lock (m_AvatarQueueUUIDMapping) | 271 | lock (queues) |
336 | { | 272 | { |
337 | // Reuse open queues. The client does! | 273 | if (queues.ContainsKey(agentID)) |
338 | if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | 274 | queue = queues[agentID]; |
275 | else | ||
276 | queue = null; | ||
277 | |||
278 | if (queue == null) | ||
339 | { | 279 | { |
340 | //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); | 280 | queue = new Queue<OSD>(); |
341 | eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; | 281 | queues[agentID] = queue; |
282 | |||
283 | // push markers to handle old responses still waiting | ||
284 | // this will cost at most viewer getting two forced noevents | ||
285 | // even being a new queue better be safe | ||
286 | queue.Enqueue(null); | ||
287 | queue.Enqueue(null); // one should be enough | ||
288 | |||
289 | lock (m_AvatarQueueUUIDMapping) | ||
290 | { | ||
291 | eventQueueGetUUID = UUID.Random(); | ||
292 | if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
293 | { | ||
294 | // oops this should not happen ? | ||
295 | m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID without a queue"); | ||
296 | eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; | ||
297 | } | ||
298 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); | ||
299 | } | ||
300 | lock (m_ids) | ||
301 | { | ||
302 | if (!m_ids.ContainsKey(agentID)) | ||
303 | m_ids.Add(agentID, nrnd); | ||
304 | else | ||
305 | m_ids[agentID] = nrnd; | ||
306 | } | ||
342 | } | 307 | } |
343 | else | 308 | else |
344 | { | 309 | { |
345 | eventQueueGetUUID = UUID.Random(); | 310 | // push markers to handle old responses still waiting |
346 | //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); | 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 | // reuse or not to reuse TODO FIX | ||
317 | lock (m_AvatarQueueUUIDMapping) | ||
318 | { | ||
319 | // Reuse open queues. The client does! | ||
320 | // Its reuse caps path not queues those are been reused already | ||
321 | if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
322 | { | ||
323 | m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); | ||
324 | eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; | ||
325 | } | ||
326 | else | ||
327 | { | ||
328 | eventQueueGetUUID = UUID.Random(); | ||
329 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); | ||
330 | m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); | ||
331 | } | ||
332 | } | ||
333 | lock (m_ids) | ||
334 | { | ||
335 | // change to negative numbers so they are changed at end of sending first marker | ||
336 | // old data on a queue may be sent on a response for a new caps | ||
337 | // but at least will be sent with coerent IDs | ||
338 | if (!m_ids.ContainsKey(agentID)) | ||
339 | m_ids.Add(agentID, -nrnd); // should not happen | ||
340 | else | ||
341 | m_ids[agentID] = -m_ids[agentID]; | ||
342 | } | ||
347 | } | 343 | } |
348 | } | 344 | } |
349 | 345 | ||
350 | lock (m_QueueUUIDAvatarMapping) | 346 | caps.RegisterPollHandler( |
351 | { | 347 | "EventQueueGet", |
352 | if (!m_QueueUUIDAvatarMapping.ContainsKey(eventQueueGetUUID)) | 348 | new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS)); |
353 | m_QueueUUIDAvatarMapping.Add(eventQueueGetUUID, agentID); | ||
354 | } | ||
355 | |||
356 | lock (m_AvatarQueueUUIDMapping) | ||
357 | { | ||
358 | if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
359 | m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); | ||
360 | } | ||
361 | |||
362 | string eventQueueGetPath = GenerateEqgCapPath(eventQueueGetUUID); | ||
363 | |||
364 | // Register this as a caps handler | ||
365 | // FIXME: Confusingly, we need to register separate as a capability so that the client is told about | ||
366 | // EventQueueGet when it receive capability information, but then we replace the rest handler immediately | ||
367 | // afterwards with the poll service. So for now, we'll pass a null instead to simplify code reading, but | ||
368 | // really it should be possible to directly register the poll handler as a capability. | ||
369 | caps.RegisterHandler("EventQueueGet", new RestHTTPHandler("POST", eventQueueGetPath, null)); | ||
370 | // delegate(Hashtable m_dhttpMethod) | ||
371 | // { | ||
372 | // return ProcessQueue(m_dhttpMethod, agentID, caps); | ||
373 | // })); | ||
374 | |||
375 | // This will persist this beyond the expiry of the caps handlers | ||
376 | // TODO: Add EventQueueGet name/description for diagnostics | ||
377 | MainServer.Instance.AddPollServiceHTTPHandler( | ||
378 | eventQueueGetPath, | ||
379 | new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID, 40000)); | ||
380 | |||
381 | // m_log.DebugFormat( | ||
382 | // "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}", | ||
383 | // eventQueueGetPath, agentID, m_scene.RegionInfo.RegionName); | ||
384 | |||
385 | Random rnd = new Random(Environment.TickCount); | ||
386 | lock (m_ids) | ||
387 | { | ||
388 | if (!m_ids.ContainsKey(agentID)) | ||
389 | m_ids.Add(agentID, rnd.Next(30000000)); | ||
390 | } | ||
391 | } | 349 | } |
392 | 350 | ||
393 | public bool HasEvents(UUID requestID, UUID agentID) | 351 | public bool HasEvents(UUID requestID, UUID agentID) |
394 | { | 352 | { |
395 | // Don't use this, because of race conditions at agent closing time | ||
396 | //Queue<OSD> queue = TryGetQueue(agentID); | ||
397 | |||
398 | Queue<OSD> queue = GetQueue(agentID); | 353 | Queue<OSD> queue = GetQueue(agentID); |
399 | if (queue != null) | 354 | if (queue != null) |
400 | lock (queue) | 355 | lock (queue) |
356 | { | ||
357 | //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count); | ||
401 | return queue.Count > 0; | 358 | return queue.Count > 0; |
359 | } | ||
402 | 360 | ||
403 | return false; | 361 | //m_log.WarnFormat("POLLED FOR EVENTS BY {0} unknown agent", agentID); |
362 | return true; | ||
404 | } | 363 | } |
405 | 364 | ||
406 | /// <summary> | 365 | /// <summary> |
@@ -414,65 +373,80 @@ namespace OpenSim.Region.ClientStack.Linden | |||
414 | OSDMap ev = (OSDMap)element; | 373 | OSDMap ev = (OSDMap)element; |
415 | m_log.DebugFormat( | 374 | m_log.DebugFormat( |
416 | "Eq OUT {0,-30} to {1,-20} {2,-20}", | 375 | "Eq OUT {0,-30} to {1,-20} {2,-20}", |
417 | ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.RegionInfo.RegionName); | 376 | ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name); |
418 | } | 377 | } |
419 | } | 378 | } |
420 | 379 | ||
421 | public Hashtable GetEvents(UUID requestID, UUID pAgentId) | 380 | public Hashtable GetEvents(UUID requestID, UUID pAgentId) |
422 | { | 381 | { |
423 | if (DebugLevel >= 2) | 382 | if (DebugLevel >= 2) |
424 | m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); | 383 | m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.Name); |
425 | 384 | ||
426 | Queue<OSD> queue = TryGetQueue(pAgentId); | 385 | Queue<OSD> queue = GetQueue(pAgentId); |
427 | OSD element; | 386 | if (queue == null) |
428 | lock (queue) | ||
429 | { | 387 | { |
430 | if (queue.Count == 0) | 388 | return NoEvents(requestID, pAgentId); |
431 | return NoEvents(requestID, pAgentId); | ||
432 | element = queue.Dequeue(); // 15s timeout | ||
433 | } | 389 | } |
434 | 390 | ||
391 | OSD element = null;; | ||
392 | OSDArray array = new OSDArray(); | ||
435 | int thisID = 0; | 393 | int thisID = 0; |
436 | lock (m_ids) | 394 | bool negativeID = false; |
437 | thisID = m_ids[pAgentId]; | ||
438 | 395 | ||
439 | OSDArray array = new OSDArray(); | 396 | lock (queue) |
440 | if (element == null) // didn't have an event in 15s | ||
441 | { | ||
442 | // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
443 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
444 | //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName); | ||
445 | } | ||
446 | else | ||
447 | { | 397 | { |
448 | if (DebugLevel > 0) | 398 | if (queue.Count == 0) |
449 | LogOutboundDebugMessage(element, pAgentId); | 399 | return NoEvents(requestID, pAgentId); |
450 | 400 | ||
451 | array.Add(element); | 401 | lock (m_ids) |
402 | thisID = m_ids[pAgentId]; | ||
452 | 403 | ||
453 | lock (queue) | 404 | if (thisID < 0) |
454 | { | 405 | { |
455 | while (queue.Count > 0) | 406 | negativeID = true; |
456 | { | 407 | thisID = -thisID; |
457 | element = queue.Dequeue(); | 408 | } |
409 | |||
410 | while (queue.Count > 0) | ||
411 | { | ||
412 | element = queue.Dequeue(); | ||
413 | // add elements until a marker is found | ||
414 | // so they get into a response | ||
415 | if (element == null) | ||
416 | break; | ||
417 | if (DebugLevel > 0) | ||
418 | LogOutboundDebugMessage(element, pAgentId); | ||
419 | array.Add(element); | ||
420 | thisID++; | ||
421 | } | ||
422 | } | ||
458 | 423 | ||
459 | if (DebugLevel > 0) | 424 | OSDMap events = null; |
460 | LogOutboundDebugMessage(element, pAgentId); | ||
461 | 425 | ||
462 | array.Add(element); | 426 | if (array.Count > 0) |
463 | thisID++; | 427 | { |
464 | } | 428 | events = new OSDMap(); |
465 | } | 429 | events.Add("events", array); |
430 | events.Add("id", new OSDInteger(thisID)); | ||
466 | } | 431 | } |
467 | 432 | ||
468 | OSDMap events = new OSDMap(); | 433 | if (negativeID && element == null) |
469 | events.Add("events", array); | 434 | { |
435 | Random rnd = new Random(Environment.TickCount); | ||
436 | thisID = rnd.Next(30000000); | ||
437 | if (thisID < 0) | ||
438 | thisID = -thisID; | ||
439 | } | ||
470 | 440 | ||
471 | events.Add("id", new OSDInteger(thisID)); | ||
472 | lock (m_ids) | 441 | lock (m_ids) |
473 | { | 442 | { |
474 | m_ids[pAgentId] = thisID + 1; | 443 | m_ids[pAgentId] = thisID + 1; |
475 | } | 444 | } |
445 | |||
446 | // if there where no elements before a marker send a NoEvents | ||
447 | if (array.Count == 0) | ||
448 | return NoEvents(requestID, pAgentId); | ||
449 | |||
476 | Hashtable responsedata = new Hashtable(); | 450 | Hashtable responsedata = new Hashtable(); |
477 | responsedata["int_response_code"] = 200; | 451 | responsedata["int_response_code"] = 200; |
478 | responsedata["content_type"] = "application/xml"; | 452 | responsedata["content_type"] = "application/xml"; |
@@ -495,289 +469,53 @@ namespace OpenSim.Region.ClientStack.Linden | |||
495 | responsedata["http_protocol_version"] = "HTTP/1.0"; | 469 | responsedata["http_protocol_version"] = "HTTP/1.0"; |
496 | return responsedata; | 470 | return responsedata; |
497 | } | 471 | } |
498 | 472 | ||
499 | // public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps) | ||
500 | // { | ||
501 | // // TODO: this has to be redone to not busy-wait (and block the thread), | ||
502 | // // TODO: as soon as we have a non-blocking way to handle HTTP-requests. | ||
503 | // | ||
504 | //// if (m_log.IsDebugEnabled) | ||
505 | //// { | ||
506 | //// String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ "; | ||
507 | //// foreach (object key in request.Keys) | ||
508 | //// { | ||
509 | //// debug += key.ToString() + "=" + request[key].ToString() + " "; | ||
510 | //// } | ||
511 | //// m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name); | ||
512 | //// } | ||
513 | // | ||
514 | // Queue<OSD> queue = TryGetQueue(agentID); | ||
515 | // OSD element; | ||
516 | // | ||
517 | // lock (queue) | ||
518 | // element = queue.Dequeue(); // 15s timeout | ||
519 | // | ||
520 | // Hashtable responsedata = new Hashtable(); | ||
521 | // | ||
522 | // int thisID = 0; | ||
523 | // lock (m_ids) | ||
524 | // thisID = m_ids[agentID]; | ||
525 | // | ||
526 | // if (element == null) | ||
527 | // { | ||
528 | // //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName); | ||
529 | // if (thisID == -1) // close-request | ||
530 | // { | ||
531 | // m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName); | ||
532 | // responsedata["int_response_code"] = 404; //501; //410; //404; | ||
533 | // responsedata["content_type"] = "text/plain"; | ||
534 | // responsedata["keepalive"] = false; | ||
535 | // responsedata["str_response_string"] = "Closed EQG"; | ||
536 | // return responsedata; | ||
537 | // } | ||
538 | // responsedata["int_response_code"] = 502; | ||
539 | // responsedata["content_type"] = "text/plain"; | ||
540 | // responsedata["keepalive"] = false; | ||
541 | // responsedata["str_response_string"] = "Upstream error: "; | ||
542 | // responsedata["error_status_text"] = "Upstream error:"; | ||
543 | // responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
544 | // return responsedata; | ||
545 | // } | ||
546 | // | ||
547 | // OSDArray array = new OSDArray(); | ||
548 | // if (element == null) // didn't have an event in 15s | ||
549 | // { | ||
550 | // // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
551 | // array.Add(EventQueueHelper.KeepAliveEvent()); | ||
552 | // //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | ||
553 | // } | ||
554 | // else | ||
555 | // { | ||
556 | // array.Add(element); | ||
557 | // | ||
558 | // if (element is OSDMap) | ||
559 | // { | ||
560 | // OSDMap ev = (OSDMap)element; | ||
561 | // m_log.DebugFormat( | ||
562 | // "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}", | ||
563 | // ev["message"], m_scene.GetScenePresence(agentID).Name); | ||
564 | // } | ||
565 | // | ||
566 | // lock (queue) | ||
567 | // { | ||
568 | // while (queue.Count > 0) | ||
569 | // { | ||
570 | // element = queue.Dequeue(); | ||
571 | // | ||
572 | // if (element is OSDMap) | ||
573 | // { | ||
574 | // OSDMap ev = (OSDMap)element; | ||
575 | // m_log.DebugFormat( | ||
576 | // "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}", | ||
577 | // ev["message"], m_scene.GetScenePresence(agentID).Name); | ||
578 | // } | ||
579 | // | ||
580 | // array.Add(element); | ||
581 | // thisID++; | ||
582 | // } | ||
583 | // } | ||
584 | // } | ||
585 | // | ||
586 | // OSDMap events = new OSDMap(); | ||
587 | // events.Add("events", array); | ||
588 | // | ||
589 | // events.Add("id", new OSDInteger(thisID)); | ||
590 | // lock (m_ids) | ||
591 | // { | ||
592 | // m_ids[agentID] = thisID + 1; | ||
593 | // } | ||
594 | // | ||
595 | // responsedata["int_response_code"] = 200; | ||
596 | // responsedata["content_type"] = "application/xml"; | ||
597 | // responsedata["keepalive"] = false; | ||
598 | // responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events); | ||
599 | // | ||
600 | // m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]); | ||
601 | // | ||
602 | // return responsedata; | ||
603 | // } | ||
604 | |||
605 | // public Hashtable EventQueuePath2(Hashtable request) | ||
606 | // { | ||
607 | // string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/",""); | ||
608 | // // pull off the last "/" in the path. | ||
609 | // Hashtable responsedata = new Hashtable(); | ||
610 | // capuuid = capuuid.Substring(0, capuuid.Length - 1); | ||
611 | // capuuid = capuuid.Replace("/CAPS/EQG/", ""); | ||
612 | // UUID AvatarID = UUID.Zero; | ||
613 | // UUID capUUID = UUID.Zero; | ||
614 | // | ||
615 | // // parse the path and search for the avatar with it registered | ||
616 | // if (UUID.TryParse(capuuid, out capUUID)) | ||
617 | // { | ||
618 | // lock (m_QueueUUIDAvatarMapping) | ||
619 | // { | ||
620 | // if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) | ||
621 | // { | ||
622 | // AvatarID = m_QueueUUIDAvatarMapping[capUUID]; | ||
623 | // } | ||
624 | // } | ||
625 | // | ||
626 | // if (AvatarID != UUID.Zero) | ||
627 | // { | ||
628 | // return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID)); | ||
629 | // } | ||
630 | // else | ||
631 | // { | ||
632 | // responsedata["int_response_code"] = 404; | ||
633 | // responsedata["content_type"] = "text/plain"; | ||
634 | // responsedata["keepalive"] = false; | ||
635 | // responsedata["str_response_string"] = "Not Found"; | ||
636 | // responsedata["error_status_text"] = "Not Found"; | ||
637 | // responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
638 | // return responsedata; | ||
639 | // // return 404 | ||
640 | // } | ||
641 | // } | ||
642 | // else | ||
643 | // { | ||
644 | // responsedata["int_response_code"] = 404; | ||
645 | // responsedata["content_type"] = "text/plain"; | ||
646 | // responsedata["keepalive"] = false; | ||
647 | // responsedata["str_response_string"] = "Not Found"; | ||
648 | // responsedata["error_status_text"] = "Not Found"; | ||
649 | // responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
650 | // return responsedata; | ||
651 | // // return 404 | ||
652 | // } | ||
653 | // } | ||
654 | |||
655 | public OSD EventQueueFallBack(string path, OSD request, string endpoint) | ||
656 | { | ||
657 | // This is a fallback element to keep the client from loosing EventQueueGet | ||
658 | // Why does CAPS fail sometimes!? | ||
659 | m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!"); | ||
660 | string capuuid = path.Replace("/CAPS/EQG/",""); | ||
661 | capuuid = capuuid.Substring(0, capuuid.Length - 1); | ||
662 | |||
663 | // UUID AvatarID = UUID.Zero; | ||
664 | UUID capUUID = UUID.Zero; | ||
665 | if (UUID.TryParse(capuuid, out capUUID)) | ||
666 | { | ||
667 | /* Don't remove this yet code cleaners! | ||
668 | * Still testing this! | ||
669 | * | ||
670 | lock (m_QueueUUIDAvatarMapping) | ||
671 | { | ||
672 | if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) | ||
673 | { | ||
674 | AvatarID = m_QueueUUIDAvatarMapping[capUUID]; | ||
675 | } | ||
676 | } | ||
677 | |||
678 | |||
679 | if (AvatarID != UUID.Zero) | ||
680 | { | ||
681 | // Repair the CAP! | ||
682 | //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID); | ||
683 | //string capsBase = "/CAPS/EQG/"; | ||
684 | //caps.RegisterHandler("EventQueueGet", | ||
685 | //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/", | ||
686 | //delegate(Hashtable m_dhttpMethod) | ||
687 | //{ | ||
688 | // return ProcessQueue(m_dhttpMethod, AvatarID, caps); | ||
689 | //})); | ||
690 | // start new ID sequence. | ||
691 | Random rnd = new Random(System.Environment.TickCount); | ||
692 | lock (m_ids) | ||
693 | { | ||
694 | if (!m_ids.ContainsKey(AvatarID)) | ||
695 | m_ids.Add(AvatarID, rnd.Next(30000000)); | ||
696 | } | ||
697 | |||
698 | |||
699 | int thisID = 0; | ||
700 | lock (m_ids) | ||
701 | thisID = m_ids[AvatarID]; | ||
702 | |||
703 | BlockingLLSDQueue queue = GetQueue(AvatarID); | ||
704 | OSDArray array = new OSDArray(); | ||
705 | LLSD element = queue.Dequeue(15000); // 15s timeout | ||
706 | if (element == null) | ||
707 | { | ||
708 | |||
709 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
710 | } | ||
711 | else | ||
712 | { | ||
713 | array.Add(element); | ||
714 | while (queue.Count() > 0) | ||
715 | { | ||
716 | array.Add(queue.Dequeue(1)); | ||
717 | thisID++; | ||
718 | } | ||
719 | } | ||
720 | OSDMap events = new OSDMap(); | ||
721 | events.Add("events", array); | ||
722 | |||
723 | events.Add("id", new LLSDInteger(thisID)); | ||
724 | |||
725 | lock (m_ids) | ||
726 | { | ||
727 | m_ids[AvatarID] = thisID + 1; | ||
728 | } | ||
729 | |||
730 | return events; | ||
731 | } | ||
732 | else | ||
733 | { | ||
734 | return new LLSD(); | ||
735 | } | ||
736 | * | ||
737 | */ | ||
738 | } | ||
739 | else | ||
740 | { | ||
741 | //return new LLSD(); | ||
742 | } | ||
743 | |||
744 | return new OSDString("shutdown404!"); | ||
745 | } | ||
746 | |||
747 | public void DisableSimulator(ulong handle, UUID avatarID) | 473 | public void DisableSimulator(ulong handle, UUID avatarID) |
748 | { | 474 | { |
749 | OSD item = EventQueueHelper.DisableSimulator(handle); | 475 | OSD item = EventQueueHelper.DisableSimulator(handle); |
750 | Enqueue(item, avatarID); | 476 | Enqueue(item, avatarID); |
751 | } | 477 | } |
752 | 478 | ||
753 | public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID) | 479 | public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY) |
754 | { | 480 | { |
755 | OSD item = EventQueueHelper.EnableSimulator(handle, endPoint); | 481 | m_log.DebugFormat("{0} EnableSimulator. handle={1}, avatarID={2}, regionSize={3},{4}>", |
482 | "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY); | ||
483 | |||
484 | OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY); | ||
756 | Enqueue(item, avatarID); | 485 | Enqueue(item, avatarID); |
757 | } | 486 | } |
758 | 487 | ||
759 | public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath) | 488 | public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath, |
489 | ulong regionHandle, int regionSizeX, int regionSizeY) | ||
760 | { | 490 | { |
761 | OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath); | 491 | m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, avatarID={2}, regionSize={3},{4}>", |
492 | "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY); | ||
493 | OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY); | ||
762 | Enqueue(item, avatarID); | 494 | Enqueue(item, avatarID); |
763 | } | 495 | } |
764 | 496 | ||
765 | public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, | 497 | public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, |
766 | IPEndPoint regionExternalEndPoint, | 498 | IPEndPoint regionExternalEndPoint, |
767 | uint locationID, uint flags, string capsURL, | 499 | uint locationID, uint flags, string capsURL, |
768 | UUID avatarID) | 500 | UUID avatarID, int regionSizeX, int regionSizeY) |
769 | { | 501 | { |
502 | m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize={3},{4}>", | ||
503 | "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY); | ||
504 | |||
770 | OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, | 505 | OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, |
771 | locationID, flags, capsURL, avatarID); | 506 | locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY); |
772 | Enqueue(item, avatarID); | 507 | Enqueue(item, avatarID); |
773 | } | 508 | } |
774 | 509 | ||
775 | public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, | 510 | public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, |
776 | IPEndPoint newRegionExternalEndPoint, | 511 | IPEndPoint newRegionExternalEndPoint, |
777 | string capsURL, UUID avatarID, UUID sessionID) | 512 | string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY) |
778 | { | 513 | { |
514 | m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>", | ||
515 | "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY); | ||
516 | |||
779 | OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, | 517 | OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, |
780 | capsURL, avatarID, sessionID); | 518 | capsURL, avatarID, sessionID, regionSizeX, regionSizeY); |
781 | Enqueue(item, avatarID); | 519 | Enqueue(item, avatarID); |
782 | } | 520 | } |
783 | 521 | ||
@@ -794,12 +532,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
794 | 532 | ||
795 | } | 533 | } |
796 | 534 | ||
797 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, | 535 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat, |
798 | bool isModerator, bool textMute) | 536 | bool isModerator, bool textMute) |
799 | { | 537 | { |
800 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, | 538 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, |
801 | isModerator, textMute); | 539 | isModerator, textMute); |
802 | Enqueue(item, toAgent); | 540 | Enqueue(item, fromAgent); |
803 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); | 541 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); |
804 | } | 542 | } |
805 | 543 | ||