using Application.Abstractions.Cache; using Application.Abstractions.Chat; using Application.Abstractions.Hub; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using StackExchange.Redis; namespace Infrastructure.Hubs; /// /// 공통 Hub — 모든 페이지에서 사용 /// 접속자 추적 + 채팅 + 알림 + 쪽지 + 크루 초대/동의/toast + YouTube 채팅 통합 /// public sealed class AppHub( IConnectionMultiplexer redis, ILogger logger ) : Hub { // ── 연결 관리 ──────────────────────────────────────────────── public override async Task OnConnectedAsync() { var memberID = GetMemberID(); if (memberID > 0) { var db = redis.GetDatabase(); await db.HashSetAsync(CacheKeys.ChatConnections, Context.ConnectionId, memberID); // 개인 그룹 (알림/쪽지용) await Groups.AddToGroupAsync(Context.ConnectionId, $"member:{memberID}"); } await base.OnConnectedAsync(); } public override async Task OnDisconnectedAsync(Exception? exception) { var db = redis.GetDatabase(); await db.HashDeleteAsync(CacheKeys.ChatConnections, Context.ConnectionId); await base.OnDisconnectedAsync(exception); } // ── 채팅 그룹 참가/퇴장 ────────────────────────────────────── public async Task JoinChat(string room) { await Groups.AddToGroupAsync(Context.ConnectionId, $"chat:{room}"); } public async Task LeaveChat(string room) { await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"chat:{room}"); } // ── 채팅 메시지 전송 ───────────────────────────────────────── public async Task SendMessage(string room, ChatMessage message) { await Clients.Group($"chat:{room}").ReceiveMessage(message); } // ── 채널 그룹 (크루 초대/동의 실시간 등) ───────────────────── public async Task JoinChannel(string channelSID) { await Groups.AddToGroupAsync(Context.ConnectionId, $"channel:{channelSID}"); } public async Task LeaveChannel(string channelSID) { await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"channel:{channelSID}"); } // ── Private ────────────────────────────────────────────────── private int GetMemberID() { var claim = Context.User?.FindFirst("memberID")?.Value; return int.TryParse(claim, out var id) ? id : 0; } }