Skip to content

Commit 80474e7

Browse files
authored
merge: release v0.1.2 (#551)
2 parents 795ef99 + 4c2553d commit 80474e7

16 files changed

+347
-55
lines changed

CHANGELOG.md

+18
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,24 @@
22

33
_This changelog follows the [keep a changelog][keep-a-changelog]_ format to maintain a human readable changelog.
44

5+
## [0.1.2](https://github.com/typestack/socket-controllers/compare/v0.1.1...v0.1.2) (2023-01-30)
6+
7+
### Added
8+
9+
- Added scoped controller support
10+
11+
```typescript
12+
// create and run socket server
13+
const server = new SocketControllers({
14+
...
15+
scopedContainerGetter: (args: ScopedContainerGetterParams) => {
16+
// Return a container instance to be used to instantiate
17+
// the controllers and their dependencies on each event
18+
}
19+
});
20+
```
21+
22+
523
## [0.1.1](https://github.com/typestack/socket-controllers/compare/v0.1.0...v0.1.1) (2023-01-27)
624

725
### Added

README.md

+29
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,35 @@ export class MessageController {
462462

463463
> Note: TypeDI won't create instances for unknown classes since 0.9.0, you have to decorate your Class as a `Service()` as well.
464464
465+
### Scoped controllers
466+
467+
You can enable scoped controllers by providing a `scopedContainerGetter` function in SocketServerOptions. This function should return a new container that will be used to instantiate the controller and its dependencies.
468+
469+
You will get a new instance for each event in the controller.
470+
471+
The `scopedContainerGetter` function receives a parameter which contains the socket, socket.io instance, event type, event name, namespace parameters and the message arguments if they are applicable.
472+
473+
```typescript
474+
import 'reflect-metadata';
475+
import { SocketControllers, ScopedContainerGetterParams } from 'socket-controllers';
476+
import { Container, Token } from "typedi";
477+
478+
const myDiToken = new Token();
479+
480+
// create and run socket server
481+
const server = new SocketControllers({
482+
port: 3000,
483+
container: Container,
484+
scopedContainerGetter: (args: ScopedContainerGetterParams) => {
485+
const container = Container.of(YOUR_REQUEST_CONTEXT);
486+
container.set(myDiToken, 'MY_VALUE');
487+
return container;
488+
},
489+
controllers: [__dirname + '/controllers/*.js'],
490+
middlewares: [__dirname + '/middlewares/*.js'],
491+
});
492+
```
493+
465494
## Decorators Reference
466495

467496
| Signature | Description |

package-lock.json

+9-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "socket-controllers",
3-
"version": "0.1.1",
3+
"version": "0.1.2",
44
"description": "Use class-based controllers to handle websocket events.",
55
"license": "MIT",
66
"main": "index.js",
@@ -44,7 +44,7 @@
4444
"@types/socket.io": "^3.0.2",
4545
"@typescript-eslint/eslint-plugin": "^5.49.0",
4646
"@typescript-eslint/parser": "^5.49.0",
47-
"eslint": "^8.32.0",
47+
"eslint": "^8.33.0",
4848
"eslint-config-prettier": "^8.6.0",
4949
"eslint-plugin-jest": "^27.2.1",
5050
"express": "^4.18.2",

src/SocketControllers.ts

+49-30
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { HandlerType } from './types/enums/HandlerType';
88
import { SocketControllersOptions } from './types/SocketControllersOptions';
99
import { ControllerMetadata } from './types/ControllerMetadata';
1010
import { MiddlewareMetadata } from './types/MiddlewareMetadata';
11-
import { ActionType } from './types/enums/ActionType';
11+
import { SocketEventType } from './types/enums/SocketEventType';
1212
import { ActionMetadata } from './types/ActionMetadata';
1313
import { ParameterMetadata } from './types/ParameterMetadata';
1414
import { ParameterType } from './types/enums/ParameterType';
@@ -18,12 +18,13 @@ import { TransformOptions } from './types/TransformOptions';
1818
import { defaultTransformOptions } from './types/constants/defaultTransformOptions';
1919
import { ActionTransformOptions } from './types/ActionTransformOptions';
2020
import { instanceToPlain, plainToInstance } from 'class-transformer';
21+
import { ScopedContainerGetterParams } from './types/ScopedContainerGetterParams';
2122
import { MiddlewareInterface } from './types/MiddlewareInterface';
2223

2324
export class SocketControllers {
2425
public container: { get<T>(someClass: { new (...args: any[]): T } | Function): T };
25-
public controllers: HandlerMetadata<any, ControllerMetadata>[];
26-
public middlewares: HandlerMetadata<MiddlewareInterface, MiddlewareMetadata>[];
26+
public controllers: HandlerMetadata<ControllerMetadata>[];
27+
public middlewares: HandlerMetadata<MiddlewareMetadata>[];
2728
public io: Server;
2829
public transformOptions: TransformOptions;
2930

@@ -34,23 +35,14 @@ export class SocketControllers {
3435
...defaultTransformOptions,
3536
...options.transformOption,
3637
};
37-
this.controllers = this.loadHandlers<Function, ControllerMetadata>(
38-
options.controllers || [],
39-
HandlerType.CONTROLLER
40-
);
41-
this.middlewares = this.loadHandlers<MiddlewareInterface, MiddlewareMetadata>(
42-
options.middlewares || [],
43-
HandlerType.MIDDLEWARE
44-
);
38+
this.controllers = this.loadHandlers<ControllerMetadata>(options.controllers || [], HandlerType.CONTROLLER);
39+
this.middlewares = this.loadHandlers<MiddlewareMetadata>(options.middlewares || [], HandlerType.MIDDLEWARE);
4540

4641
this.registerMiddlewares();
4742
this.registerControllers();
4843
}
4944

50-
private loadHandlers<T extends Object, U>(
51-
handlers: Array<Function | string>,
52-
type: HandlerType
53-
): HandlerMetadata<T, U>[] {
45+
private loadHandlers<T extends Object>(handlers: Array<Function | string>, type: HandlerType): HandlerMetadata<T>[] {
5446
const loadedHandlers: Function[] = [];
5547

5648
for (const handler of handlers) {
@@ -64,7 +56,7 @@ export class SocketControllers {
6456
return loadedHandlers.map(handler => {
6557
return {
6658
metadata: getMetadata(handler),
67-
instance: this.container.get(handler),
59+
target: handler,
6860
};
6961
});
7062
}
@@ -101,7 +93,7 @@ export class SocketControllers {
10193
const middlewaresWithNamespace = middlewares.filter(middleware => !!middleware.metadata.namespace);
10294

10395
for (const middleware of middlewaresWithoutNamespace) {
104-
this.registerMiddleware(this.io as unknown as Namespace, middleware.instance);
96+
this.registerMiddleware(this.io as unknown as Namespace, middleware);
10597
}
10698

10799
this.io.on('new_namespace', (namespace: Namespace) => {
@@ -116,7 +108,7 @@ export class SocketControllers {
116108
});
117109

118110
if (shouldApply) {
119-
this.registerMiddleware(namespace, middleware.instance);
111+
this.registerMiddleware(namespace, middleware);
120112
}
121113
}
122114
});
@@ -132,7 +124,7 @@ export class SocketControllers {
132124
}
133125
});
134126

135-
const controllerNamespaceMap: Record<string, HandlerMetadata<unknown, ControllerMetadata>[]> = {};
127+
const controllerNamespaceMap: Record<string, HandlerMetadata<ControllerMetadata>[]> = {};
136128
const controllerNamespaceRegExpMap: Record<string, string | RegExp> = {};
137129

138130
for (const controller of controllersWithNamespace) {
@@ -156,18 +148,18 @@ export class SocketControllers {
156148
}
157149
}
158150

159-
private registerController(socket: Socket, controller: HandlerMetadata<any, ControllerMetadata>) {
151+
private registerController(socket: Socket, controller: HandlerMetadata<ControllerMetadata>) {
160152
const connectedAction = Object.values(controller.metadata.actions || {}).find(
161-
action => action.type === ActionType.CONNECT
153+
action => action.type === SocketEventType.CONNECT
162154
);
163155
const disconnectedAction = Object.values(controller.metadata.actions || {}).find(
164-
action => action.type === ActionType.DISCONNECT
156+
action => action.type === SocketEventType.DISCONNECT
165157
);
166158
const disconnectingAction = Object.values(controller.metadata.actions || {}).find(
167-
action => action.type === ActionType.DISCONNECTING
159+
action => action.type === SocketEventType.DISCONNECTING
168160
);
169161
const messageActions = Object.values(controller.metadata.actions || {}).filter(
170-
action => action.type === ActionType.MESSAGE
162+
action => action.type === SocketEventType.MESSAGE
171163
);
172164

173165
if (connectedAction) {
@@ -195,20 +187,29 @@ export class SocketControllers {
195187
messages.push(ack);
196188
}
197189

198-
this.executeAction(socket, controller, messageAction, messages);
190+
this.executeAction(socket, controller, messageAction, messageAction.options.name as string, messages);
199191
});
200192
}
201193
}
202194

203195
private executeAction(
204196
socket: Socket,
205-
controller: HandlerMetadata<any, ControllerMetadata>,
197+
controller: HandlerMetadata<ControllerMetadata>,
206198
action: ActionMetadata,
199+
eventName?: string,
207200
data?: any[]
208201
) {
209202
const parameters = this.resolveParameters(socket, controller.metadata, action.parameters || [], data);
210203
try {
211-
const actionResult = controller.instance[action.methodName](...parameters);
204+
let container = this.container;
205+
if (this.options.scopedContainerGetter) {
206+
container = this.options.scopedContainerGetter(
207+
this.collectScopedContainerParams(socket, action.type, eventName, data, controller.metadata.namespace)
208+
);
209+
}
210+
211+
const controllerInstance: any = container.get(controller.target);
212+
const actionResult = controllerInstance[action.methodName](...parameters);
212213
Promise.resolve(actionResult)
213214
.then(result => {
214215
this.handleActionResult(socket, action, result, ResultType.EMIT_ON_SUCCESS);
@@ -251,9 +252,10 @@ export class SocketControllers {
251252
}
252253
}
253254

254-
private registerMiddleware(namespace: Namespace, middleware: MiddlewareInterface) {
255+
private registerMiddleware(namespace: Namespace, middleware: HandlerMetadata<MiddlewareMetadata>) {
255256
namespace.use((socket: Socket, next: (err?: any) => void) => {
256-
middleware.use(socket, next);
257+
const instance: MiddlewareInterface = this.container.get(middleware.target);
258+
instance.use(socket, next);
257259
});
258260
}
259261

@@ -334,10 +336,27 @@ export class SocketControllers {
334336
return value;
335337
}
336338

339+
private collectScopedContainerParams(
340+
socket: Socket,
341+
eventType: SocketEventType,
342+
eventName?: string,
343+
messageBody?: any[],
344+
namespace?: string | RegExp
345+
): ScopedContainerGetterParams {
346+
return {
347+
eventType,
348+
eventName,
349+
socket,
350+
socketIo: this.io,
351+
nspParams: this.extractNamespaceParameters(socket, namespace),
352+
messageArgs: messageBody,
353+
};
354+
}
355+
337356
private extractNamespaceParameters(
338357
socket: Socket,
339358
namespace: string | RegExp | undefined,
340-
parameterMetadata: ParameterMetadata
359+
parameterMetadata?: ParameterMetadata
341360
) {
342361
const keys: any[] = [];
343362
const regexp = namespace instanceof RegExp ? namespace : pathToRegexp(namespace || '/', keys);

src/decorators/OnConnect.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { addActionToControllerMetadata } from '../util/add-action-to-controller-metadata';
2-
import { ActionType } from '../types/enums/ActionType';
2+
import { SocketEventType } from '../types/enums/SocketEventType';
33

44
export function OnConnect(): Function {
55
return function (object: Object, methodName: string) {
66
addActionToControllerMetadata(object.constructor, {
77
methodName,
8-
type: ActionType.CONNECT,
8+
type: SocketEventType.CONNECT,
99
options: {},
1010
});
1111
};

src/decorators/OnDisconnect.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { addActionToControllerMetadata } from '../util/add-action-to-controller-metadata';
2-
import { ActionType } from '../types/enums/ActionType';
2+
import { SocketEventType } from '../types/enums/SocketEventType';
33

44
export function OnDisconnect(): Function {
55
return function (object: Object, methodName: string) {
66
addActionToControllerMetadata(object.constructor, {
77
methodName,
8-
type: ActionType.DISCONNECT,
8+
type: SocketEventType.DISCONNECT,
99
options: {},
1010
});
1111
};

src/decorators/OnDisconnecting.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { addActionToControllerMetadata } from '../util/add-action-to-controller-metadata';
2-
import { ActionType } from '../types/enums/ActionType';
2+
import { SocketEventType } from '../types/enums/SocketEventType';
33

44
export function OnDisconnecting(): Function {
55
return function (object: Object, methodName: string) {
66
addActionToControllerMetadata(object.constructor, {
77
methodName,
8-
type: ActionType.DISCONNECTING,
8+
type: SocketEventType.DISCONNECTING,
99
options: {},
1010
});
1111
};

src/decorators/OnMessage.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { addActionToControllerMetadata } from '../util/add-action-to-controller-metadata';
2-
import { ActionType } from '../types/enums/ActionType';
2+
import { SocketEventType } from '../types/enums/SocketEventType';
33

44
export function OnMessage(name?: string): Function {
55
return function (object: Object, methodName: string) {
66
addActionToControllerMetadata(object.constructor, {
77
methodName,
8-
type: ActionType.MESSAGE,
8+
type: SocketEventType.MESSAGE,
99
options: { name },
1010
});
1111
};

src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ export * from './decorators/SocketRooms';
1919
export * from './types/MiddlewareInterface';
2020
export * from './types/TransformOptions';
2121
export * from './types/SocketControllersOptions';
22+
export * from './types/enums/SocketEventType';
2223

2324
export * from './SocketControllers';

src/types/ActionMetadata.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { ParameterMetadata } from './ParameterMetadata';
22
import { ResultMetadata } from './ResultMetadata';
3-
import { ActionType } from './enums/ActionType';
3+
import { SocketEventType } from './enums/SocketEventType';
44

55
export interface ActionMetadata {
6-
type: ActionType;
6+
type: SocketEventType;
77
methodName: string;
88
options: any;
99
parameters: ParameterMetadata[];

src/types/HandlerMetadata.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export interface HandlerMetadata<T, U> {
2-
instance: T;
3-
metadata: U;
1+
export interface HandlerMetadata<T> {
2+
metadata: T;
3+
target: Function;
44
}

0 commit comments

Comments
 (0)