@@ -4,15 +4,55 @@ import { useEffect, useRef } from 'react';
44import useAuthStore from '@/stores/authStore' ;
55import useToastStore from '@/stores/toastStore' ;
66import { useNavigate } from 'react-router' ;
7+ import useNotificationStore from '@/stores/notificationStore' ;
8+ import { getNewToken } from '@/apis/auth' ;
9+
10+ interface MessageEventData {
11+ title : string ;
12+ alarmType : AlarmType ;
13+ }
714
815export const useServerSentEvents = ( ) => {
16+ let reconnect : number | undefined ;
17+
918 const navigate = useNavigate ( ) ;
19+ const recallCountRef = useRef ( 1 ) ;
1020
1121 const accessToken = useAuthStore ( ( state ) => state . accessToken ) ;
22+ const setAccessToken = useAuthStore ( ( state ) => state . setAccessToken ) ;
1223 const sourceRef = useRef < EventSourcePolyfill | null > ( null ) ;
1324
1425 const setToastActive = useToastStore ( ( state ) => state . setToastActive ) ;
1526
27+ const incrementNotReadCount = useNotificationStore ( ( state ) => state . incrementNotReadCount ) ;
28+
29+ const ALARM_TYPE : AlarmType [ ] = [ 'SENDING' , 'LETTER' , 'REPORT' , 'SHARE' , 'POSTED' ] ;
30+ const handleOnMessage = async ( data : string ) => {
31+ const message : MessageEventData = await JSON . parse ( data ) ;
32+ if ( ALARM_TYPE . includes ( message . alarmType ) ) {
33+ incrementNotReadCount ( ) ;
34+ setToastActive ( {
35+ toastType : 'Info' ,
36+ title : message . title ,
37+ position : 'Top' ,
38+ time : 5 ,
39+ onClick : ( ) => navigate ( '/mypage/notifications' ) ,
40+ } ) ;
41+ }
42+ } ;
43+
44+ // 토큰 재발급 함수
45+ const callReissue = async ( ) => {
46+ try {
47+ const response = await getNewToken ( ) ;
48+ if ( response ?. status !== 200 ) throw new Error ( 'error while fetching newToken' ) ;
49+ const newToken = response ?. data . data . accessToken ;
50+ return setAccessToken ( newToken ) ;
51+ } catch ( e ) {
52+ return Promise . reject ( e ) ;
53+ }
54+ } ;
55+
1656 useEffect ( ( ) => {
1757 if ( ! accessToken ) {
1858 console . log ( '로그인 정보 확인불가' ) ;
@@ -32,23 +72,24 @@ export const useServerSentEvents = () => {
3272 ) ;
3373
3474 sourceRef . current . onmessage = ( event ) => {
35- console . log ( event ) ;
36- console . log ( '알림 수신' ) ;
37- setToastActive ( {
38- toastType : 'Info' ,
39- title : '새 알림이 도착했어요!' ,
40- position : 'Top' ,
41- time : 5 ,
42- onClick : ( ) => navigate ( '/mypage/notifications' ) ,
43- } ) ;
75+ // console.log(event);
76+ // console.log('알림 수신');
77+ handleOnMessage ( event . data ) ;
4478 } ;
4579
46- sourceRef . current . onerror = ( error ) => {
47- console . log ( error ) ;
48- console . log ( '에러 발생함' ) ;
80+ sourceRef . current . onerror = ( ) => {
81+ // 에러 발생시 해당 에러가 45초를 넘어서 발생한 에러인지, 401에러인지 판단할 수 있는게 없어서 그냥 에러 발생하면 reissue 넣는걸로 때움
82+ callReissue ( ) ;
4983 closeSSE ( ) ;
84+ recallCountRef . current += 1 ;
85+ console . log ( 'SSE연결 에러 발생' ) ;
86+
5087 // 재연결 로직 추가 가능
51- setTimeout ( connectSSE , 5000 ) ; // 5초 후 재연결 시도
88+ if ( recallCountRef . current < 5 ) {
89+ reconnect = setTimeout ( connectSSE , 5000 ) ;
90+ } else {
91+ console . log ( '5회 이상 에러발생으로 구독기능 제거' ) ;
92+ }
5293 } ;
5394 } catch ( error ) {
5495 console . error ( error ) ;
@@ -64,6 +105,7 @@ export const useServerSentEvents = () => {
64105 } , [ accessToken ] ) ;
65106
66107 const closeSSE = ( ) => {
108+ if ( reconnect ) clearTimeout ( reconnect ) ;
67109 sourceRef . current ?. close ( ) ;
68110 sourceRef . current = null ;
69111 } ;
0 commit comments