|
1 | 1 | import { useAuthStore } from '@/store/authStore'; |
2 | | -import { useChatStore } from '@/store/chatStore'; |
3 | | -import { useModalStore } from '@/store/modalStore'; |
4 | 2 | import { useSheetStore } from '@/store/sheetStore'; |
5 | | -import { EventSourcePolyfill } from 'event-source-polyfill'; |
6 | | -import { useEffect, useRef } from 'react'; |
7 | | -import { useNavigate } from 'react-router'; |
| 3 | +import { closeSSE, getSSE } from '@/utils/sseClient'; |
| 4 | +import { useEffect } from 'react'; |
8 | 5 |
|
9 | | -export const useSSE = () => { |
10 | | - const navigate = useNavigate(); |
11 | | - const { openSheet, closeSheet, setRequesterInfo, setChatConnectFail, closeAllSheets } = |
12 | | - useSheetStore(); |
13 | | - const { openModal } = useModalStore(); |
14 | | - const { setCurrentChatRoomId } = useChatStore(); |
| 6 | +export function useSSE() { |
15 | 7 | const { isAuthenticated, accessToken } = useAuthStore(); |
16 | | - const eventSourceRef = useRef<EventSourcePolyfill | null>(null); |
17 | | - const reconnectAttemptsRef = useRef(0); // 재연결 횟수 저장 |
18 | | - |
| 8 | + const { openSheet, closeSheet, setRequesterInfo } = useSheetStore(); |
19 | 9 | useEffect(() => { |
20 | | - let timeoutId: NodeJS.Timeout; |
21 | | - // 로그인 상태가 아니거나 토큰이 없으면 SSE 연결을 하지 않음 |
22 | | - if (!isAuthenticated || !accessToken) { |
23 | | - // console.log('로그아웃상태이거나 토큰이 없어서 SSE 연결을 해제합니다.'); |
24 | | - eventSourceRef.current?.close(); // 혹시 연결이 살아있으면 종료 |
| 10 | + // 토큰이 없거나 로그인 상태가 아니면 끊기 |
| 11 | + if (!accessToken || !isAuthenticated) { |
| 12 | + closeSSE(); |
25 | 13 | return; |
26 | 14 | } |
| 15 | + const es = getSSE(accessToken); // 토큰 있으면 연결 보장(토큰 바뀌면 재연결) |
27 | 16 |
|
28 | | - const connectSSE = () => { |
29 | | - // 최대 재연결 횟수 초과 시 종료 |
30 | | - if (reconnectAttemptsRef.current >= 3) { |
31 | | - openModal({ |
32 | | - title: '⚠️ 알림 연결이 불안정합니다.', |
33 | | - message: '새로고침으로 복구할 수 있어요.', |
34 | | - onConfirm: () => window.location.reload(), |
35 | | - }); |
36 | | - // console.warn('🚫 SSE: 최대 재연결 횟수(3번) 초과, 더 이상 재연결하지 않습니다.'); |
37 | | - return; |
38 | | - } |
39 | | - |
40 | | - // console.log(`🔌 SSE: 연결 시도 중... (재연결 횟수: ${reconnectAttemptsRef.current})`); |
41 | | - |
42 | | - // 기존 연결이 있다면 종료 |
43 | | - eventSourceRef.current?.close(); |
44 | | - |
45 | | - // 로그인 상태와 토큰을 한 번 더 검증 |
46 | | - if (!isAuthenticated || !accessToken) { |
47 | | - // console.log('⛔ SSE 연결 시도 중단: 로그아웃 상태거나 토큰 없음'); |
48 | | - return; |
49 | | - } |
50 | | - |
51 | | - // SSE 연결 |
52 | | - eventSourceRef.current = new EventSourcePolyfill( |
53 | | - `${import.meta.env.VITE_API_URL}/api/alert/connect`, |
54 | | - { |
55 | | - headers: { Authorization: `Bearer ${accessToken}` }, |
56 | | - }, |
57 | | - ); |
58 | | - |
59 | | - const eventSource = eventSourceRef.current; |
60 | | - |
61 | | - eventSource.addEventListener('open', () => { |
62 | | - // console.log('✅ SSE: 연결 성공!'); |
63 | | - reconnectAttemptsRef.current = 0; // 연결 성공하면 재연결 횟수 초기화 |
64 | | - }); |
65 | | - |
66 | | - eventSource.addEventListener('alarm', (event: any) => { |
67 | | - // console.log('📩 SSE: 채팅 요청 수신!', JSON.parse(event.data)); |
68 | | - const { emotionRecordId, nickname } = JSON.parse(event.data); |
69 | | - setRequesterInfo(emotionRecordId, nickname); |
70 | | - openSheet('isRequestReceivingSheetOpen'); |
71 | | - }); |
72 | | - |
73 | | - eventSource.addEventListener('cancel', () => { |
74 | | - // console.log('🚨 SSE: 채팅 취소 수신!', JSON.parse(event.data)); |
75 | | - closeSheet('isRequestReceivingSheetOpen'); |
76 | | - }); |
77 | | - |
78 | | - eventSource.addEventListener('fail', () => { |
79 | | - // console.log('⛔ SSE: 채팅 거절 수신!', JSON.parse(event.data)); |
80 | | - setChatConnectFail(true); |
81 | | - }); |
82 | | - |
83 | | - eventSource.addEventListener('accept', (event: any) => { |
84 | | - // console.log('✅ SSE: 채팅방으로 이동!', JSON.parse(event.data)); |
85 | | - const { chatRoomId } = JSON.parse(event.data); |
86 | | - |
87 | | - setCurrentChatRoomId(chatRoomId); |
88 | | - closeAllSheets(); |
89 | | - navigate(`/chatroom/${chatRoomId}`); |
90 | | - }); |
91 | | - |
92 | | - eventSource.addEventListener('error', () => { |
93 | | - console.error('❌ SSE: 오류 발생!'); |
| 17 | + // 📩 채팅 요청 받았을 때를 감지 |
| 18 | + const onAlarm = (event: any) => { |
| 19 | + const { emotionRecordId, nickname } = JSON.parse(event.data); |
| 20 | + setRequesterInfo(emotionRecordId, nickname); |
| 21 | + openSheet('isRequestReceivingSheetOpen'); |
| 22 | + }; |
94 | 23 |
|
95 | | - eventSource.close(); |
| 24 | + // 🚨 채팅 요청 취소를 받았을 때를 감지 |
| 25 | + es.addEventListener('alarm', onAlarm); |
96 | 26 |
|
97 | | - if (reconnectAttemptsRef.current < 3) { |
98 | | - reconnectAttemptsRef.current += 1; |
99 | | - // console.warn( |
100 | | - // `⚠️ SSE: 재연결 시도 중... (남은 재연결 횟수: ${3 - reconnectAttemptsRef.current})`, |
101 | | - // ); |
102 | | - timeoutId = setTimeout(connectSSE, 1000); |
103 | | - } else { |
104 | | - console.error('🚫 SSE: 최대 재연결 횟수 초과. 더 이상 재연결하지 않습니다.'); |
105 | | - } |
106 | | - }); |
| 27 | + const onCancel = () => { |
| 28 | + console.log('🚨 SSE: 채팅 취소 수신!'); |
| 29 | + closeSheet('isRequestReceivingSheetOpen'); |
107 | 30 | }; |
108 | 31 |
|
109 | | - connectSSE(); |
| 32 | + es.addEventListener('cancel', onCancel); |
110 | 33 |
|
111 | 34 | return () => { |
112 | | - // console.log('🔴 SSE: 연결 해제'); |
113 | | - clearTimeout(timeoutId); |
114 | | - eventSourceRef.current?.close(); |
| 35 | + es.removeEventListener('alarm', onAlarm); |
| 36 | + es.removeEventListener('cancel', onCancel); |
115 | 37 | }; |
116 | | - }, [isAuthenticated, accessToken]); |
117 | | -}; |
| 38 | + }, [accessToken, isAuthenticated]); |
| 39 | +} |
0 commit comments