using Microsoft.AspNetCore.Mvc; using System.Text.Json; using System.Text.Json.Nodes; namespace RadicadeServer.API.Launcher { [Route("api/launcher")] public class LauncherBuildAPI : Controller { private static readonly string LauncherDirectory = Path.GetFullPath("./Launcher"); private static readonly string LauncherManifestPath = Path.Join(LauncherDirectory, "manifest.json"); private static async Task LoadLauncherManifest() { if (!System.IO.File.Exists(LauncherManifestPath)) return null; var raw = await System.IO.File.ReadAllTextAsync(LauncherManifestPath); return JsonNode.Parse(raw)?.AsObject(); } private static string? GetString(JsonObject manifest, string key) { return manifest[key]?.GetValue(); } private static string? GetNestedString(JsonObject manifest, string parentKey, string childKey) { return manifest[parentKey]?[childKey]?.GetValue(); } private static bool GetBool(JsonObject manifest, string key, bool fallback = false) { return manifest[key]?.GetValue() ?? fallback; } private static IActionResult MissingManifestFile() { return new JsonResult(new { error = "Launcher manifest file was not found.", path = LauncherManifestPath }) { StatusCode = StatusCodes.Status404NotFound }; } private static IActionResult InvalidManifestFile(string message, object? extra = null) { return new JsonResult(new { error = message, path = LauncherManifestPath, extra }) { StatusCode = StatusCodes.Status503ServiceUnavailable }; } [HttpGet("approved-build")] public async Task GetApprovedBuild() { if (!System.IO.File.Exists(LauncherManifestPath)) return MissingManifestFile(); try { var raw = await System.IO.File.ReadAllTextAsync(LauncherManifestPath); var manifest = JsonNode.Parse(raw)?.AsObject(); if (manifest == null) return InvalidManifestFile("Launcher manifest file is not a JSON object."); var gameVersion = GetString(manifest, "version"); var manifestVersion = GetString(manifest, "manifestVersion"); var gameDownloadUrl = GetNestedString(manifest, "package", "url"); var packageSha256 = GetNestedString(manifest, "package", "sha256"); if (string.IsNullOrWhiteSpace(gameVersion) || string.IsNullOrWhiteSpace(manifestVersion) || string.IsNullOrWhiteSpace(gameDownloadUrl) || string.IsNullOrWhiteSpace(packageSha256)) { return InvalidManifestFile( "Approved build metadata is incomplete.", new { missing = new[] { string.IsNullOrWhiteSpace(gameVersion) ? "version" : null, string.IsNullOrWhiteSpace(manifestVersion) ? "manifestVersion" : null, string.IsNullOrWhiteSpace(gameDownloadUrl) ? "package.url" : null, string.IsNullOrWhiteSpace(packageSha256) ? "package.sha256" : null }.Where(x => x != null).ToArray() }); } return Ok(new { gameVersion, manifestVersion, gameDownloadUrl, packageSha256, required = GetBool(manifest, "required", true), launchTicket = GetString(manifest, "launchTicket"), launchTicketRequired = GetBool(manifest, "launchTicketRequired"), launchTicketUrl = GetString(manifest, "launchTicketUrl"), launchTicketAudience = GetString(manifest, "launchTicketAudience"), launchTicketNonce = GetString(manifest, "launchTicketNonce") }); } catch (JsonException ex) { return InvalidManifestFile("Launcher manifest file contains invalid JSON.", new { details = ex.Message }); } } [HttpGet("manifest.json")] public async Task GetManifest() { if (!System.IO.File.Exists(LauncherManifestPath)) return MissingManifestFile(); try { var raw = await System.IO.File.ReadAllTextAsync(LauncherManifestPath); var manifest = JsonNode.Parse(raw)?.AsObject(); if (manifest == null) return InvalidManifestFile("Launcher manifest file is not a JSON object."); var version = GetString(manifest, "version"); var packageUrl = GetNestedString(manifest, "package", "url"); if (string.IsNullOrWhiteSpace(version) || string.IsNullOrWhiteSpace(packageUrl)) { return InvalidManifestFile( "Launcher manifest file is missing required fields.", new { missing = new[] { string.IsNullOrWhiteSpace(version) ? "version" : null, string.IsNullOrWhiteSpace(packageUrl) ? "package.url" : null }.Where(x => x != null).ToArray() }); } return Content(raw, "application/json"); } catch (JsonException ex) { return InvalidManifestFile("Launcher manifest file contains invalid JSON.", new { details = ex.Message }); } } } }