|
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using System.Net;
- using System.Reflection;
- using System.Text;
- using HarmonyLib;
- using Svelto.DataStructures;
-
- namespace CLre_server.WebStatus
- {
- public class WebServer
- {
- private const uint DEFAULT_PORT = 5030;
- private const string DEFAULT_IP = "localhost";
- private readonly HttpListener _httpListener;
-
- public delegate void RequestHandler(HttpListenerContext ctx);
-
- private Dictionary<string, RequestHandler> _handlers = new Dictionary<string, RequestHandler>();
-
- public bool IsRunning
- {
- get => _httpListener.IsListening;
- }
-
- private string _ip_addr;
- private uint _port;
-
- public static WebServer MainInstance { get; internal set; }
-
- internal static List<Assembly> _assembliesToCheck = new List<Assembly>(new []{typeof(CLre).Assembly});
-
- public WebServer() : this(DEFAULT_IP, DEFAULT_PORT)
- {
- }
-
- public WebServer(string ip, uint port)
- {
- if (!HttpListener.IsSupported)
- {
- API.Utility.Logging.LogWarning("HTTP Server is unsupported on earlier Windows versions. CLre webserver will fail to start.");
- }
- _httpListener = new HttpListener();
- _httpListener.Prefixes.Add($"http://{ip}:{port}/");
- _ip_addr = ip;
- _port = port;
- }
-
- internal static void Init()
- {
- if (CLre.Config.web_server || Environment.GetCommandLineArgs().Contains("-web"))
- {
- API.Utility.Logging.Log("Starting status web server");
- StatusEndpoints.Init();
- MainInstance = new WebServer();
- MainInstance.Start();
- }
- else
- {
- API.Utility.Logging.Log("Not starting web server (use CLI argument -web to enable)");
- }
- }
-
- internal static void Deinit()
- {
- if (MainInstance != null) MainInstance.Stop();
- MainInstance = null;
- }
-
- public void Start()
- {
- LoadHandlers();
- try
- {
- _httpListener.Start();
- }
- catch (Exception e)
- {
- API.Utility.Logging.LogWarning(e);
- return;
- }
-
- HandleAllRequests().Run();
- }
-
- public void Stop()
- {
- try
- {
- _httpListener.Stop();
- _httpListener.Close();
- }
- catch (Exception e)
- {
- API.Utility.Logging.LogWarning(e);
- return;
- }
- }
-
- private IEnumerator HandleAllRequests()
- {
- API.Utility.Logging.MetaLog($"Started HTTP web server at http://{_ip_addr}:{_port}/");
- while (_httpListener.IsListening)
- {
- var awaiter = _httpListener.GetContextAsync();
- awaiter.GetAwaiter().OnCompleted(() => DoRequest(awaiter.Result));
- yield return null;
- }
- API.Utility.Logging.MetaLog("Terminated HTTP web server");
- }
-
- private void DoRequest(HttpListenerContext ctx)
- {
- string endpoint = ctx.Request.Url.LocalPath.ToLower();
- #if DEBUG
- API.Utility.Logging.LogWarning($"Handling HTTP request {endpoint}");
- #endif
- bool handled = false;
- foreach (string path in _handlers.Keys)
- {
- if (endpoint == path)
- {
- handled = true;
- _handlers[path](ctx);
- break;
- }
- }
-
- if (!handled)
- {
- AssetEndpoints.Asset404(ctx);
- }
- //byte[] output = Encoding.UTF8.GetBytes(endpoint);
- //ctx.Response.OutputStream.Write(output, 0, output.Length);
- ctx.Response.Close();
- }
-
- private void LoadHandlers()
- {
- _handlers = new Dictionary<string, RequestHandler>();
- foreach (Assembly asm in _assembliesToCheck.ToArray())
- {
- foreach (Type t in asm.GetTypes())
- {
- foreach (MethodInfo m in t.GetMethods(AccessTools.all))
- {
- WebEndpointAttribute attr = m.GetCustomAttribute<WebEndpointAttribute>();
- if (attr != null)
- {
- // TODO validate that method signature matches that of RequestHandler
- string key = attr.GetPath().ToLower();
- API.Utility.Logging.MetaLog($"{t.FullName}:{m.Name} is handling {key}");
- _handlers.Add(key, (RequestHandler) Delegate.CreateDelegate(typeof(RequestHandler), m));
- }
- }
- }
- }
- }
- }
- }
|