Skip to content

Commit 0d0a7a2

Browse files
committedFeb 20, 2023
fix: properly handle manually created dynamic namespaces
Namespaces that match the regex of a parent namespace will now be added as a child of this namespace: ```js const parentNamespace = io.of(/^\/dynamic-\d+$/); const childNamespace = io.of("/dynamic-101"); ``` Related: - #4615 - #4164 - #4015 - #3960
1 parent 2a8565f commit 0d0a7a2

File tree

3 files changed

+50
-2
lines changed

3 files changed

+50
-2
lines changed
 

‎lib/index.ts

+20-2
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,18 @@ export class Server<
178178
ParentNspNameMatchFn,
179179
ParentNamespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
180180
> = new Map();
181+
182+
/**
183+
* A subset of the {@link parentNsps} map, only containing {@link ParentNamespace} which are based on a regular
184+
* expression.
185+
*
186+
* @private
187+
*/
188+
private parentNamespacesFromRegExp: Map<
189+
RegExp,
190+
ParentNamespace<ListenEvents, EmitEvents, ServerSideEvents, SocketData>
191+
> = new Map();
192+
181193
private _adapter?: AdapterConstructor;
182194
private _serveClient: boolean;
183195
private readonly opts: Partial<ServerOptions>;
@@ -314,8 +326,6 @@ export class Server<
314326
}
315327
const namespace = this.parentNsps.get(nextFn.value)!.createChild(name);
316328
debug("dynamic namespace %s was created", name);
317-
// @ts-ignore
318-
this.sockets.emitReserved("new_namespace", namespace);
319329
fn(namespace);
320330
});
321331
};
@@ -691,6 +701,7 @@ export class Server<
691701
(nsp, conn, next) => next(null, (name as RegExp).test(nsp)),
692702
parentNsp
693703
);
704+
this.parentNamespacesFromRegExp.set(name, parentNsp);
694705
}
695706
if (fn) {
696707
// @ts-ignore
@@ -703,6 +714,13 @@ export class Server<
703714

704715
let nsp = this._nsps.get(name);
705716
if (!nsp) {
717+
for (const [regex, parentNamespace] of this.parentNamespacesFromRegExp) {
718+
if (regex.test(name as string)) {
719+
debug("attaching namespace %s to parent namespace %s", name, regex);
720+
return parentNamespace.createChild(name as string);
721+
}
722+
}
723+
706724
debug("initializing namespace %s", name);
707725
nsp = new Namespace(this, name);
708726
this._nsps.set(name, nsp);

‎lib/parent-namespace.ts

+19
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@ import debugModule from "debug";
1111

1212
const debug = debugModule("socket.io:parent-namespace");
1313

14+
/**
15+
* A parent namespace is a special {@link Namespace} that holds a list of child namespaces which were created either
16+
* with a regular expression or with a function.
17+
*
18+
* @example
19+
* const parentNamespace = io.of(/\/dynamic-\d+/);
20+
*
21+
* parentNamespace.on("connection", (socket) => {
22+
* const childNamespace = socket.nsp;
23+
* }
24+
*
25+
* // will reach all the clients that are in one of the child namespaces, like "/dynamic-101"
26+
* parentNamespace.emit("hello", "world");
27+
*
28+
*/
1429
export class ParentNamespace<
1530
ListenEvents extends EventsMap = DefaultEventsMap,
1631
EmitEvents extends EventsMap = ListenEvents,
@@ -81,6 +96,10 @@ export class ParentNamespace<
8196
}
8297

8398
this.server._nsps.set(name, namespace);
99+
100+
// @ts-ignore
101+
this.server.sockets.emitReserved("new_namespace", namespace);
102+
84103
return namespace;
85104
}
86105

‎test/namespaces.ts

+11
Original file line numberDiff line numberDiff line change
@@ -652,5 +652,16 @@ describe("namespaces", () => {
652652

653653
io.of(/^\/dynamic-\d+$/);
654654
});
655+
656+
it("should attach a child namespace to its parent upon manual creation", () => {
657+
const io = new Server(0);
658+
const parentNamespace = io.of(/^\/dynamic-\d+$/);
659+
const childNamespace = io.of("/dynamic-101");
660+
661+
// @ts-ignore
662+
expect(parentNamespace.children.has(childNamespace)).to.be(true);
663+
664+
io.close();
665+
});
655666
});
656667
});

0 commit comments

Comments
 (0)
Please sign in to comment.