From 9cd059bad2485202234ca351b2e302f26b422ad2 Mon Sep 17 00:00:00 2001 From: Timerix22 Date: Mon, 18 Dec 2023 12:41:07 +0600 Subject: [PATCH] moved *.cs to src/ --- Fluzm/{ => src}/Config.cs | 81 ++++++++-------- Fluzm/{ => src}/Program.cs | 166 +++++++++++++++---------------- Fluzm/{ => src}/Router.cs | 194 +++++++++++++++++++------------------ 3 files changed, 222 insertions(+), 219 deletions(-) rename Fluzm/{ => src}/Config.cs (91%) rename Fluzm/{ => src}/Program.cs (96%) rename Fluzm/{ => src}/Router.cs (91%) diff --git a/Fluzm/Config.cs b/Fluzm/src/Config.cs similarity index 91% rename from Fluzm/Config.cs rename to Fluzm/src/Config.cs index 097772b..d7041f5 100644 --- a/Fluzm/Config.cs +++ b/Fluzm/src/Config.cs @@ -1,43 +1,40 @@ -using System; -using DTLib.Dtsod; - -namespace Fluzm; - -public class Config -{ - public const int ActualVersion = 1; - - public int Version = ActualVersion; - public string Address = "127.0.0.1"; - public int Port = 8080; - - public Config() - { } - - public Config(int version, string address, int port) - { - Version = version; - Address = address; - Port = port; - } - - public static Config FromDtsod(DtsodV23 d) - { - var cfg = new Config(d["version"], d["address"], d["port"]); - if (cfg.Version < ActualVersion) - throw new Exception($"config is obsolete (config v{cfg.Version} < program v{ActualVersion})"); - if(cfg.Version > ActualVersion) - throw new Exception($"program is obsolete (config v{cfg.Version} > program v{ActualVersion})"); - return cfg; - } - - public DtsodV23 ToDtsod() => - new() - { - { "version", Version }, - { "address", Address }, - { "port", Port } - }; - - public override string ToString() => ToDtsod().ToString()!; +namespace Fluzm; + +public class Config +{ + public const int ActualVersion = 1; + + public int Version = ActualVersion; + public string Address = "127.0.0.1"; + public int Port = 8080; + + public Config() + { } + + public Config(int version, string address, int port) + { + Version = version; + Address = address; + Port = port; + } + + public static Config FromDtsod(DtsodV23 d) + { + var cfg = new Config(d["version"], d["address"], d["port"]); + if (cfg.Version < ActualVersion) + throw new Exception($"config is obsolete (config v{cfg.Version} < program v{ActualVersion})"); + if(cfg.Version > ActualVersion) + throw new Exception($"program is obsolete (config v{cfg.Version} > program v{ActualVersion})"); + return cfg; + } + + public DtsodV23 ToDtsod() => + new() + { + { "version", Version }, + { "address", Address }, + { "port", Port } + }; + + public override string ToString() => ToDtsod().ToString()!; } \ No newline at end of file diff --git a/Fluzm/Program.cs b/Fluzm/src/Program.cs similarity index 96% rename from Fluzm/Program.cs rename to Fluzm/src/Program.cs index c5edde1..2528751 100644 --- a/Fluzm/Program.cs +++ b/Fluzm/src/Program.cs @@ -1,84 +1,84 @@ -global using System; -global using System.Collections.Generic; -global using System.Net; -global using System.Text; -global using System.Threading; -global using System.Threading.Tasks; -global using DTLib.Filesystem; -global using DTLib.Extensions; -using DTLib.Dtsod; -using DTLib.Logging; - -namespace Fluzm; - -internal static class Program -{ - private static readonly IOPath configPath = "./config.dtsod"; - private static CancellationTokenSource mainCancel = new(); - private static ILogger logger = new ConsoleLogger(); - private static Router router = new Router(); - - public static async Task Main(string[] args) - { - try - { - Console.InputEncoding = Encoding.UTF8; - Console.OutputEncoding = Encoding.UTF8; - Console.CancelKeyPress += (_, _) => - { - logger.LogInfo("Main","stopping server..."); - mainCancel.Cancel(); - }; - - Config config; - if (!File.Exists(configPath)) - { - logger.LogWarn("Main", "Config file not found."); - config = new Config(); - File.WriteAllText(configPath, config.ToString()); - logger.LogWarn("Main", $"Created default at {configPath}."); - } - else config = Config.FromDtsod(new DtsodV23(File.ReadAllText(configPath))); - - string baseUrl = $"http://{config.Address}:{config.Port}/"; - logger.LogInfo("Main", $"starting webserver at {baseUrl} ..."); - var server = new HttpListener(); - server.Prefixes.Add(baseUrl); - server.Start(); - logger.LogInfo("Main", "server started"); - long requestId = 0; - while (!mainCancel.IsCancellationRequested) - { - await Task.Run(async () => - { - var ctx = await server.GetContextAsync(); - HandleRequestAsync(ctx, requestId); - }, mainCancel.Token); - requestId++; - } - - server.Stop(); - logger.LogInfo("Main", "server stopped"); - } - catch (Exception ex) - { - logger.LogError("Main", ex); - } - } - - private static async void HandleRequestAsync(HttpListenerContext ctx, long requestId) - { - await Task.Yield(); - string logContext = "Request " + requestId; - try - { - logger.LogInfo(logContext, $"{ctx.Request.HttpMethod} request for {ctx.Request.RawUrl} from {ctx.Request.RemoteEndPoint}"); - bool isRequestHandled = router.TryResolve(ctx); - logger.LogInfo(logContext, isRequestHandled ? "request handled" : "request rejected"); - } - catch (Exception ex) - { - logger.LogWarn(logContext, ex); - } - } +global using System; +global using System.Collections.Generic; +global using System.Net; +global using System.Text; +global using System.Threading; +global using System.Threading.Tasks; +global using DTLib.Filesystem; +global using DTLib.Extensions; +global using DTLib.Dtsod; +using DTLib.Logging; + +namespace Fluzm; + +internal static class Program +{ + private static readonly IOPath configPath = "./config.dtsod"; + private static CancellationTokenSource mainCancel = new(); + private static ILogger logger = new ConsoleLogger(); + private static Router router = new Router(); + + public static async Task Main(string[] args) + { + try + { + Console.InputEncoding = Encoding.UTF8; + Console.OutputEncoding = Encoding.UTF8; + Console.CancelKeyPress += (_, _) => + { + logger.LogInfo("Main","stopping server..."); + mainCancel.Cancel(); + }; + + Config config; + if (!File.Exists(configPath)) + { + logger.LogWarn("Main", "Config file not found."); + config = new Config(); + File.WriteAllText(configPath, config.ToString()); + logger.LogWarn("Main", $"Created default at {configPath}."); + } + else config = Config.FromDtsod(new DtsodV23(File.ReadAllText(configPath))); + + string baseUrl = $"http://{config.Address}:{config.Port}/"; + logger.LogInfo("Main", $"starting webserver at {baseUrl} ..."); + var server = new HttpListener(); + server.Prefixes.Add(baseUrl); + server.Start(); + logger.LogInfo("Main", "server started"); + long requestId = 0; + while (!mainCancel.IsCancellationRequested) + { + await Task.Run(async () => + { + var ctx = await server.GetContextAsync(); + HandleRequestAsync(ctx, requestId); + }, mainCancel.Token); + requestId++; + } + + server.Stop(); + logger.LogInfo("Main", "server stopped"); + } + catch (Exception ex) + { + logger.LogError("Main", ex); + } + } + + private static async void HandleRequestAsync(HttpListenerContext ctx, long requestId) + { + await Task.Yield(); + string logContext = "Request " + requestId; + try + { + logger.LogInfo(logContext, $"{ctx.Request.HttpMethod} request for {ctx.Request.RawUrl} from {ctx.Request.RemoteEndPoint}"); + bool isRequestHandled = router.TryResolve(ctx); + logger.LogInfo(logContext, isRequestHandled ? "request handled" : "request rejected"); + } + catch (Exception ex) + { + logger.LogWarn(logContext, ex); + } + } } \ No newline at end of file diff --git a/Fluzm/Router.cs b/Fluzm/src/Router.cs similarity index 91% rename from Fluzm/Router.cs rename to Fluzm/src/Router.cs index b0a07ed..a1fe139 100644 --- a/Fluzm/Router.cs +++ b/Fluzm/src/Router.cs @@ -1,95 +1,101 @@ -namespace Fluzm; - -public class Router -{ - private Dictionary> routes = new(); - private readonly IOPath publicDirPath = "./public"; - private readonly IOPath homepagePath = "./public/html/index.html"; - private readonly IOPath pare404Path = "./public/html/404.html"; - - public Router() - { - routes.Add("UwU", ctx => - { - var buffer = "

UwU

".ToBytes(); - ctx.Response.ContentLength64 = buffer.Length; - ctx.Response.OutputStream.Write(buffer); - ctx.Response.OutputStream.Flush(); - return 200; - }); - } - - public bool TryResolve(HttpListenerContext ctx) - { - int status; - if (routes.TryGetValue(ctx.Request.Url!.AbsolutePath, out var routeDelegate)) - status = routeDelegate(ctx); - else if(ctx.Request.HttpMethod == "GET") - { - string urlPath = ctx.Request.Url.AbsolutePath; - string ext = urlPath.EndsWith(".js.map") - ? ".js.map" // extname of '*.js.map' is '.map' so it has to be set explicitely - : Path.Extension(urlPath).Str; - IOPath filePath; - switch (ext) - { - case "html": - filePath = Path.Concat(publicDirPath, "html", urlPath); - ctx.Response.Headers.Set("Content-Type", "text/html"); - break; - case "css": - filePath = Path.Concat(publicDirPath, "css", urlPath); - ctx.Response.Headers.Set("Content-Type", "text/css"); - break; - case "js": - case "js.map": - case "jsx": - case "ts": - case "tsx": - filePath = Path.Concat(publicDirPath, "scripts", urlPath); - ctx.Response.Headers.Set("Content-Type", "text/javascript"); - break; - default: - if (urlPath == "/") - { - filePath = homepagePath; - ctx.Response.Headers.Set("Content-Type", "text/html"); - break; - } - filePath = Path.Concat(publicDirPath, urlPath); - ctx.Response.Headers.Set("Content-Type", "binary/octet-stream"); - ctx.Response.Headers.Set("Content-Disposition", "attachment filename="+filePath.LastName()); - break; - } - - if (File.Exists(filePath)) - status = 200; - else - { - status = 404; - if (ext == "html") - { - filePath = pare404Path; - ctx.Response.Headers.Set("Content-Type", "text/html"); - } - } - - if(status == 200 || ext == "html") - { - var fileStream = File.OpenRead(filePath); - ctx.Response.ContentLength64 = fileStream.Length; - fileStream.CopyTo(ctx.Response.OutputStream); - } - } - // reject all incorrect requests - else - { - status = 501; - ctx.Response.ContentLength64 = 0; - } - ctx.Response.StatusCode = status; - ctx.Response.OutputStream.Flush(); - ctx.Response.OutputStream.Close(); - return status == 200; - } +namespace Fluzm; + +public class Router +{ + private Dictionary> routes = new(); + private readonly IOPath publicDirPath = "./public"; + private readonly IOPath homepagePath = "./public/html/index.html"; + private readonly IOPath pare404Path = "./public/html/404.html"; + + public Router() + { + routes.Add("/aaa", ctx => + { + var buffer = """ + + +

aaa

+ + + """.ToBytes(); + ctx.Response.ContentLength64 = buffer.Length; + ctx.Response.OutputStream.Write(buffer); + return 200; + }); + } + + public bool TryResolve(HttpListenerContext ctx) + { + int status; + if (routes.TryGetValue(ctx.Request.Url!.AbsolutePath, out var routeDelegate)) + status = routeDelegate(ctx); + else if(ctx.Request.HttpMethod == "GET") + { + string urlPath = ctx.Request.Url.AbsolutePath; + string ext = urlPath.EndsWith(".js.map") + ? ".js.map" // extname of '*.js.map' is '.map' so it has to be set explicitely + : Path.Extension(urlPath).Str; + IOPath filePath; + switch (ext) + { + case "html": + filePath = Path.Concat(publicDirPath, "html", urlPath); + ctx.Response.Headers.Set("Content-Type", "text/html"); + break; + case "css": + filePath = Path.Concat(publicDirPath, "css", urlPath); + ctx.Response.Headers.Set("Content-Type", "text/css"); + break; + case "js": + case "js.map": + case "jsx": + case "ts": + case "tsx": + filePath = Path.Concat(publicDirPath, "scripts", urlPath); + ctx.Response.Headers.Set("Content-Type", "text/javascript"); + break; + default: + if (urlPath == "/") + { + filePath = homepagePath; + ctx.Response.Headers.Set("Content-Type", "text/html"); + break; + } + filePath = Path.Concat(publicDirPath, urlPath); + ctx.Response.Headers.Set("Content-Type", "binary/octet-stream"); + ctx.Response.Headers.Set("Content-Disposition", "attachment filename="+filePath.LastName()); + break; + } + + if (File.Exists(filePath)) + status = 200; + else + { + status = 404; + if (ext == "html") + { + filePath = pare404Path; + ctx.Response.Headers.Set("Content-Type", "text/html"); + } + } + + if(status == 200 || ext == "html") + { + var fileStream = File.OpenRead(filePath); + ctx.Response.ContentLength64 = fileStream.Length; + fileStream.CopyTo(ctx.Response.OutputStream); + } + } + // reject all incorrect requests + else + { + status = 400; + ctx.Response.ContentLength64 = 0; + // ctx.Response.Headers.Set(); + } + ctx.Response.StatusCode = status; + ctx.Response.OutputStream.Flush(); + ctx.Response.OutputStream.Close(); + return status == 200; + } } \ No newline at end of file