KIM-JINO5 2 месяцев назад
Родитель
Сommit
5bf768e846

+ 6 - 0
Application/Abstractions/Chat/ChatParticipant.cs

@@ -0,0 +1,6 @@
+namespace Application.Abstractions.Chat;
+
+public sealed record ChatParticipant(
+    string MemberName,
+    bool IsGuest
+);

+ 2 - 0
Application/Abstractions/Chat/IChatHubClient.cs

@@ -5,6 +5,8 @@ public interface IChatHubClient
     Task ReceiveMessage(ChatMessage message);
     Task ReceiveHistory(IReadOnlyList<ChatMessage> messages);
     Task ReceiveSystemMessage(string message);
+    Task ReceiveParticipantCount(int count);
+    Task ReceiveParticipants(IReadOnlyList<ChatParticipant> participants);
     Task Connected(string message);
     Task Logout(string message);
     Task Kick();

+ 43 - 1
Web.Api/Hubs/ChatHub.cs

@@ -1,4 +1,4 @@
-using Application.Abstractions.Chat;
+using Application.Abstractions.Chat;
 using Application.Abstractions.Data;
 using Microsoft.AspNetCore.SignalR;
 using Microsoft.EntityFrameworkCore;
@@ -53,6 +53,7 @@ public sealed class ChatHub(IChatMessageStore messageStore, IChatConnectionTrack
         Context.Items["user"] = user;
 
         await tracker.AddAsync(user);
+        await BroadcastParticipantCountAsync();
         await base.OnConnectedAsync();
     }
 
@@ -66,6 +67,7 @@ public sealed class ChatHub(IChatMessageStore messageStore, IChatConnectionTrack
             await Clients.Others.ReceiveSystemMessage($"{user.MemberName}님이 퇴장했습니다.");
         }
 
+        await BroadcastParticipantCountAsync();
         await base.OnDisconnectedAsync(exception);
     }
 
@@ -162,4 +164,44 @@ public sealed class ChatHub(IChatMessageStore messageStore, IChatConnectionTrack
     {
         return Context.User?.FindFirst(JwtRegisteredClaimNames.Name)?.Value;
     }
+
+    /// <summary>
+    /// 클라이언트가 채팅 기록 요청 시 호출
+    /// </summary>
+    public async Task RequestHistory()
+    {
+        var messages = await messageStore.GetRecentMessagesAsync(ChatSettings.MaxMessages);
+        await Clients.Caller.ReceiveHistory(messages);
+    }
+
+    /// <summary>
+    /// 클라이언트가 접속자 수 요청 시 호출
+    /// </summary>
+    public async Task RequestParticipantCount()
+    {
+        var users = await tracker.GetAllAsync();
+        await Clients.Caller.ReceiveParticipantCount(users.Count);
+    }
+
+    /// <summary>
+    /// 클라이언트가 참여자 목록 요청 시 호출
+    /// </summary>
+    public async Task RequestParticipants()
+    {
+        var users = await tracker.GetAllAsync();
+        var participants = users
+            .Where(u => !u.IsGuest && !string.IsNullOrEmpty(u.MemberName))
+            .Select(u => new ChatParticipant(u.MemberName!, u.IsGuest))
+            .DistinctBy(p => p.MemberName)
+            .OrderBy(p => p.MemberName)
+            .ToList();
+        await Clients.Caller.ReceiveParticipants(participants);
+    }
+
+    // 전체 접속자 수 브로드캐스트
+    private async Task BroadcastParticipantCountAsync()
+    {
+        var users = await tracker.GetAllAsync();
+        await Clients.All.ReceiveParticipantCount(users.Count);
+    }
 }