diff --git a/docs/tutorials/snippets/socketio/connection-state-recovery-configuration.ts b/docs/tutorials/snippets/socketio/connection-state-recovery-configuration.ts new file mode 100644 index 00000000000..d9a901f398b --- /dev/null +++ b/docs/tutorials/snippets/socketio/connection-state-recovery-configuration.ts @@ -0,0 +1,16 @@ +import {Configuration} from "@tsed/di"; +import "@tsed/platform-express"; +import "@tsed/socketio"; + +@Configuration({ + socketIO: { + // ... see configuration + connectionStateRecovery: { + // the backup duration of the sessions and the packets + maxDisconnectionDuration: 2 * 60 * 1000, + // whether to skip middlewares upon successful recovery + skipMiddlewares: true + } + } +}) +export class Server {} diff --git a/docs/tutorials/socket-io.md b/docs/tutorials/socket-io.md index 22baf164172..38e39fdf2ff 100644 --- a/docs/tutorials/socket-io.md +++ b/docs/tutorials/socket-io.md @@ -105,6 +105,18 @@ Ts.ED creates a new session for each socket. <<< @/tutorials/snippets/socketio/socket-session.ts +The session represents an arbitrary object that facilitates the storage of session data, allowing the sharing of information between Socket.IO servers. + +In the event of an unexpected disconnection (i.e., when the socket is not manually disconnected using `socket.disconnect()`), the server will store the session of the socket. Upon reconnection, the server will make an attempt to restore the previous session. + +To enable this behavior, you need to configure the [Connection state recovery](https://socket.io/docs/v4/connection-state-recovery) as follows: + +<<< @/tutorials/snippets/socketio/connection-state-recovery-configuration.ts + +::: tip +By default, Ts.ED uses the built-in in-memory adapter for session management. However, for production environments, it is recommended to use [the persistent adapters](https://socket.io/docs/v4/connection-state-recovery#compatibility-with-existing-adapters) to enhance reliability. +::: + ### Middlewares A middleware can also be used on a @@SocketService@@ either on a class or on a method. diff --git a/packages/third-parties/socketio/jest.config.js b/packages/third-parties/socketio/jest.config.js index e0a6005ae09..4e49186886d 100644 --- a/packages/third-parties/socketio/jest.config.js +++ b/packages/third-parties/socketio/jest.config.js @@ -8,10 +8,10 @@ module.exports = { }, coverageThreshold: { global: { - statements: 99.6, - branches: 94.59, + statements: 99.68, + branches: 95.52, functions: 100, - lines: 99.6 + lines: 99.68 } } }; diff --git a/packages/third-parties/socketio/readme.md b/packages/third-parties/socketio/readme.md index eb96bd44f61..ff808ab5fac 100644 --- a/packages/third-parties/socketio/readme.md +++ b/packages/third-parties/socketio/readme.md @@ -197,6 +197,33 @@ export class MySocketService { } ``` +The session represents an arbitrary object that facilitates the storage of session data, allowing the sharing of information between Socket.IO servers. + +In the event of an unexpected disconnection (i.e., when the socket is not manually disconnected using `socket.disconnect()`), the server will store the session of the socket. Upon reconnection, the server will make an attempt to restore the previous session. + +To enable this behavior, you need to configure the [Connection state recovery](https://socket.io/docs/v4/connection-state-recovery) as follows: + +```ts +import {Configuration} from "@tsed/di"; +import "@tsed/platform-express"; +import "@tsed/socketio"; + +@Configuration({ + socketIO: { + // ... see configuration + connectionStateRecovery: { + // the backup duration of the sessions and the packets + maxDisconnectionDuration: 2 * 60 * 1000, + // whether to skip middlewares upon successful recovery + skipMiddlewares: true + } + } +}) +export class Server {} +``` + +> By default, Ts.ED uses the built-in in-memory adapter for session management. However, for production environments, it is recommended to use [the persistent adapters](https://socket.io/docs/v4/connection-state-recovery#compatibility-with-existing-adapters) to enhance reliability. + ### Middlewares A middleware can be also used on a `SocketService` either on a class or on a method. @@ -258,6 +285,7 @@ Middlewares chain use the `Promise` to run it. If one of this middlewares/method import {SocketService, SocketUseAfter, SocketUseBefore, Emit, Input, Args, SocketSession} from "@tsed/socketio"; import {UserConverterSocketMiddleware, ErrorHandlerSocketMiddleware} from "../middlewares"; import {User} from "../models/User"; +import {SocketSessionData} from "@tsed/socketio/lib/cjs"; @SocketService("/my-namespace") @SocketUseBefore(UserConverterSocketMiddleware) // global version @@ -267,7 +295,7 @@ export class MySocketService { @Emit("responseEventName") // or Broadcast or BroadcastOthers @SocketUseBefore(UserConverterSocketMiddleware) @SocketUseAfter(ErrorHandlerSocketMiddleware) - async myMethod(@Args(0) userName: User) { + async myMethod(@Args(0) userName: User, @SocketSessionData session: SocketSessionData) { const user = session.get("user") || {}; user.name = userName; diff --git a/packages/third-parties/socketio/src/class/SocketHandlersBuilder.spec.ts b/packages/third-parties/socketio/src/class/SocketHandlersBuilder.spec.ts index b9d23045e43..1fe23bfec92 100644 --- a/packages/third-parties/socketio/src/class/SocketHandlersBuilder.spec.ts +++ b/packages/third-parties/socketio/src/class/SocketHandlersBuilder.spec.ts @@ -102,11 +102,6 @@ describe("SocketHandlersBuilder", () => { const {instance} = createServiceFixture(); expect(instance.nsp).toEqual("namespace1"); }); - - it("should init the nspSession", () => { - const {instance} = createServiceFixture(); - expect(instance._nspSession).toBeInstanceOf(Map); - }); }); describe("onConnection()", () => { it("should build handler and invoke onConnection instance method", async () => { @@ -138,12 +133,10 @@ describe("SocketHandlersBuilder", () => { const invokeStub = jest.spyOn(builder, "invoke").mockReturnValue(undefined); const buildHandlersStub = jest.spyOn(builder, "buildHandlers").mockReturnValue(undefined); - const createSessionStub = jest.spyOn(builder, "createSession").mockReturnValue(undefined); await builder.onConnection(socketStub, nspStub); expect(buildHandlersStub).toBeCalledWith(socketStub, nspStub); - expect(createSessionStub).toBeCalledWith(socketStub); expect(invokeStub).toBeCalledWith( instance, {eventName: "onConnection"}, @@ -155,7 +148,7 @@ describe("SocketHandlersBuilder", () => { }); }); describe("onDisconnect()", () => { - it("should call the createSession method and create the $onDisconnect method if is missing", async () => { + it("should create the $onDisconnect method if is missing", async () => { const instance = { $onDisconnect: jest.fn() }; @@ -183,11 +176,9 @@ describe("SocketHandlersBuilder", () => { } } as any); const invokeStub = jest.spyOn(builder, "invoke").mockReturnValue(undefined); - const destroySessionStub = jest.spyOn(builder, "destroySession").mockReturnValue(undefined); await builder.onDisconnect(socketStub, nspStub); - expect(destroySessionStub).toBeCalledWith(socketStub); expect(invokeStub).toBeCalledWith( instance, {eventName: "onDisconnect"}, @@ -227,7 +218,6 @@ describe("SocketHandlersBuilder", () => { } } as any); const invokeStub = jest.spyOn(builder, "invoke").mockReturnValue(undefined); - jest.spyOn(builder, "destroySession").mockReturnValue(undefined); await builder.onDisconnect(socketStub, nspStub, reason); @@ -241,87 +231,8 @@ describe("SocketHandlersBuilder", () => { } ); }); - - it("should destroy the session only when $onDisconnect is completed invocation", async () => { - const instance = { - $onDisconnect: jest.fn() - }; - - const provider: any = { - store: { - get: jest.fn().mockReturnValue({ - injectNamespace: "nsp", - handlers: { - $onDisconnect: { - eventName: "onDisconnect" - } - } - }) - } - }; - const nspStub: any = {nsp: "nsp"}; - const socketStub: any = { - on: jest.fn() - }; - - const builder: any = new SocketHandlersBuilder(provider, { - get() { - return instance; - } - } as any); - const invokeStub = jest.spyOn(builder, "invoke").mockReturnValue(undefined); - const destroySessionStub = jest.spyOn(builder, "destroySession").mockReturnValue(undefined); - - await builder.onDisconnect(socketStub, nspStub); - - expect(destroySessionStub.mock.invocationCallOrder[0]).toBeGreaterThan(invokeStub.mock.invocationCallOrder[0]); - }); - }); - describe("createSession()", () => { - it("should create session for the socket", () => { - const instance = { - _nspSession: new Map() - }; - const provider: any = { - store: { - get: jest.fn() - } - }; - - const builder: any = new SocketHandlersBuilder(provider, { - get() { - return instance; - } - } as any); - builder.createSession({id: "id"}); - - expect(instance._nspSession.get("id")).toBeInstanceOf(Map); - }); }); - describe("destroySession()", () => { - it("should destroy session for the socket", () => { - const instance = { - _nspSession: new Map() - }; - const provider: any = { - store: { - get: jest.fn() - } - }; - - instance._nspSession.set("id", new Map()); - - const builder: any = new SocketHandlersBuilder(provider, { - get() { - return instance; - } - } as any); - - builder.destroySession({id: "id"}); - expect(instance._nspSession.get("id")).toBeUndefined(); - }); - }); describe("buildHandlers()", () => { it("should call socket.on() method", async () => { const metadata = { @@ -521,12 +432,9 @@ describe("SocketHandlersBuilder", () => { describe("when SESSION", () => { it("should return a list of parameters", () => { - const map = new Map(); - map.set("id", new Map()); - - const {builder, instance, provider} = createFixture(); + const data = {id: "id"}; - instance._nspSession = map; + const {builder} = createFixture(); const result = builder.buildParameters( { @@ -534,10 +442,29 @@ describe("SocketHandlersBuilder", () => { filter: SocketFilters.SESSION } }, - {socket: {id: "id"}} + {socket: {data, id: "id"}} + ); + + expect(new Map(result[0])).toEqual(new Map(Object.entries(data))); + }); + }); + + describe("when RAW_SESSION", () => { + it("should return a list of parameters", () => { + const data = {id: "id"}; + + const {builder} = createFixture(); + + const result = builder.buildParameters( + { + 0: { + filter: SocketFilters.RAW_SESSION + } + }, + {socket: {data, id: "id"}} ); - expect(result[0]).toBeInstanceOf(Map); + expect(result[0]).toEqual(data); }); }); diff --git a/packages/third-parties/socketio/src/class/SocketHandlersBuilder.ts b/packages/third-parties/socketio/src/class/SocketHandlersBuilder.ts index 712d227a4af..cde8a9b8c7a 100644 --- a/packages/third-parties/socketio/src/class/SocketHandlersBuilder.ts +++ b/packages/third-parties/socketio/src/class/SocketHandlersBuilder.ts @@ -9,14 +9,14 @@ import {SocketInjectableNsp} from "../interfaces/SocketInjectableNsp"; import {SocketParamMetadata} from "../interfaces/SocketParamMetadata"; import {SocketProviderTypes} from "../interfaces/SocketProviderTypes"; import {SocketReturnsTypes} from "../interfaces/SocketReturnsTypes"; -import {getNspSession} from "../registries/NspSessionRegistry"; import {SocketProviderMetadata} from "./SocketProviderMetadata"; +import {SocketSessionData} from "./SocketSessionData"; /** * @ignore */ export class SocketHandlersBuilder { - private socketProviderMetadata: SocketProviderMetadata; + private readonly socketProviderMetadata: SocketProviderMetadata; constructor(private provider: Provider, private injector: InjectorService) { this.socketProviderMetadata = new SocketProviderMetadata(this.provider.store.get("socketIO")); @@ -60,8 +60,6 @@ export class SocketHandlersBuilder { instance.$onConnection && this.socketProviderMetadata.createHook("$onConnection", "connection"); instance.$onDisconnect && this.socketProviderMetadata.createHook("$onDisconnect", "disconnect"); - instance._nspSession = getNspSession(namespace); - injectNamespaces.forEach((setting: SocketInjectableNsp) => { instance[setting.propertyKey] = nsps.get(setting.nsp || namespace); }); @@ -85,7 +83,6 @@ export class SocketHandlersBuilder { const instance = this.injector.get(this.provider.token); this.buildHandlers(socket, nsp); - this.createSession(socket); if (instance.$onConnection) { await this.invoke(instance, socketProviderMetadata.$onConnection, {socket, nsp}); @@ -99,26 +96,6 @@ export class SocketHandlersBuilder { if (instance.$onDisconnect) { await this.invoke(instance, socketProviderMetadata.$onDisconnect, {socket, nsp, reason}); } - - this.destroySession(socket); - } - - /** - * - * @param {Socket} socket - */ - private createSession(socket: Socket) { - const instance = this.injector.get(this.provider.token); - instance._nspSession.set(socket.id, new Map()); - } - - /** - * - * @param {Socket} socket - */ - private destroySession(socket: Socket) { - const instance = this.injector.get(this.provider.token); - instance._nspSession.delete(socket.id); } private buildHandlers(socket: Socket, nsp: Namespace) { @@ -183,9 +160,9 @@ export class SocketHandlersBuilder { if (filter === SocketFilters.ARGS && useMapper) { value = deserialize(value, { - useAlias: true, type, - collectionType + collectionType, + useAlias: true }); scope.args[mapIndex!] = value; } @@ -247,8 +224,10 @@ export class SocketHandlersBuilder { return scope.error; case SocketFilters.SESSION: - const instance = this.injector.get(this.provider.token); - return instance._nspSession.get(scope.socket.id); + return new SocketSessionData(scope.socket.data); + + case SocketFilters.RAW_SESSION: + return scope.socket.data; case SocketFilters.SOCKET_NSP: return scope.socket.nsp; diff --git a/packages/third-parties/socketio/src/class/SocketSessionData.spec.ts b/packages/third-parties/socketio/src/class/SocketSessionData.spec.ts new file mode 100644 index 00000000000..6210a37e21f --- /dev/null +++ b/packages/third-parties/socketio/src/class/SocketSessionData.spec.ts @@ -0,0 +1,190 @@ +import {SocketSessionData} from "./SocketSessionData"; + +describe("SocketSessionData", () => { + let socketSessionData!: SocketSessionData; + let data!: Record; + + beforeEach(() => { + data = { + key1: "value1", + key2: "value2" + }; + socketSessionData = new SocketSessionData(data); + }); + + describe("Symbol.species", () => { + it("should return Map constructor", () => { + // act + const result = SocketSessionData[Symbol.species]; + + // assert + expect(result).toBe(Map); + }); + }); + + describe("instanceof", () => { + it("should return true when right side is an reference ot Map type", () => { + // act + const result = socketSessionData instanceof Map; + + // assert + expect(result).toBe(true); + }); + }); + + describe("size", () => { + it("should return the size of session data", () => { + // act + const size = socketSessionData.size; + + // assert + expect(size).toBe(2); + }); + }); + + describe("clear", () => { + it("should remove all entries from session data", () => { + // act + socketSessionData.clear(); + + // assert + expect(socketSessionData.size).toBe(0); + expect(data).toEqual({}); + }); + }); + + describe("delete", () => { + it("should remove an entry from session data if it exists", () => { + // arrange + const keyToDelete = "key1"; + + // act + const deleted = socketSessionData.delete(keyToDelete); + + // assert + expect(deleted).toBe(true); + expect(socketSessionData.size).toBe(1); + expect(socketSessionData.has(keyToDelete)).toBe(false); + expect(data).not.toHaveProperty(keyToDelete); + }); + + it("should return false if the entry does not exist in session data", () => { + // arrange + const keyToDelete = "nonExistentKey"; + const expected = {...data}; + + // act + const deleted = socketSessionData.delete(keyToDelete); + + // assert + expect(deleted).toBe(false); + expect(socketSessionData.size).toBe(2); + expect(data).toEqual(expected); + }); + }); + + describe("get", () => { + it("should return the value associated with the given key", () => { + // arrange + const key = "key2"; + + // act + const value = socketSessionData.get(key); + + // assert + expect(value).toBe("value2"); + }); + + it("should return undefined if the key does not exist", () => { + // arrange + const key = "nonExistentKey"; + + // act + const value = socketSessionData.get(key); + + // assert + expect(value).toBeUndefined(); + }); + }); + + describe("set", () => { + it("should return this", () => { + // act + const result = socketSessionData.set("key3", "value3"); + + // assert + expect(result).toBe(socketSessionData); + }); + + it("should set the value by the key", () => { + // arrange + const key = "key3"; + const value = "value3"; + + // act + socketSessionData.set(key, value); + + // assert + expect([...socketSessionData]).toMatchObject(expect.arrayContaining([[key, value]])); + }); + }); + + describe("forEach", () => { + it("should call the callback function for each key-value pair", () => { + // arrange + const callbackFn = jest.fn(); + + // act + socketSessionData.forEach(callbackFn); + + // assert + expect(callbackFn).toHaveBeenCalledTimes(2); + expect(callbackFn).toHaveBeenCalledWith("value1", "key1", socketSessionData); + expect(callbackFn).toHaveBeenCalledWith("value2", "key2", socketSessionData); + }); + + it("should call the callback function with the specified thisArg", () => { + // arrange + const thisArg = {customProp: "customValue"}; + const callbackFn = jest.fn(function () { + expect(this).toBe(thisArg); + }); + + // act + socketSessionData.forEach(callbackFn, thisArg); + }); + }); + + describe("values", () => { + it("should return an iterator for the values", () => { + // act + const values = socketSessionData.values(); + + // assert + expect([...values]).toEqual(["value1", "value2"]); + }); + }); + + describe("keys", () => { + it("should return an iterator for the keys", () => { + // act + const keys = socketSessionData.keys(); + + // assert + expect([...keys]).toEqual(["key1", "key2"]); + }); + }); + + describe("entries", () => { + it("should return an iterator for the key-value pairs", () => { + // act + const entries = [...socketSessionData.entries()]; + + // assert + expect(entries).toEqual([ + ["key1", "value1"], + ["key2", "value2"] + ]); + }); + }); +}); diff --git a/packages/third-parties/socketio/src/class/SocketSessionData.ts b/packages/third-parties/socketio/src/class/SocketSessionData.ts new file mode 100644 index 00000000000..603625d2bef --- /dev/null +++ b/packages/third-parties/socketio/src/class/SocketSessionData.ts @@ -0,0 +1,81 @@ +/** + * Represents session data associated with a socket connection, providing a compatibility layer with Ts.ED v7 by wrapping a `socket.data` which is used to archive recoverability and resiliency to a `Map` instance. + * + * This class implements the `Map` interface and provides methods and properties to manage and manipulate session data. + * + * @internal This class is designed for internal use. + */ +export class SocketSessionData extends Map { + readonly #data: Record; + + get size(): number { + return Object.keys(this.#data).length; + } + + static get [Symbol.species]() { + return Map; + } + + constructor(data: Record) { + super(); + this.#data = data; + } + + public *[Symbol.iterator](): IterableIterator<[string, unknown]> { + for (const key in this.#data) { + yield [key, this.#data[key]]; + } + } + + public clear(): void { + for (const key in this.#data) { + delete this.#data[key]; + } + } + + public delete(key: string): boolean { + const hasKey = key in this.#data; + if (hasKey) { + delete this.#data[key]; + return true; + } + return false; + } + + public *entries(): IterableIterator<[string, unknown]> { + for (const key in this.#data) { + yield [key, this.#data[key]]; + } + } + + public forEach(callbackfn: (value: unknown, key: string, map: Map) => void, thisArg?: any): void { + for (const key in this.#data) { + callbackfn.call(thisArg, this.#data[key], key, this); + } + } + + public get(key: string): unknown | undefined { + return this.#data[key]; + } + + public has(key: string): boolean { + return key in this.#data; + } + + public *keys(): IterableIterator { + for (const key in this.#data) { + yield key; + } + } + + public set(key: string, value: unknown): this { + this.#data[key] = value; + return this; + } + + public *values(): IterableIterator { + for (const key in this.#data) { + yield this.#data[key]; + } + } +} diff --git a/packages/third-parties/socketio/src/decorators/socketSession.spec.ts b/packages/third-parties/socketio/src/decorators/socketSession.spec.ts index e0fe85dcb83..456e06043b6 100644 --- a/packages/third-parties/socketio/src/decorators/socketSession.spec.ts +++ b/packages/third-parties/socketio/src/decorators/socketSession.spec.ts @@ -1,5 +1,5 @@ import {Store} from "@tsed/core"; -import {SocketSession} from "../index"; +import {RawSocketSession, SocketFilters, SocketSession} from "../index"; describe("SocketSession", () => { it("should set metadata", () => { @@ -13,7 +13,29 @@ describe("SocketSession", () => { test: { parameters: { "0": { - filter: "session", + filter: SocketFilters.SESSION, + mapIndex: undefined + } + } + } + } + }); + }); +}); + +describe("RawSocketSession", () => { + it("should set metadata", () => { + class Test {} + + RawSocketSession(Test, "test", 0); + const store = Store.from(Test); + + expect(store.get("socketIO")).toEqual({ + handlers: { + test: { + parameters: { + "0": { + filter: SocketFilters.RAW_SESSION, mapIndex: undefined } } diff --git a/packages/third-parties/socketio/src/decorators/socketSession.ts b/packages/third-parties/socketio/src/decorators/socketSession.ts index 3849532759d..9f767d97c71 100644 --- a/packages/third-parties/socketio/src/decorators/socketSession.ts +++ b/packages/third-parties/socketio/src/decorators/socketSession.ts @@ -4,7 +4,7 @@ import {SocketFilter} from "./socketFilter"; export type SocketSession = Map; /** - * Inject the Socket instance in the decorated parameter. + * Inject the socket session data in the decorated parameter. * * ### Example * @@ -13,7 +13,7 @@ export type SocketSession = Map; * export class MyWS { * * @Input("event") - * myMethod(@SocketSession session: Map) { + * myMethod(@SocketSession session: SocketSession) { * console.log(session); * } * } @@ -24,6 +24,30 @@ export type SocketSession = Map; * @param {number} index * @decorator */ -export function SocketSession(target: any, propertyKey: string, index: number): any { +export function SocketSession(target: any, propertyKey: string, index: number) { return SocketFilter(SocketFilters.SESSION)(target, propertyKey, index); } + +/** + * Inject the raw `socket.data` in the decorated parameter. + * + * @example + * ```typescript + * @SocketService("/nsp") + * export class MyWS { + * + * @Input("event") + * myMethod(@RawSocketSession session: Record) { + * console.log(session); + * } + * } + * ``` + * + * @param target + * @param {string} propertyKey + * @param {number} index + * @constructor + */ +export function RawSocketSession(target: any, propertyKey: string, index: number) { + return SocketFilter(SocketFilters.RAW_SESSION)(target, propertyKey, index); +} diff --git a/packages/third-parties/socketio/src/index.ts b/packages/third-parties/socketio/src/index.ts index aed327f1519..9d56a21b1da 100644 --- a/packages/third-parties/socketio/src/index.ts +++ b/packages/third-parties/socketio/src/index.ts @@ -5,6 +5,7 @@ export * from "./SocketIOModule"; export * from "./class/SocketHandlersBuilder"; export * from "./class/SocketProviderMetadata"; +export * from "./class/SocketSessionData"; export * from "./constants/constants"; export * from "./decorators/args"; export * from "./decorators/broadcast"; @@ -37,6 +38,5 @@ export * from "./interfaces/SocketParamMetadata"; export * from "./interfaces/SocketProviderTypes"; export * from "./interfaces/SocketReturnsTypes"; export * from "./interfaces/interfaces"; -export * from "./registries/NspSessionRegistry"; export * from "./services/SocketIOServer"; export * from "./services/SocketIOService"; diff --git a/packages/third-parties/socketio/src/interfaces/SocketFilters.ts b/packages/third-parties/socketio/src/interfaces/SocketFilters.ts index 9a8a017acc4..0d49bd076c3 100644 --- a/packages/third-parties/socketio/src/interfaces/SocketFilters.ts +++ b/packages/third-parties/socketio/src/interfaces/SocketFilters.ts @@ -7,6 +7,7 @@ export enum SocketFilters { EVENT_NAME = "eventName", NSP = "nsp", SESSION = "session", + RAW_SESSION = "raw_session", ERR = "error", SOCKET_NSP = "socket_nsp", REASON = "reason" diff --git a/packages/third-parties/socketio/src/registries/NspSessionRegistry.spec.ts b/packages/third-parties/socketio/src/registries/NspSessionRegistry.spec.ts deleted file mode 100644 index 13b6a6e9c4b..00000000000 --- a/packages/third-parties/socketio/src/registries/NspSessionRegistry.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import {getNspSession} from "./NspSessionRegistry"; - -describe("NspSessionRegistry", () => { - it("should return session", () => { - expect(getNspSession()!).toBeInstanceOf(Map); - expect(getNspSession("/")!).toBeInstanceOf(Map); - }); -}); diff --git a/packages/third-parties/socketio/src/registries/NspSessionRegistry.ts b/packages/third-parties/socketio/src/registries/NspSessionRegistry.ts deleted file mode 100644 index cce58fb83cc..00000000000 --- a/packages/third-parties/socketio/src/registries/NspSessionRegistry.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * - * @type {Map} - */ -const SESSIONS: Map> = new Map(); - -export function getNspSession(namespace: string | RegExp = "/") { - if (!SESSIONS.has(namespace)) { - SESSIONS.set(namespace, new Map()); - } - - return SESSIONS.get(namespace); -} diff --git a/packages/third-parties/socketio/test/app/middlewares/ConverterUserSocketMiddleware.ts b/packages/third-parties/socketio/test/app/middlewares/ConverterUserSocketMiddleware.ts index ece4d523f86..35867a35b88 100644 --- a/packages/third-parties/socketio/test/app/middlewares/ConverterUserSocketMiddleware.ts +++ b/packages/third-parties/socketio/test/app/middlewares/ConverterUserSocketMiddleware.ts @@ -4,7 +4,7 @@ import {deserialize} from "@tsed/json-mapper"; @SocketMiddleware() export class ConverterUserSocketMiddleware { - use(@Args(0) user: any[], @SocketSession session: Map) { + use(@Args(0) user: any[], @SocketSession session: SocketSession) { session.set("test", "test2"); user = deserialize(user, {type: User, useAlias: true}); diff --git a/packages/third-parties/socketio/test/app/services/RoomWS.ts b/packages/third-parties/socketio/test/app/services/RoomWS.ts index 584161fac22..920ef65e8f4 100644 --- a/packages/third-parties/socketio/test/app/services/RoomWS.ts +++ b/packages/third-parties/socketio/test/app/services/RoomWS.ts @@ -24,7 +24,7 @@ export class RoomWS { @Input("eventName") @Emit("eventTest") @SocketUseBefore(ConverterUserSocketMiddleware) - myMethod(@SocketSession session: Map) { + myMethod(@SocketSession session: SocketSession) { console.log("session", session.get("test")); return Promise.resolve("my Message " + session.get("test")); @@ -34,8 +34,7 @@ export class RoomWS { @Emit("eventUserReturn") user( @Args(0) - user: User, - @SocketSession session: Map + user: User ): User { console.log("user", nameOf(getClass(user)), user); diff --git a/packages/third-parties/socketio/test/socket.integration.spec.ts b/packages/third-parties/socketio/test/socket.integration.spec.ts index 501f4eefe52..61e8b3c0bdf 100644 --- a/packages/third-parties/socketio/test/socket.integration.spec.ts +++ b/packages/third-parties/socketio/test/socket.integration.spec.ts @@ -1,6 +1,6 @@ import {Inject, PlatformTest} from "@tsed/common"; import {PlatformExpress} from "@tsed/platform-express"; -import {Emit, Input, Nsp, SocketNsp, SocketIOServer, SocketService, SocketSession, SocketUseBefore} from "@tsed/socketio"; +import {Emit, Input, Nsp, SocketNsp, SocketIOServer, SocketService, SocketSession, SocketUseBefore} from "../src"; import {SocketClientService} from "@tsed/socketio-testing"; import {Namespace, Socket as IOSocket} from "socket.io"; import {ConverterUserSocketMiddleware} from "./app/middlewares/ConverterUserSocketMiddleware"; @@ -18,7 +18,7 @@ export class TestWS { @Input("input:scenario1") @Emit("output:scenario1") @SocketUseBefore(ConverterUserSocketMiddleware) - scenario1(@SocketSession session: Map) { + scenario1(@SocketSession session: SocketSession) { return Promise.resolve("my Message " + session.get("test")); } }