diff --git a/LinkRouter.sln b/LinkRouter.sln
deleted file mode 100644
index 5659e00..0000000
--- a/LinkRouter.sln
+++ /dev/null
@@ -1,16 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinkRouter", "LinkRouter\LinkRouter.csproj", "{0DEC18EE-615C-4E89-BA5C-B8B4AE83FE94}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {0DEC18EE-615C-4E89-BA5C-B8B4AE83FE94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0DEC18EE-615C-4E89-BA5C-B8B4AE83FE94}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0DEC18EE-615C-4E89-BA5C-B8B4AE83FE94}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0DEC18EE-615C-4E89-BA5C-B8B4AE83FE94}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
-EndGlobal
diff --git a/LinkRouter.slnx b/LinkRouter.slnx
new file mode 100644
index 0000000..aaaca24
--- /dev/null
+++ b/LinkRouter.slnx
@@ -0,0 +1,3 @@
+
+
+
diff --git a/LinkRouter/App/Http/Controllers/RedirectController.cs b/LinkRouter/App/Http/Controllers/RedirectController.cs
index 6a940ad..0a62b0f 100644
--- a/LinkRouter/App/Http/Controllers/RedirectController.cs
+++ b/LinkRouter/App/Http/Controllers/RedirectController.cs
@@ -1,4 +1,4 @@
-using LinkRouter.App.Configuration;
+using LinkRouter.App.Models;
using LinkRouter.App.Services;
using Microsoft.AspNetCore.Mvc;
@@ -9,22 +9,42 @@ public class RedirectController : Controller
{
private readonly Config Config;
private readonly RedirectionService RedirectionService;
+ private readonly MetricsService MetricsService;
- public RedirectController(Config config, RedirectionService redirectionService)
+ public RedirectController(Config config, RedirectionService redirectionService, MetricsService metricsService)
{
Config = config;
RedirectionService = redirectionService;
+ MetricsService = metricsService;
}
- [HttpGet("/{*path}")]
- public async Task RedirectToExternalUrl(string path)
+ [HttpGet("{*path}")]
+ public async Task RedirectTo(string? path)
{
- return await RedirectionService.GetRedirect(path);
- }
+ Console.WriteLine(path);
- [HttpGet("/")]
- public async Task GetRootRoute()
- {
- return await RedirectionService.GetRedirect(string.Empty);
+ path = string.IsNullOrWhiteSpace(path)
+ ? "/"
+ : $"/{path.Trim('/')}/";
+
+ if (!RedirectionService.TryGetRedirect(path, out var rawRedirect) || rawRedirect == null)
+ {
+ if (string.IsNullOrEmpty(rawRedirect))
+ return NotFound();
+
+ if (RedirectionService.TryGetStatusCode(rawRedirect, out var notFoundStatusCode))
+ return StatusCode(notFoundStatusCode);
+
+ await MetricsService.IncrementNotFound(path);
+
+ return Redirect(rawRedirect);
+ }
+
+ if (RedirectionService.TryGetStatusCode(path.Trim('/'), out var code))
+ return StatusCode(code);
+
+ await MetricsService.IncrementFound(path);
+
+ return Redirect(rawRedirect);
}
}
\ No newline at end of file
diff --git a/LinkRouter/App/Implemlementations/LoggingConsoleFormatter.cs b/LinkRouter/App/Implemlementations/LoggingConsoleFormatter.cs
new file mode 100644
index 0000000..bff7cfc
--- /dev/null
+++ b/LinkRouter/App/Implemlementations/LoggingConsoleFormatter.cs
@@ -0,0 +1,58 @@
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Logging.Console;
+
+namespace LinkRouter.App.Implemlementations;
+
+public class LoggingConsoleFormatter : ConsoleFormatter
+{
+ public LoggingConsoleFormatter() : base(nameof(LoggingConsoleFormatter))
+ {
+ }
+
+ public override void Write(
+ in LogEntry logEntry,
+ IExternalScopeProvider? scopeProvider,
+ TextWriter textWriter)
+ {
+ var message = logEntry.Formatter?.Invoke(logEntry.State, logEntry.Exception)
+ ?? logEntry.State?.ToString();
+
+ // Timestamp
+ textWriter.Write(DateTime.Now.ToString("dd.MM.yy HH:mm:ss"));
+ textWriter.Write(' ');
+
+ // Log level
+ textWriter.Write(GetLevelText(logEntry.LogLevel));
+ textWriter.Write(' ');
+
+ // Category
+ textWriter.Write(logEntry.Category);
+ textWriter.Write(": ");
+
+ // Message
+ textWriter.Write(message);
+
+ // Exception (if any)
+ if (logEntry.Exception != null)
+ {
+ textWriter.Write(" | ");
+ textWriter.Write(logEntry.Exception);
+ }
+
+ textWriter.WriteLine();
+ }
+
+ private static string GetLevelText(LogLevel logLevel)
+ {
+ return logLevel switch
+ {
+ LogLevel.Critical => "CRIT",
+ LogLevel.Error => "ERRO",
+ LogLevel.Warning => "WARN",
+ LogLevel.Information => "INFO",
+ LogLevel.Debug => "DEBG",
+ LogLevel.Trace => "TRCE",
+ _ => "NONE"
+ };
+ }
+}
\ No newline at end of file
diff --git a/LinkRouter/App/Configuration/Config.cs b/LinkRouter/App/Models/Config.cs
similarity index 81%
rename from LinkRouter/App/Configuration/Config.cs
rename to LinkRouter/App/Models/Config.cs
index 5166264..c9410b1 100644
--- a/LinkRouter/App/Configuration/Config.cs
+++ b/LinkRouter/App/Models/Config.cs
@@ -1,13 +1,28 @@
using System.Text;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
-using LinkRouter.App.Models;
-namespace LinkRouter.App.Configuration;
+namespace LinkRouter.App.Models;
public class Config
{
- public string RootRoute { get; set; } = "https://example.com";
+ [JsonPropertyName("RootRedirect")] public string? RootRedirect { get; set; } = "https://example.com";
+
+ // Legacy property, only used during deserialization
+ [Obsolete]
+ [JsonPropertyName("RootRoute")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public string? LegacyRootRoute
+ {
+ get => null; // never serialize
+ set
+ {
+ if (!string.IsNullOrEmpty(value) && string.IsNullOrEmpty(RootRedirect))
+ {
+ RootRedirect = value;
+ }
+ }
+ }
public NotFoundBehaviorConfig NotFoundBehavior { get; set; } = new();
@@ -39,11 +54,7 @@ public void CompileRoutes()
foreach (var route in Routes)
{
- if (!route.Route.StartsWith("/"))
- route.Route = "/" + route.Route;
-
- if (!route.Route.EndsWith("/"))
- route.Route += "/";
+ route.Route = "/" + route.Route.Trim('/') + "/";
var compiled = new CompiledRoute
{
@@ -55,9 +66,9 @@ public void CompileRoutes()
var escaped = Regex.Escape(route.Route);
- var pattern = new Regex(@"\\\{(\d|\w+)\}", RegexOptions.CultureInvariant);
- var matches = pattern.Matches(escaped);
+
+ var matches = Patterns.PlaceholderPattern.Matches(escaped);
foreach (var match in matches.Select(x => x))
{
@@ -102,7 +113,5 @@ public void CompileRoutes()
CompiledRoutes = compiledRoutes
.ToArray();
}
-
- [JsonIgnore] public static Regex ErrorCodePattern = new(@"\s*\-\>\s*(\d+)\s*$", RegexOptions.Compiled | RegexOptions.CultureInvariant);
}
\ No newline at end of file
diff --git a/LinkRouter/App/Models/Patterns.cs b/LinkRouter/App/Models/Patterns.cs
new file mode 100644
index 0000000..859e109
--- /dev/null
+++ b/LinkRouter/App/Models/Patterns.cs
@@ -0,0 +1,10 @@
+using System.Text.RegularExpressions;
+
+namespace LinkRouter.App.Models;
+
+public static class Patterns
+{
+ public static Regex ErrorCodePattern = new(@"\s*\-\>\s*(\d+)\s*$", RegexOptions.Compiled | RegexOptions.CultureInvariant);
+
+ public static Regex PlaceholderPattern = new (@"\\\{(\d|\w+)\}", RegexOptions.Compiled | RegexOptions.CultureInvariant);
+}
\ No newline at end of file
diff --git a/LinkRouter/App/Services/ConfigWatcher.cs b/LinkRouter/App/Services/ConfigWatcher.cs
index a78570d..cf7079e 100644
--- a/LinkRouter/App/Services/ConfigWatcher.cs
+++ b/LinkRouter/App/Services/ConfigWatcher.cs
@@ -1,5 +1,5 @@
using System.Text.Json;
-using LinkRouter.App.Configuration;
+using LinkRouter.App.Models;
namespace LinkRouter.App.Services;
@@ -47,7 +47,7 @@ private void OnChanged(object sender, FileSystemEventArgs e)
var config = JsonSerializer.Deserialize(content);
Config.Routes = config?.Routes ?? [];
- Config.RootRoute = config?.RootRoute ?? "https://example.com";
+ Config.RootRedirect = config?.RootRedirect ?? "https://example.com";
Logger.LogInformation("Config file changed.");
diff --git a/LinkRouter/App/Services/MetricsService.cs b/LinkRouter/App/Services/MetricsService.cs
index 56a182a..c56ae0c 100644
--- a/LinkRouter/App/Services/MetricsService.cs
+++ b/LinkRouter/App/Services/MetricsService.cs
@@ -1,9 +1,8 @@
-using MoonCore.Attributes;
using Prometheus;
namespace LinkRouter.App.Services;
-[Singleton]
+
public class MetricsService
{
private readonly Counter RouteCounter = Metrics.CreateCounter(
diff --git a/LinkRouter/App/Services/RedirectionService.cs b/LinkRouter/App/Services/RedirectionService.cs
index b6dfefc..336911c 100644
--- a/LinkRouter/App/Services/RedirectionService.cs
+++ b/LinkRouter/App/Services/RedirectionService.cs
@@ -1,81 +1,66 @@
-using LinkRouter.App.Configuration;
-using Microsoft.AspNetCore.Mvc;
-using MoonCore.Attributes;
+using LinkRouter.App.Models;
namespace LinkRouter.App.Services;
-[Singleton]
public class RedirectionService
{
private readonly Config Config;
- private readonly MetricsService MetricsService;
- public RedirectionService(Config config, MetricsService metricsService)
+ public RedirectionService(Config config)
{
Config = config;
- MetricsService = metricsService;
}
- public async Task GetRedirect(string path)
+ public bool TryGetRedirect(string path, out string? redirectPath)
{
- if (path == "")
+ redirectPath = null;
+
+ if (path == "/")
{
- var url = Config.RootRoute;
+ var url = Config.RootRedirect;
- if (TryGetErrorCode(url, out var notFoundStatusCode))
- return new StatusCodeResult(notFoundStatusCode);
+ if (string.IsNullOrEmpty(url))
+ return false;
- await MetricsService.IncrementFound("/");
+ redirectPath = url;
- return new RedirectResult(url);
+ return true;
}
- if (!path.EndsWith("/"))
- path += "/";
-
- path = "/" + path;
-
-
var redirectRoute = Config.CompiledRoutes?.FirstOrDefault(x => x.CompiledPattern.IsMatch(path));
-
if (redirectRoute == null)
{
- await MetricsService.IncrementNotFound(path);
-
if (!Config.NotFoundBehavior.RedirectOn404)
- return new NotFoundResult();
-
+ {
+ return false;
+ }
- if (TryGetErrorCode(Config.NotFoundBehavior.RedirectUrl, out var notFoundStatusCode))
- return new StatusCodeResult(notFoundStatusCode);
+ redirectPath = Config.NotFoundBehavior.RedirectUrl;
- return new RedirectResult(Config.NotFoundBehavior.RedirectUrl);
+ return true;
}
var match = redirectRoute.CompiledPattern.Match(path);
- if (TryGetErrorCode(redirectRoute.RedirectUrl, out var statusCode))
- return new StatusCodeResult(statusCode);
-
-
foreach (var placeholder in redirectRoute.Placeholders)
{
var value = match.Groups[placeholder.Value].Value;
redirectRoute.RedirectUrl = redirectRoute.RedirectUrl.Replace("{" + placeholder.Key + "}", value);
}
- await MetricsService.IncrementFound(path);
+ redirectPath = redirectRoute.RedirectUrl;
- return new RedirectResult(redirectRoute.RedirectUrl);
+ return true;
}
- private bool TryGetErrorCode(string url, out int code)
+ public bool TryGetStatusCode(string path, out int code)
{
- if (Config.ErrorCodePattern.IsMatch(url))
+ var match = Patterns.ErrorCodePattern.Match(path);
+
+ if (match.Success)
{
- var errorCodeMatch = Config.ErrorCodePattern.Match(url);
- code = int.Parse(errorCodeMatch.Groups[1].Value);
+ code = int.Parse(match.Groups[1].Value);
return true;
}
diff --git a/LinkRouter/LinkRouter.csproj b/LinkRouter/LinkRouter.csproj
index 07143a2..ff702c5 100644
--- a/LinkRouter/LinkRouter.csproj
+++ b/LinkRouter/LinkRouter.csproj
@@ -1,7 +1,7 @@
- net9.0
+ net10.0
enable
enable
Linux
@@ -9,7 +9,6 @@
-
diff --git a/LinkRouter/Program.cs b/LinkRouter/Program.cs
index 846359f..47033a6 100644
--- a/LinkRouter/Program.cs
+++ b/LinkRouter/Program.cs
@@ -1,9 +1,8 @@
using System.Text.Json;
-using LinkRouter.App.Configuration;
+using LinkRouter.App.Implemlementations;
+using LinkRouter.App.Models;
using LinkRouter.App.Services;
-using MoonCore.Extensions;
-using MoonCore.Helpers;
-using MoonCore.Logging;
+using Microsoft.Extensions.Logging.Console;
using Prometheus;
namespace LinkRouter;
@@ -19,8 +18,8 @@ public static void Main(string[] args)
builder.Services.AddControllers();
builder.Logging.ClearProviders();
-
- builder.Logging.AddAnsiConsole();
+ builder.Logging.AddConsole(options => { options.FormatterName = nameof(LoggingConsoleFormatter); });
+ builder.Logging.AddConsoleFormatter();
builder.Services.AddHostedService();
@@ -39,7 +38,9 @@ public static void Main(string[] args)
builder.Services.AddSingleton(config);
- builder.Services.AutoAddServices();
+ builder.Services.AddSingleton();
+
+ builder.Services.AddSingleton();
builder.Services.AddMetricServer(options => { options.Port = 5000; });
diff --git a/global.json b/global.json
deleted file mode 100644
index 93681ff..0000000
--- a/global.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "sdk": {
- "version": "9.0.0",
- "rollForward": "latestMinor",
- "allowPrerelease": false
- }
-}
\ No newline at end of file