using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; using SameBeat.Api.Hubs; using SameBeat.Application.Interfejsy; using SameBeat.Application.Komendy; namespace SameBeat.Api.Controllers; [ApiController] [Route("api/join")] public class JoinController : ControllerBase { private readonly ISerwisPoczekalni _serwisPoczekalni; private readonly ISerwisSceny _serwisSceny; private readonly IHubContext _hubKontekst; public JoinController(ISerwisPoczekalni serwisPoczekalni, ISerwisSceny serwisSceny, IHubContext hubKontekst) { _serwisPoczekalni = serwisPoczekalni; _serwisSceny = serwisSceny; _hubKontekst = hubKontekst; } /// /// Dolaczenie do poczekalni biezacego wydarzenia. Dostepne bez logowania -- to punkt wejscia dla /// gosci, ktorzy chca wystapic kamera. Tozsamosc LiveKit jest generowana wylacznie na serwerze /// (patrz UczestnikOczekujacy.Dolacz), token zwracany od razu ma grant Uczestnika: tylko kamera, /// mikrofon nigdy nie jest publikowany przy dolaczeniu. /// [HttpPost] [AllowAnonymous] public async Task DolaczAsync([FromBody] DolaczKomenda komenda, CancellationToken token) { var wynik = await _serwisPoczekalni.DolaczAsync(komenda, token); if (!wynik.Sukces || wynik.Dane is null) { return BadRequest(new { blad = wynik.Blad }); } // Powiadomienie hosta, ze poczekalnia sie zmienila -- host frontend po otrzymaniu tego // zdarzenia sam odswiezy liste przez GET /api/host/waiting-room. Zdarzenie celowo bez // payloadu (patrz komentarz przy StanImprezyHub.DolaczDoGrupyHosta). await _hubKontekst.Clients.Group(StanImprezyHub.GrupaHost).SendAsync("PoczekalniaZmieniona", cancellationToken: token); return Ok(wynik.Dane); } /// /// Odpytywanie przegladarki uczestnika, czy zostal juz wpuszczony na scene. Zabezpieczone /// WYLACZNIE sekretem sesji z odpowiedzi na dolaczenie -- zly sekret (albo nieznany uczestnikId) /// daje czytelny 403, nigdy 500. /// [HttpGet("{uczestnikId:guid}/status")] [AllowAnonymous] public async Task PobierzStatusAsync(Guid uczestnikId, [FromQuery] string sekret, CancellationToken token) { var wynik = await _serwisSceny.PobierzStatusUczestnikaAsync(uczestnikId, sekret, token); if (!wynik.Sukces || wynik.Dane is null) { return StatusCode(StatusCodes.Status403Forbidden, new { blad = wynik.Blad }); } return Ok(wynik.Dane); } /// /// Wymiana sekretu sesji na token LiveKit do sceny GLOWNEJ -- dziala tylko, gdy sekret sie zgadza /// I host juz przypisal uczestnika do slotu (Status=NaScenie). Kazde niepowodzenie (zly sekret, /// zly status) to 403 -- to endpoint dowodu tozsamosci, nie zwykla walidacja danych. /// [HttpPost("token-sceny")] [AllowAnonymous] public async Task WydajTokenScenyAsync([FromBody] TokenScenyKomenda komenda, CancellationToken token) { var wynik = await _serwisSceny.WydajTokenScenyAsync(komenda, token); if (!wynik.Sukces || wynik.Dane is null) { return StatusCode(StatusCodes.Status403Forbidden, new { blad = wynik.Blad }); } return Ok(wynik.Dane); } }