2023-06-20 23:15:56 +02:00
|
|
|
|
using System.Net;
|
2023-06-21 16:52:57 +02:00
|
|
|
|
using System.Runtime.InteropServices;
|
2023-06-20 23:15:56 +02:00
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using Logging;
|
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
using Tranga;
|
|
|
|
|
|
|
|
|
|
namespace API;
|
|
|
|
|
|
|
|
|
|
public class Server
|
|
|
|
|
{
|
|
|
|
|
private readonly HttpListener _listener = new ();
|
|
|
|
|
private readonly RequestHandler _requestHandler;
|
|
|
|
|
internal readonly Logger? logger;
|
|
|
|
|
|
|
|
|
|
private readonly Regex _validUrl =
|
|
|
|
|
new (@"https?:\/\/(www\.)?[-A-z0-9]{1,256}(\.[-a-zA-Z0-9]{1,6})?(:[0-9]{1,5})?(\/{1}[A-z0-9()@:%_\+.~#?&=]+)*\/?");
|
|
|
|
|
public Server(int port, TaskManager taskManager, Logger? logger = null)
|
|
|
|
|
{
|
|
|
|
|
this.logger = logger;
|
2023-06-21 16:52:57 +02:00
|
|
|
|
if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
|
|
|
this._listener.Prefixes.Add($"http://*:{port}/");
|
|
|
|
|
else
|
|
|
|
|
this._listener.Prefixes.Add($"http://localhost:{port}/");
|
2023-06-20 23:15:56 +02:00
|
|
|
|
this._requestHandler = new RequestHandler(taskManager, this);
|
|
|
|
|
Listen();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Listen()
|
|
|
|
|
{
|
|
|
|
|
this._listener.Start();
|
|
|
|
|
foreach (string prefix in this._listener.Prefixes)
|
|
|
|
|
this.logger?.WriteLine(this.GetType().ToString(), $"Listening on {prefix}");
|
|
|
|
|
while (this._listener.IsListening)
|
|
|
|
|
{
|
|
|
|
|
HttpListenerContext context = this._listener.GetContextAsync().Result;
|
|
|
|
|
Task t = new (() =>
|
|
|
|
|
{
|
|
|
|
|
HandleContext(context);
|
|
|
|
|
});
|
|
|
|
|
t.Start();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleContext(HttpListenerContext context)
|
|
|
|
|
{
|
|
|
|
|
HttpListenerRequest request = context.Request;
|
|
|
|
|
HttpListenerResponse response = context.Response;
|
|
|
|
|
//logger?.WriteLine(this.GetType().ToString(), $"New request: {request.HttpMethod} {request.Url}");
|
|
|
|
|
|
|
|
|
|
if (!_validUrl.IsMatch(request.Url!.ToString()))
|
|
|
|
|
{
|
|
|
|
|
SendResponse(HttpStatusCode.BadRequest, response);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-06-21 16:53:07 +02:00
|
|
|
|
|
|
|
|
|
if (request.HttpMethod == "OPTIONS")
|
|
|
|
|
{
|
|
|
|
|
SendResponse(HttpStatusCode.OK, response);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_requestHandler.HandleRequest(request, response);
|
|
|
|
|
}
|
2023-06-20 23:15:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void SendResponse(HttpStatusCode statusCode, HttpListenerResponse response, object? content = null)
|
|
|
|
|
{
|
|
|
|
|
//logger?.WriteLine(this.GetType().ToString(), $"Sending response: {statusCode}");
|
|
|
|
|
response.StatusCode = (int)statusCode;
|
|
|
|
|
response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
|
|
|
|
|
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, DELETE");
|
|
|
|
|
response.AddHeader("Access-Control-Max-Age", "1728000");
|
|
|
|
|
response.AppendHeader("Access-Control-Allow-Origin", "*");
|
|
|
|
|
response.ContentType = "application/json";
|
2023-06-21 17:42:56 +02:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
response.OutputStream.Write(content is not null
|
|
|
|
|
? Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(content))
|
|
|
|
|
: Array.Empty<byte>());
|
|
|
|
|
}
|
|
|
|
|
catch (HttpListenerException)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
2023-06-20 23:15:56 +02:00
|
|
|
|
response.OutputStream.Close();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|