using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using SVSim.Database.Repositories.Viewer; using SVSim.EmulatedEntrypoint.Extensions; using SVSim.EmulatedEntrypoint.Models.Dtos.Requests; using SVSim.EmulatedEntrypoint.Models.Dtos.Responses; namespace SVSim.EmulatedEntrypoint.Controllers; public class ToolController : SVSimController { private readonly ILogger _logger; private readonly IViewerRepository _viewerRepository; public ToolController(ILogger logger, IViewerRepository viewerRepository) { _logger = logger; _viewerRepository = viewerRepository; } /// /// POST /tool/signup — the client's first request on a fresh boot. Creates (or returns /// the existing) Viewer keyed on the request's UDID. The interesting outputs (viewer_id, /// short_udid, udid) all flow back via data_headers, populated by the translation /// middleware after this action returns — we just need to stash the viewer on HttpContext so /// the middleware picks it up the same way the auth handler does for logged-in endpoints. /// /// Spec: docs/api-spec/endpoints/pre-login/tool-signup.md. /// [AllowAnonymous] [HttpPost("signup")] public async Task Signup([FromBody] SignupRequest request) { Guid? maybeUdid = HttpContext.GetUdid(); if (maybeUdid is not Guid udid || udid == Guid.Empty) { throw new InvalidOperationException( "Cannot register viewer: request has no resolvable UDID (missing UDID/SID headers, or " + "SessionidMappingMiddleware couldn't decode the UDID header)."); } var viewer = await _viewerRepository.GetViewerByUdid(udid) ?? await _viewerRepository.RegisterAnonymousViewer(udid); HttpContext.SetViewer(viewer); _logger.LogInformation("Signup resolved for udid={Udid} → viewer_id={ViewerId}, short_udid={ShortUdid}.", udid, viewer.Id, viewer.ShortUdid); return new SignupResponse(); } }