// eslint-disable-next-line no-undef importScripts(`/js/stomp.js`) // eslint-disable-next-line no-undef importScripts(`/js/sockjs.js`) let sockJS; let stompClient; let reConnectAttempts = 0 let maxReconnectAttempts = 3 let messageList = [] let connectLock = false; let lastHeartbeat = null; /*재귀 함수 변수*/ let sendPing= null; /*소켓 연결 변수*/ let subscribe = null; // 클라이언트 에게 메시지 전달 async function hubToClients(message) { const allClients = await clients.matchAll({ includeUncontrolled: true, type: 'window', }); allClients.forEach(client => { client.postMessage(message); }); } // 브라우저 종료시 소켓 연결 해지 async function disConnectWebSocket(message) { console.log('disConnect', message) try {subscribe.unsubscribe()} catch (e) {} try {stompClient.disconnect()} catch (e) {} try {sockJS.close()} catch (e) {} sockJS = null stompClient = null // 모든 클라이언트가 종료시 서비스워커 heartbeat 제거 const allClients = await clients.matchAll({ includeUncontrolled: true, type: 'window', }); if(allClients.length === 1) { clearInterval(sendPing) sendPing = null; } } // 브라우저 종료시 소켓 연결 해지 async function kill() { console.log('service worker stompClient', stompClient) console.log('service worker sockJS', sockJS) clearInterval(sendPing) sendPing = null try {subscribe.unsubscribe()} catch (e) {} try {stompClient.disconnect()} catch (e) {} try {sockJS.close()} catch (e) {} stompClient = null; sockJS = null; } // 웹소켓 연결 관리 function connectWebSocket(message) { lastHeartbeat = Date.now(); console.log('sockJSConn',typeof (sockJS)) console.log('sockJSInfo',sockJS) if (sockJS === null || sockJS === undefined) { if(sockJS !== null && sockJS !== undefined) { if(sockJS.readyState && sockJS.readyState === WebSocket.OPEN) { try{subscribe.unsubscribe()} catch(e) {} try{stompClient.disconnect();} catch(e) {} try{sockJS.close();} catch(e) {} stompClient = null; sockJS = null; } } sockJS = new WebSocket(`${message.url}/stomp/ws`); if (sockJS !== WebSocket.CLOSED && sockJS !== WebSocket.CLOSING) { stompClient = Stomp.over(sockJS); stompClient.heartbeat.outgoing = 20000; stompClient.heartbeat.incoming = 20000; stompClient.debug = (e) => { if (e.includes('ERROR') || e.includes('Exception') || e.includes('failed')) { console.error('STOMP error:', e, new Date().toString()); } }; stompClient.connect({location: 'SW'}, function (frame) { console.log('message.sabun', message.sabun, stompClient) subscribe = stompClient.subscribe(`/exchange/user.exchange/user.${message.sabun}`, async (content) => { const payload = JSON.parse(content.body); console.log('servicew-usersubcribe', payload) }) console.log('hub connect()') if (sendPing == null) { sendPing = setInterval(() => { hubToClients({type: "PING"}) }, 10000); } reConnectAttempts = 0; }) } const baseDelay = 500 sockJS.onclose = (e) => { console.error('sockjs onclose', e); if (e.code !== 1000) { const delay = Math.min(baseDelay * Math.pow(2, reConnectAttempts), 5000) setTimeout(() => { hubReconnect() if (reConnectAttempts < maxReconnectAttempts) { reConnectAttempts++; } else { console.log('[Service Worker Hub] Max Reconnect attempts reached.') } }, delay) } } } else { console.log('socket is connected') } } const hubReconnect = () => { try {subscribe.unsubscribe()} catch (e) {} try {stompClient.disconnect()} catch (e) {} try {sockJS.close()} catch (e) {} stompClient = null sockJS = null clearInterval(sendPing) sendPing = null; hubToClients({type:'RECONNECT'}); lastHeartbeat = Date.now(); } // 서비스워커 설치 self.addEventListener('install', (event) => { console.log('SW: Installing...'); event.waitUntil( self.skipWaiting() ); }); // 서비스워커 활성화 this.addEventListener('activate', function activator(event) { console.log('activate!'); event.waitUntil( self.clients.claim() ); }) // 클라이언트로부터의 메시지 처리 self.addEventListener('message', async (event) => { const message = event.data; switch (message.type) { case 'CONNECT': connectWebSocket(message); break; case 'CLOSE': disConnectWebSocket(message); break; case "KILL" : kill(); break; case 'PONG' : if(typeof (stompClient) === "undefined") { hubReconnect() } break; case "WAKEUP" : if(typeof (stompClient) === "undefined") { if(!connectLock) { connectLock = true; hubReconnect() } } else { if(!connectLock) { hubToClients({type:"GETUP"}) } } break; case 'RECONNECT_SUCCESS' : let suc = true; while (suc) { if (stompClient.connected) { connectLock = false; suc = false; } await sleep(100) } break; } }); const sleep = (delay) => { return new Promise(resolve => setTimeout(resolve, delay)); }