import { Container } from '@decorators/di' ; import { ParameterType , Param , EventType , Listener , SocketMeta , SocketClass , getMeta } from './meta' ; import { executeMiddleware , IO_MIDDLEWARE , middlewareHandler , Type } from './middleware' ; param { SocketIO . Server } io param { Type [ ] } controllers export function attachControllers ( io , controllers ) { io . use ( ( socket , next ) => middlewareHandler ( IO_MIDDLEWARE ) ( io , socket , next ) ) ; controllers . forEach ( ( controller ) => attachController ( io , controller ) ) ; } param { SocketIO . Server } IO param { Type } Controller function attachController ( io , controller ) { const instance = Container . get ( controller ) ; const meta = getMeta ( instance ) ; const ioNS = io . of ( meta . namespace ) ; /**
     * Apply io based events
     */ applyEvents ( io , null , controller , EventType . IO ) ; /**
     * Apply local listeners (socket based)
     */ ioNS . on ( 'connection' , ( socket ) => { /**
         * Apply all registered controller-based and event-based middlewares to socket
         */ ( socket as any ) . use ( socketMiddlewareHandler ( io , socket , meta ) ) ; /**
         * Apply socket based events
         */ applyEvents ( io , socket , controller , EventType . Socket ) ; } ) ; } param { IO } io param { SocketIO . Socket } socket param { SocketMeta } meta function socketMiddlewareHandler ( io , socket , meta ) { return ( packet , next ) => { const [ event , data ] = packet ; const args = [ io , socket , { event , data } ] ; /**
         * Find listener that serves this event
         */ const listener = meta . listeners . find ( ( lst ) => lst . event === event ) ; /**
         * And if listener exists, loop through controller middlewares
         * and after that event (registered in listener) middlewares
         */ if ( listener ) { return executeMiddleware ( meta . middleware , args ) . then ( ( ) => executeMiddleware ( listener . middleware , args ) ) . then ( ( ) => next ( ) ) . catch ( err => next ( err ) ) ; } next ( ) ; } ; } param { SocketIO . Server | SocketIO . Namespace } io param { SocketIO . Socket } socket param { Type } controller param { EventType } type function applyEvents ( io , socket , controller , type ) { const instance = Container . get ( controller ) ; const meta = getMeta ( instance ) ; const ioSock = socket || io ; meta . listeners . filter ( ( listener ) => listener . type === type ) . forEach ( ( listener ) => ioSock . on ( listener . event , ( ... args ) => { const methodName = listener . methodName ; const newArgs = mapArguments ( io , socket || args [ 0 ] , meta . params [ methodName ] , args ) ; return instance [ methodName ] . apply ( instance , newArgs ) ; } ) ) ; } param { SocketIO . Server | SocketIO . Namespace } io param { SocketIO . Socket } socket param { Param [ ] } params param { any [ ] } args returns { Array } function mapArguments ( io , socket , params , args ) { /**
     * if no parameters provided, return io and socket, and event arguments
     * (which came for default handler)
     */ if ( ! params || ! params . length ) { return [ io , socket , ... args ] ; } /**
     * loop through all params and put them into correct order
     */ return params . sort ( ( p1 , p2 ) => p1 . index - p2 . index ) . map ( ( param ) => { switch ( param . type ) { case ParameterType . IO : return getWrapper ( param , io ) ; case ParameterType . Socket : return getWrapper ( param , socket ) ; case ParameterType . Args : return getArgs ( args ) ; case ParameterType . Ack : return getAck ( args ) ; } } ) ; } description param { any [ ] } args function getAck ( args ) { const ackExists = typeof args [ args . length - 1 ] === 'function' ; return ackExists ? args . pop ( ) : noop ; } param { any [ ] } args returns { * } function getArgs ( args ) { return typeof args [ args . length - 1 ] === 'function' ? args [ args . length - 2 ] : args [ args . length - 1 ] ; } param { Param } item param { object } obj returns { * } function getWrapper ( item , obj ) { return item . wrapper ? new item . wrapper ( obj ) : obj ; } /**
 * Dummy empty function, to ensure that callback exists
 */ function noop ( ) { } type IO = SocketIO . Server | SocketIO . Namespace ;