import * as WebSocket from 'isomorphic-ws' ; import { URL } from 'url' ; import { toNumber } from 'lodash' ; import { EventEmitter } from 'events' ; import SocketOptions from './socketOptions' ; import Endpoint from './webSocketEndpoint' ; import * as http from 'http' ; import * as https from 'https' ; import * as net from "net" ; import * as url from 'url' ; import { IListener } from './types' ; type HttpServer = http . Server | https . Server ; class HttpServerListener { servers = new Map < string , WebSocket . Server > ( ) ; constructor ( private server ) { server . on ( 'upgrade' , this . onUpgrade . bind ( this ) ) ; } onUpgrade ( request , socket , head ) { let wsServer ; if ( request . url ) { const path = url . parse ( request . url ) . pathname ; if ( path ) { const wsServer = this . servers . get ( path ) ; if ( wsServer ) { wsServer . handleUpgrade ( request , socket , head , function done ( ws ) { wsServer . emit ( 'connection' , ws , request ) ; } ) ; return ; } } } socket . destroy ( ) ; } add ( path , wsServer ) { this . servers . set ( path , wsServer ) ; } remove ( path ) { this . servers . delete ( path ) ; if ( this . servers . size === 0 ) listeners . delete ( this . server ) ; } } const listeners = new Map < HttpServer , HttpServerListener > ( ) ; function getHttpServerListener ( httpServer ) { let listener = listeners . get ( httpServer ) ; if ( listener ) return listener ; listener = new HttpServerListener ( httpServer ) ; listeners . set ( httpServer , listener ) ; return listener ; } export default class WebSocketListener extends EventEmitter implements IListener { server : WebSocket . Server ; path : string | undefined ; constructor ( public address , private httpServer , private options ) { super ( ) ; this . onConnection = this . onConnection . bind ( this ) ; if ( ! WebSocket . Server ) throw 'binding websocket is not supported on browser' ; const url = new URL ( address ) ; let port ; if ( url . port ) port = toNumber ( url . port ) ; else if ( url . protocol === 'wss' ) port = 443 ; else if ( url . protocol == 'ws' ) port = 80 ; else throw new Error ( 'not a websocket address' ) ; if ( httpServer ) { this . server = new WebSocket . Server ( { noServer : true } ) ; const listener = getHttpServerListener ( httpServer ) ; this . path = url . pathname ; listener . add ( url . pathname , this . server ) ; } else { this . server = new WebSocket . Server ( { port : port , path : url . pathname } ) ; } this . server . on ( 'connection' , this . onConnection ) ; } onConnection ( connection ) { const endpoint = new Endpoint ( connection , this . options ) ; this . emit ( 'attach' , endpoint ) ; } close ( ) { if ( this . path && this . httpServer ) getHttpServerListener ( this . httpServer ) . remove ( this . path ) ; this . server . close ( ) ; } }