diff --git a/Streetwriters.Messenger/Helpers/SSEHelper.cs b/Streetwriters.Messenger/Helpers/SSEHelper.cs index 7481bfc..df1c6cb 100644 --- a/Streetwriters.Messenger/Helpers/SSEHelper.cs +++ b/Streetwriters.Messenger/Helpers/SSEHelper.cs @@ -18,28 +18,49 @@ along with this program. If not, see . */ using System.Linq; +using System; +using System.Threading; using System.Threading.Tasks; using Lib.AspNetCore.ServerSentEvents; using System.Security.Claims; +using System.Collections.Generic; namespace Streetwriters.Messenger.Helpers { public class SSEHelper { - public static async Task SendEventToUserAsync(string data, IServerSentEventsService sseService, string userId, string? originTokenId = null) + public static async Task SendEventToUserAsync(string data, IServerSentEventsService sseService, string userId, string? originTokenId = null, CancellationToken cancellationToken = default) { - var clients = sseService.GetClients().Where(c => c.User.FindFirstValue("sub") == userId); - foreach (var client in clients) - { - if (originTokenId != null && client.User.FindFirstValue("jti") == originTokenId) continue; - if (!client.IsConnected) continue; - await client.SendEventAsync(data); - } + var clients = sseService.GetClients() + .Where(c => c.User?.FindFirstValue("sub") == userId) + .Where(c => originTokenId == null || c.User?.FindFirstValue("jti") != originTokenId); + + await SendEventToClientsAsync(clients, data, cancellationToken); } - public static async Task SendEventToAllUsersAsync(string data, IServerSentEventsService sseService) + public static async Task SendEventToAllUsersAsync(string data, IServerSentEventsService sseService, CancellationToken cancellationToken = default) { - await sseService.SendEventAsync(data); + await SendEventToClientsAsync(sseService.GetClients(), data, cancellationToken); + } + + private static async Task SendEventToClientsAsync(IEnumerable clients, string data, CancellationToken cancellationToken) + { + foreach (var client in clients) + { + if (!client.IsConnected) continue; + + try + { + await client.SendEventAsync(data, cancellationToken); + } + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) + { + break; + } + catch + { + } + } } } } \ No newline at end of file diff --git a/Streetwriters.Messenger/Services/HeartbeatService.cs b/Streetwriters.Messenger/Services/HeartbeatService.cs index f33911a..ce52747 100644 --- a/Streetwriters.Messenger/Services/HeartbeatService.cs +++ b/Streetwriters.Messenger/Services/HeartbeatService.cs @@ -21,6 +21,7 @@ using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using Lib.AspNetCore.ServerSentEvents; using Streetwriters.Messenger.Helpers; using System.Text.Json; @@ -33,12 +34,14 @@ namespace Streetwriters.Messenger.Services private const string HEARTBEAT_MESSAGE_FORMAT = "Streetwriters Heartbeat ({0} UTC)"; private readonly IServerSentEventsService _serverSentEventsService; + private readonly ILogger _logger; #endregion #region Constructor - public HeartbeatService(IServerSentEventsService serverSentEventsService) + public HeartbeatService(IServerSentEventsService serverSentEventsService, ILogger logger) { _serverSentEventsService = serverSentEventsService; + _logger = logger; } #endregion @@ -47,15 +50,28 @@ namespace Streetwriters.Messenger.Services { while (!stoppingToken.IsCancellationRequested) { - var message = JsonSerializer.Serialize(new + try { - type = "heartbeat", - data = JsonSerializer.Serialize(new + var message = JsonSerializer.Serialize(new { - t = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - }) - }); - await SSEHelper.SendEventToAllUsersAsync(message, _serverSentEventsService); + type = "heartbeat", + data = JsonSerializer.Serialize(new + { + t = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + }) + }); + + await SSEHelper.SendEventToAllUsersAsync(message, _serverSentEventsService, stoppingToken); + } + catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested) + { + break; + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to send SSE heartbeat to one or more clients."); + } + await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken); } } diff --git a/Streetwriters.Messenger/Streetwriters.Messenger.csproj b/Streetwriters.Messenger/Streetwriters.Messenger.csproj index 395a829..e71646e 100644 --- a/Streetwriters.Messenger/Streetwriters.Messenger.csproj +++ b/Streetwriters.Messenger/Streetwriters.Messenger.csproj @@ -8,7 +8,7 @@ - +