@gleamkit/engine.io 6.6.3
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/LICENSE +19 -0
- package/README.md +603 -0
- package/build/engine.io.d.ts +26 -0
- package/build/engine.io.js +54 -0
- package/build/parser-v3/index.d.ts +94 -0
- package/build/parser-v3/index.js +424 -0
- package/build/parser-v3/utf8.d.ts +14 -0
- package/build/parser-v3/utf8.js +187 -0
- package/build/server.d.ts +267 -0
- package/build/server.js +786 -0
- package/build/socket.d.ts +180 -0
- package/build/socket.js +460 -0
- package/build/transport.d.ts +124 -0
- package/build/transport.js +117 -0
- package/build/transports/index.d.ts +16 -0
- package/build/transports/index.js +23 -0
- package/build/transports/polling-jsonp.d.ts +12 -0
- package/build/transports/polling-jsonp.js +41 -0
- package/build/transports/polling.d.ts +87 -0
- package/build/transports/polling.js +332 -0
- package/build/transports/websocket.d.ts +32 -0
- package/build/transports/websocket.js +94 -0
- package/build/transports/webtransport.d.ts +12 -0
- package/build/transports/webtransport.js +63 -0
- package/build/transports-uws/index.d.ts +7 -0
- package/build/transports-uws/index.js +8 -0
- package/build/transports-uws/polling.d.ts +99 -0
- package/build/transports-uws/polling.js +364 -0
- package/build/transports-uws/websocket.d.ts +32 -0
- package/build/transports-uws/websocket.js +73 -0
- package/build/userver.d.ts +42 -0
- package/build/userver.js +279 -0
- package/package.json +71 -0
- package/wrapper.mjs +10 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import type { IncomingMessage } from "http";
|
|
3
|
+
import type { EngineRequest, Transport } from "./transport";
|
|
4
|
+
import type { BaseServer } from "./server";
|
|
5
|
+
import type { RawData } from "engine.io-parser";
|
|
6
|
+
export interface SendOptions {
|
|
7
|
+
compress?: boolean;
|
|
8
|
+
}
|
|
9
|
+
type ReadyState = "opening" | "open" | "closing" | "closed";
|
|
10
|
+
type SendCallback = (transport: Transport) => void;
|
|
11
|
+
export declare class Socket extends EventEmitter {
|
|
12
|
+
/**
|
|
13
|
+
* The revision of the protocol:
|
|
14
|
+
*
|
|
15
|
+
* - 3rd is used in Engine.IO v3 / Socket.IO v2
|
|
16
|
+
* - 4th is used in Engine.IO v4 and above / Socket.IO v3 and above
|
|
17
|
+
*
|
|
18
|
+
* It is found in the `EIO` query parameters of the HTTP requests.
|
|
19
|
+
*
|
|
20
|
+
* @see https://github.com/socketio/engine.io-protocol
|
|
21
|
+
*/
|
|
22
|
+
readonly protocol: number;
|
|
23
|
+
/**
|
|
24
|
+
* A reference to the first HTTP request of the session
|
|
25
|
+
*
|
|
26
|
+
* TODO for the next major release: remove it
|
|
27
|
+
*/
|
|
28
|
+
request: IncomingMessage;
|
|
29
|
+
/**
|
|
30
|
+
* The IP address of the client.
|
|
31
|
+
*/
|
|
32
|
+
readonly remoteAddress: string;
|
|
33
|
+
/**
|
|
34
|
+
* The current state of the socket.
|
|
35
|
+
*/
|
|
36
|
+
_readyState: ReadyState;
|
|
37
|
+
/**
|
|
38
|
+
* The current low-level transport.
|
|
39
|
+
*/
|
|
40
|
+
transport: Transport;
|
|
41
|
+
private server;
|
|
42
|
+
upgrading: boolean;
|
|
43
|
+
upgraded: boolean;
|
|
44
|
+
private writeBuffer;
|
|
45
|
+
private packetsFn;
|
|
46
|
+
private sentCallbackFn;
|
|
47
|
+
private cleanupFn;
|
|
48
|
+
private pingTimeoutTimer;
|
|
49
|
+
private pingIntervalTimer;
|
|
50
|
+
/**
|
|
51
|
+
* This is the session identifier that the client will use in the subsequent HTTP requests. It must not be shared with
|
|
52
|
+
* others parties, as it might lead to session hijacking.
|
|
53
|
+
*
|
|
54
|
+
* @private
|
|
55
|
+
*/
|
|
56
|
+
private readonly id;
|
|
57
|
+
get readyState(): ReadyState;
|
|
58
|
+
set readyState(state: ReadyState);
|
|
59
|
+
constructor(id: string, server: BaseServer, transport: Transport, req: EngineRequest, protocol: number);
|
|
60
|
+
/**
|
|
61
|
+
* Called upon transport considered open.
|
|
62
|
+
*
|
|
63
|
+
* @private
|
|
64
|
+
*/
|
|
65
|
+
private onOpen;
|
|
66
|
+
/**
|
|
67
|
+
* Called upon transport packet.
|
|
68
|
+
*
|
|
69
|
+
* @param {Object} packet
|
|
70
|
+
* @private
|
|
71
|
+
*/
|
|
72
|
+
private onPacket;
|
|
73
|
+
/**
|
|
74
|
+
* Called upon transport error.
|
|
75
|
+
*
|
|
76
|
+
* @param {Error} err - error object
|
|
77
|
+
* @private
|
|
78
|
+
*/
|
|
79
|
+
private onError;
|
|
80
|
+
/**
|
|
81
|
+
* Pings client every `this.pingInterval` and expects response
|
|
82
|
+
* within `this.pingTimeout` or closes connection.
|
|
83
|
+
*
|
|
84
|
+
* @private
|
|
85
|
+
*/
|
|
86
|
+
private schedulePing;
|
|
87
|
+
/**
|
|
88
|
+
* Resets ping timeout.
|
|
89
|
+
*
|
|
90
|
+
* @private
|
|
91
|
+
*/
|
|
92
|
+
private resetPingTimeout;
|
|
93
|
+
/**
|
|
94
|
+
* Attaches handlers for the given transport.
|
|
95
|
+
*
|
|
96
|
+
* @param {Transport} transport
|
|
97
|
+
* @private
|
|
98
|
+
*/
|
|
99
|
+
private setTransport;
|
|
100
|
+
/**
|
|
101
|
+
* Upon transport "drain" event
|
|
102
|
+
*
|
|
103
|
+
* @private
|
|
104
|
+
*/
|
|
105
|
+
private onDrain;
|
|
106
|
+
/**
|
|
107
|
+
* Upgrades socket to the given transport
|
|
108
|
+
*
|
|
109
|
+
* @param {Transport} transport
|
|
110
|
+
* @private
|
|
111
|
+
*/
|
|
112
|
+
_maybeUpgrade(transport: Transport): void;
|
|
113
|
+
/**
|
|
114
|
+
* Clears listeners and timers associated with current transport.
|
|
115
|
+
*
|
|
116
|
+
* @private
|
|
117
|
+
*/
|
|
118
|
+
private clearTransport;
|
|
119
|
+
/**
|
|
120
|
+
* Called upon transport considered closed.
|
|
121
|
+
* Possible reasons: `ping timeout`, `client error`, `parse error`,
|
|
122
|
+
* `transport error`, `server close`, `transport close`
|
|
123
|
+
*/
|
|
124
|
+
private onClose;
|
|
125
|
+
/**
|
|
126
|
+
* Sends a message packet.
|
|
127
|
+
*
|
|
128
|
+
* @param {Object} data
|
|
129
|
+
* @param {Object} options
|
|
130
|
+
* @param {Function} callback
|
|
131
|
+
* @return {Socket} for chaining
|
|
132
|
+
*/
|
|
133
|
+
send(data: RawData, options?: SendOptions, callback?: SendCallback): this;
|
|
134
|
+
/**
|
|
135
|
+
* Alias of {@link send}.
|
|
136
|
+
*
|
|
137
|
+
* @param data
|
|
138
|
+
* @param options
|
|
139
|
+
* @param callback
|
|
140
|
+
*/
|
|
141
|
+
write(data: RawData, options?: SendOptions, callback?: SendCallback): this;
|
|
142
|
+
/**
|
|
143
|
+
* Sends a packet.
|
|
144
|
+
*
|
|
145
|
+
* @param {String} type - packet type
|
|
146
|
+
* @param {String} data
|
|
147
|
+
* @param {Object} options
|
|
148
|
+
* @param {Function} callback
|
|
149
|
+
*
|
|
150
|
+
* @private
|
|
151
|
+
*/
|
|
152
|
+
private sendPacket;
|
|
153
|
+
/**
|
|
154
|
+
* Attempts to flush the packets buffer.
|
|
155
|
+
*
|
|
156
|
+
* @private
|
|
157
|
+
*/
|
|
158
|
+
private flush;
|
|
159
|
+
/**
|
|
160
|
+
* Get available upgrades for this socket.
|
|
161
|
+
*
|
|
162
|
+
* @private
|
|
163
|
+
*/
|
|
164
|
+
private getAvailableUpgrades;
|
|
165
|
+
/**
|
|
166
|
+
* Closes the socket and underlying transport.
|
|
167
|
+
*
|
|
168
|
+
* @param {Boolean} discard - optional, discard the transport
|
|
169
|
+
* @return {Socket} for chaining
|
|
170
|
+
*/
|
|
171
|
+
close(discard?: boolean): void;
|
|
172
|
+
/**
|
|
173
|
+
* Closes the underlying transport.
|
|
174
|
+
*
|
|
175
|
+
* @param {Boolean} discard
|
|
176
|
+
* @private
|
|
177
|
+
*/
|
|
178
|
+
private closeTransport;
|
|
179
|
+
}
|
|
180
|
+
export {};
|
package/build/socket.js
ADDED
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Socket = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
5
|
+
const debug_1 = require("debug");
|
|
6
|
+
const timers_1 = require("timers");
|
|
7
|
+
const debug = (0, debug_1.default)("engine:socket");
|
|
8
|
+
class Socket extends events_1.EventEmitter {
|
|
9
|
+
get readyState() {
|
|
10
|
+
return this._readyState;
|
|
11
|
+
}
|
|
12
|
+
set readyState(state) {
|
|
13
|
+
debug("readyState updated from %s to %s", this._readyState, state);
|
|
14
|
+
this._readyState = state;
|
|
15
|
+
}
|
|
16
|
+
constructor(id, server, transport, req, protocol) {
|
|
17
|
+
super();
|
|
18
|
+
/**
|
|
19
|
+
* The current state of the socket.
|
|
20
|
+
*/
|
|
21
|
+
this._readyState = "opening";
|
|
22
|
+
/* private */ this.upgrading = false;
|
|
23
|
+
/* private */ this.upgraded = false;
|
|
24
|
+
this.writeBuffer = [];
|
|
25
|
+
this.packetsFn = [];
|
|
26
|
+
this.sentCallbackFn = [];
|
|
27
|
+
this.cleanupFn = [];
|
|
28
|
+
this.id = id;
|
|
29
|
+
this.server = server;
|
|
30
|
+
this.request = req;
|
|
31
|
+
this.protocol = protocol;
|
|
32
|
+
// Cache IP since it might not be in the req later
|
|
33
|
+
if (req) {
|
|
34
|
+
if (req.websocket && req.websocket._socket) {
|
|
35
|
+
this.remoteAddress = req.websocket._socket.remoteAddress;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
this.remoteAddress = req.connection.remoteAddress;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// TODO there is currently no way to get the IP address of the client when it connects with WebTransport
|
|
43
|
+
// see https://github.com/fails-components/webtransport/issues/114
|
|
44
|
+
}
|
|
45
|
+
this.pingTimeoutTimer = null;
|
|
46
|
+
this.pingIntervalTimer = null;
|
|
47
|
+
this.setTransport(transport);
|
|
48
|
+
this.onOpen();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Called upon transport considered open.
|
|
52
|
+
*
|
|
53
|
+
* @private
|
|
54
|
+
*/
|
|
55
|
+
onOpen() {
|
|
56
|
+
this.readyState = "open";
|
|
57
|
+
// sends an `open` packet
|
|
58
|
+
this.transport.sid = this.id;
|
|
59
|
+
this.sendPacket("open", JSON.stringify({
|
|
60
|
+
sid: this.id,
|
|
61
|
+
upgrades: this.getAvailableUpgrades(),
|
|
62
|
+
pingInterval: this.server.opts.pingInterval,
|
|
63
|
+
pingTimeout: this.server.opts.pingTimeout,
|
|
64
|
+
maxPayload: this.server.opts.maxHttpBufferSize,
|
|
65
|
+
}));
|
|
66
|
+
if (this.server.opts.initialPacket) {
|
|
67
|
+
this.sendPacket("message", this.server.opts.initialPacket);
|
|
68
|
+
}
|
|
69
|
+
this.emit("open");
|
|
70
|
+
if (this.protocol === 3) {
|
|
71
|
+
// in protocol v3, the client sends a ping, and the server answers with a pong
|
|
72
|
+
this.resetPingTimeout();
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// in protocol v4, the server sends a ping, and the client answers with a pong
|
|
76
|
+
this.schedulePing();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Called upon transport packet.
|
|
81
|
+
*
|
|
82
|
+
* @param {Object} packet
|
|
83
|
+
* @private
|
|
84
|
+
*/
|
|
85
|
+
onPacket(packet) {
|
|
86
|
+
if ("open" !== this.readyState) {
|
|
87
|
+
return debug("packet received with closed socket");
|
|
88
|
+
}
|
|
89
|
+
// export packet event
|
|
90
|
+
debug(`received packet ${packet.type}`);
|
|
91
|
+
this.emit("packet", packet);
|
|
92
|
+
switch (packet.type) {
|
|
93
|
+
case "ping":
|
|
94
|
+
if (this.transport.protocol !== 3) {
|
|
95
|
+
this.onError(new Error("invalid heartbeat direction"));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
debug("got ping");
|
|
99
|
+
this.pingTimeoutTimer.refresh();
|
|
100
|
+
this.sendPacket("pong");
|
|
101
|
+
this.emit("heartbeat");
|
|
102
|
+
break;
|
|
103
|
+
case "pong":
|
|
104
|
+
if (this.transport.protocol === 3) {
|
|
105
|
+
this.onError(new Error("invalid heartbeat direction"));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
debug("got pong");
|
|
109
|
+
(0, timers_1.clearTimeout)(this.pingTimeoutTimer);
|
|
110
|
+
this.pingIntervalTimer.refresh();
|
|
111
|
+
this.emit("heartbeat");
|
|
112
|
+
break;
|
|
113
|
+
case "error":
|
|
114
|
+
this.onClose("parse error");
|
|
115
|
+
break;
|
|
116
|
+
case "message":
|
|
117
|
+
this.emit("data", packet.data);
|
|
118
|
+
this.emit("message", packet.data);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Called upon transport error.
|
|
124
|
+
*
|
|
125
|
+
* @param {Error} err - error object
|
|
126
|
+
* @private
|
|
127
|
+
*/
|
|
128
|
+
onError(err) {
|
|
129
|
+
debug("transport error");
|
|
130
|
+
this.onClose("transport error", err);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Pings client every `this.pingInterval` and expects response
|
|
134
|
+
* within `this.pingTimeout` or closes connection.
|
|
135
|
+
*
|
|
136
|
+
* @private
|
|
137
|
+
*/
|
|
138
|
+
schedulePing() {
|
|
139
|
+
this.pingIntervalTimer = (0, timers_1.setTimeout)(() => {
|
|
140
|
+
debug("writing ping packet - expecting pong within %sms", this.server.opts.pingTimeout);
|
|
141
|
+
this.sendPacket("ping");
|
|
142
|
+
this.resetPingTimeout();
|
|
143
|
+
}, this.server.opts.pingInterval);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Resets ping timeout.
|
|
147
|
+
*
|
|
148
|
+
* @private
|
|
149
|
+
*/
|
|
150
|
+
resetPingTimeout() {
|
|
151
|
+
(0, timers_1.clearTimeout)(this.pingTimeoutTimer);
|
|
152
|
+
this.pingTimeoutTimer = (0, timers_1.setTimeout)(() => {
|
|
153
|
+
if (this.readyState === "closed")
|
|
154
|
+
return;
|
|
155
|
+
this.onClose("ping timeout");
|
|
156
|
+
}, this.protocol === 3
|
|
157
|
+
? this.server.opts.pingInterval + this.server.opts.pingTimeout
|
|
158
|
+
: this.server.opts.pingTimeout);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Attaches handlers for the given transport.
|
|
162
|
+
*
|
|
163
|
+
* @param {Transport} transport
|
|
164
|
+
* @private
|
|
165
|
+
*/
|
|
166
|
+
setTransport(transport) {
|
|
167
|
+
const onError = this.onError.bind(this);
|
|
168
|
+
const onReady = () => this.flush();
|
|
169
|
+
const onPacket = this.onPacket.bind(this);
|
|
170
|
+
const onDrain = this.onDrain.bind(this);
|
|
171
|
+
const onClose = this.onClose.bind(this, "transport close");
|
|
172
|
+
this.transport = transport;
|
|
173
|
+
this.transport.once("error", onError);
|
|
174
|
+
this.transport.on("ready", onReady);
|
|
175
|
+
this.transport.on("packet", onPacket);
|
|
176
|
+
this.transport.on("drain", onDrain);
|
|
177
|
+
this.transport.once("close", onClose);
|
|
178
|
+
this.cleanupFn.push(function () {
|
|
179
|
+
transport.removeListener("error", onError);
|
|
180
|
+
transport.removeListener("ready", onReady);
|
|
181
|
+
transport.removeListener("packet", onPacket);
|
|
182
|
+
transport.removeListener("drain", onDrain);
|
|
183
|
+
transport.removeListener("close", onClose);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Upon transport "drain" event
|
|
188
|
+
*
|
|
189
|
+
* @private
|
|
190
|
+
*/
|
|
191
|
+
onDrain() {
|
|
192
|
+
if (this.sentCallbackFn.length > 0) {
|
|
193
|
+
debug("executing batch send callback");
|
|
194
|
+
const seqFn = this.sentCallbackFn.shift();
|
|
195
|
+
if (seqFn) {
|
|
196
|
+
for (let i = 0; i < seqFn.length; i++) {
|
|
197
|
+
seqFn[i](this.transport);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Upgrades socket to the given transport
|
|
204
|
+
*
|
|
205
|
+
* @param {Transport} transport
|
|
206
|
+
* @private
|
|
207
|
+
*/
|
|
208
|
+
/* private */ _maybeUpgrade(transport) {
|
|
209
|
+
debug('might upgrade socket transport from "%s" to "%s"', this.transport.name, transport.name);
|
|
210
|
+
this.upgrading = true;
|
|
211
|
+
// set transport upgrade timer
|
|
212
|
+
const upgradeTimeoutTimer = (0, timers_1.setTimeout)(() => {
|
|
213
|
+
debug("client did not complete upgrade - closing transport");
|
|
214
|
+
cleanup();
|
|
215
|
+
if ("open" === transport.readyState) {
|
|
216
|
+
transport.close();
|
|
217
|
+
}
|
|
218
|
+
}, this.server.opts.upgradeTimeout);
|
|
219
|
+
let checkIntervalTimer;
|
|
220
|
+
const onPacket = (packet) => {
|
|
221
|
+
if ("ping" === packet.type && "probe" === packet.data) {
|
|
222
|
+
debug("got probe ping packet, sending pong");
|
|
223
|
+
transport.send([{ type: "pong", data: "probe" }]);
|
|
224
|
+
this.emit("upgrading", transport);
|
|
225
|
+
clearInterval(checkIntervalTimer);
|
|
226
|
+
checkIntervalTimer = setInterval(check, 100);
|
|
227
|
+
}
|
|
228
|
+
else if ("upgrade" === packet.type && this.readyState !== "closed") {
|
|
229
|
+
debug("got upgrade packet - upgrading");
|
|
230
|
+
cleanup();
|
|
231
|
+
this.transport.discard();
|
|
232
|
+
this.upgraded = true;
|
|
233
|
+
this.clearTransport();
|
|
234
|
+
this.setTransport(transport);
|
|
235
|
+
this.emit("upgrade", transport);
|
|
236
|
+
this.flush();
|
|
237
|
+
if (this.readyState === "closing") {
|
|
238
|
+
transport.close(() => {
|
|
239
|
+
this.onClose("forced close");
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
cleanup();
|
|
245
|
+
transport.close();
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
// we force a polling cycle to ensure a fast upgrade
|
|
249
|
+
const check = () => {
|
|
250
|
+
if ("polling" === this.transport.name && this.transport.writable) {
|
|
251
|
+
debug("writing a noop packet to polling for fast upgrade");
|
|
252
|
+
this.transport.send([{ type: "noop" }]);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
const cleanup = () => {
|
|
256
|
+
this.upgrading = false;
|
|
257
|
+
clearInterval(checkIntervalTimer);
|
|
258
|
+
(0, timers_1.clearTimeout)(upgradeTimeoutTimer);
|
|
259
|
+
transport.removeListener("packet", onPacket);
|
|
260
|
+
transport.removeListener("close", onTransportClose);
|
|
261
|
+
transport.removeListener("error", onError);
|
|
262
|
+
this.removeListener("close", onClose);
|
|
263
|
+
};
|
|
264
|
+
const onError = (err) => {
|
|
265
|
+
debug("client did not complete upgrade - %s", err);
|
|
266
|
+
cleanup();
|
|
267
|
+
transport.close();
|
|
268
|
+
transport = null;
|
|
269
|
+
};
|
|
270
|
+
const onTransportClose = () => {
|
|
271
|
+
onError("transport closed");
|
|
272
|
+
};
|
|
273
|
+
const onClose = () => {
|
|
274
|
+
onError("socket closed");
|
|
275
|
+
};
|
|
276
|
+
transport.on("packet", onPacket);
|
|
277
|
+
transport.once("close", onTransportClose);
|
|
278
|
+
transport.once("error", onError);
|
|
279
|
+
this.once("close", onClose);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Clears listeners and timers associated with current transport.
|
|
283
|
+
*
|
|
284
|
+
* @private
|
|
285
|
+
*/
|
|
286
|
+
clearTransport() {
|
|
287
|
+
let cleanup;
|
|
288
|
+
const toCleanUp = this.cleanupFn.length;
|
|
289
|
+
for (let i = 0; i < toCleanUp; i++) {
|
|
290
|
+
cleanup = this.cleanupFn.shift();
|
|
291
|
+
cleanup();
|
|
292
|
+
}
|
|
293
|
+
// silence further transport errors and prevent uncaught exceptions
|
|
294
|
+
this.transport.on("error", function () {
|
|
295
|
+
debug("error triggered by discarded transport");
|
|
296
|
+
});
|
|
297
|
+
// ensure transport won't stay open
|
|
298
|
+
this.transport.close();
|
|
299
|
+
(0, timers_1.clearTimeout)(this.pingTimeoutTimer);
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Called upon transport considered closed.
|
|
303
|
+
* Possible reasons: `ping timeout`, `client error`, `parse error`,
|
|
304
|
+
* `transport error`, `server close`, `transport close`
|
|
305
|
+
*/
|
|
306
|
+
onClose(reason, description) {
|
|
307
|
+
if ("closed" !== this.readyState) {
|
|
308
|
+
this.readyState = "closed";
|
|
309
|
+
// clear timers
|
|
310
|
+
(0, timers_1.clearTimeout)(this.pingIntervalTimer);
|
|
311
|
+
(0, timers_1.clearTimeout)(this.pingTimeoutTimer);
|
|
312
|
+
// clean writeBuffer in next tick, so developers can still
|
|
313
|
+
// grab the writeBuffer on 'close' event
|
|
314
|
+
process.nextTick(() => {
|
|
315
|
+
this.writeBuffer = [];
|
|
316
|
+
});
|
|
317
|
+
this.packetsFn = [];
|
|
318
|
+
this.sentCallbackFn = [];
|
|
319
|
+
this.clearTransport();
|
|
320
|
+
this.emit("close", reason, description);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Sends a message packet.
|
|
325
|
+
*
|
|
326
|
+
* @param {Object} data
|
|
327
|
+
* @param {Object} options
|
|
328
|
+
* @param {Function} callback
|
|
329
|
+
* @return {Socket} for chaining
|
|
330
|
+
*/
|
|
331
|
+
send(data, options, callback) {
|
|
332
|
+
this.sendPacket("message", data, options, callback);
|
|
333
|
+
return this;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Alias of {@link send}.
|
|
337
|
+
*
|
|
338
|
+
* @param data
|
|
339
|
+
* @param options
|
|
340
|
+
* @param callback
|
|
341
|
+
*/
|
|
342
|
+
write(data, options, callback) {
|
|
343
|
+
this.sendPacket("message", data, options, callback);
|
|
344
|
+
return this;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Sends a packet.
|
|
348
|
+
*
|
|
349
|
+
* @param {String} type - packet type
|
|
350
|
+
* @param {String} data
|
|
351
|
+
* @param {Object} options
|
|
352
|
+
* @param {Function} callback
|
|
353
|
+
*
|
|
354
|
+
* @private
|
|
355
|
+
*/
|
|
356
|
+
sendPacket(type, data, options = {}, callback) {
|
|
357
|
+
if ("function" === typeof options) {
|
|
358
|
+
callback = options;
|
|
359
|
+
options = {};
|
|
360
|
+
}
|
|
361
|
+
if ("closing" !== this.readyState && "closed" !== this.readyState) {
|
|
362
|
+
debug('sending packet "%s" (%s)', type, data);
|
|
363
|
+
// compression is enabled by default
|
|
364
|
+
options.compress = options.compress !== false;
|
|
365
|
+
const packet = {
|
|
366
|
+
type,
|
|
367
|
+
options: options,
|
|
368
|
+
};
|
|
369
|
+
if (data)
|
|
370
|
+
packet.data = data;
|
|
371
|
+
// exports packetCreate event
|
|
372
|
+
this.emit("packetCreate", packet);
|
|
373
|
+
this.writeBuffer.push(packet);
|
|
374
|
+
// add send callback to object, if defined
|
|
375
|
+
if ("function" === typeof callback)
|
|
376
|
+
this.packetsFn.push(callback);
|
|
377
|
+
this.flush();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Attempts to flush the packets buffer.
|
|
382
|
+
*
|
|
383
|
+
* @private
|
|
384
|
+
*/
|
|
385
|
+
flush() {
|
|
386
|
+
if ("closed" !== this.readyState &&
|
|
387
|
+
this.transport.writable &&
|
|
388
|
+
this.writeBuffer.length) {
|
|
389
|
+
debug("flushing buffer to transport");
|
|
390
|
+
this.emit("flush", this.writeBuffer);
|
|
391
|
+
this.server.emit("flush", this, this.writeBuffer);
|
|
392
|
+
const wbuf = this.writeBuffer;
|
|
393
|
+
this.writeBuffer = [];
|
|
394
|
+
if (this.packetsFn.length) {
|
|
395
|
+
this.sentCallbackFn.push(this.packetsFn);
|
|
396
|
+
this.packetsFn = [];
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
this.sentCallbackFn.push(null);
|
|
400
|
+
}
|
|
401
|
+
this.transport.send(wbuf);
|
|
402
|
+
this.emit("drain");
|
|
403
|
+
this.server.emit("drain", this);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Get available upgrades for this socket.
|
|
408
|
+
*
|
|
409
|
+
* @private
|
|
410
|
+
*/
|
|
411
|
+
getAvailableUpgrades() {
|
|
412
|
+
const availableUpgrades = [];
|
|
413
|
+
const allUpgrades = this.server.upgrades(this.transport.name);
|
|
414
|
+
for (let i = 0; i < allUpgrades.length; ++i) {
|
|
415
|
+
const upg = allUpgrades[i];
|
|
416
|
+
if (this.server.opts.transports.indexOf(upg) !== -1) {
|
|
417
|
+
availableUpgrades.push(upg);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return availableUpgrades;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Closes the socket and underlying transport.
|
|
424
|
+
*
|
|
425
|
+
* @param {Boolean} discard - optional, discard the transport
|
|
426
|
+
* @return {Socket} for chaining
|
|
427
|
+
*/
|
|
428
|
+
close(discard) {
|
|
429
|
+
if (discard &&
|
|
430
|
+
(this.readyState === "open" || this.readyState === "closing")) {
|
|
431
|
+
return this.closeTransport(discard);
|
|
432
|
+
}
|
|
433
|
+
if ("open" !== this.readyState)
|
|
434
|
+
return;
|
|
435
|
+
this.readyState = "closing";
|
|
436
|
+
if (this.writeBuffer.length) {
|
|
437
|
+
debug("there are %d remaining packets in the buffer, waiting for the 'drain' event", this.writeBuffer.length);
|
|
438
|
+
this.once("drain", () => {
|
|
439
|
+
debug("all packets have been sent, closing the transport");
|
|
440
|
+
this.closeTransport(discard);
|
|
441
|
+
});
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
debug("the buffer is empty, closing the transport right away");
|
|
445
|
+
this.closeTransport(discard);
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Closes the underlying transport.
|
|
449
|
+
*
|
|
450
|
+
* @param {Boolean} discard
|
|
451
|
+
* @private
|
|
452
|
+
*/
|
|
453
|
+
closeTransport(discard) {
|
|
454
|
+
debug("closing the transport (discard? %s)", !!discard);
|
|
455
|
+
if (discard)
|
|
456
|
+
this.transport.discard();
|
|
457
|
+
this.transport.close(this.onClose.bind(this, "forced close"));
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
exports.Socket = Socket;
|