diff --git a/DysonNetwork.Sphere/Chat/ChatRoomService.cs b/DysonNetwork.Sphere/Chat/ChatRoomService.cs index 957a26d..d0bb770 100644 --- a/DysonNetwork.Sphere/Chat/ChatRoomService.cs +++ b/DysonNetwork.Sphere/Chat/ChatRoomService.cs @@ -162,4 +162,25 @@ public class ChatRoomService( return m; })]; } -} \ No newline at end of file + + private const string ChatRoomSubscribeKeyPrefix = "chatroom:subscribe:"; + + public async Task SubscribeChatRoom(SnChatMember member) + { + var cacheKey = ChatRoomSubscribeKeyPrefix + member.Id; + await cache.SetAsync(cacheKey, true, TimeSpan.FromHours(1)); + } + + public async Task UnsubscribeChatRoom(SnChatMember member) + { + var cacheKey = ChatRoomSubscribeKeyPrefix + member.Id; + await cache.RemoveAsync(cacheKey); + } + + public async Task IsSubscribedChatRoom(Guid memberId) + { + var cacheKey = ChatRoomSubscribeKeyPrefix + memberId; + var result = await cache.GetAsync(cacheKey); + return result ?? false; + } +} diff --git a/DysonNetwork.Sphere/Chat/ChatService.cs b/DysonNetwork.Sphere/Chat/ChatService.cs index 7ef4447..14248bb 100644 --- a/DysonNetwork.Sphere/Chat/ChatService.cs +++ b/DysonNetwork.Sphere/Chat/ChatService.cs @@ -280,7 +280,16 @@ public partial class ChatService( var accountsToNotify = FilterAccountsForNotification(members, message, sender); - logger.LogInformation($"Trying to deliver message to {accountsToNotify.Count} accounts..."); + // Filter out subscribed users from push notifications + var subscribedMemberIds = new List(); + foreach (var member in members) + { + if (await scopedCrs.IsSubscribedChatRoom(member.Id)) + subscribedMemberIds.Add(member.AccountId); + } + accountsToNotify = accountsToNotify.Where(a => !subscribedMemberIds.Contains(Guid.Parse(a.Id))).ToList(); + + logger.LogInformation("Trying to deliver message to {count} accounts...", accountsToNotify.Count); if (accountsToNotify.Count > 0) { @@ -289,7 +298,7 @@ public partial class ChatService( await scopedNty.SendPushNotificationToUsersAsync(ntyRequest); } - logger.LogInformation($"Delivered message to {accountsToNotify.Count} accounts."); + logger.LogInformation("Delivered message to {count} accounts.", accountsToNotify.Count); } private PushNotification BuildNotification(SnChatMessage message, SnChatMember sender, SnChatRoom room, string roomSubject, diff --git a/DysonNetwork.Sphere/Startup/BroadcastEventHandler.cs b/DysonNetwork.Sphere/Startup/BroadcastEventHandler.cs index 799ddde..b8fb0f3 100644 --- a/DysonNetwork.Sphere/Startup/BroadcastEventHandler.cs +++ b/DysonNetwork.Sphere/Startup/BroadcastEventHandler.cs @@ -192,6 +192,12 @@ public class BroadcastEventHandler( case "messages.typing": await HandleMessageTyping(evt, packet); break; + case "messages.subscribe": + await HandleMessageSubscribe(evt, packet); + break; + case "messages.unsubscribe": + await HandleMessageUnsubscribe(evt, packet); + break; } } catch (Exception ex) @@ -278,6 +284,62 @@ public class BroadcastEventHandler( await pusher.PushWebSocketPacketToUsersAsync(respRequest); } + private async Task HandleMessageSubscribe(WebSocketPacketEvent evt, WebSocketPacket packet) + { + using var scope = serviceProvider.CreateScope(); + var crs = scope.ServiceProvider.GetRequiredService(); + + if (packet.Data == null) + { + await SendErrorResponse(evt, "messages.subscribe requires you to provide the ChatRoomId"); + return; + } + + var requestData = packet.GetData(); + if (requestData == null) + { + await SendErrorResponse(evt, "Invalid request data"); + return; + } + + var sender = await crs.GetRoomMember(evt.AccountId, requestData.ChatRoomId); + if (sender == null) + { + await SendErrorResponse(evt, "User is not a member of the chat room."); + return; + } + + await crs.SubscribeChatRoom(sender); + } + + private async Task HandleMessageUnsubscribe(WebSocketPacketEvent evt, WebSocketPacket packet) + { + using var scope = serviceProvider.CreateScope(); + var crs = scope.ServiceProvider.GetRequiredService(); + + if (packet.Data == null) + { + await SendErrorResponse(evt, "messages.unsubscribe requires you to provide the ChatRoomId"); + return; + } + + var requestData = packet.GetData(); + if (requestData == null) + { + await SendErrorResponse(evt, "Invalid request data"); + return; + } + + var sender = await crs.GetRoomMember(evt.AccountId, requestData.ChatRoomId); + if (sender == null) + { + await SendErrorResponse(evt, "User is not a member of the chat room."); + return; + } + + await crs.UnsubscribeChatRoom(sender); + } + private async Task SendErrorResponse(WebSocketPacketEvent evt, string message) { await pusher.PushWebSocketPacketToDeviceAsync(new PushWebSocketPacketToDeviceRequest