import { MutableRefObject } from 'react' ; import { sharedWebSockets , ReadyState } from './globals' ; import { Options , ReadyStateState , SendMessage } from './types' ; interface Setters { setLastMessage : ( message : WebSocketEventMap [ 'message' ] ) => void ; setReadyState : ( callback : ( readyState : ReadyStateState ) => void ) => void ; } type Subscriber = { setLastMessage : ( message : WebSocketEventMap [ 'message' ] ) => void ; setReadyState : ( callback : ( readyState : ReadyStateState ) => void ) => void ; options : Options ; reconnect : ( ) => void ; id : string ; } ; type Subscribers = { [ url ] : Subscriber [ ] | undefined ; } ; const subscribers = { } ; export const attachListeners = ( wsInstance , url , setters , options , reconnect , reconnectCount , expectClose , sendMessage ) : ( ( ) => void ) => { const { setLastMessage , setReadyState } = setters ; let reconnectTimeout ; if ( typeof subscribers [ url ] === 'undefined' ) { subscribers [ url ] = [ ] ; wsInstance . onopen = ( event ) => { reconnectCount . current = 0 ; subscribers [ url ] ?. forEach ( subscriber => { if ( expectClose . current === false ) { subscriber . setReadyState ( readyState => { readyState [ url ] = ReadyState . OPEN ; } ) ; } if ( subscriber . options . onOpen ) { subscriber . options . onOpen ( event , sendMessage ) ; } } ) ; } ; wsInstance . onmessage = ( message ) => { if ( typeof options . filter === 'function' && options . filter ( message ) !== true ) { return ; } subscribers [ url ] ?. forEach ( subscriber => { subscriber . setLastMessage ( message ) ; if ( subscriber . options . onMessage ) { subscriber . options . onMessage ( message ) ; } } ) ; } ; wsInstance . onclose = ( event ) => { const { reconnectAttempts = 0 , reconnectInterval = 0 , shouldReconnect , } = options ; subscribers [ url ] ?. forEach ( subscriber => { if ( expectClose . current === false ) { subscriber . setReadyState ( readyState => { readyState [ url ] = ReadyState . CLOSED ; } ) ; } if ( subscriber . options . onClose ) { subscriber . options . onClose ( event ) ; } } ) ; sharedWebSockets [ url ] = undefined ; const subscribersToReconnect = [ ... subscribers [ url ] ] ; subscribers [ url ] = undefined ; if ( ! shouldReconnect ) { return ; } if ( shouldReconnect === true || ( typeof shouldReconnect === 'function' && shouldReconnect ( event ) ) ) { if ( reconnectCount . current < reconnectAttempts ) { if ( expectClose . current === false ) { console . log ( `Auto Reconnecting...${ reconnectCount . current }...` ) ; reconnectTimeout = setTimeout ( ( ) => { reconnectCount . current ++ ; subscribersToReconnect . forEach ( subscriber => { subscriber . reconnect ( ) ; } ) ; } , reconnectInterval ) ; } } else { console . error ( `Max reconnect attempts of ${ reconnectAttempts } exceeded` ) ; } } } ; wsInstance . onerror = ( error ) => { subscribers [ url ] ?. forEach ( subscriber => { if ( subscriber . options . onError ) { subscriber . options . onError ( error ) ; } } ) ; } ; } else { setReadyState ( readyState => { readyState [ url ] = ( sharedWebSockets [ url ] as WebSocket ) . readyState ; } ) ; } const subscriber = { setLastMessage , setReadyState , options , reconnect , id : Math . random ( ) . toFixed ( 10 ) . substring ( 2 ) } ; subscribers [ url ] ?. push ( subscriber ) ; return ( ) => { if ( reconnectTimeout ) clearTimeout ( reconnectTimeout ) ; const subsArr = subscribers [ url ] ; if ( subsArr && subsArr . length > 0 ) { const index = subsArr . indexOf ( subscriber ) ; if ( index === - 1 ) { return ; } if ( subsArr . length === 1 ) { subsArr [ 0 ] . setReadyState ( ( readyState ) => { readyState [ url ] = ReadyState . CLOSING ; } ) ; wsInstance . close ( ) ; } else { subsArr . splice ( index , 1 ) ; } } } ; } ;