@nestjs/websockets 12.0.0-alpha.4 → 12.0.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +1 -0
- package/adapters/ws-adapter.js +4 -0
- package/context/exception-filters-context.d.ts +1 -1
- package/context/exception-filters-context.js +3 -3
- package/context/ws-context-creator.d.ts +1 -1
- package/context/ws-context-creator.js +6 -6
- package/package.json +4 -4
- package/socket-module.d.ts +1 -0
- package/socket-module.js +12 -6
- package/web-sockets-controller.d.ts +17 -5
- package/web-sockets-controller.js +154 -20
package/Readme.md
CHANGED
|
@@ -129,6 +129,7 @@ Nest is an MIT-licensed open source project. It can grow thanks to the sponsors
|
|
|
129
129
|
<tr>
|
|
130
130
|
<td align="center" valign="middle"><a href="https://solcellsforetag.se/" target="_blank"><img src="https://nestjs.com/img/logos/solcellsforetag-logo.svg" width="140" valign="middle" /></a></td>
|
|
131
131
|
<td align="center" valign="middle"><a href="https://www.route4me.com/" target="_blank"><img src="https://nestjs.com/img/logos/route4me-logo.svg" width="100" valign="middle" /></a></td>
|
|
132
|
+
<td align="center" valign="middle"><a href="https://memory2.co/" target="_blank"><img src="https://images.opencollective.com/memory-squared/bbe37f5/avatar/256.png?height=50" width="50" valign="middle" /></a></td>
|
|
132
133
|
</tr>
|
|
133
134
|
</table>
|
|
134
135
|
|
package/adapters/ws-adapter.js
CHANGED
|
@@ -22,6 +22,10 @@ export class AbstractWsAdapter {
|
|
|
22
22
|
server.on(CONNECTION_EVENT, callback);
|
|
23
23
|
}
|
|
24
24
|
bindClientDisconnect(client, callback) {
|
|
25
|
+
if (typeof client.once === 'function') {
|
|
26
|
+
client.once(DISCONNECT_EVENT, callback);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
25
29
|
client.on(DISCONNECT_EVENT, callback);
|
|
26
30
|
}
|
|
27
31
|
async close(server) {
|
|
@@ -6,6 +6,6 @@ import type { NestContainer } from '@nestjs/core';
|
|
|
6
6
|
*/
|
|
7
7
|
export declare class ExceptionFiltersContext extends BaseExceptionFilterContext {
|
|
8
8
|
constructor(container: NestContainer);
|
|
9
|
-
create(instance: object, callback: <TClient>(client: TClient, data: any) => any, moduleKey: string): WsExceptionsHandler;
|
|
9
|
+
create(instance: object, callback: <TClient>(client: TClient, data: any) => any, moduleKey: string, contextId?: import("@nestjs/core").ContextId, inquirerId?: string): WsExceptionsHandler;
|
|
10
10
|
getGlobalMetadata<T extends any[]>(): T;
|
|
11
11
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WsExceptionsHandler } from '../exceptions/ws-exceptions-handler.js';
|
|
2
2
|
import { EXCEPTION_FILTERS_METADATA, isEmptyArray, } from '@nestjs/common/internal';
|
|
3
|
-
import { BaseExceptionFilterContext } from '@nestjs/core/internal';
|
|
3
|
+
import { BaseExceptionFilterContext, STATIC_CONTEXT, } from '@nestjs/core/internal';
|
|
4
4
|
/**
|
|
5
5
|
* @publicApi
|
|
6
6
|
*/
|
|
@@ -8,10 +8,10 @@ export class ExceptionFiltersContext extends BaseExceptionFilterContext {
|
|
|
8
8
|
constructor(container) {
|
|
9
9
|
super(container);
|
|
10
10
|
}
|
|
11
|
-
create(instance, callback, moduleKey) {
|
|
11
|
+
create(instance, callback, moduleKey, contextId = STATIC_CONTEXT, inquirerId) {
|
|
12
12
|
this.moduleContext = moduleKey;
|
|
13
13
|
const exceptionHandler = new WsExceptionsHandler();
|
|
14
|
-
const filters = this.createContext(instance, callback, EXCEPTION_FILTERS_METADATA);
|
|
14
|
+
const filters = this.createContext(instance, callback, EXCEPTION_FILTERS_METADATA, contextId, inquirerId);
|
|
15
15
|
if (isEmptyArray(filters)) {
|
|
16
16
|
return exceptionHandler;
|
|
17
17
|
}
|
|
@@ -25,7 +25,7 @@ export declare class WsContextCreator {
|
|
|
25
25
|
private readonly wsParamsFactory;
|
|
26
26
|
private readonly handlerMetadataStorage;
|
|
27
27
|
constructor(wsProxy: WsProxy, exceptionFiltersContext: ExceptionFiltersContext, pipesContextCreator: PipesContextCreator, pipesConsumer: PipesConsumer, guardsContextCreator: GuardsContextCreator, guardsConsumer: GuardsConsumer, interceptorsContextCreator: InterceptorsContextCreator, interceptorsConsumer: InterceptorsConsumer);
|
|
28
|
-
create<T extends ParamsMetadata = ParamsMetadata>(instance: Controller, callback: (...args: unknown[]) => void, moduleKey: string, methodName: string): (...args: any[]) => Promise<void>;
|
|
28
|
+
create<T extends ParamsMetadata = ParamsMetadata>(instance: Controller, callback: (...args: unknown[]) => void, moduleKey: string, methodName: string, contextId?: import("@nestjs/core").ContextId, inquirerId?: string): (...args: any[]) => Promise<void>;
|
|
29
29
|
reflectCallbackParamtypes(instance: Controller, callback: (...args: any[]) => any): any[];
|
|
30
30
|
reflectCallbackPattern(callback: (...args: any[]) => any): string;
|
|
31
31
|
createGuardsFn<TContext extends string = ContextType>(guards: any[], instance: Controller, callback: (...args: unknown[]) => any, contextType?: TContext): Function | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CUSTOM_ROUTE_ARGS_METADATA, isEmptyArray, PARAMTYPES_METADATA, } from '@nestjs/common/internal';
|
|
2
|
-
import { ContextUtils, FORBIDDEN_MESSAGE, HandlerMetadataStorage, } from '@nestjs/core/internal';
|
|
2
|
+
import { ContextUtils, FORBIDDEN_MESSAGE, HandlerMetadataStorage, STATIC_CONTEXT, } from '@nestjs/core/internal';
|
|
3
3
|
import { MESSAGE_METADATA, PARAM_ARGS_METADATA } from '../constants.js';
|
|
4
4
|
import { WsException } from '../errors/ws-exception.js';
|
|
5
5
|
import { WsParamsFactory } from '../factories/ws-params-factory.js';
|
|
@@ -26,13 +26,13 @@ export class WsContextCreator {
|
|
|
26
26
|
this.interceptorsContextCreator = interceptorsContextCreator;
|
|
27
27
|
this.interceptorsConsumer = interceptorsConsumer;
|
|
28
28
|
}
|
|
29
|
-
create(instance, callback, moduleKey, methodName) {
|
|
29
|
+
create(instance, callback, moduleKey, methodName, contextId = STATIC_CONTEXT, inquirerId) {
|
|
30
30
|
const contextType = 'ws';
|
|
31
31
|
const { argsLength, paramtypes, getParamsMetadata } = this.getMetadata(instance, methodName, contextType);
|
|
32
|
-
const exceptionHandler = this.exceptionFiltersContext.create(instance, callback, moduleKey);
|
|
33
|
-
const pipes = this.pipesContextCreator.create(instance, callback, moduleKey);
|
|
34
|
-
const guards = this.guardsContextCreator.create(instance, callback, moduleKey);
|
|
35
|
-
const interceptors = this.interceptorsContextCreator.create(instance, callback, moduleKey);
|
|
32
|
+
const exceptionHandler = this.exceptionFiltersContext.create(instance, callback, moduleKey, contextId, inquirerId);
|
|
33
|
+
const pipes = this.pipesContextCreator.create(instance, callback, moduleKey, contextId, inquirerId);
|
|
34
|
+
const guards = this.guardsContextCreator.create(instance, callback, moduleKey, contextId, inquirerId);
|
|
35
|
+
const interceptors = this.interceptorsContextCreator.create(instance, callback, moduleKey, contextId, inquirerId);
|
|
36
36
|
const paramsMetadata = getParamsMetadata(moduleKey);
|
|
37
37
|
const paramsOptions = paramsMetadata
|
|
38
38
|
? this.contextUtils.mergeParamsMetatypes(paramsMetadata, paramtypes)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestjs/websockets",
|
|
3
|
-
"version": "12.0.0-alpha.
|
|
3
|
+
"version": "12.0.0-alpha.5",
|
|
4
4
|
"description": "Nest - modern, fast, powerful node.js web framework (@websockets)",
|
|
5
5
|
"author": "Kamil Mysliwiec",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"tslib": "2.8.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@nestjs/common": "^12.0.0-alpha.
|
|
30
|
-
"@nestjs/core": "^12.0.0-alpha.
|
|
29
|
+
"@nestjs/common": "^12.0.0-alpha.5",
|
|
30
|
+
"@nestjs/core": "^12.0.0-alpha.5"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@nestjs/common": "^11.0.0",
|
|
@@ -41,5 +41,5 @@
|
|
|
41
41
|
"optional": true
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "d91b72cc9567e6a09e3ad6075b2fb801e71adfc8"
|
|
45
45
|
}
|
package/socket-module.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export declare class SocketModule<THttpServer = any, TAppOptions extends NestApp
|
|
|
9
9
|
private isAdapterInitialized;
|
|
10
10
|
private httpServer;
|
|
11
11
|
private appOptions;
|
|
12
|
+
private injector;
|
|
12
13
|
register(container: NestContainer, applicationConfig: ApplicationConfig, graphInspector: GraphInspector, appOptions: TAppOptions, httpServer?: THttpServer): void;
|
|
13
14
|
connectAllGateways(providers: Map<InjectionToken, InstanceWrapper<Injectable>>, moduleName: string): void;
|
|
14
15
|
connectGatewayToServer(wrapper: InstanceWrapper<Injectable>, moduleName: string): Promise<void>;
|
package/socket-module.js
CHANGED
|
@@ -6,7 +6,7 @@ import { WsProxy } from './context/ws-proxy.js';
|
|
|
6
6
|
import { SocketServerProvider } from './socket-server-provider.js';
|
|
7
7
|
import { SocketsContainer } from './sockets-container.js';
|
|
8
8
|
import { WebSocketsController } from './web-sockets-controller.js';
|
|
9
|
-
import { GuardsConsumer, GuardsContextCreator, loadAdapter, InterceptorsConsumer, InterceptorsContextCreator, PipesConsumer, PipesContextCreator, } from '@nestjs/core/internal';
|
|
9
|
+
import { Injector, GuardsConsumer, GuardsContextCreator, loadAdapter, InterceptorsConsumer, InterceptorsContextCreator, PipesConsumer, PipesContextCreator, } from '@nestjs/core/internal';
|
|
10
10
|
export class SocketModule {
|
|
11
11
|
socketsContainer = new SocketsContainer();
|
|
12
12
|
applicationConfig;
|
|
@@ -14,13 +14,19 @@ export class SocketModule {
|
|
|
14
14
|
isAdapterInitialized;
|
|
15
15
|
httpServer;
|
|
16
16
|
appOptions;
|
|
17
|
+
injector;
|
|
17
18
|
register(container, applicationConfig, graphInspector, appOptions, httpServer) {
|
|
18
19
|
this.applicationConfig = applicationConfig;
|
|
19
20
|
this.appOptions = appOptions;
|
|
20
21
|
this.httpServer = httpServer;
|
|
21
|
-
|
|
22
|
+
this.injector = new Injector({
|
|
23
|
+
preview: container.contextOptions?.preview,
|
|
24
|
+
instanceDecorator: container.contextOptions?.instrument?.instanceDecorator,
|
|
25
|
+
});
|
|
26
|
+
const exceptionFiltersContext = new ExceptionFiltersContext(container);
|
|
27
|
+
const contextCreator = this.getContextCreator(container, applicationConfig, exceptionFiltersContext);
|
|
22
28
|
const serverProvider = new SocketServerProvider(this.socketsContainer, applicationConfig);
|
|
23
|
-
this.webSocketsController = new WebSocketsController(serverProvider, applicationConfig, contextCreator, graphInspector, this.appOptions);
|
|
29
|
+
this.webSocketsController = new WebSocketsController(serverProvider, applicationConfig, contextCreator, container, this.injector, exceptionFiltersContext, graphInspector, this.appOptions);
|
|
24
30
|
const modules = container.getModules();
|
|
25
31
|
modules.forEach(({ providers }, moduleName) => this.connectAllGateways(providers, moduleName));
|
|
26
32
|
}
|
|
@@ -38,7 +44,7 @@ export class SocketModule {
|
|
|
38
44
|
if (!this.isAdapterInitialized) {
|
|
39
45
|
await this.initializeAdapter();
|
|
40
46
|
}
|
|
41
|
-
this.webSocketsController.connectGatewayToServer(
|
|
47
|
+
this.webSocketsController.connectGatewayToServer(wrapper, moduleName);
|
|
42
48
|
}
|
|
43
49
|
async close() {
|
|
44
50
|
if (!this.applicationConfig) {
|
|
@@ -71,7 +77,7 @@ export class SocketModule {
|
|
|
71
77
|
this.applicationConfig.setIoAdapter(ioAdapter);
|
|
72
78
|
this.isAdapterInitialized = true;
|
|
73
79
|
}
|
|
74
|
-
getContextCreator(container) {
|
|
75
|
-
return new WsContextCreator(new WsProxy(),
|
|
80
|
+
getContextCreator(container, config, exceptionFiltersContext) {
|
|
81
|
+
return new WsContextCreator(new WsProxy(), exceptionFiltersContext, new PipesContextCreator(container, config), new PipesConsumer(), new GuardsContextCreator(container, config), new GuardsConsumer(), new InterceptorsContextCreator(container, config), new InterceptorsConsumer());
|
|
76
82
|
}
|
|
77
83
|
}
|
|
@@ -7,26 +7,38 @@ import { ServerAndEventStreamsHost } from './interfaces/server-and-event-streams
|
|
|
7
7
|
import { SocketServerProvider } from './socket-server-provider.js';
|
|
8
8
|
import type { NestApplicationContextOptions } from '@nestjs/common/internal';
|
|
9
9
|
import { type Type } from '@nestjs/common';
|
|
10
|
-
import { type ApplicationConfig, type GraphInspector } from '@nestjs/core';
|
|
10
|
+
import { type ApplicationConfig, type ContextId, type GraphInspector, type NestContainer } from '@nestjs/core';
|
|
11
|
+
import { type Injector, type InstanceWrapper, type Module } from '@nestjs/core/internal';
|
|
12
|
+
import { ExceptionFiltersContext } from './context/exception-filters-context.js';
|
|
11
13
|
export declare class WebSocketsController {
|
|
12
14
|
private readonly socketServerProvider;
|
|
13
15
|
private readonly config;
|
|
14
16
|
private readonly contextCreator;
|
|
17
|
+
private readonly container;
|
|
18
|
+
private readonly injector;
|
|
19
|
+
private readonly exceptionFiltersContext;
|
|
15
20
|
private readonly graphInspector;
|
|
16
21
|
private readonly appOptions;
|
|
17
22
|
private readonly logger;
|
|
18
23
|
private readonly metadataExplorer;
|
|
19
|
-
|
|
24
|
+
private readonly exceptionFiltersCache;
|
|
25
|
+
constructor(socketServerProvider: SocketServerProvider, config: ApplicationConfig, contextCreator: WsContextCreator, container: NestContainer, injector: Injector, exceptionFiltersContext: ExceptionFiltersContext, graphInspector: GraphInspector, appOptions?: NestApplicationContextOptions);
|
|
26
|
+
connectGatewayToServer(instanceWrapper: InstanceWrapper<NestGateway>, moduleKey: string): void;
|
|
20
27
|
connectGatewayToServer(instance: NestGateway, metatype: Type<unknown> | Function, moduleKey: string, instanceWrapperId: string): void;
|
|
28
|
+
subscribeToServerEvents<T extends GatewayMetadata>(instanceWrapper: InstanceWrapper<NestGateway>, options: T, port: number, moduleKey: string, instanceWrapperId: string): void;
|
|
21
29
|
subscribeToServerEvents<T extends GatewayMetadata>(instance: NestGateway, options: T, port: number, moduleKey: string, instanceWrapperId: string): void;
|
|
22
|
-
subscribeEvents(
|
|
30
|
+
subscribeEvents(instanceWrapper: InstanceWrapper<NestGateway>, subscribersMap: MessageMappingProperties[], observableServer: ServerAndEventStreamsHost, connectionHandler?: Function, disconnectHandler?: Function): void;
|
|
23
31
|
getConnectionHandler(context: WebSocketsController, instance: NestGateway, subscribersMap: MessageMappingProperties[], disconnect: Subject<any>, connection: Subject<any>): (...args: unknown[]) => void;
|
|
24
32
|
subscribeInitEvent(instance: NestGateway, event: Subject<any>): void;
|
|
25
|
-
subscribeConnectionEvent(
|
|
26
|
-
subscribeDisconnectEvent(
|
|
33
|
+
subscribeConnectionEvent(handlerOrGateway: Function | NestGateway | undefined, event: Subject<any>): void;
|
|
34
|
+
subscribeDisconnectEvent(handlerOrGateway: Function | NestGateway | undefined, event: Subject<any>): void;
|
|
27
35
|
subscribeMessages<T = any>(subscribersMap: MessageMappingProperties[], client: T, instance: NestGateway): void;
|
|
28
36
|
pickResult(deferredResult: Promise<any>): Promise<Observable<any>>;
|
|
29
37
|
inspectEntrypointDefinitions(instance: NestGateway, port: number, messageHandlers: MessageMappingProperties[], instanceWrapperId: string): void;
|
|
38
|
+
createRequestScopedHandler(instanceWrapper: InstanceWrapper<NestGateway>, moduleRef: Module, moduleKey: string, methodName: string): (...args: unknown[]) => Promise<void>;
|
|
39
|
+
createRequestScopedEventHandler(instanceWrapper: InstanceWrapper<NestGateway>, moduleRef: Module, moduleKey: string, methodName: 'handleConnection' | 'handleDisconnect', server: object): (...args: unknown[]) => Promise<unknown>;
|
|
40
|
+
getContextId<T extends Record<any, unknown> = any>(request: T, isTreeDurable: boolean): ContextId;
|
|
41
|
+
private cleanupRequestScopedContext;
|
|
30
42
|
private assignServerToProperties;
|
|
31
43
|
private printSubscriptionLogs;
|
|
32
44
|
}
|
|
@@ -5,38 +5,84 @@ import { InvalidSocketPortException } from './errors/invalid-socket-port.excepti
|
|
|
5
5
|
import { GatewayMetadataExplorer, } from './gateway-metadata-explorer.js';
|
|
6
6
|
import { compareElementAt } from './utils/compare-element.util.js';
|
|
7
7
|
import { Logger } from '@nestjs/common';
|
|
8
|
-
import { MetadataScanner, } from '@nestjs/core';
|
|
8
|
+
import { ContextIdFactory, MetadataScanner, } from '@nestjs/core';
|
|
9
|
+
import { ExecutionContextHost, REQUEST_CONTEXT_ID, STATIC_CONTEXT, } from '@nestjs/core/internal';
|
|
9
10
|
export class WebSocketsController {
|
|
10
11
|
socketServerProvider;
|
|
11
12
|
config;
|
|
12
13
|
contextCreator;
|
|
14
|
+
container;
|
|
15
|
+
injector;
|
|
16
|
+
exceptionFiltersContext;
|
|
13
17
|
graphInspector;
|
|
14
18
|
appOptions;
|
|
15
19
|
logger = new Logger(WebSocketsController.name, {
|
|
16
20
|
timestamp: true,
|
|
17
21
|
});
|
|
18
22
|
metadataExplorer = new GatewayMetadataExplorer(new MetadataScanner());
|
|
19
|
-
|
|
23
|
+
exceptionFiltersCache = new WeakMap();
|
|
24
|
+
constructor(socketServerProvider, config, contextCreator, container, injector, exceptionFiltersContext, graphInspector, appOptions = {}) {
|
|
20
25
|
this.socketServerProvider = socketServerProvider;
|
|
21
26
|
this.config = config;
|
|
22
27
|
this.contextCreator = contextCreator;
|
|
28
|
+
this.container = container;
|
|
29
|
+
this.injector = injector;
|
|
30
|
+
this.exceptionFiltersContext = exceptionFiltersContext;
|
|
23
31
|
this.graphInspector = graphInspector;
|
|
24
32
|
this.appOptions = appOptions;
|
|
25
33
|
}
|
|
26
|
-
connectGatewayToServer(
|
|
27
|
-
const
|
|
28
|
-
|
|
34
|
+
connectGatewayToServer(instanceOrWrapper, metatypeOrModuleKey, moduleKey, instanceWrapperId) {
|
|
35
|
+
const isInstanceWrapper = typeof metatypeOrModuleKey === 'string' &&
|
|
36
|
+
'instance' in instanceOrWrapper;
|
|
37
|
+
const instance = isInstanceWrapper
|
|
38
|
+
? instanceOrWrapper.instance
|
|
39
|
+
: instanceOrWrapper;
|
|
40
|
+
const metatype = isInstanceWrapper
|
|
41
|
+
? instanceOrWrapper.metatype
|
|
42
|
+
: metatypeOrModuleKey;
|
|
43
|
+
const targetModuleKey = isInstanceWrapper
|
|
44
|
+
? metatypeOrModuleKey
|
|
45
|
+
: moduleKey;
|
|
46
|
+
const targetInstanceWrapperId = isInstanceWrapper
|
|
47
|
+
? instanceOrWrapper.id
|
|
48
|
+
: instanceWrapperId;
|
|
49
|
+
const instanceWrapper = isInstanceWrapper
|
|
50
|
+
? instanceOrWrapper
|
|
51
|
+
: {
|
|
52
|
+
instance,
|
|
53
|
+
metatype,
|
|
54
|
+
id: targetInstanceWrapperId,
|
|
55
|
+
isDependencyTreeStatic: () => true,
|
|
56
|
+
isDependencyTreeDurable: () => false,
|
|
57
|
+
};
|
|
58
|
+
const gatewayMetatype = metatype ?? instance.constructor;
|
|
59
|
+
const options = Reflect.getMetadata(GATEWAY_OPTIONS, gatewayMetatype) || {};
|
|
60
|
+
const port = Reflect.getMetadata(PORT_METADATA, gatewayMetatype) || 0;
|
|
29
61
|
if (!Number.isInteger(port)) {
|
|
30
|
-
throw new InvalidSocketPortException(port,
|
|
62
|
+
throw new InvalidSocketPortException(port, gatewayMetatype);
|
|
31
63
|
}
|
|
32
|
-
this.subscribeToServerEvents(
|
|
64
|
+
this.subscribeToServerEvents(instanceWrapper, options, port, targetModuleKey, targetInstanceWrapperId);
|
|
33
65
|
}
|
|
34
|
-
subscribeToServerEvents(
|
|
66
|
+
subscribeToServerEvents(instanceOrWrapper, options, port, moduleKey, instanceWrapperId) {
|
|
67
|
+
const instanceWrapper = 'instance' in instanceOrWrapper
|
|
68
|
+
? instanceOrWrapper
|
|
69
|
+
: {
|
|
70
|
+
instance: instanceOrWrapper,
|
|
71
|
+
metatype: instanceOrWrapper.constructor,
|
|
72
|
+
id: instanceWrapperId,
|
|
73
|
+
isDependencyTreeStatic: () => true,
|
|
74
|
+
isDependencyTreeDurable: () => false,
|
|
75
|
+
};
|
|
76
|
+
const { instance } = instanceWrapper;
|
|
35
77
|
const nativeMessageHandlers = this.metadataExplorer.explore(instance);
|
|
78
|
+
const isStatic = instanceWrapper.isDependencyTreeStatic();
|
|
79
|
+
const moduleRef = this.container.getModuleByKey(moduleKey);
|
|
36
80
|
const messageHandlers = nativeMessageHandlers.map(({ callback, isAckHandledManually, message, methodName }) => ({
|
|
37
81
|
message,
|
|
38
82
|
methodName,
|
|
39
|
-
callback:
|
|
83
|
+
callback: isStatic
|
|
84
|
+
? this.contextCreator.create(instance, callback, moduleKey, methodName, STATIC_CONTEXT)
|
|
85
|
+
: this.createRequestScopedHandler(instanceWrapper, moduleRef, moduleKey, methodName),
|
|
40
86
|
isAckHandledManually,
|
|
41
87
|
}));
|
|
42
88
|
this.inspectEntrypointDefinitions(instance, port, messageHandlers, instanceWrapperId);
|
|
@@ -45,14 +91,19 @@ export class WebSocketsController {
|
|
|
45
91
|
}
|
|
46
92
|
const observableServer = this.socketServerProvider.scanForSocketServer(options, port);
|
|
47
93
|
this.assignServerToProperties(instance, observableServer.server);
|
|
48
|
-
this.subscribeEvents(
|
|
94
|
+
this.subscribeEvents(instanceWrapper, messageHandlers, observableServer, isStatic
|
|
95
|
+
? instance.handleConnection?.bind(instance)
|
|
96
|
+
: this.createRequestScopedEventHandler(instanceWrapper, moduleRef, moduleKey, 'handleConnection', observableServer.server), isStatic
|
|
97
|
+
? instance.handleDisconnect?.bind(instance)
|
|
98
|
+
: this.createRequestScopedEventHandler(instanceWrapper, moduleRef, moduleKey, 'handleDisconnect', observableServer.server));
|
|
49
99
|
}
|
|
50
|
-
subscribeEvents(
|
|
100
|
+
subscribeEvents(instanceWrapper, subscribersMap, observableServer, connectionHandler, disconnectHandler) {
|
|
101
|
+
const { instance } = instanceWrapper;
|
|
51
102
|
const { init, disconnect, connection, server } = observableServer;
|
|
52
103
|
const adapter = this.config.getIoAdapter();
|
|
53
104
|
this.subscribeInitEvent(instance, init);
|
|
54
|
-
this.subscribeConnectionEvent(
|
|
55
|
-
this.subscribeDisconnectEvent(
|
|
105
|
+
this.subscribeConnectionEvent(connectionHandler, connection);
|
|
106
|
+
this.subscribeDisconnectEvent(disconnectHandler, disconnect);
|
|
56
107
|
const handler = this.getConnectionHandler(this, instance, subscribersMap, disconnect, connection);
|
|
57
108
|
adapter.bindClientConnect(server, handler);
|
|
58
109
|
this.printSubscriptionLogs(instance, subscribersMap);
|
|
@@ -73,15 +124,21 @@ export class WebSocketsController {
|
|
|
73
124
|
event.subscribe(instance.afterInit.bind(instance));
|
|
74
125
|
}
|
|
75
126
|
}
|
|
76
|
-
subscribeConnectionEvent(
|
|
77
|
-
|
|
127
|
+
subscribeConnectionEvent(handlerOrGateway, event) {
|
|
128
|
+
const handler = typeof handlerOrGateway === 'function'
|
|
129
|
+
? handlerOrGateway
|
|
130
|
+
: handlerOrGateway?.handleConnection?.bind(handlerOrGateway);
|
|
131
|
+
if (handler) {
|
|
78
132
|
event
|
|
79
133
|
.pipe(distinctUntilChanged((prev, curr) => compareElementAt(prev, curr, 0)))
|
|
80
|
-
.subscribe((args) =>
|
|
134
|
+
.subscribe((args) => handler(...args));
|
|
81
135
|
}
|
|
82
136
|
}
|
|
83
|
-
subscribeDisconnectEvent(
|
|
84
|
-
|
|
137
|
+
subscribeDisconnectEvent(handlerOrGateway, event) {
|
|
138
|
+
const handler = typeof handlerOrGateway === 'function'
|
|
139
|
+
? handlerOrGateway
|
|
140
|
+
: handlerOrGateway?.handleDisconnect?.bind(handlerOrGateway);
|
|
141
|
+
if (handler) {
|
|
85
142
|
event
|
|
86
143
|
.pipe(distinctUntilChanged((prev, curr) => {
|
|
87
144
|
const prevClient = prev?.client || prev;
|
|
@@ -90,11 +147,11 @@ export class WebSocketsController {
|
|
|
90
147
|
}))
|
|
91
148
|
.subscribe((data) => {
|
|
92
149
|
if (data && typeof data === 'object' && 'client' in data) {
|
|
93
|
-
|
|
150
|
+
handler(data.client, data.reason);
|
|
94
151
|
}
|
|
95
152
|
else {
|
|
96
153
|
// Backward compatibility: if it's just the client
|
|
97
|
-
|
|
154
|
+
handler(data);
|
|
98
155
|
}
|
|
99
156
|
});
|
|
100
157
|
}
|
|
@@ -133,6 +190,83 @@ export class WebSocketsController {
|
|
|
133
190
|
}, instanceWrapperId);
|
|
134
191
|
});
|
|
135
192
|
}
|
|
193
|
+
createRequestScopedHandler(instanceWrapper, moduleRef, moduleKey, methodName) {
|
|
194
|
+
const { instance } = instanceWrapper;
|
|
195
|
+
const collection = moduleRef.providers;
|
|
196
|
+
const isTreeDurable = instanceWrapper.isDependencyTreeDurable();
|
|
197
|
+
return async (...args) => {
|
|
198
|
+
const [client] = args;
|
|
199
|
+
try {
|
|
200
|
+
const contextId = this.getContextId(client, isTreeDurable);
|
|
201
|
+
const contextInstance = await this.injector.loadPerContext(instance, moduleRef, collection, contextId);
|
|
202
|
+
return this.contextCreator.create(contextInstance, contextInstance[methodName], moduleKey, methodName, contextId, instanceWrapper.id)(...args);
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
let exceptionFilter = this.exceptionFiltersCache.get(instance[methodName]);
|
|
206
|
+
if (!exceptionFilter) {
|
|
207
|
+
exceptionFilter = this.exceptionFiltersContext.create(instance, instance[methodName], moduleKey);
|
|
208
|
+
this.exceptionFiltersCache.set(instance[methodName], exceptionFilter);
|
|
209
|
+
}
|
|
210
|
+
const host = new ExecutionContextHost(args);
|
|
211
|
+
host.setType('ws');
|
|
212
|
+
exceptionFilter.handle(err, host);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
createRequestScopedEventHandler(instanceWrapper, moduleRef, moduleKey, methodName, server) {
|
|
217
|
+
const { instance } = instanceWrapper;
|
|
218
|
+
const collection = moduleRef.providers;
|
|
219
|
+
const isTreeDurable = instanceWrapper.isDependencyTreeDurable();
|
|
220
|
+
const targetCallback = instance[methodName];
|
|
221
|
+
return async (...args) => {
|
|
222
|
+
const [client] = args;
|
|
223
|
+
let contextId;
|
|
224
|
+
try {
|
|
225
|
+
contextId = this.getContextId(client, isTreeDurable);
|
|
226
|
+
const contextInstance = await this.injector.loadPerContext(instance, moduleRef, collection, contextId);
|
|
227
|
+
this.assignServerToProperties(contextInstance, server);
|
|
228
|
+
const scopedMethod = contextInstance[methodName];
|
|
229
|
+
return scopedMethod?.apply(contextInstance, args);
|
|
230
|
+
}
|
|
231
|
+
catch (err) {
|
|
232
|
+
if (!targetCallback) {
|
|
233
|
+
throw err;
|
|
234
|
+
}
|
|
235
|
+
let exceptionFilter = this.exceptionFiltersCache.get(targetCallback);
|
|
236
|
+
if (!exceptionFilter) {
|
|
237
|
+
exceptionFilter = this.exceptionFiltersContext.create(instance, targetCallback, moduleKey);
|
|
238
|
+
this.exceptionFiltersCache.set(targetCallback, exceptionFilter);
|
|
239
|
+
}
|
|
240
|
+
const host = new ExecutionContextHost(args);
|
|
241
|
+
host.setType('ws');
|
|
242
|
+
exceptionFilter.handle(err, host);
|
|
243
|
+
}
|
|
244
|
+
finally {
|
|
245
|
+
if (methodName === 'handleDisconnect' && contextId) {
|
|
246
|
+
this.cleanupRequestScopedContext(instanceWrapper, contextId, client);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
getContextId(request, isTreeDurable) {
|
|
252
|
+
const contextId = ContextIdFactory.getByRequest(request);
|
|
253
|
+
if (!request[REQUEST_CONTEXT_ID]) {
|
|
254
|
+
Object.defineProperty(request, REQUEST_CONTEXT_ID, {
|
|
255
|
+
value: contextId,
|
|
256
|
+
enumerable: false,
|
|
257
|
+
writable: false,
|
|
258
|
+
configurable: true,
|
|
259
|
+
});
|
|
260
|
+
const requestProviderValue = isTreeDurable
|
|
261
|
+
? contextId.payload
|
|
262
|
+
: Object.assign(request, contextId.payload);
|
|
263
|
+
this.container.registerRequestProvider(requestProviderValue, contextId);
|
|
264
|
+
}
|
|
265
|
+
return contextId;
|
|
266
|
+
}
|
|
267
|
+
cleanupRequestScopedContext(_instanceWrapper, _contextId, request) {
|
|
268
|
+
Reflect.deleteProperty(request, REQUEST_CONTEXT_ID);
|
|
269
|
+
}
|
|
136
270
|
assignServerToProperties(instance, server) {
|
|
137
271
|
for (const propertyKey of this.metadataExplorer.scanForServerHooks(instance)) {
|
|
138
272
|
Reflect.set(instance, propertyKey, server);
|