parent-namespace.js 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.ParentNamespace = void 0;
  7. const namespace_1 = require("./namespace");
  8. const socket_io_adapter_1 = require("socket.io-adapter");
  9. const debug_1 = __importDefault(require("debug"));
  10. const debug = (0, debug_1.default)("socket.io:parent-namespace");
  11. /**
  12. * A parent namespace is a special {@link Namespace} that holds a list of child namespaces which were created either
  13. * with a regular expression or with a function.
  14. *
  15. * @example
  16. * const parentNamespace = io.of(/\/dynamic-\d+/);
  17. *
  18. * parentNamespace.on("connection", (socket) => {
  19. * const childNamespace = socket.nsp;
  20. * }
  21. *
  22. * // will reach all the clients that are in one of the child namespaces, like "/dynamic-101"
  23. * parentNamespace.emit("hello", "world");
  24. *
  25. */
  26. class ParentNamespace extends namespace_1.Namespace {
  27. constructor(server) {
  28. super(server, "/_" + ParentNamespace.count++);
  29. this.children = new Set();
  30. }
  31. /**
  32. * @private
  33. */
  34. _initAdapter() {
  35. this.adapter = new ParentBroadcastAdapter(this, this.children);
  36. }
  37. emit(ev, ...args) {
  38. this.children.forEach((nsp) => {
  39. nsp.emit(ev, ...args);
  40. });
  41. return true;
  42. }
  43. createChild(name) {
  44. debug("creating child namespace %s", name);
  45. const namespace = new namespace_1.Namespace(this.server, name);
  46. namespace._fns = this._fns.slice(0);
  47. this.listeners("connect").forEach((listener) => namespace.on("connect", listener));
  48. this.listeners("connection").forEach((listener) => namespace.on("connection", listener));
  49. this.children.add(namespace);
  50. if (this.server._opts.cleanupEmptyChildNamespaces) {
  51. const remove = namespace._remove;
  52. namespace._remove = (socket) => {
  53. remove.call(namespace, socket);
  54. if (namespace.sockets.size === 0) {
  55. debug("closing child namespace %s", name);
  56. namespace.adapter.close();
  57. this.server._nsps.delete(namespace.name);
  58. this.children.delete(namespace);
  59. }
  60. };
  61. }
  62. this.server._nsps.set(name, namespace);
  63. // @ts-ignore
  64. this.server.sockets.emitReserved("new_namespace", namespace);
  65. return namespace;
  66. }
  67. fetchSockets() {
  68. // note: we could make the fetchSockets() method work for dynamic namespaces created with a regex (by sending the
  69. // regex to the other Socket.IO servers, and returning the sockets of each matching namespace for example), but
  70. // the behavior for namespaces created with a function is less clear
  71. // note²: we cannot loop over each children namespace, because with multiple Socket.IO servers, a given namespace
  72. // may exist on one node but not exist on another (since it is created upon client connection)
  73. throw new Error("fetchSockets() is not supported on parent namespaces");
  74. }
  75. }
  76. exports.ParentNamespace = ParentNamespace;
  77. ParentNamespace.count = 0;
  78. /**
  79. * A dummy adapter that only supports broadcasting to child (concrete) namespaces.
  80. * @private file
  81. */
  82. class ParentBroadcastAdapter extends socket_io_adapter_1.Adapter {
  83. constructor(parentNsp, children) {
  84. super(parentNsp);
  85. this.children = children;
  86. }
  87. broadcast(packet, opts) {
  88. this.children.forEach((nsp) => {
  89. nsp.adapter.broadcast(packet, opts);
  90. });
  91. }
  92. }