UNPKG

@nestjs/websockets

Version:

Nest - modern, fast, powerful node.js web framework (@websockets)

91 lines (90 loc) 4.55 kB
import { iterate } from 'iterare'; import { GATEWAY_METADATA } from './constants.js'; import { ExceptionFiltersContext } from './context/exception-filters-context.js'; import { WsContextCreator } from './context/ws-context-creator.js'; import { WsProxy } from './context/ws-proxy.js'; import { SocketServerProvider } from './socket-server-provider.js'; import { SocketsContainer } from './sockets-container.js'; import { WebSocketsController } from './web-sockets-controller.js'; import { Injector, GuardsConsumer, GuardsContextCreator, loadAdapter, InterceptorsConsumer, InterceptorsContextCreator, PipesConsumer, PipesContextCreator, } from '@nestjs/core/internal'; export class SocketModule { socketsContainer = new SocketsContainer(); applicationConfig; webSocketsController; isAdapterInitialized; adapterInitPromise = null; httpServer; appOptions; injector; register(container, applicationConfig, graphInspector, appOptions, httpServer) { this.applicationConfig = applicationConfig; this.appOptions = appOptions; this.httpServer = httpServer; this.injector = new Injector({ preview: container.contextOptions?.preview, instanceDecorator: container.contextOptions?.instrument?.instanceDecorator, }); const exceptionFiltersContext = new ExceptionFiltersContext(container); const contextCreator = this.getContextCreator(container, applicationConfig, exceptionFiltersContext); const serverProvider = new SocketServerProvider(this.socketsContainer, applicationConfig); this.webSocketsController = new WebSocketsController(serverProvider, applicationConfig, contextCreator, container, this.injector, exceptionFiltersContext, graphInspector, this.appOptions); const modules = container.getModules(); return Promise.all(iterate(modules.entries()) .map(([moduleName, { providers }]) => this.connectAllGateways(providers, moduleName)) .toArray()); } connectAllGateways(providers, moduleName) { return Promise.all(iterate(providers.values()) .filter(wrapper => wrapper && !wrapper.isNotMetatype) .map(wrapper => this.connectGatewayToServer(wrapper, moduleName)) .toArray()); } async connectGatewayToServer(wrapper, moduleName) { const { instance, metatype } = wrapper; const metadataKeys = Reflect.getMetadataKeys(metatype); if (!metadataKeys.includes(GATEWAY_METADATA)) { return; } if (!this.isAdapterInitialized) { // Memoize the initialization promise so concurrent gateway connections // share a single adapter instead of racing to create their own. this.adapterInitPromise ??= this.initializeAdapter(); await this.adapterInitPromise; } this.webSocketsController.connectGatewayToServer(wrapper, moduleName); } async close() { if (!this.applicationConfig) { return; } const adapter = this.applicationConfig.getIoAdapter(); if (!adapter) { return; } const servers = this.socketsContainer.getAll(); await Promise.all(iterate(servers.values()) .filter(({ server }) => server) .map(async ({ server }) => adapter.close(server))); await adapter?.dispose(); this.socketsContainer.clear(); } async initializeAdapter() { const forceCloseConnections = this.appOptions .forceCloseConnections; const adapter = this.applicationConfig.getIoAdapter(); if (adapter) { adapter.forceCloseConnections = forceCloseConnections; this.isAdapterInitialized = true; return; } const { IoAdapter } = await loadAdapter('@nestjs/platform-socket.io', 'WebSockets', () => import('@nestjs/platform-socket.io')); const ioAdapter = new IoAdapter(this.httpServer); ioAdapter.forceCloseConnections = forceCloseConnections; this.applicationConfig.setIoAdapter(ioAdapter); this.isAdapterInitialized = true; } getContextCreator(container, config, exceptionFiltersContext) { return new WsContextCreator(new WsProxy(), exceptionFiltersContext, new PipesContextCreator(container, config), new PipesConsumer(), new GuardsContextCreator(container, config), new GuardsConsumer(), new InterceptorsContextCreator(container, config), new InterceptorsConsumer()); } }