Files
Radicade/Server/Health/ServiceRootHealthAPI.cs
T
2026-10-16 23:33:13 -07:00

101 lines
3.6 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RadicadeServer.API.Notifications;
using RadicadeServer.DB;
namespace RadicadeServer.API;
[ApiController]
public sealed class ServiceRootHealthAPI(IDbContextFactory<RecDBContext> dbFactory) : ControllerBase
{
private static readonly HashSet<string> HealthRootPaths = new(StringComparer.OrdinalIgnoreCase)
{
"auth", "ai", "data", "www", "cards", "notify", "images", "cdn", "commerce",
"datacollection", "discovery", "matchmaking", "storage", "chat", "geo", "leaderboard",
"accounts", "link", "locker", "moderation", "roomcomments", "roomieintegrations",
"clubs", "rooms", "econ", "bugreporting", "cms", "gamelogs", "platformnotifications",
"stringscdn", "strings", "lists", "studio", "studiocdn", "thorn", "videos"
};
internal static bool IsHealthRootPath(string path) => HealthRootPaths.Contains(path.Trim('/'));
[HttpGet("~/auth")]
[HttpGet("~/ai")]
[HttpGet("~/www")]
[HttpGet("~/cards")]
[HttpGet("~/notify")]
[HttpGet("~/images")]
[HttpGet("~/cdn")]
[HttpGet("~/commerce")]
[HttpGet("~/datacollection")]
[HttpGet("~/discovery")]
[HttpGet("~/matchmaking")]
[HttpGet("~/storage")]
[HttpGet("~/chat")]
[HttpGet("~/geo")]
[HttpGet("~/leaderboard")]
[HttpGet("~/accounts")]
[HttpGet("~/link")]
[HttpGet("~/locker")]
[HttpGet("~/moderation")]
[HttpGet("~/roomcomments")]
[HttpGet("~/roomieintegrations")]
[HttpGet("~/clubs")]
[HttpGet("~/rooms")]
[HttpGet("~/econ")]
[HttpGet("~/bugreporting")]
[HttpGet("~/cms")]
[HttpGet("~/gamelogs")]
[HttpGet("~/platformnotifications")]
[HttpGet("~/stringscdn")]
[HttpGet("~/strings")]
[HttpGet("~/lists")]
[HttpGet("~/studio")]
[HttpGet("~/studiocdn")]
[HttpGet("~/thorn")]
[HttpGet("~/videos")]
[AllowAnonymous]
public Task<IActionResult> GetServiceStatus()
{
var service = (Request.Path.Value ?? string.Empty).Trim('/').ToLowerInvariant();
var notifyService = service == "notify";
return ServiceRootHealth.CheckAsync(this, service, dbFactory, notifyService);
}
}
internal static class ServiceRootHealth
{
public static async Task<IActionResult> CheckAsync(
ControllerBase controller,
string service,
IDbContextFactory<RecDBContext>? dbFactory,
bool requireNotifyHub = false)
{
if (requireNotifyHub && Notify.Context is null)
return Unavailable(controller, service, "NOTIFY_HUB_UNAVAILABLE");
var effectiveFactory = requireNotifyHub ? Notify.DbFactory : dbFactory;
if (effectiveFactory is null)
return Unavailable(controller, service, $"{ErrorPrefix(service)}_DATABASE_NOT_CONFIGURED");
try
{
await using var db = await effectiveFactory.CreateDbContextAsync();
if (!await db.Database.CanConnectAsync())
return Unavailable(controller, service, $"{ErrorPrefix(service)}_DATABASE_UNAVAILABLE");
}
catch
{
return Unavailable(controller, service, $"{ErrorPrefix(service)}_DATABASE_UNAVAILABLE");
}
return controller.Ok(new { service, status = "ok" });
}
private static IActionResult Unavailable(ControllerBase controller, string service, string errorCode) =>
controller.StatusCode(StatusCodes.Status503ServiceUnavailable, new { service, status = errorCode });
private static string ErrorPrefix(string service) => service.ToUpperInvariant();
}