moved *.cs to src/

This commit is contained in:
Timerix22 2023-12-18 12:41:07 +06:00
parent e37be491ba
commit 9cd059bad2
3 changed files with 222 additions and 219 deletions

View File

@ -1,43 +1,40 @@
using System; namespace Fluzm;
using DTLib.Dtsod;
public class Config
namespace Fluzm; {
public const int ActualVersion = 1;
public class Config
{ public int Version = ActualVersion;
public const int ActualVersion = 1; public string Address = "127.0.0.1";
public int Port = 8080;
public int Version = ActualVersion;
public string Address = "127.0.0.1"; public Config()
public int Port = 8080; { }
public Config() public Config(int version, string address, int port)
{ } {
Version = version;
public Config(int version, string address, int port) Address = address;
{ Port = port;
Version = version; }
Address = address;
Port = port; public static Config FromDtsod(DtsodV23 d)
} {
var cfg = new Config(d["version"], d["address"], d["port"]);
public static Config FromDtsod(DtsodV23 d) if (cfg.Version < ActualVersion)
{ throw new Exception($"config is obsolete (config v{cfg.Version} < program v{ActualVersion})");
var cfg = new Config(d["version"], d["address"], d["port"]); if(cfg.Version > ActualVersion)
if (cfg.Version < ActualVersion) throw new Exception($"program is obsolete (config v{cfg.Version} > program v{ActualVersion})");
throw new Exception($"config is obsolete (config v{cfg.Version} < program v{ActualVersion})"); return cfg;
if(cfg.Version > ActualVersion) }
throw new Exception($"program is obsolete (config v{cfg.Version} > program v{ActualVersion})");
return cfg; public DtsodV23 ToDtsod() =>
} new()
{
public DtsodV23 ToDtsod() => { "version", Version },
new() { "address", Address },
{ { "port", Port }
{ "version", Version }, };
{ "address", Address },
{ "port", Port } public override string ToString() => ToDtsod().ToString()!;
};
public override string ToString() => ToDtsod().ToString()!;
} }

View File

@ -1,84 +1,84 @@
global using System; global using System;
global using System.Collections.Generic; global using System.Collections.Generic;
global using System.Net; global using System.Net;
global using System.Text; global using System.Text;
global using System.Threading; global using System.Threading;
global using System.Threading.Tasks; global using System.Threading.Tasks;
global using DTLib.Filesystem; global using DTLib.Filesystem;
global using DTLib.Extensions; global using DTLib.Extensions;
using DTLib.Dtsod; global using DTLib.Dtsod;
using DTLib.Logging; using DTLib.Logging;
namespace Fluzm; namespace Fluzm;
internal static class Program internal static class Program
{ {
private static readonly IOPath configPath = "./config.dtsod"; private static readonly IOPath configPath = "./config.dtsod";
private static CancellationTokenSource mainCancel = new(); private static CancellationTokenSource mainCancel = new();
private static ILogger logger = new ConsoleLogger(); private static ILogger logger = new ConsoleLogger();
private static Router router = new Router(); private static Router router = new Router();
public static async Task Main(string[] args) public static async Task Main(string[] args)
{ {
try try
{ {
Console.InputEncoding = Encoding.UTF8; Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8; Console.OutputEncoding = Encoding.UTF8;
Console.CancelKeyPress += (_, _) => Console.CancelKeyPress += (_, _) =>
{ {
logger.LogInfo("Main","stopping server..."); logger.LogInfo("Main","stopping server...");
mainCancel.Cancel(); mainCancel.Cancel();
}; };
Config config; Config config;
if (!File.Exists(configPath)) if (!File.Exists(configPath))
{ {
logger.LogWarn("Main", "Config file not found."); logger.LogWarn("Main", "Config file not found.");
config = new Config(); config = new Config();
File.WriteAllText(configPath, config.ToString()); File.WriteAllText(configPath, config.ToString());
logger.LogWarn("Main", $"Created default at {configPath}."); logger.LogWarn("Main", $"Created default at {configPath}.");
} }
else config = Config.FromDtsod(new DtsodV23(File.ReadAllText(configPath))); else config = Config.FromDtsod(new DtsodV23(File.ReadAllText(configPath)));
string baseUrl = $"http://{config.Address}:{config.Port}/"; string baseUrl = $"http://{config.Address}:{config.Port}/";
logger.LogInfo("Main", $"starting webserver at {baseUrl} ..."); logger.LogInfo("Main", $"starting webserver at {baseUrl} ...");
var server = new HttpListener(); var server = new HttpListener();
server.Prefixes.Add(baseUrl); server.Prefixes.Add(baseUrl);
server.Start(); server.Start();
logger.LogInfo("Main", "server started"); logger.LogInfo("Main", "server started");
long requestId = 0; long requestId = 0;
while (!mainCancel.IsCancellationRequested) while (!mainCancel.IsCancellationRequested)
{ {
await Task.Run(async () => await Task.Run(async () =>
{ {
var ctx = await server.GetContextAsync(); var ctx = await server.GetContextAsync();
HandleRequestAsync(ctx, requestId); HandleRequestAsync(ctx, requestId);
}, mainCancel.Token); }, mainCancel.Token);
requestId++; requestId++;
} }
server.Stop(); server.Stop();
logger.LogInfo("Main", "server stopped"); logger.LogInfo("Main", "server stopped");
} }
catch (Exception ex) catch (Exception ex)
{ {
logger.LogError("Main", ex); logger.LogError("Main", ex);
} }
} }
private static async void HandleRequestAsync(HttpListenerContext ctx, long requestId) private static async void HandleRequestAsync(HttpListenerContext ctx, long requestId)
{ {
await Task.Yield(); await Task.Yield();
string logContext = "Request " + requestId; string logContext = "Request " + requestId;
try try
{ {
logger.LogInfo(logContext, $"{ctx.Request.HttpMethod} request for {ctx.Request.RawUrl} from {ctx.Request.RemoteEndPoint}"); logger.LogInfo(logContext, $"{ctx.Request.HttpMethod} request for {ctx.Request.RawUrl} from {ctx.Request.RemoteEndPoint}");
bool isRequestHandled = router.TryResolve(ctx); bool isRequestHandled = router.TryResolve(ctx);
logger.LogInfo(logContext, isRequestHandled ? "request handled" : "request rejected"); logger.LogInfo(logContext, isRequestHandled ? "request handled" : "request rejected");
} }
catch (Exception ex) catch (Exception ex)
{ {
logger.LogWarn(logContext, ex); logger.LogWarn(logContext, ex);
} }
} }
} }

View File

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