diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | 731 |
1 files changed, 731 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..139d8b8 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | |||
@@ -0,0 +1,731 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using System.Threading; | ||
34 | using log4net; | ||
35 | using Nini.Config; | ||
36 | using Mono.Addins; | ||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.Messages.Linden; | ||
39 | using OpenMetaverse.Packets; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenSim.Framework; | ||
42 | using OpenSim.Framework.Servers; | ||
43 | using OpenSim.Framework.Servers.HttpServer; | ||
44 | using OpenSim.Region.Framework.Interfaces; | ||
45 | using OpenSim.Region.Framework.Scenes; | ||
46 | using BlockingLLSDQueue = OpenSim.Framework.BlockingQueue<OpenMetaverse.StructuredData.OSD>; | ||
47 | using Caps=OpenSim.Framework.Capabilities.Caps; | ||
48 | |||
49 | namespace OpenSim.Region.ClientStack.Linden | ||
50 | { | ||
51 | public struct QueueItem | ||
52 | { | ||
53 | public int id; | ||
54 | public OSDMap body; | ||
55 | } | ||
56 | |||
57 | //[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
58 | public class EventQueueGetModule : IEventQueue, IRegionModule | ||
59 | { | ||
60 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
61 | protected Scene m_scene = null; | ||
62 | private IConfigSource m_gConfig; | ||
63 | bool enabledYN = false; | ||
64 | |||
65 | private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); | ||
66 | |||
67 | private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); | ||
68 | private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>(); | ||
69 | private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); | ||
70 | |||
71 | #region IRegionModule methods | ||
72 | public virtual void Initialise(Scene scene, IConfigSource config) | ||
73 | { | ||
74 | m_gConfig = config; | ||
75 | |||
76 | IConfig startupConfig = m_gConfig.Configs["Startup"]; | ||
77 | |||
78 | ReadConfigAndPopulate(scene, startupConfig, "Startup"); | ||
79 | |||
80 | if (enabledYN) | ||
81 | { | ||
82 | m_scene = scene; | ||
83 | scene.RegisterModuleInterface<IEventQueue>(this); | ||
84 | |||
85 | // Register fallback handler | ||
86 | // Why does EQG Fail on region crossings! | ||
87 | |||
88 | //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack); | ||
89 | |||
90 | scene.EventManager.OnNewClient += OnNewClient; | ||
91 | |||
92 | // TODO: Leaving these open, or closing them when we | ||
93 | // become a child is incorrect. It messes up TP in a big | ||
94 | // way. CAPS/EQ need to be active as long as the UDP | ||
95 | // circuit is there. | ||
96 | |||
97 | scene.EventManager.OnClientClosed += ClientClosed; | ||
98 | scene.EventManager.OnMakeChildAgent += MakeChildAgent; | ||
99 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
100 | } | ||
101 | else | ||
102 | { | ||
103 | m_gConfig = null; | ||
104 | } | ||
105 | |||
106 | } | ||
107 | |||
108 | private void ReadConfigAndPopulate(Scene scene, IConfig startupConfig, string p) | ||
109 | { | ||
110 | enabledYN = startupConfig.GetBoolean("EventQueue", true); | ||
111 | } | ||
112 | |||
113 | public void PostInitialise() | ||
114 | { | ||
115 | } | ||
116 | |||
117 | public virtual void Close() | ||
118 | { | ||
119 | } | ||
120 | |||
121 | public virtual string Name | ||
122 | { | ||
123 | get { return "EventQueueGetModule"; } | ||
124 | } | ||
125 | |||
126 | public bool IsSharedModule | ||
127 | { | ||
128 | get { return false; } | ||
129 | } | ||
130 | #endregion | ||
131 | |||
132 | /// <summary> | ||
133 | /// Always returns a valid queue | ||
134 | /// </summary> | ||
135 | /// <param name="agentId"></param> | ||
136 | /// <returns></returns> | ||
137 | private Queue<OSD> TryGetQueue(UUID agentId) | ||
138 | { | ||
139 | lock (queues) | ||
140 | { | ||
141 | if (!queues.ContainsKey(agentId)) | ||
142 | { | ||
143 | /* | ||
144 | m_log.DebugFormat( | ||
145 | "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", | ||
146 | agentId, m_scene.RegionInfo.RegionName); | ||
147 | */ | ||
148 | queues[agentId] = new Queue<OSD>(); | ||
149 | } | ||
150 | |||
151 | return queues[agentId]; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | /// <summary> | ||
156 | /// May return a null queue | ||
157 | /// </summary> | ||
158 | /// <param name="agentId"></param> | ||
159 | /// <returns></returns> | ||
160 | private Queue<OSD> GetQueue(UUID agentId) | ||
161 | { | ||
162 | lock (queues) | ||
163 | { | ||
164 | if (queues.ContainsKey(agentId)) | ||
165 | { | ||
166 | return queues[agentId]; | ||
167 | } | ||
168 | else | ||
169 | return null; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | #region IEventQueue Members | ||
174 | |||
175 | public bool Enqueue(OSD ev, UUID avatarID) | ||
176 | { | ||
177 | //m_log.DebugFormat("[EVENTQUEUE]: Enqueuing event for {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName); | ||
178 | try | ||
179 | { | ||
180 | Queue<OSD> queue = GetQueue(avatarID); | ||
181 | if (queue != null) | ||
182 | queue.Enqueue(ev); | ||
183 | } | ||
184 | catch(NullReferenceException e) | ||
185 | { | ||
186 | m_log.Error("[EVENTQUEUE] Caught exception: " + e); | ||
187 | return false; | ||
188 | } | ||
189 | |||
190 | return true; | ||
191 | } | ||
192 | |||
193 | #endregion | ||
194 | |||
195 | private void OnNewClient(IClientAPI client) | ||
196 | { | ||
197 | //client.OnLogout += ClientClosed; | ||
198 | } | ||
199 | |||
200 | // private void ClientClosed(IClientAPI client) | ||
201 | // { | ||
202 | // ClientClosed(client.AgentId); | ||
203 | // } | ||
204 | |||
205 | private void ClientClosed(UUID AgentID, Scene scene) | ||
206 | { | ||
207 | //m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", AgentID, m_scene.RegionInfo.RegionName); | ||
208 | |||
209 | int count = 0; | ||
210 | while (queues.ContainsKey(AgentID) && queues[AgentID].Count > 0 && count++ < 5) | ||
211 | { | ||
212 | Thread.Sleep(1000); | ||
213 | } | ||
214 | |||
215 | lock (queues) | ||
216 | { | ||
217 | queues.Remove(AgentID); | ||
218 | } | ||
219 | List<UUID> removeitems = new List<UUID>(); | ||
220 | lock (m_AvatarQueueUUIDMapping) | ||
221 | { | ||
222 | foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys) | ||
223 | { | ||
224 | if (ky == AgentID) | ||
225 | { | ||
226 | removeitems.Add(ky); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | foreach (UUID ky in removeitems) | ||
231 | { | ||
232 | m_AvatarQueueUUIDMapping.Remove(ky); | ||
233 | MainServer.Instance.RemovePollServiceHTTPHandler("","/CAPS/EQG/" + ky.ToString() + "/"); | ||
234 | } | ||
235 | |||
236 | } | ||
237 | UUID searchval = UUID.Zero; | ||
238 | |||
239 | removeitems.Clear(); | ||
240 | |||
241 | lock (m_QueueUUIDAvatarMapping) | ||
242 | { | ||
243 | foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys) | ||
244 | { | ||
245 | searchval = m_QueueUUIDAvatarMapping[ky]; | ||
246 | |||
247 | if (searchval == AgentID) | ||
248 | { | ||
249 | removeitems.Add(ky); | ||
250 | } | ||
251 | } | ||
252 | |||
253 | foreach (UUID ky in removeitems) | ||
254 | m_QueueUUIDAvatarMapping.Remove(ky); | ||
255 | |||
256 | } | ||
257 | } | ||
258 | |||
259 | private void MakeChildAgent(ScenePresence avatar) | ||
260 | { | ||
261 | //m_log.DebugFormat("[EVENTQUEUE]: Make Child agent {0} in region {1}.", avatar.UUID, m_scene.RegionInfo.RegionName); | ||
262 | //lock (m_ids) | ||
263 | // { | ||
264 | //if (m_ids.ContainsKey(avatar.UUID)) | ||
265 | //{ | ||
266 | // close the event queue. | ||
267 | //m_ids[avatar.UUID] = -1; | ||
268 | //} | ||
269 | //} | ||
270 | } | ||
271 | |||
272 | public void OnRegisterCaps(UUID agentID, Caps caps) | ||
273 | { | ||
274 | // Register an event queue for the client | ||
275 | |||
276 | //m_log.DebugFormat( | ||
277 | // "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", | ||
278 | // agentID, caps, m_scene.RegionInfo.RegionName); | ||
279 | |||
280 | // Let's instantiate a Queue for this agent right now | ||
281 | TryGetQueue(agentID); | ||
282 | |||
283 | string capsBase = "/CAPS/EQG/"; | ||
284 | UUID EventQueueGetUUID = UUID.Zero; | ||
285 | |||
286 | lock (m_AvatarQueueUUIDMapping) | ||
287 | { | ||
288 | // Reuse open queues. The client does! | ||
289 | if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
290 | { | ||
291 | //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); | ||
292 | EventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; | ||
293 | } | ||
294 | else | ||
295 | { | ||
296 | EventQueueGetUUID = UUID.Random(); | ||
297 | //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | lock (m_QueueUUIDAvatarMapping) | ||
302 | { | ||
303 | if (!m_QueueUUIDAvatarMapping.ContainsKey(EventQueueGetUUID)) | ||
304 | m_QueueUUIDAvatarMapping.Add(EventQueueGetUUID, agentID); | ||
305 | } | ||
306 | |||
307 | lock (m_AvatarQueueUUIDMapping) | ||
308 | { | ||
309 | if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID)) | ||
310 | m_AvatarQueueUUIDMapping.Add(agentID, EventQueueGetUUID); | ||
311 | } | ||
312 | |||
313 | // Register this as a caps handler | ||
314 | caps.RegisterHandler("EventQueueGet", | ||
315 | new RestHTTPHandler("POST", capsBase + EventQueueGetUUID.ToString() + "/", | ||
316 | delegate(Hashtable m_dhttpMethod) | ||
317 | { | ||
318 | return ProcessQueue(m_dhttpMethod, agentID, caps); | ||
319 | })); | ||
320 | |||
321 | // This will persist this beyond the expiry of the caps handlers | ||
322 | MainServer.Instance.AddPollServiceHTTPHandler( | ||
323 | capsBase + EventQueueGetUUID.ToString() + "/", EventQueuePoll, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID)); | ||
324 | |||
325 | Random rnd = new Random(Environment.TickCount); | ||
326 | lock (m_ids) | ||
327 | { | ||
328 | if (!m_ids.ContainsKey(agentID)) | ||
329 | m_ids.Add(agentID, rnd.Next(30000000)); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | public bool HasEvents(UUID requestID, UUID agentID) | ||
334 | { | ||
335 | // Don't use this, because of race conditions at agent closing time | ||
336 | //Queue<OSD> queue = TryGetQueue(agentID); | ||
337 | |||
338 | Queue<OSD> queue = GetQueue(agentID); | ||
339 | if (queue != null) | ||
340 | lock (queue) | ||
341 | { | ||
342 | if (queue.Count > 0) | ||
343 | return true; | ||
344 | else | ||
345 | return false; | ||
346 | } | ||
347 | return false; | ||
348 | } | ||
349 | |||
350 | public Hashtable GetEvents(UUID requestID, UUID pAgentId, string request) | ||
351 | { | ||
352 | Queue<OSD> queue = TryGetQueue(pAgentId); | ||
353 | OSD element; | ||
354 | lock (queue) | ||
355 | { | ||
356 | if (queue.Count == 0) | ||
357 | return NoEvents(requestID, pAgentId); | ||
358 | element = queue.Dequeue(); // 15s timeout | ||
359 | } | ||
360 | |||
361 | |||
362 | |||
363 | int thisID = 0; | ||
364 | lock (m_ids) | ||
365 | thisID = m_ids[pAgentId]; | ||
366 | |||
367 | OSDArray array = new OSDArray(); | ||
368 | if (element == null) // didn't have an event in 15s | ||
369 | { | ||
370 | // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
371 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
372 | //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName); | ||
373 | } | ||
374 | else | ||
375 | { | ||
376 | array.Add(element); | ||
377 | lock (queue) | ||
378 | { | ||
379 | while (queue.Count > 0) | ||
380 | { | ||
381 | array.Add(queue.Dequeue()); | ||
382 | thisID++; | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | |||
387 | OSDMap events = new OSDMap(); | ||
388 | events.Add("events", array); | ||
389 | |||
390 | events.Add("id", new OSDInteger(thisID)); | ||
391 | lock (m_ids) | ||
392 | { | ||
393 | m_ids[pAgentId] = thisID + 1; | ||
394 | } | ||
395 | Hashtable responsedata = new Hashtable(); | ||
396 | responsedata["int_response_code"] = 200; | ||
397 | responsedata["content_type"] = "application/xml"; | ||
398 | responsedata["keepalive"] = false; | ||
399 | responsedata["reusecontext"] = false; | ||
400 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events); | ||
401 | //m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", pAgentId, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]); | ||
402 | return responsedata; | ||
403 | } | ||
404 | |||
405 | public Hashtable NoEvents(UUID requestID, UUID agentID) | ||
406 | { | ||
407 | Hashtable responsedata = new Hashtable(); | ||
408 | responsedata["int_response_code"] = 502; | ||
409 | responsedata["content_type"] = "text/plain"; | ||
410 | responsedata["keepalive"] = false; | ||
411 | responsedata["reusecontext"] = false; | ||
412 | responsedata["str_response_string"] = "Upstream error: "; | ||
413 | responsedata["error_status_text"] = "Upstream error:"; | ||
414 | responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
415 | return responsedata; | ||
416 | } | ||
417 | |||
418 | public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps) | ||
419 | { | ||
420 | // TODO: this has to be redone to not busy-wait (and block the thread), | ||
421 | // TODO: as soon as we have a non-blocking way to handle HTTP-requests. | ||
422 | |||
423 | // if (m_log.IsDebugEnabled) | ||
424 | // { | ||
425 | // String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ "; | ||
426 | // foreach (object key in request.Keys) | ||
427 | // { | ||
428 | // debug += key.ToString() + "=" + request[key].ToString() + " "; | ||
429 | // } | ||
430 | // m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name); | ||
431 | // } | ||
432 | |||
433 | Queue<OSD> queue = TryGetQueue(agentID); | ||
434 | OSD element = queue.Dequeue(); // 15s timeout | ||
435 | |||
436 | Hashtable responsedata = new Hashtable(); | ||
437 | |||
438 | int thisID = 0; | ||
439 | lock (m_ids) | ||
440 | thisID = m_ids[agentID]; | ||
441 | |||
442 | if (element == null) | ||
443 | { | ||
444 | //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName); | ||
445 | if (thisID == -1) // close-request | ||
446 | { | ||
447 | m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName); | ||
448 | responsedata["int_response_code"] = 404; //501; //410; //404; | ||
449 | responsedata["content_type"] = "text/plain"; | ||
450 | responsedata["keepalive"] = false; | ||
451 | responsedata["str_response_string"] = "Closed EQG"; | ||
452 | return responsedata; | ||
453 | } | ||
454 | responsedata["int_response_code"] = 502; | ||
455 | responsedata["content_type"] = "text/plain"; | ||
456 | responsedata["keepalive"] = false; | ||
457 | responsedata["str_response_string"] = "Upstream error: "; | ||
458 | responsedata["error_status_text"] = "Upstream error:"; | ||
459 | responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
460 | return responsedata; | ||
461 | } | ||
462 | |||
463 | OSDArray array = new OSDArray(); | ||
464 | if (element == null) // didn't have an event in 15s | ||
465 | { | ||
466 | // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! | ||
467 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
468 | //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | ||
469 | } | ||
470 | else | ||
471 | { | ||
472 | array.Add(element); | ||
473 | while (queue.Count > 0) | ||
474 | { | ||
475 | array.Add(queue.Dequeue()); | ||
476 | thisID++; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | OSDMap events = new OSDMap(); | ||
481 | events.Add("events", array); | ||
482 | |||
483 | events.Add("id", new OSDInteger(thisID)); | ||
484 | lock (m_ids) | ||
485 | { | ||
486 | m_ids[agentID] = thisID + 1; | ||
487 | } | ||
488 | |||
489 | responsedata["int_response_code"] = 200; | ||
490 | responsedata["content_type"] = "application/xml"; | ||
491 | responsedata["keepalive"] = false; | ||
492 | responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events); | ||
493 | //m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]); | ||
494 | |||
495 | return responsedata; | ||
496 | } | ||
497 | |||
498 | public Hashtable EventQueuePoll(Hashtable request) | ||
499 | { | ||
500 | return new Hashtable(); | ||
501 | } | ||
502 | |||
503 | public Hashtable EventQueuePath2(Hashtable request) | ||
504 | { | ||
505 | string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/",""); | ||
506 | // pull off the last "/" in the path. | ||
507 | Hashtable responsedata = new Hashtable(); | ||
508 | capuuid = capuuid.Substring(0, capuuid.Length - 1); | ||
509 | capuuid = capuuid.Replace("/CAPS/EQG/", ""); | ||
510 | UUID AvatarID = UUID.Zero; | ||
511 | UUID capUUID = UUID.Zero; | ||
512 | |||
513 | // parse the path and search for the avatar with it registered | ||
514 | if (UUID.TryParse(capuuid, out capUUID)) | ||
515 | { | ||
516 | lock (m_QueueUUIDAvatarMapping) | ||
517 | { | ||
518 | if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) | ||
519 | { | ||
520 | AvatarID = m_QueueUUIDAvatarMapping[capUUID]; | ||
521 | } | ||
522 | } | ||
523 | if (AvatarID != UUID.Zero) | ||
524 | { | ||
525 | return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID)); | ||
526 | } | ||
527 | else | ||
528 | { | ||
529 | responsedata["int_response_code"] = 404; | ||
530 | responsedata["content_type"] = "text/plain"; | ||
531 | responsedata["keepalive"] = false; | ||
532 | responsedata["str_response_string"] = "Not Found"; | ||
533 | responsedata["error_status_text"] = "Not Found"; | ||
534 | responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
535 | return responsedata; | ||
536 | // return 404 | ||
537 | } | ||
538 | } | ||
539 | else | ||
540 | { | ||
541 | responsedata["int_response_code"] = 404; | ||
542 | responsedata["content_type"] = "text/plain"; | ||
543 | responsedata["keepalive"] = false; | ||
544 | responsedata["str_response_string"] = "Not Found"; | ||
545 | responsedata["error_status_text"] = "Not Found"; | ||
546 | responsedata["http_protocol_version"] = "HTTP/1.0"; | ||
547 | return responsedata; | ||
548 | // return 404 | ||
549 | } | ||
550 | |||
551 | } | ||
552 | |||
553 | public OSD EventQueueFallBack(string path, OSD request, string endpoint) | ||
554 | { | ||
555 | // This is a fallback element to keep the client from loosing EventQueueGet | ||
556 | // Why does CAPS fail sometimes!? | ||
557 | m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!"); | ||
558 | string capuuid = path.Replace("/CAPS/EQG/",""); | ||
559 | capuuid = capuuid.Substring(0, capuuid.Length - 1); | ||
560 | |||
561 | // UUID AvatarID = UUID.Zero; | ||
562 | UUID capUUID = UUID.Zero; | ||
563 | if (UUID.TryParse(capuuid, out capUUID)) | ||
564 | { | ||
565 | /* Don't remove this yet code cleaners! | ||
566 | * Still testing this! | ||
567 | * | ||
568 | lock (m_QueueUUIDAvatarMapping) | ||
569 | { | ||
570 | if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) | ||
571 | { | ||
572 | AvatarID = m_QueueUUIDAvatarMapping[capUUID]; | ||
573 | } | ||
574 | } | ||
575 | |||
576 | |||
577 | if (AvatarID != UUID.Zero) | ||
578 | { | ||
579 | // Repair the CAP! | ||
580 | //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID); | ||
581 | //string capsBase = "/CAPS/EQG/"; | ||
582 | //caps.RegisterHandler("EventQueueGet", | ||
583 | //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/", | ||
584 | //delegate(Hashtable m_dhttpMethod) | ||
585 | //{ | ||
586 | // return ProcessQueue(m_dhttpMethod, AvatarID, caps); | ||
587 | //})); | ||
588 | // start new ID sequence. | ||
589 | Random rnd = new Random(System.Environment.TickCount); | ||
590 | lock (m_ids) | ||
591 | { | ||
592 | if (!m_ids.ContainsKey(AvatarID)) | ||
593 | m_ids.Add(AvatarID, rnd.Next(30000000)); | ||
594 | } | ||
595 | |||
596 | |||
597 | int thisID = 0; | ||
598 | lock (m_ids) | ||
599 | thisID = m_ids[AvatarID]; | ||
600 | |||
601 | BlockingLLSDQueue queue = GetQueue(AvatarID); | ||
602 | OSDArray array = new OSDArray(); | ||
603 | LLSD element = queue.Dequeue(15000); // 15s timeout | ||
604 | if (element == null) | ||
605 | { | ||
606 | |||
607 | array.Add(EventQueueHelper.KeepAliveEvent()); | ||
608 | } | ||
609 | else | ||
610 | { | ||
611 | array.Add(element); | ||
612 | while (queue.Count() > 0) | ||
613 | { | ||
614 | array.Add(queue.Dequeue(1)); | ||
615 | thisID++; | ||
616 | } | ||
617 | } | ||
618 | OSDMap events = new OSDMap(); | ||
619 | events.Add("events", array); | ||
620 | |||
621 | events.Add("id", new LLSDInteger(thisID)); | ||
622 | |||
623 | lock (m_ids) | ||
624 | { | ||
625 | m_ids[AvatarID] = thisID + 1; | ||
626 | } | ||
627 | |||
628 | return events; | ||
629 | } | ||
630 | else | ||
631 | { | ||
632 | return new LLSD(); | ||
633 | } | ||
634 | * | ||
635 | */ | ||
636 | } | ||
637 | else | ||
638 | { | ||
639 | //return new LLSD(); | ||
640 | } | ||
641 | |||
642 | return new OSDString("shutdown404!"); | ||
643 | } | ||
644 | |||
645 | public void DisableSimulator(ulong handle, UUID avatarID) | ||
646 | { | ||
647 | OSD item = EventQueueHelper.DisableSimulator(handle); | ||
648 | Enqueue(item, avatarID); | ||
649 | } | ||
650 | |||
651 | public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID) | ||
652 | { | ||
653 | OSD item = EventQueueHelper.EnableSimulator(handle, endPoint); | ||
654 | Enqueue(item, avatarID); | ||
655 | } | ||
656 | |||
657 | public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath) | ||
658 | { | ||
659 | OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath); | ||
660 | Enqueue(item, avatarID); | ||
661 | } | ||
662 | |||
663 | public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, | ||
664 | IPEndPoint regionExternalEndPoint, | ||
665 | uint locationID, uint flags, string capsURL, | ||
666 | UUID avatarID) | ||
667 | { | ||
668 | OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, | ||
669 | locationID, flags, capsURL, avatarID); | ||
670 | Enqueue(item, avatarID); | ||
671 | } | ||
672 | |||
673 | public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, | ||
674 | IPEndPoint newRegionExternalEndPoint, | ||
675 | string capsURL, UUID avatarID, UUID sessionID) | ||
676 | { | ||
677 | OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, | ||
678 | capsURL, avatarID, sessionID); | ||
679 | Enqueue(item, avatarID); | ||
680 | } | ||
681 | |||
682 | public void ChatterboxInvitation(UUID sessionID, string sessionName, | ||
683 | UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog, | ||
684 | uint timeStamp, bool offline, int parentEstateID, Vector3 position, | ||
685 | uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket) | ||
686 | { | ||
687 | OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog, | ||
688 | timeStamp, offline, parentEstateID, position, ttl, transactionID, | ||
689 | fromGroup, binaryBucket); | ||
690 | Enqueue(item, toAgent); | ||
691 | //m_log.InfoFormat("########### eq ChatterboxInvitation #############\n{0}", item); | ||
692 | |||
693 | } | ||
694 | |||
695 | public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, | ||
696 | bool isModerator, bool textMute) | ||
697 | { | ||
698 | OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, | ||
699 | isModerator, textMute); | ||
700 | Enqueue(item, toAgent); | ||
701 | //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); | ||
702 | } | ||
703 | |||
704 | public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID) | ||
705 | { | ||
706 | OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage); | ||
707 | Enqueue(item, avatarID); | ||
708 | } | ||
709 | |||
710 | public void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID) | ||
711 | { | ||
712 | OSD item = EventQueueHelper.GroupMembership(groupUpdate); | ||
713 | Enqueue(item, avatarID); | ||
714 | } | ||
715 | public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID) | ||
716 | { | ||
717 | OSD item = EventQueueHelper.PlacesQuery(groupUpdate); | ||
718 | Enqueue(item, avatarID); | ||
719 | } | ||
720 | |||
721 | public OSD ScriptRunningEvent(UUID objectID, UUID itemID, bool running, bool mono) | ||
722 | { | ||
723 | return EventQueueHelper.ScriptRunningReplyEvent(objectID, itemID, running, mono); | ||
724 | } | ||
725 | |||
726 | public OSD BuildEvent(string eventName, OSD eventBody) | ||
727 | { | ||
728 | return EventQueueHelper.BuildEvent(eventName, eventBody); | ||
729 | } | ||
730 | } | ||
731 | } | ||