using SameBeat.Domain.Wyjatki; namespace SameBeat.Domain.Encje; /// /// Log/audyt przyznan mikrofonu (ETAP 5) -- KAZDE przyznanie mikrofonu zostawia tu jeden wiersz, /// niezaleznie od tego, czy sie skonczylo timerem czy hostem przerywajacym recznie. To NIE jest zywy /// stan (ten siedzi na Wydarzenie.AktywnyMikrofonUczestnikId/AktywnyMikrofonKoniecUtc) -- zgodnie z /// zasada "nie zapisuj kazdego pakietu WebRTC do bazy, baza przechowuje stan biznesowy": tu zapisujemy /// tylko fakt biznesowy "kto, kiedy i na jak dlugo dostal mikrofon", raz na przyznanie. /// public class HistoriaMikrofonu { public Guid Id { get; private set; } public Guid WydarzenieId { get; private set; } public Guid UczestnikOczekujacyId { get; private set; } public DateTime StartUtc { get; private set; } public DateTime KoniecPlanowanyUtc { get; private set; } /// /// Kiedy mikrofon FAKTYCZNIE zostal odebrany -- null dopoki jest aktywny. Rozni sie od /// KoniecPlanowanyUtc, gdy host przerwal recznie przed czasem (wtedy KoniecFaktycznyUtc < /// KoniecPlanowanyUtc); rowny (z dokladnoscia do czestotliwosci timera) przy naturalnym wygasnieciu. /// public DateTime? KoniecFaktycznyUtc { get; private set; } public int CzasSekundy { get; private set; } /// Nick hosta, ktory przyznal mikrofon -- do audytu (kto z ekipy to zrobil), nie do logiki. public string PrzyznalHostNick { get; private set; } = string.Empty; // Prywatny konstruktor bez parametrow -- wymagany przez EF Core do materializacji encji z bazy. private HistoriaMikrofonu() { } private HistoriaMikrofonu(Guid id, Guid wydarzenieId, Guid uczestnikOczekujacyId, DateTime startUtc, int czasSekundy, string przyznalHostNick) { Id = id; WydarzenieId = wydarzenieId; UczestnikOczekujacyId = uczestnikOczekujacyId; StartUtc = startUtc; KoniecPlanowanyUtc = startUtc.AddSeconds(czasSekundy); CzasSekundy = czasSekundy; PrzyznalHostNick = przyznalHostNick; } /// /// Otwiera nowy wpis audytu w chwili przyznania mikrofonu -- StartUtc/KoniecPlanowanyUtc licza /// sie z tej samej chwili, co Wydarzenie.PrzyznajMikrofon (serwis wywoluje oba tuz obok siebie). /// public static HistoriaMikrofonu Rozpocznij(Guid wydarzenieId, Guid uczestnikOczekujacyId, int czasSekundy, string przyznalHostNick) { if (wydarzenieId == Guid.Empty) { throw new NieprawidlowyStanEncjiWyjatek("Historia mikrofonu musi byc powiazana z konkretnym wydarzeniem."); } if (uczestnikOczekujacyId == Guid.Empty) { throw new NieprawidlowyStanEncjiWyjatek("Historia mikrofonu musi byc powiazana z konkretnym uczestnikiem."); } if (czasSekundy <= 0) { throw new NieprawidlowyStanEncjiWyjatek("Czas przyznania mikrofonu musi byc dodatni."); } var hostNickPrzyciety = string.IsNullOrWhiteSpace(przyznalHostNick) ? "nieznany" : przyznalHostNick.Trim(); return new HistoriaMikrofonu(Guid.NewGuid(), wydarzenieId, uczestnikOczekujacyId, DateTime.UtcNow, czasSekundy, hostNickPrzyciety); } /// Zamyka wpis w chwili faktycznego odebrania mikrofonu. Idempotentne -- druga zamiana nic nie zmienia. public void Zakoncz() { if (KoniecFaktycznyUtc is not null) { return; } KoniecFaktycznyUtc = DateTime.UtcNow; } }