33import com .back .global .exception .ErrorCode ;
44import com .back .global .exception .CustomException ;
55import com .back .global .security .user .CustomUserDetails ;
6- import com .back .global .websocket .dto .WebSocketSessionInfo ;
7- import com .back .global .websocket .service .WebSocketSessionManager ;
86import com .back .global .websocket .util .WebSocketAuthHelper ;
97import com .back .global .websocket .webrtc .dto .WebRTCErrorResponse ;
108import com .back .global .websocket .webrtc .dto .media .WebRTCMediaStateResponse ;
119import com .back .global .websocket .webrtc .dto .media .WebRTCMediaToggleRequest ;
1210import com .back .global .websocket .webrtc .dto .signal .*;
1311import com .back .global .websocket .webrtc .service .WebRTCSignalValidator ;
14- import com .back .global .websocket .util .WebSocketErrorHelper ;
1512import lombok .RequiredArgsConstructor ;
1613import lombok .extern .slf4j .Slf4j ;
1714import org .springframework .messaging .handler .annotation .MessageExceptionHandler ;
2926public class WebRTCSignalingController {
3027
3128 private final SimpMessagingTemplate messagingTemplate ;
32- private final WebSocketErrorHelper errorHelper ;
3329 private final WebRTCSignalValidator validator ;
34- private final WebSocketSessionManager sessionManager ;
3530
3631 // WebRTC Offer 메시지 처리
3732 @ MessageMapping ("/webrtc/offer" )
@@ -44,21 +39,28 @@ public void handleOffer(@Validated @Payload WebRTCOfferRequest request, Principa
4439 Long fromUserId = userDetails .getUserId ();
4540 Long targetUserId = request .targetUserId ();
4641
47- log .info ("WebRTC Offer 처리 시작 - Room: {}, From: {}, To: {}" , request .roomId (), fromUserId , targetUserId );
42+ log .info ("[ WebRTC] Offer 처리 - Room: {}, From: {}, To: {}" , request .roomId (), fromUserId , targetUserId );
4843
44+ // 같은 방에 있는지, 자기 자신에게 보내는 건 아닌지 검증
4945 validator .validateSignal (request .roomId (), fromUserId , targetUserId );
5046
51- WebSocketSessionInfo targetSessionInfo = sessionManager .getSessionInfo (targetUserId );
52- if (targetSessionInfo == null ) {
53- log .warn ("WebRTC Offer 전송 실패 - 대상이 오프라인 상태입니다. User ID: {}" , targetUserId );
54- throw new CustomException (ErrorCode .WS_TARGET_OFFLINE );
55- }
56-
47+ // Offer 응답 생성
5748 WebRTCSignalResponse response = WebRTCSignalResponse .offerOrAnswer (
58- WebRTCSignalType .OFFER , fromUserId , targetUserId , request .roomId (), request .sdp (), request .mediaType ()
49+ WebRTCSignalType .OFFER ,
50+ fromUserId ,
51+ targetUserId ,
52+ request .roomId (),
53+ request .sdp (),
54+ request .mediaType ()
5955 );
6056
61- messagingTemplate .convertAndSendToUser (targetSessionInfo .username (), "/queue/webrtc" , response );
57+ // 방 토픽으로 브로드캐스트
58+ messagingTemplate .convertAndSend (
59+ "/topic/room/" + request .roomId () + "/webrtc" ,
60+ response
61+ );
62+
63+ log .debug ("[WebRTC] Offer 전송 완료 - Room: {}, From: {}, To: {}" , request .roomId (), fromUserId , targetUserId );
6264 }
6365
6466 // WebRTC Answer 메시지 처리
@@ -72,21 +74,28 @@ public void handleAnswer(@Validated @Payload WebRTCAnswerRequest request, Princi
7274 Long fromUserId = userDetails .getUserId ();
7375 Long targetUserId = request .targetUserId ();
7476
75- log .info ("WebRTC Answer 처리 시작 - Room: {}, From: {}, To: {}" , request .roomId (), fromUserId , targetUserId );
77+ log .info ("[ WebRTC] Answer 처리 - Room: {}, From: {}, To: {}" , request .roomId (), fromUserId , targetUserId );
7678
79+ // 같은 방에 있는지, 자기 자신에게 보내는 건 아닌지 검증
7780 validator .validateSignal (request .roomId (), fromUserId , targetUserId );
7881
79- WebSocketSessionInfo targetSessionInfo = sessionManager .getSessionInfo (targetUserId );
80- if (targetSessionInfo == null ) {
81- log .warn ("WebRTC Answer 전송 실패 - 대상이 오프라인 상태입니다. User ID: {}" , targetUserId );
82- throw new CustomException (ErrorCode .WS_TARGET_OFFLINE );
83- }
84-
82+ // Answer 응답 생성 (targetUserId 포함)
8583 WebRTCSignalResponse response = WebRTCSignalResponse .offerOrAnswer (
86- WebRTCSignalType .ANSWER , fromUserId , targetUserId , request .roomId (), request .sdp (), request .mediaType ()
84+ WebRTCSignalType .ANSWER ,
85+ fromUserId ,
86+ targetUserId ,
87+ request .roomId (),
88+ request .sdp (),
89+ request .mediaType ()
90+ );
91+
92+ // 방 토픽으로 브로드캐스트
93+ messagingTemplate .convertAndSend (
94+ "/topic/room/" + request .roomId () + "/webrtc" ,
95+ response
8796 );
8897
89- messagingTemplate . convertAndSendToUser ( targetSessionInfo . username (), "/queue/webrtc" , response );
98+ log . debug ( "[WebRTC] Answer 전송 완료 - Room: {}, From: {}, To: {}" , request . roomId (), fromUserId , targetUserId );
9099 }
91100
92101 // ICE Candidate 메시지 처리
@@ -100,23 +109,32 @@ public void handleIceCandidate(@Validated @Payload WebRTCIceCandidateRequest req
100109 Long fromUserId = userDetails .getUserId ();
101110 Long targetUserId = request .targetUserId ();
102111
103- log .debug ("WebRTC ICE Candidate 처리 시작 - Room: {}, From: {}, To: {}" , request .roomId (), fromUserId , targetUserId );
112+ log .debug ("[ WebRTC] ICE Candidate 처리 - Room: {}, From: {}, To: {}" , request .roomId (), fromUserId , targetUserId );
104113
114+ // 같은 방에 있는지, 자기 자신에게 보내는 건 아닌지 검증
105115 validator .validateSignal (request .roomId (), fromUserId , targetUserId );
106116
107- WebSocketSessionInfo targetSessionInfo = sessionManager .getSessionInfo (targetUserId );
108- if (targetSessionInfo == null ) {
109- return ; // ICE Candidate는 실패해도 에러를 보내지 않고 조용히 무시
110- }
111-
117+ // ICE Candidate 응답 생성
112118 WebRTCSignalResponse response = WebRTCSignalResponse .iceCandidate (
113- fromUserId , targetUserId , request .roomId (), request .candidate (), request .sdpMid (), request .sdpMLineIndex ()
119+ fromUserId ,
120+ targetUserId ,
121+ request .roomId (),
122+ request .candidate (),
123+ request .sdpMid (),
124+ request .sdpMLineIndex ()
114125 );
115126
116- messagingTemplate .convertAndSendToUser (targetSessionInfo .username (), "/queue/webrtc" , response );
127+ // 방 토픽으로 브로드캐스트
128+ messagingTemplate .convertAndSend (
129+ "/topic/room/" + request .roomId () + "/webrtc" ,
130+ response
131+ );
117132 }
118133
119- // 미디어 상태 토글 처리 (방 전체에 상태 공유)
134+ /**
135+ * 미디어 상태 토글 처리
136+ * 방 전체에 미디어 상태 변경 브로드캐스트
137+ */
120138 @ MessageMapping ("/webrtc/media/toggle" )
121139 public void handleMediaToggle (@ Validated @ Payload WebRTCMediaToggleRequest request , Principal principal ) {
122140 CustomUserDetails userDetails = WebSocketAuthHelper .extractUserDetails (principal );
@@ -125,53 +143,71 @@ public void handleMediaToggle(@Validated @Payload WebRTCMediaToggleRequest reque
125143 }
126144
127145 Long userId = userDetails .getUserId ();
128- log .info ("미디어 상태 변경 처리 시작 - Room: {}, User: {}" , request .roomId (), userId );
129146
147+ log .info ("[WebRTC] 미디어 상태 변경 - Room: {}, User: {}, Type: {}, Enabled: {}" ,
148+ request .roomId (), userId , request .mediaType (), request .enabled ());
149+
150+ // 방 멤버인지 검증
130151 validator .validateMediaStateChange (request .roomId (), userId );
131152
153+ // 미디어 상태 응답 생성
132154 WebRTCMediaStateResponse response = WebRTCMediaStateResponse .of (
133- userId , userDetails .getUsername (), request .mediaType (), request .enabled ()
155+ userId ,
156+ userDetails .getUsername (),
157+ request .mediaType (),
158+ request .enabled ()
134159 );
135160
136- messagingTemplate .convertAndSend ("/topic/room/" + request .roomId () + "/media-status" , response );
161+ // 방 전체에 미디어 상태 브로드캐스트
162+ messagingTemplate .convertAndSend (
163+ "/topic/room/" + request .roomId () + "/media-status" ,
164+ response
165+ );
137166 }
138167
139168 // WebRTC 시그널링 처리 중 발생하는 CustomException 처리
140169 @ MessageExceptionHandler (CustomException .class )
141170 public void handleCustomException (CustomException e , Principal principal ) {
142171 if (principal == null ) {
143- log .warn ("인증 정보 없는 사용자의 WebRTC 오류: {}" , e .getMessage ());
172+ log .warn ("[WebRTC] 인증 정보 없는 사용자의 오류: {}" , e .getMessage ());
144173 return ;
145174 }
146175
147- log .warn ("WebRTC 시그널링 오류 발생 (to {}): {}" , principal .getName (), e .getMessage ());
176+ CustomUserDetails userDetails = WebSocketAuthHelper .extractUserDetails (principal );
177+ if (userDetails == null ) {
178+ log .warn ("[WebRTC] Principal에서 사용자 정보 추출 실패" );
179+ return ;
180+ }
148181
182+ log .warn ("[WebRTC] 시그널링 오류 - User: {} (ID: {}), Error: {}" ,
183+ principal .getName (), userDetails .getUserId (), e .getMessage ());
184+
185+ // 에러는 개인 큐로 전송 (방 전체에 보낼 필요 없음)
149186 WebRTCErrorResponse errorResponse = WebRTCErrorResponse .from (e );
150187
151188 messagingTemplate .convertAndSendToUser (
152- principal .getName (), // 에러를 발생시킨 사람의 username
153- "/queue/webrtc" ,
189+ principal .getName (),
190+ "/queue/errors" , // 에러 전용 큐
154191 errorResponse
155192 );
156193 }
157194
158195 // 예상치 못한 모든 Exception 처리
159196 @ MessageExceptionHandler (Exception .class )
160- public void handleGeneralException (Exception e , Principal principal ) { // headerAccessor -> Principal
197+ public void handleGeneralException (Exception e , Principal principal ) {
161198 if (principal == null ) {
162- log .error ("WebRTC 처리 중 인증 정보 없는 사용자의 예외 발생" , e );
199+ log .error ("[ WebRTC] 인증 정보 없는 사용자의 예외 발생" , e );
163200 return ;
164201 }
165202
166- log .error ("WebRTC 시그널링 처리 중 예상치 못한 오류 발생 (to {}) " , principal .getName (), e );
203+ log .error ("[ WebRTC] 예상치 못한 오류 발생 - User: {} " , principal .getName (), e );
167204
168- // CustomException으로 감싸서 일관된 형식의 에러 DTO를 생성
169205 CustomException customException = new CustomException (ErrorCode .WS_INTERNAL_ERROR );
170206 WebRTCErrorResponse errorResponse = WebRTCErrorResponse .from (customException );
171207
172208 messagingTemplate .convertAndSendToUser (
173209 principal .getName (),
174- "/queue/webrtc " ,
210+ "/queue/errors " ,
175211 errorResponse
176212 );
177213 }
0 commit comments