import "reflect-metadata"; import * as io from 'socket.io' import { Container } from 'inversify' import { TYPE } from './constants' import { interfaces, BroadcastMessage } from './interfaces' import { getNamespaces, getNamespaceMetadata, getNamespaceListenerMetadata } from './utils' export function buildWebSocket(container: Container, server: io.Server) { let constructors = getNamespaces(); if (!constructors.length) { return; } registryNamespace(container, constructors); // get all namespaces let namespaces = container.getAll(TYPE.Namespace) for (const namespace of namespaces) { let namespaceMetadata = getNamespaceMetadata(namespace); let namespaceEventMetadata = getNamespaceListenerMetadata(namespace); let ns = server.of(namespaceMetadata.name); namespace.constructor.prototype.nsp = ns; applyNamespaceMiddleware(namespaceMetadata, ns); ns.on('connection', async (socket: io.Socket) => { let namespaceInstance = container.getNamed(TYPE.Namespace, namespace.constructor.name); await applyEvent(namespaceInstance, socket); await applyMiddlewares(namespaceEventMetadata, socket); await applyListeners(namespaceEventMetadata, socket, namespaceInstance); }) } } function registryNamespace(container: Container, constructors: any[]) { constructors.forEach((constructor) => { const name = constructor.name; if (container.isBoundNamed(TYPE.Namespace, name)) { throw new Error(`DUPLICATED_NAMESPACE(${name})`); } container.bind(TYPE.Namespace) .to(constructor) .whenTargetNamed(name); }); } function applyNamespaceMiddleware(namespaceMetadata: interfaces.NamespaceMetadata, ns: io.Namespace) { for (const middleware of namespaceMetadata.middleware) { ns.use(middleware); } } function flatten(arr: Array) { while (arr.some(item => Array.isArray(item))) { arr = [].concat(...arr); } return arr; } function applyMiddlewares(namespaceEventMetadata: interfaces.ListenerMetadata[], socket: io.Socket) { let middlewares = [...new Set(flatten(namespaceEventMetadata.map((data) => data.middleware)))]; for (const middleware of middlewares) { socket.use((packet: io.Packet, next: (err?: any) => void) => { middleware(socket, packet, next); }); } } async function applyEvent(namespaceInstance: interfaces.Namespace, socket: io.Socket) { if (namespaceInstance.connection) { let result = await namespaceInstance.connection(socket); if (result != undefined) { socket.send(result); } } if (namespaceInstance.disconnect) { socket.on('disconnect', async () => await namespaceInstance.disconnect(socket)); } } function applyListeners(namespaceEventMetadata: interfaces.ListenerMetadata[], socket: io.Socket, namespaceInstance: interfaces.Namespace) { for (const event of namespaceEventMetadata) { socket.on(event.name, async data => { let result = await namespaceInstance[event.key](socket, data); if (result != undefined) { if (result instanceof BroadcastMessage) { socket.broadcast.emit(event.name, result.message); } else { socket.emit(event.name, result); } } }); } }