@gleamkit/socket.io 4.8.6

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/dist/client.js ADDED
@@ -0,0 +1,274 @@
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.Client = void 0;
7
+ const socket_io_parser_1 = require("socket.io-parser");
8
+ const debug_1 = __importDefault(require("debug"));
9
+ const debug = (0, debug_1.default)("socket.io:client");
10
+ class Client {
11
+ /**
12
+ * Client constructor.
13
+ *
14
+ * @param server instance
15
+ * @param conn
16
+ * @package
17
+ */
18
+ constructor(server, conn) {
19
+ this.sockets = new Map();
20
+ this.nsps = new Map();
21
+ this.server = server;
22
+ this.conn = conn;
23
+ this.encoder = server.encoder;
24
+ this.decoder = new server._parser.Decoder();
25
+ // @ts-expect-error use of private
26
+ this.id = conn.id;
27
+ this.setup();
28
+ }
29
+ /**
30
+ * @return the reference to the request that originated the Engine.IO connection
31
+ *
32
+ * @public
33
+ */
34
+ get request() {
35
+ return this.conn.request;
36
+ }
37
+ /**
38
+ * Sets up event listeners.
39
+ *
40
+ * @private
41
+ */
42
+ setup() {
43
+ this.onclose = this.onclose.bind(this);
44
+ this.ondata = this.ondata.bind(this);
45
+ this.onerror = this.onerror.bind(this);
46
+ this.ondecoded = this.ondecoded.bind(this);
47
+ // @ts-ignore
48
+ this.decoder.on("decoded", this.ondecoded);
49
+ this.conn.on("data", this.ondata);
50
+ this.conn.on("error", this.onerror);
51
+ this.conn.on("close", this.onclose);
52
+ this.connectTimeout = setTimeout(() => {
53
+ if (this.nsps.size === 0) {
54
+ debug("no namespace joined yet, close the client");
55
+ this.close();
56
+ }
57
+ else {
58
+ debug("the client has already joined a namespace, nothing to do");
59
+ }
60
+ }, this.server._connectTimeout);
61
+ }
62
+ /**
63
+ * Connects a client to a namespace.
64
+ *
65
+ * @param {String} name - the namespace
66
+ * @param {Object} auth - the auth parameters
67
+ * @private
68
+ */
69
+ connect(name, auth = {}) {
70
+ if (this.server._nsps.has(name)) {
71
+ debug("connecting to namespace %s", name);
72
+ return this.doConnect(name, auth);
73
+ }
74
+ this.server._checkNamespace(name, auth, (dynamicNspName) => {
75
+ if (dynamicNspName) {
76
+ this.doConnect(name, auth);
77
+ }
78
+ else {
79
+ debug("creation of namespace %s was denied", name);
80
+ this._packet({
81
+ type: socket_io_parser_1.PacketType.CONNECT_ERROR,
82
+ nsp: name,
83
+ data: {
84
+ message: "Invalid namespace",
85
+ },
86
+ });
87
+ }
88
+ });
89
+ }
90
+ /**
91
+ * Connects a client to a namespace.
92
+ *
93
+ * @param name - the namespace
94
+ * @param {Object} auth - the auth parameters
95
+ *
96
+ * @private
97
+ */
98
+ doConnect(name, auth) {
99
+ const nsp = this.server.of(name);
100
+ nsp._add(this, auth, (socket) => {
101
+ this.sockets.set(socket.id, socket);
102
+ this.nsps.set(nsp.name, socket);
103
+ if (this.connectTimeout) {
104
+ clearTimeout(this.connectTimeout);
105
+ this.connectTimeout = undefined;
106
+ }
107
+ });
108
+ }
109
+ /**
110
+ * Disconnects from all namespaces and closes transport.
111
+ *
112
+ * @private
113
+ */
114
+ _disconnect() {
115
+ for (const socket of this.sockets.values()) {
116
+ socket.disconnect();
117
+ }
118
+ this.sockets.clear();
119
+ this.close();
120
+ }
121
+ /**
122
+ * Removes a socket. Called by each `Socket`.
123
+ *
124
+ * @private
125
+ */
126
+ _remove(socket) {
127
+ if (this.sockets.has(socket.id)) {
128
+ const nsp = this.sockets.get(socket.id).nsp.name;
129
+ this.sockets.delete(socket.id);
130
+ this.nsps.delete(nsp);
131
+ }
132
+ else {
133
+ debug("ignoring remove for %s", socket.id);
134
+ }
135
+ }
136
+ /**
137
+ * Closes the underlying connection.
138
+ *
139
+ * @private
140
+ */
141
+ close() {
142
+ if ("open" === this.conn.readyState) {
143
+ debug("forcing transport close");
144
+ this.conn.close();
145
+ this.onclose("forced server close");
146
+ }
147
+ }
148
+ /**
149
+ * Writes a packet to the transport.
150
+ *
151
+ * @param {Object} packet object
152
+ * @param {Object} opts
153
+ * @private
154
+ */
155
+ _packet(packet, opts = {}) {
156
+ if (this.conn.readyState !== "open") {
157
+ debug("ignoring packet write %j", packet);
158
+ return;
159
+ }
160
+ const encodedPackets = opts.preEncoded
161
+ ? packet // previous versions of the adapter incorrectly used socket.packet() instead of writeToEngine()
162
+ : this.encoder.encode(packet);
163
+ this.writeToEngine(encodedPackets, opts);
164
+ }
165
+ writeToEngine(encodedPackets, opts) {
166
+ if (opts.volatile && !this.conn.transport.writable) {
167
+ debug("volatile packet is discarded since the transport is not currently writable");
168
+ return;
169
+ }
170
+ const packets = Array.isArray(encodedPackets)
171
+ ? encodedPackets
172
+ : [encodedPackets];
173
+ for (const encodedPacket of packets) {
174
+ this.conn.write(encodedPacket, opts);
175
+ }
176
+ }
177
+ /**
178
+ * Called with incoming transport data.
179
+ *
180
+ * @private
181
+ */
182
+ ondata(data) {
183
+ // try/catch is needed for protocol violations (GH-1880)
184
+ try {
185
+ this.decoder.add(data);
186
+ }
187
+ catch (e) {
188
+ debug("invalid packet format");
189
+ this.onerror(e);
190
+ }
191
+ }
192
+ /**
193
+ * Called when parser fully decodes a packet.
194
+ *
195
+ * @private
196
+ */
197
+ ondecoded(packet) {
198
+ const { namespace, authPayload } = this._parseNamespace(packet);
199
+ const socket = this.nsps.get(namespace);
200
+ if (!socket && packet.type === socket_io_parser_1.PacketType.CONNECT) {
201
+ this.connect(namespace, authPayload);
202
+ }
203
+ else if (socket &&
204
+ packet.type !== socket_io_parser_1.PacketType.CONNECT &&
205
+ packet.type !== socket_io_parser_1.PacketType.CONNECT_ERROR) {
206
+ process.nextTick(function () {
207
+ socket._onpacket(packet);
208
+ });
209
+ }
210
+ else {
211
+ debug("invalid state (packet type: %s)", packet.type);
212
+ this.close();
213
+ }
214
+ }
215
+ _parseNamespace(packet) {
216
+ if (this.conn.protocol !== 3) {
217
+ return {
218
+ namespace: packet.nsp,
219
+ authPayload: packet.data,
220
+ };
221
+ }
222
+ const url = new URL(packet.nsp, "https://socket.io");
223
+ return {
224
+ namespace: url.pathname,
225
+ authPayload: Object.fromEntries(url.searchParams.entries()),
226
+ };
227
+ }
228
+ /**
229
+ * Handles an error.
230
+ *
231
+ * @param {Object} err object
232
+ * @private
233
+ */
234
+ onerror(err) {
235
+ for (const socket of this.sockets.values()) {
236
+ socket._onerror(err);
237
+ }
238
+ this.conn.close();
239
+ }
240
+ /**
241
+ * Called upon transport close.
242
+ *
243
+ * @param reason
244
+ * @param description
245
+ * @private
246
+ */
247
+ onclose(reason, description) {
248
+ debug("client close with reason %s", reason);
249
+ // ignore a potential subsequent `close` event
250
+ this.destroy();
251
+ // `nsps` and `sockets` are cleaned up seamlessly
252
+ for (const socket of this.sockets.values()) {
253
+ socket._onclose(reason, description);
254
+ }
255
+ this.sockets.clear();
256
+ this.decoder.destroy(); // clean up decoder
257
+ }
258
+ /**
259
+ * Cleans up event listeners.
260
+ * @private
261
+ */
262
+ destroy() {
263
+ this.conn.removeListener("data", this.ondata);
264
+ this.conn.removeListener("error", this.onerror);
265
+ this.conn.removeListener("close", this.onclose);
266
+ // @ts-ignore
267
+ this.decoder.removeListener("decoded", this.ondecoded);
268
+ if (this.connectTimeout) {
269
+ clearTimeout(this.connectTimeout);
270
+ this.connectTimeout = undefined;
271
+ }
272
+ }
273
+ }
274
+ exports.Client = Client;