using Deal.Modules.Kanban.Application.Models; namespace Deal.Api.Events; /// /// Публикация SSE-тостов статистики тика правил хранения в канал тенанта. /// public sealed class StorageToastPublisher { private const string ToastEventType = "toast"; private const string AutoArchiveToastText = "Автоархив: {0} карточек"; private const string ArchiveClearedToastText = "Архив очищен: {0} (90 дн.)"; private const string TrashClearedToastText = "Корзина очищена: {0} (7 дн.)"; private const string RejectedPurgedToastText = "Отсев очищен: {0} записей (3 дн.)"; private const string ClockIcon = "clock"; private const string TrashIcon = "trash"; private readonly SseBroker _broker; /// /// Создаёт публикатора тостов тика. /// /// SSE-брокер каналов тенантов (singleton). public StorageToastPublisher(SseBroker broker) { ArgumentNullException.ThrowIfNull(broker); _broker = broker; } /// /// Публикует тосты статистики тика по ненулевым счётчикам. /// /// Тенант-получатель тостов (сессия запроса / канал тенанта цикла). /// Статистика только что выполненного тика. public void PublishTickToasts(Guid tenantId, StorageTickStatsDto stats) { if (stats.Archived > 0) { _broker.Publish(tenantId, ToastEventType, new { text = string.Format(AutoArchiveToastText, stats.Archived), icon = ClockIcon }); } if (stats.PurgedArchive > 0) { _broker.Publish(tenantId, ToastEventType, new { text = string.Format(ArchiveClearedToastText, stats.PurgedArchive), icon = TrashIcon }); } if (stats.PurgedTrash > 0) { _broker.Publish(tenantId, ToastEventType, new { text = string.Format(TrashClearedToastText, stats.PurgedTrash), icon = TrashIcon }); } if (stats.PurgedRejected > 0) { _broker.Publish(tenantId, ToastEventType, new { text = string.Format(RejectedPurgedToastText, stats.PurgedRejected), icon = TrashIcon }); } } }