import * as notepack from "notepack.io" ; import * as http from "http" ; import * as https from "https" ; import WebSocket from "ws" ; import url from "url" ; import { Transport , WebSocketClient , IWebSocketClientData } from "../../internal" ; const noop = ( ) => { } ; export interface IMessagePack { encode < T > ( value ) : Buffer ; decode < T > ( buffer ) : T ; } export interface IWebSocketTransportOptions { port ? : number ; proxyPort ? : number ; server ? : http . Server | https . Server ; pingInterval ? : number ; maxPingRetries ? : number ; clientRequestTimeout ? : number ; messagePack ? : IMessagePack ; } export class WebSocketTransport extends Transport < WebSocketClient > { public clients : Set < WebSocketClient > = new Set < WebSocketClient > ( ) ; public wss : WebSocket . Server ; public pingTimeout : NodeJS . Timeout | undefined ; public clientRequestTimeout : number ; public messagePack : IMessagePack ; public _proxyPort : number | undefined ; public get port ( ) { return this . wss . options . port ; } public get proxyPort ( ) { return this . _proxyPort || this . port ; } constructor ( options ) { super ( ) ; this . wss = new WebSocket . Server ( { port : options . port , server : ! options . port ? options . server : undefined } ) ; this . _proxyPort = options . proxyPort ; this . messagePack = options . messagePack || notepack ; this . clientRequestTimeout = options . clientRequestTimeout || 1000 ; const pingInterval = options . pingInterval || 1500 ; const maxPingRetries = options . maxPingRetries || 2 ; if ( pingInterval > 0 && maxPingRetries > 0 ) { this . pingTimeout = this . pingClients ( pingInterval , maxPingRetries ) ; } this . wss . on ( "connection" , this . onConnection . bind ( this ) ) ; this . wss . on ( "close" , this . onClose . bind ( this ) ) ; } public pingClients ( pingInterval , maxPingRetries ) { return setInterval ( ( ) => { this . clients . forEach ( ( client ) => { if ( client . pingCount >= maxPingRetries ) { console . debug ( "Client terminated - not responding" ) ; this . pingTimeout && clearInterval ( this . pingTimeout ) ; return client . ws . terminate ( ) ; } client . pingCount ++ ; client . ws . ping ( noop ) ; } ) ; } , pingInterval ) ; } public onConnection ( socket , request ) { const parsedURL = request . url && url . parse ( request . url ) || { } as any ; const query = parsedURL . query || "" ; const data = { roomId : parsedURL . pathname . slice ( 1 ) , ref : socket , requestTimeout : this . clientRequestTimeout , messagePack : this . messagePack , } ; const client = new WebSocketClient ( data ) ; this . clients . add ( client ) ; this . onConnect ( client , query ) ; socket . on ( "pong" , ( ) => client . pingCount = 0 ) ; socket . on ( "close" , ( code , respon ) => { this . clients . delete ( client ) ; this . onDisconnect ( client , code ) ; } ) ; } public onClose ( ) { this . pingTimeout && clearInterval ( this . pingTimeout ) ; } public terminate ( ) { this . wss . close ( ) ; } }