using System.IO; using System.Text; using System.Text.Json; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Diagnostics.HealthChecks; using TanksServer.GameLogic; using TanksServer.Interactivity; namespace TanksServer; internal sealed class Endpoints( ClientScreenServer clientScreenServer, PlayerServer playerService, ControlsServer controlsServer, MapService mapService, ChangeToRequestedMap changeToRequestedMap ) { public void Map(WebApplication app) { app.MapPost("/player", PostPlayer); app.MapGet("/player", GetPlayerAsync); app.MapGet("/scores", () => playerService.Players); app.Map("/screen", ConnectScreenAsync); app.Map("/controls", ConnectControlsAsync); app.MapGet("/map", () => mapService.MapNames); app.MapPost("/map", PostMap); app.MapGet("/map/{name}", GetMapByName); app.MapHealthChecks("/health", new HealthCheckOptions { ResponseWriter = WriteJsonHealthCheckResponse }); } private Results, NotFound, Ok> PostMap([FromQuery] string name) { if (string.IsNullOrWhiteSpace(name)) return TypedResults.BadRequest("invalid map name"); name = name.Trim().ToUpperInvariant(); if (!mapService.TryGetPrototype(name, out var map)) return TypedResults.NotFound("map with name not found"); changeToRequestedMap.Request(map); return TypedResults.Ok(); } private async Task> ConnectControlsAsync(HttpContext context, [FromQuery] string playerName) { if (!context.WebSockets.IsWebSocketRequest) return TypedResults.BadRequest(); if (!playerService.TryGet(playerName, out var player)) return TypedResults.NotFound(); using var ws = await context.WebSockets.AcceptWebSocketAsync(); await controlsServer.HandleClientAsync(ws, player); return TypedResults.Empty; } private async Task> ConnectScreenAsync(HttpContext context, [FromQuery] string? playerName) { if (!context.WebSockets.IsWebSocketRequest) return TypedResults.BadRequest(); Player? player = null; if (!string.IsNullOrWhiteSpace(playerName) && !playerService.TryGet(playerName, out player)) return TypedResults.NotFound(); using var ws = await context.WebSockets.AcceptWebSocketAsync(); await clientScreenServer.HandleClientAsync(ws, player); return TypedResults.Empty; } private async Task, EmptyHttpResult>> GetPlayerAsync(HttpContext context, [FromQuery] string name) { if (!playerService.TryGet(name, out var foundPlayer)) return TypedResults.NotFound(); if (!context.WebSockets.IsWebSocketRequest) return TypedResults.Ok(foundPlayer); using var ws = await context.WebSockets.AcceptWebSocketAsync(); await playerService.HandleClientAsync(ws, foundPlayer); return TypedResults.Empty; } private Results, Ok, UnauthorizedHttpResult> PostPlayer([FromQuery] string name) { name = name.Trim().ToUpperInvariant(); if (name == string.Empty) return TypedResults.BadRequest("name cannot be blank"); if (name.Length > 12) return TypedResults.BadRequest("name too long"); var player = playerService.GetOrAdd(name); return TypedResults.Ok(player.Name); } private Results, NotFound, BadRequest> GetMapByName(string name) { name = name.Trim().ToUpperInvariant(); if (string.IsNullOrEmpty(name)) return TypedResults.BadRequest("map name cannot be empty"); if (!mapService.TryGetPrototype(name, out var prototype)) return TypedResults.NotFound(); if (!mapService.TryGetPreview(name, out var preview)) return TypedResults.NotFound(); var mapInfo = new MapInfo(prototype.Name, prototype.GetType().Name, preview.Data); return TypedResults.Ok(mapInfo); } private static Task WriteJsonHealthCheckResponse(HttpContext context, HealthReport healthReport) { context.Response.ContentType = "application/json; charset=utf-8"; var options = new JsonWriterOptions { Indented = true }; using var memoryStream = new MemoryStream(); using (var jsonWriter = new Utf8JsonWriter(memoryStream, options)) { jsonWriter.WriteStartObject(); jsonWriter.WriteString("status", healthReport.Status.ToString()); jsonWriter.WriteStartObject("results"); foreach (var healthReportEntry in healthReport.Entries) { jsonWriter.WriteStartObject(healthReportEntry.Key); jsonWriter.WriteString("status", healthReportEntry.Value.Status.ToString()); jsonWriter.WriteString("description", healthReportEntry.Value.Description); jsonWriter.WriteStartObject("data"); foreach (var item in healthReportEntry.Value.Data) jsonWriter.WriteString(item.Key, item.Value.ToString()); jsonWriter.WriteEndObject(); jsonWriter.WriteEndObject(); } jsonWriter.WriteEndObject(); jsonWriter.WriteEndObject(); } return context.Response.WriteAsync( Encoding.UTF8.GetString(memoryStream.ToArray())); } }