Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 7 additions & 83 deletions LinkRouter/App/Http/Controllers/RedirectController.cs
Original file line number Diff line number Diff line change
@@ -1,106 +1,30 @@
using LinkRouter.App.Configuration;
using LinkRouter.App.Services;
using Microsoft.AspNetCore.Mvc;
using Prometheus;


namespace LinkRouter.App.Http.Controllers;

[ApiController]
public class RedirectController : Controller
{

private readonly Config Config;

private readonly Counter RouteCounter = Metrics.CreateCounter(
"linkrouter_requests",
"Counts the number of requests to the link router",
new CounterConfiguration
{
LabelNames = new[] { "route" }
}
);


private readonly Counter NotFoundCounter = Metrics.CreateCounter(
"linkrouter_404_requests",
"Counts the number of not found requests to the link router",
new CounterConfiguration
{
LabelNames = new[] { "route" }
}
);
private readonly RedirectionService RedirectionService;

public RedirectController(Config config)
public RedirectController(Config config, RedirectionService redirectionService)
{
Config = config;
RedirectionService = redirectionService;
}

[HttpGet("/{*path}")]
public async Task<ActionResult> RedirectToExternalUrl(string path)
{
if (!path.EndsWith("/"))
path += "/";

path = "/" + path;

Console.WriteLine(path);

var redirectRoute = Config.CompiledRoutes?.FirstOrDefault(x => x.CompiledPattern.IsMatch(path));

if (redirectRoute == null)
{
NotFoundCounter
.WithLabels(path)
.Inc();

if (Config.NotFoundBehavior.RedirectOn404)
if (Config.ErrorCodePattern.IsMatch(Config.NotFoundBehavior.RedirectUrl))
{
var errorCodeMatch = Config.ErrorCodePattern.Match(Config.NotFoundBehavior.RedirectUrl);
var errorCode = int.Parse(errorCodeMatch.Groups[1].Value);
return StatusCode(errorCode);
} else
return Redirect(Config.NotFoundBehavior.RedirectUrl);

return NotFound();
}

var match = redirectRoute.CompiledPattern.Match(path);

string redirectUrl = redirectRoute.RedirectUrl;

if (Config.ErrorCodePattern.IsMatch(redirectUrl))
{
var errorCodeMatch = Config.ErrorCodePattern.Match(redirectUrl);
var errorCode = int.Parse(errorCodeMatch.Groups[1].Value);
return StatusCode(errorCode);
}

foreach (var placeholder in redirectRoute.Placeholders)
{
var value = match.Groups[placeholder.Value].Value;
redirectUrl = redirectUrl.Replace("{" + placeholder.Key + "}", value);
}

return Redirect(redirectUrl);
return await RedirectionService.GetRedirect(path);
}

[HttpGet("/")]
public IActionResult GetRootRoute()
public async Task<ActionResult> GetRootRoute()
{
RouteCounter
.WithLabels("/")
.Inc();

string url = Config.RootRoute;

if (Config.ErrorCodePattern.IsMatch(url))
{
var errorCodeMatch = Config.ErrorCodePattern.Match(url);
var errorCode = int.Parse(errorCodeMatch.Groups[1].Value);
return StatusCode(errorCode);
}

return Redirect(url);
return await RedirectionService.GetRedirect(string.Empty);
}
}
45 changes: 45 additions & 0 deletions LinkRouter/App/Services/MetricsService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using MoonCore.Attributes;
using Prometheus;

namespace LinkRouter.App.Services;

[Singleton]
public class MetricsService
{
private readonly Counter RouteCounter = Metrics.CreateCounter(
"linkrouter_requests",
"Counts the number of requests to the link router",
new CounterConfiguration
{
LabelNames = new[] { "route" }
}
);


private readonly Counter NotFoundCounter = Metrics.CreateCounter(
"linkrouter_404_requests",
"Counts the number of not found requests to the link router",
new CounterConfiguration
{
LabelNames = new[] { "route" }
}
);

public Task IncrementNotFound(string path)
{
NotFoundCounter
.WithLabels(path)
.Inc();

return Task.CompletedTask;
}

public Task IncrementFound(string path)
{
RouteCounter
.WithLabels(path)
.Inc();

return Task.CompletedTask;
}
}
86 changes: 86 additions & 0 deletions LinkRouter/App/Services/RedirectionService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using LinkRouter.App.Configuration;
using Microsoft.AspNetCore.Mvc;
using MoonCore.Attributes;

namespace LinkRouter.App.Services;

[Singleton]
public class RedirectionService
{
private readonly Config Config;
private readonly MetricsService MetricsService;

public RedirectionService(Config config, MetricsService metricsService)
{
Config = config;
MetricsService = metricsService;
}

public async Task<ActionResult> GetRedirect(string path)
{
if (path == "")
{
var url = Config.RootRoute;

if (TryGetErrorCode(url, out var notFoundStatusCode))
return new StatusCodeResult(notFoundStatusCode);

await MetricsService.IncrementFound("/");

return new RedirectResult(url);
}

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();


if (TryGetErrorCode(Config.NotFoundBehavior.RedirectUrl, out var notFoundStatusCode))
return new StatusCodeResult(notFoundStatusCode);

return new RedirectResult(Config.NotFoundBehavior.RedirectUrl);
}

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);

return new RedirectResult(redirectRoute.RedirectUrl);
}

private bool TryGetErrorCode(string url, out int code)
{
if (Config.ErrorCodePattern.IsMatch(url))
{
var errorCodeMatch = Config.ErrorCodePattern.Match(url);
code = int.Parse(errorCodeMatch.Groups[1].Value);
return true;
}

code = 0;

return false;
}
}
4 changes: 1 addition & 3 deletions LinkRouter/LinkRouter.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.20"/>
<PackageReference Include="MoonCore" Version="1.5.4" />
<PackageReference Include="MoonCore" Version="2.0.6" />
<PackageReference Include="prometheus-net.AspNetCore" Version="8.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0"/>
</ItemGroup>

<ItemGroup>
Expand Down
14 changes: 6 additions & 8 deletions LinkRouter/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using LinkRouter.App.Services;
using MoonCore.Extensions;
using MoonCore.Helpers;
using MoonCore.Logging;
using Prometheus;

namespace LinkRouter;
Expand All @@ -13,18 +14,13 @@ public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);

Directory.CreateDirectory(PathBuilder.Dir("data"));
Directory.CreateDirectory(Path.Combine("data"));

builder.Services.AddControllers();

var loggerProviders = LoggerBuildHelper.BuildFromConfiguration(configuration =>
{
configuration.Console.Enable = true;
configuration.Console.EnableAnsiMode = true;
});

builder.Logging.ClearProviders();
builder.Logging.AddProviders(loggerProviders);

builder.Logging.AddAnsiConsole();

builder.Services.AddHostedService<ConfigWatcher>();

Expand All @@ -42,6 +38,8 @@ public static void Main(string[] args)
JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true }));

builder.Services.AddSingleton(config);

builder.Services.AutoAddServices<Program>();

builder.Services.AddMetricServer(options => { options.Port = 5000; });

Expand Down