import { SCServerSocket } from 'socketcluster-server' ; import { ConnectionKind , DEFAULT_PING_INTERVAL_MAX , DEFAULT_PING_INTERVAL_MIN , INTENTIONAL_DISCONNECT_CODE , } from '../constants' ; import { EVENT_CLOSE_INBOUND , EVENT_INBOUND_SOCKET_ERROR , REMOTE_EVENT_PING , REMOTE_SC_EVENT_MESSAGE , REMOTE_SC_EVENT_RPC_REQUEST , } from '../events' ; import { PeerConfig , P2PPeerInfo } from '../types' ; import { Peer , SCServerSocketUpdated , socketErrorStatusCodes } from './base' ; const getRandomPingDelay = ( ) : number => Math . random ( ) * ( DEFAULT_PING_INTERVAL_MAX - DEFAULT_PING_INTERVAL_MIN ) + DEFAULT_PING_INTERVAL_MIN ; export class InboundPeer extends Peer { protected _socket : SCServerSocketUpdated ; protected readonly _handleInboundSocketError : ( error : Error ) => void ; protected readonly _handleInboundSocketClose : ( code : number , reason : string | undefined ) => void ; private _pingTimeoutId : NodeJS . Timer ; public constructor ( peerInfo , peerSocket , peerConfig ) { super ( peerInfo , peerConfig ) ; this . _peerInfo . internalState . connectionKind = ConnectionKind . INBOUND ; this . _handleInboundSocketError = ( error ) : void => { this . emit ( EVENT_INBOUND_SOCKET_ERROR , error ) ; } ; this . _handleInboundSocketClose = ( code , reasonMessage ) : void => { const reason = reasonMessage !== undefined && reasonMessage !== '' ? reasonMessage : socketErrorStatusCodes [ code ] ?? 'Unknown reason' ; if ( this . _pingTimeoutId ) { clearTimeout ( this . _pingTimeoutId ) ; } this . emit ( EVENT_CLOSE_INBOUND , { peerInfo , code , reason , } ) ; } ; this . _pingTimeoutId = setTimeout ( ( ) => { this . _sendPing ( ) ; } , getRandomPingDelay ( ) ) ; this . _socket = peerSocket ; this . _bindHandlersToInboundSocket ( this . _socket ) ; } public set socket ( scServerSocket ) { this . _unbindHandlersFromInboundSocket ( this . _socket ) ; this . _socket = scServerSocket as SCServerSocketUpdated ; this . _bindHandlersToInboundSocket ( this . _socket ) ; } public disconnect ( code = INTENTIONAL_DISCONNECT_CODE , reason ? ) { super . disconnect ( code , reason ) ; clearTimeout ( this . _pingTimeoutId ) ; this . _unbindHandlersFromInboundSocket ( this . _socket ) ; } private _sendPing ( ) { const pingStart = Date . now ( ) ; this . request ( { procedure : REMOTE_EVENT_PING } ) . catch ( ( ) => { } ) . finally ( ( ) => { this . _peerInfo . internalState . latency = Date . now ( ) - pingStart ; this . _pingTimeoutId = setTimeout ( ( ) => { this . _sendPing ( ) ; } , getRandomPingDelay ( ) ) ; } ) ; } private _bindHandlersToInboundSocket ( inboundSocket ) { inboundSocket . on ( 'close' , this . _handleInboundSocketClose ) ; inboundSocket . on ( 'error' , this . _handleInboundSocketError ) ; inboundSocket . on ( 'message' , this . _handleWSMessage ) ; inboundSocket . on ( REMOTE_SC_EVENT_RPC_REQUEST , this . _handleRawRPC ) ; inboundSocket . on ( REMOTE_SC_EVENT_MESSAGE , this . _handleRawMessage ) ; } private _unbindHandlersFromInboundSocket ( inboundSocket ) { inboundSocket . off ( 'close' , this . _handleInboundSocketClose ) ; inboundSocket . off ( 'message' , this . _handleWSMessage ) ; inboundSocket . off ( REMOTE_SC_EVENT_RPC_REQUEST , this . _handleRawRPC ) ; inboundSocket . off ( REMOTE_SC_EVENT_MESSAGE , this . _handleRawMessage ) ; } }