source: binary-improvements2/MapRendering/Web/SSE/SseHandler.cs@ 382

Last change on this file since 382 was 382, checked in by alloc, 2 years ago

Switched to use SpaceWizards.HttpListener

File size: 3.8 KB
Line 
1using System;
2using System.Net;
3using System.Collections.Generic;
4using System.Reflection;
5using System.Threading;
6using AllocsFixes.NetConnections.Servers.Web.Handlers;
7using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
8using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
9
10// Implemented following HTML spec
11// https://html.spec.whatwg.org/multipage/server-sent-events.html
12
13namespace AllocsFixes.NetConnections.Servers.Web.SSE {
14 public class SseHandler : AbsHandler {
15 private readonly Dictionary<string, EventBase> events = new CaseInsensitiveStringDictionary<EventBase> ();
16
17 private ThreadManager.ThreadInfo queueThead;
18 private readonly AutoResetEvent evSendRequest = new AutoResetEvent (false);
19 private bool shutdown;
20
21 public SseHandler (string _moduleName = null) : base (_moduleName) {
22 Type[] ctorTypes = { typeof (SseHandler) };
23 object[] ctorParams = { this };
24
25 foreach (Type t in Assembly.GetExecutingAssembly ().GetTypes ()) {
26 if (!t.IsAbstract && t.IsSubclassOf (typeof (EventBase))) {
27 ConstructorInfo ctor = t.GetConstructor (ctorTypes);
28 if (ctor != null) {
29 EventBase apiInstance = (EventBase)ctor.Invoke (ctorParams);
30 AddEvent (apiInstance.Name, apiInstance);
31 }
32 }
33 }
34 }
35
36 public override void SetBasePathAndParent (Web _parent, string _relativePath) {
37 base.SetBasePathAndParent (_parent, _relativePath);
38
39 queueThead = ThreadManager.StartThread ("SSE-Processing_" + urlBasePath, QueueProcessThread, ThreadPriority.BelowNormal,
40 _useRealThread: true);
41 }
42
43 public override void Shutdown () {
44 base.Shutdown ();
45 shutdown = true;
46 SignalSendQueue ();
47 }
48
49 public void AddEvent (string _eventName, EventBase _eventInstance) {
50 events.Add (_eventName, _eventInstance);
51 WebPermissions.Instance.AddKnownModule ("webevent." + _eventName, _eventInstance.DefaultPermissionLevel ());
52 }
53
54 public override void HandleRequest (string _requestPath, HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _con,
55 int _permissionLevel) {
56 string eventName = _requestPath.Remove (0, urlBasePath.Length);
57
58 if (!events.TryGetValue (eventName, out EventBase eventInstance)) {
59 Log.Out ($"Error in {nameof (SseHandler)}.HandleRequest(): No handler found for event \"{eventName}\"");
60 _resp.StatusCode = (int)HttpStatusCode.NotFound;
61 return;
62 }
63
64 if (!IsAuthorizedForEvent (eventName, _permissionLevel)) {
65 _resp.StatusCode = (int)HttpStatusCode.Forbidden;
66 if (_con != null) {
67 //Log.Out ($"{nameof(SseHandler)}: user '{user.SteamID}' not allowed to access '{eventName}'");
68 }
69
70 return;
71 }
72
73 try {
74 eventInstance.AddListener (_resp);
75
76 // Keep the request open
77 _resp.SendChunked = true;
78
79 _resp.AddHeader ("Content-Type", "text/event-stream");
80 _resp.OutputStream.Flush ();
81 } catch (Exception e) {
82 Log.Error ($"Error in {nameof (SseHandler)}.HandleRequest(): Handler {eventInstance.Name} threw an exception:");
83 Log.Exception (e);
84 _resp.StatusCode = (int)HttpStatusCode.InternalServerError;
85 }
86 }
87
88 private bool IsAuthorizedForEvent (string _eventName, int _permissionLevel) {
89 return WebPermissions.Instance.ModuleAllowedWithLevel ("webevent." + _eventName, _permissionLevel);
90 }
91
92 private void QueueProcessThread (ThreadManager.ThreadInfo _threadInfo) {
93 while (!shutdown && !_threadInfo.TerminationRequested ()) {
94 evSendRequest.WaitOne (500);
95
96 foreach (KeyValuePair<string, EventBase> kvp in events) {
97 try {
98 kvp.Value.ProcessSendQueue ();
99 } catch (Exception e) {
100 Log.Error ($"SSE ({kvp.Key}): Error processing send queue");
101 Log.Exception (e);
102 }
103 }
104 }
105 }
106
107 public void SignalSendQueue () {
108 evSendRequest.Set ();
109 }
110 }
111}
Note: See TracBrowser for help on using the repository browser.