65 lines
2.5 KiB
C#
65 lines
2.5 KiB
C#
namespace DTLib.Web.Routes;
|
|
|
|
public class SimpleRouter : IRouter
|
|
{
|
|
/// route for any url that doesn't have its own handler
|
|
public record RouteWithMethod(HttpMethod method, IRouteHandler routeHandler)
|
|
{
|
|
public bool CheckMethod(HttpMethod requestMethod) => (requestMethod & method) != 0;
|
|
|
|
public bool CheckMethod(string requestMethodStr)
|
|
=> Enum.TryParse<HttpMethod>(requestMethodStr, out var requestMethod)
|
|
&& CheckMethod(requestMethod);
|
|
}
|
|
|
|
private readonly Dictionary<string, RouteWithMethod> _routes = new();
|
|
private readonly ILogger _logger;
|
|
|
|
public RouteWithMethod? DefaultRoute { get; set; }
|
|
|
|
public SimpleRouter(ILogger logger)
|
|
{
|
|
_logger = new ContextLogger(nameof(SimpleRouter), logger);
|
|
}
|
|
|
|
public void MapRoute(string url, HttpMethod method, IRouteHandler route)
|
|
=> _routes.Add(url, new RouteWithMethod(method, route));
|
|
|
|
public void MapRoute(string url, HttpMethod method,
|
|
Func<HttpListenerContext, ContextLogger, Task<HttpStatusCode>> route)
|
|
=> MapRoute(url, method, new DelegateRouteHandler(route));
|
|
|
|
public async Task Resolve(HttpListenerContext ctx, ContextLogger requestLogger)
|
|
{
|
|
HttpStatusCode status = HttpStatusCode.InternalServerError;
|
|
try
|
|
{
|
|
string? requestPath = ctx.Request.Url?.AbsolutePath;
|
|
if (string.IsNullOrEmpty(requestPath))
|
|
requestPath = "/";
|
|
|
|
if(!_routes.TryGetValue(requestPath!, out var routeWithMethod))
|
|
routeWithMethod = DefaultRoute;
|
|
|
|
if (routeWithMethod is null)
|
|
{
|
|
_logger.LogWarn(nameof(SimpleRouter),
|
|
$"couldn't resolve request path {ctx.Request.HttpMethod} {requestPath}");
|
|
status = HttpStatusCode.NotFound;
|
|
}
|
|
else if (!routeWithMethod.CheckMethod(ctx.Request.HttpMethod))
|
|
{
|
|
_logger.LogWarn(nameof(SimpleRouter),
|
|
$"received request with invalid method {ctx.Request.HttpMethod} {requestPath}");
|
|
status = HttpStatusCode.MethodNotAllowed;
|
|
}
|
|
else status = await routeWithMethod.routeHandler.HandleRequest(ctx, requestLogger);
|
|
}
|
|
finally
|
|
{
|
|
ctx.Response.StatusCode = (int)status;
|
|
await ctx.Response.OutputStream.FlushAsync();
|
|
ctx.Response.OutputStream.Close();
|
|
}
|
|
}
|
|
} |