@depup/primus 8.0.9-depup.0
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 +22 -0
- package/README.md +36 -0
- package/changes.json +30 -0
- package/dist/primus.js +3663 -0
- package/errors.js +51 -0
- package/index.js +1153 -0
- package/middleware/access-control.js +20 -0
- package/middleware/authorization.js +57 -0
- package/middleware/error.js +41 -0
- package/middleware/forwarded.js +18 -0
- package/middleware/no-cache.js +25 -0
- package/middleware/primus.js +47 -0
- package/middleware/spec.js +36 -0
- package/middleware/xss.js +28 -0
- package/package.json +140 -0
- package/parsers/binary.js +54 -0
- package/parsers/ejson.js +41 -0
- package/parsers/json.js +35 -0
- package/parsers/msgpack.js +55 -0
- package/parsers.json +12 -0
- package/primus.js +1158 -0
- package/spark.js +515 -0
- package/transformer.js +237 -0
- package/transformers/browserchannel/client.js +92 -0
- package/transformers/browserchannel/index.js +19 -0
- package/transformers/browserchannel/server.js +64 -0
- package/transformers/engine.io/README.md +34 -0
- package/transformers/engine.io/client.js +111 -0
- package/transformers/engine.io/index.js +15 -0
- package/transformers/engine.io/library.js +2273 -0
- package/transformers/engine.io/server.js +63 -0
- package/transformers/faye/client.js +103 -0
- package/transformers/faye/index.js +12 -0
- package/transformers/faye/server.js +85 -0
- package/transformers/sockjs/README.md +31 -0
- package/transformers/sockjs/client.js +86 -0
- package/transformers/sockjs/index.js +15 -0
- package/transformers/sockjs/library.js +4201 -0
- package/transformers/sockjs/server.js +108 -0
- package/transformers/uws/index.js +12 -0
- package/transformers/uws/server.js +131 -0
- package/transformers/websockets/client.js +112 -0
- package/transformers/websockets/index.js +12 -0
- package/transformers/websockets/server.js +77 -0
- package/transformers.json +26 -0
package/spark.js
ADDED
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var ParserError = require('./errors').ParserError
|
|
4
|
+
, log = require('diagnostics')('primus:spark')
|
|
5
|
+
, parse = require('querystring').parse
|
|
6
|
+
, forwarded = require('forwarded-for')
|
|
7
|
+
, nanoid = require('nanoid').nanoid
|
|
8
|
+
, Ultron = require('ultron')
|
|
9
|
+
, fuse = require('fusing')
|
|
10
|
+
, u2028 = /\u2028/g
|
|
11
|
+
, u2029 = /\u2029/g;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The Spark is an indefinable, indescribable energy or soul of a transformer
|
|
15
|
+
* which can be used to create new transformers. In our case, it's a simple
|
|
16
|
+
* wrapping interface.
|
|
17
|
+
*
|
|
18
|
+
* @constructor
|
|
19
|
+
* @param {Primus} primus Reference to the Primus server. (Set using .bind)
|
|
20
|
+
* @param {Object} headers The request headers for this connection.
|
|
21
|
+
* @param {Object} address The object that holds the remoteAddress and port.
|
|
22
|
+
* @param {Object} query The query string of request.
|
|
23
|
+
* @param {String} id An optional id of the socket, or we will generate one.
|
|
24
|
+
* @param {Request} request The HTTP Request instance that initialised the spark.
|
|
25
|
+
* @param {Mixed} socket Reference to the transformer socket.
|
|
26
|
+
* @api public
|
|
27
|
+
*/
|
|
28
|
+
function Spark(primus, headers, address, query, id, request, socket) {
|
|
29
|
+
this.fuse();
|
|
30
|
+
|
|
31
|
+
var writable = this.writable
|
|
32
|
+
, spark = this
|
|
33
|
+
, idgen = primus.options.idGenerator;
|
|
34
|
+
|
|
35
|
+
query = query || {};
|
|
36
|
+
id = idgen ? idgen() : (id || nanoid());
|
|
37
|
+
headers = headers || {};
|
|
38
|
+
address = address || {};
|
|
39
|
+
request = request || headers['primus::req::backup'];
|
|
40
|
+
|
|
41
|
+
writable('id', id); // Unique id for socket.
|
|
42
|
+
writable('primus', primus); // References to Primus.
|
|
43
|
+
writable('remote', address); // The remote address location.
|
|
44
|
+
writable('headers', headers); // The request headers.
|
|
45
|
+
writable('request', request); // Reference to an HTTP request.
|
|
46
|
+
writable('socket', socket); // Reference to the transformer's socket
|
|
47
|
+
writable('writable', true); // Silly stream compatibility.
|
|
48
|
+
writable('readable', true); // Silly stream compatibility.
|
|
49
|
+
writable('queue', []); // Data queue for data events.
|
|
50
|
+
writable('query', query); // The query string.
|
|
51
|
+
writable('ultron', new Ultron(this)); // Our event listening cleanup.
|
|
52
|
+
writable('alive', true); // Flag used to detect zombie sparks.
|
|
53
|
+
|
|
54
|
+
//
|
|
55
|
+
// Parse our query string.
|
|
56
|
+
//
|
|
57
|
+
if ('string' === typeof this.query) {
|
|
58
|
+
this.query = parse(this.query);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.__initialise.forEach(function execute(initialise) {
|
|
62
|
+
initialise.call(spark);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
fuse(Spark, require('stream'), { merge: false, mixin: false });
|
|
67
|
+
|
|
68
|
+
//
|
|
69
|
+
// Internal readyState's to prevent writes against close sockets.
|
|
70
|
+
//
|
|
71
|
+
Spark.OPENING = 1; // Only here for primus.js readyState number compatibility.
|
|
72
|
+
Spark.CLOSED = 2; // The connection is closed.
|
|
73
|
+
Spark.OPEN = 3; // The connection is open.
|
|
74
|
+
|
|
75
|
+
//
|
|
76
|
+
// Make sure that we emit `readyState` change events when a new readyState is
|
|
77
|
+
// checked. This way plugins can correctly act according to this.
|
|
78
|
+
//
|
|
79
|
+
Spark.readable('readyState', {
|
|
80
|
+
get: function get() {
|
|
81
|
+
return this.__readyState;
|
|
82
|
+
},
|
|
83
|
+
set: function set(readyState) {
|
|
84
|
+
if (this.__readyState === readyState) return readyState;
|
|
85
|
+
|
|
86
|
+
this.__readyState = readyState;
|
|
87
|
+
this.emit('readyStateChange');
|
|
88
|
+
|
|
89
|
+
return readyState;
|
|
90
|
+
}
|
|
91
|
+
}, true);
|
|
92
|
+
|
|
93
|
+
Spark.writable('__readyState', Spark.OPEN);
|
|
94
|
+
|
|
95
|
+
//
|
|
96
|
+
// Lazy parse interface for IP address information. As nobody is always
|
|
97
|
+
// interested in this, we're going to defer parsing until it's actually needed.
|
|
98
|
+
//
|
|
99
|
+
Spark.get('address', function address() {
|
|
100
|
+
return this.request.forwarded || forwarded(this.remote, this.headers, this.primus.whitelist);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Checks if the given event is an emitted event by Primus.
|
|
105
|
+
*
|
|
106
|
+
* @param {String} evt The event name.
|
|
107
|
+
* @returns {Boolean}
|
|
108
|
+
* @api public
|
|
109
|
+
*/
|
|
110
|
+
Spark.readable('reserved', function reserved(evt) {
|
|
111
|
+
return (/^(incoming|outgoing)::/).test(evt)
|
|
112
|
+
|| evt in reserved.events;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The actual events that are used by the Spark.
|
|
117
|
+
*
|
|
118
|
+
* @type {Object}
|
|
119
|
+
* @api public
|
|
120
|
+
*/
|
|
121
|
+
Spark.prototype.reserved.events = {
|
|
122
|
+
readyStateChange: 1,
|
|
123
|
+
heartbeat: 1,
|
|
124
|
+
error: 1,
|
|
125
|
+
data: 1,
|
|
126
|
+
end: 1
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Allows for adding initialise listeners without people overriding our default
|
|
131
|
+
* initializer. If they are feeling adventures and really want want to hack it
|
|
132
|
+
* up, they can remove it from the __initialise array.
|
|
133
|
+
*
|
|
134
|
+
* @returns {Function} The last added initialise hook.
|
|
135
|
+
* @api public
|
|
136
|
+
*/
|
|
137
|
+
Spark.readable('initialise', {
|
|
138
|
+
get: function get() {
|
|
139
|
+
return this.__initialise[this.__initialise.length - 1];
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
set: function set(initialise) {
|
|
143
|
+
if ('function' === typeof initialise) this.__initialise.push(initialise);
|
|
144
|
+
}
|
|
145
|
+
}, true);
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Send a heartbeat to the client.
|
|
149
|
+
*
|
|
150
|
+
* Checks if any message has been received from the client before sending
|
|
151
|
+
* another heartbeat. If not, we can assume it's dead (no response to our last
|
|
152
|
+
* ping), so we should close.
|
|
153
|
+
*
|
|
154
|
+
* This is intentionally writable so it can be overwritten for custom heartbeat
|
|
155
|
+
* policies.
|
|
156
|
+
*
|
|
157
|
+
* @returns {undefined}
|
|
158
|
+
* @api public
|
|
159
|
+
*/
|
|
160
|
+
Spark.writable('heartbeat', function heartbeat() {
|
|
161
|
+
var spark = this;
|
|
162
|
+
if (!spark.alive) {
|
|
163
|
+
//
|
|
164
|
+
// Set the `reconnect` option to `true` so we don't send a
|
|
165
|
+
// `primus::server::close` packet to an already broken connection.
|
|
166
|
+
//
|
|
167
|
+
spark.end(undefined, { reconnect: true });
|
|
168
|
+
} else {
|
|
169
|
+
const now = Date.now();
|
|
170
|
+
|
|
171
|
+
spark.alive = false;
|
|
172
|
+
spark.emit('outgoing::ping', now);
|
|
173
|
+
spark._write(`primus::ping::${now}`);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Attach hooks and automatically announce a new connection.
|
|
179
|
+
*
|
|
180
|
+
* @type {Array}
|
|
181
|
+
* @api private
|
|
182
|
+
*/
|
|
183
|
+
Spark.readable('__initialise', [function initialise() {
|
|
184
|
+
var primus = this.primus
|
|
185
|
+
, ultron = this.ultron
|
|
186
|
+
, spark = this;
|
|
187
|
+
|
|
188
|
+
//
|
|
189
|
+
// Prevent double initialization of the spark. If we already have an
|
|
190
|
+
// `incoming::data` handler we assume that all other cases are handled as well.
|
|
191
|
+
//
|
|
192
|
+
if (this.listeners('incoming::data').length) {
|
|
193
|
+
return log('already has incoming::data listeners, bailing out');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
//
|
|
197
|
+
// We've received new data from our client, decode and emit it.
|
|
198
|
+
//
|
|
199
|
+
ultron.on('incoming::data', function message(raw) {
|
|
200
|
+
primus.decoder.call(spark, raw, function decoding(err, data) {
|
|
201
|
+
//
|
|
202
|
+
// Do a "save" emit('error') when we fail to parse a message. We don't
|
|
203
|
+
// want to throw here as listening to errors should be optional.
|
|
204
|
+
//
|
|
205
|
+
if (err) {
|
|
206
|
+
log('failed to decode the incoming data for %s', spark.id);
|
|
207
|
+
return new ParserError('Failed to decode incoming data: '+ err.message, spark, err);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
//
|
|
211
|
+
// Handle "primus::" prefixed protocol messages.
|
|
212
|
+
//
|
|
213
|
+
if (spark.protocol(data)) return;
|
|
214
|
+
|
|
215
|
+
spark.transforms(primus, spark, 'incoming', data, raw);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
//
|
|
220
|
+
// We've received a pong event. This is fired upon receipt of a
|
|
221
|
+
// `pimus::pong::<timestamp>` message.
|
|
222
|
+
//
|
|
223
|
+
ultron.on('incoming::pong', function pong() {
|
|
224
|
+
spark.alive = true;
|
|
225
|
+
spark.emit('heartbeat');
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
//
|
|
229
|
+
// The client has disconnected.
|
|
230
|
+
//
|
|
231
|
+
ultron.on('incoming::end', function disconnect() {
|
|
232
|
+
//
|
|
233
|
+
// The socket is closed, sending data over it will throw an error.
|
|
234
|
+
//
|
|
235
|
+
log('transformer closed connection for %s', spark.id);
|
|
236
|
+
spark.end(undefined, { reconnect: true });
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
ultron.on('incoming::error', function error(err) {
|
|
240
|
+
//
|
|
241
|
+
// Ensure that the error we emit is always an Error instance. There are
|
|
242
|
+
// transformers that used to emit only strings. A string is not an Error.
|
|
243
|
+
//
|
|
244
|
+
if ('string' === typeof err) {
|
|
245
|
+
err = new Error(err);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (spark.listeners('error').length) spark.emit('error', err);
|
|
249
|
+
spark.primus.emit('log', 'error', err);
|
|
250
|
+
|
|
251
|
+
log('transformer received error `%s` for %s', err.message, spark.id);
|
|
252
|
+
spark.end();
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
//
|
|
256
|
+
// End is triggered by both incoming and outgoing events.
|
|
257
|
+
//
|
|
258
|
+
ultron.on('end', function end() {
|
|
259
|
+
primus.emit('disconnection', spark);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
//
|
|
263
|
+
// Announce a new connection. This allows the transformers to change or listen
|
|
264
|
+
// to events before we announce it.
|
|
265
|
+
//
|
|
266
|
+
process.nextTick(function tick() {
|
|
267
|
+
primus.asyncemit('connection', spark, function damn(err) {
|
|
268
|
+
if (!err) {
|
|
269
|
+
if (spark.queue) spark.queue.forEach(function each(packet) {
|
|
270
|
+
spark.emit('data', packet.data, packet.raw);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
spark.queue = null;
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
spark.emit('incoming::error', err);
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
}]);
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Execute the set of message transformers from Primus on the incoming or
|
|
284
|
+
* outgoing message.
|
|
285
|
+
* This function and it's content should be in sync with Primus#transforms in
|
|
286
|
+
* primus.js.
|
|
287
|
+
*
|
|
288
|
+
* @param {Primus} primus Reference to the Primus instance with message transformers.
|
|
289
|
+
* @param {Spark|Primus} connection Connection that receives or sends data.
|
|
290
|
+
* @param {String} type The type of message, 'incoming' or 'outgoing'.
|
|
291
|
+
* @param {Mixed} data The data to send or that has been received.
|
|
292
|
+
* @param {String} raw The raw encoded data.
|
|
293
|
+
* @returns {Spark}
|
|
294
|
+
* @api public
|
|
295
|
+
*/
|
|
296
|
+
Spark.readable('transforms', function transforms(primus, connection, type, data, raw) {
|
|
297
|
+
var packet = { data: data, raw: raw }
|
|
298
|
+
, fns = primus.transformers[type];
|
|
299
|
+
|
|
300
|
+
//
|
|
301
|
+
// Iterate in series over the message transformers so we can allow optional
|
|
302
|
+
// asynchronous execution of message transformers which could for example
|
|
303
|
+
// retrieve additional data from the server, do extra decoding or even
|
|
304
|
+
// message validation.
|
|
305
|
+
//
|
|
306
|
+
(function transform(index, done) {
|
|
307
|
+
var transformer = fns[index++];
|
|
308
|
+
|
|
309
|
+
if (!transformer) return done();
|
|
310
|
+
|
|
311
|
+
if (1 === transformer.length) {
|
|
312
|
+
if (false === transformer.call(connection, packet)) {
|
|
313
|
+
//
|
|
314
|
+
// When false is returned by an incoming transformer it means that's
|
|
315
|
+
// being handled by the transformer and we should not emit the `data`
|
|
316
|
+
// event.
|
|
317
|
+
//
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return transform(index, done);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
transformer.call(connection, packet, function finished(err, arg) {
|
|
325
|
+
if (err) return connection.emit('error', err);
|
|
326
|
+
if (false === arg) return;
|
|
327
|
+
|
|
328
|
+
transform(index, done);
|
|
329
|
+
});
|
|
330
|
+
}(0, function done() {
|
|
331
|
+
//
|
|
332
|
+
// We always emit 2 arguments for the data event, the first argument is the
|
|
333
|
+
// parsed data and the second argument is the raw string that we received.
|
|
334
|
+
// This allows you, for example, to do some validation on the parsed data
|
|
335
|
+
// and then save the raw string in your database without the stringify
|
|
336
|
+
// overhead.
|
|
337
|
+
//
|
|
338
|
+
if ('incoming' === type) {
|
|
339
|
+
//
|
|
340
|
+
// This is pretty bad edge case, it's possible that the async version of
|
|
341
|
+
// the `connection` event listener takes so long that we cannot assign
|
|
342
|
+
// `data` handlers and we are already receiving data as the connection is
|
|
343
|
+
// already established. In this edge case we need to queue the data and
|
|
344
|
+
// pass it to the data event once we're listening.
|
|
345
|
+
//
|
|
346
|
+
if (connection.queue) return connection.queue.push(packet);
|
|
347
|
+
return connection.emit('data', packet.data, packet.raw);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
connection._write(packet.data);
|
|
351
|
+
}));
|
|
352
|
+
|
|
353
|
+
return this;
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Really dead simple protocol parser. We simply assume that every message that
|
|
358
|
+
* is prefixed with `primus::` could be used as some sort of protocol definition
|
|
359
|
+
* for Primus.
|
|
360
|
+
*
|
|
361
|
+
* @param {String} msg The data.
|
|
362
|
+
* @returns {Boolean} Is a protocol message.
|
|
363
|
+
* @api private
|
|
364
|
+
*/
|
|
365
|
+
Spark.readable('protocol', function protocol(msg) {
|
|
366
|
+
if (
|
|
367
|
+
'string' !== typeof msg
|
|
368
|
+
|| msg.indexOf('primus::') !== 0
|
|
369
|
+
) return false;
|
|
370
|
+
|
|
371
|
+
var last = msg.indexOf(':', 8)
|
|
372
|
+
, value = msg.slice(last + 2);
|
|
373
|
+
|
|
374
|
+
switch (msg.slice(8, last)) {
|
|
375
|
+
case 'pong':
|
|
376
|
+
this.emit('incoming::pong', +value);
|
|
377
|
+
break;
|
|
378
|
+
|
|
379
|
+
case 'id':
|
|
380
|
+
this._write('primus::id::'+ this.id);
|
|
381
|
+
break;
|
|
382
|
+
|
|
383
|
+
//
|
|
384
|
+
// Unknown protocol, somebody is probably sending `primus::` prefixed
|
|
385
|
+
// messages.
|
|
386
|
+
//
|
|
387
|
+
default:
|
|
388
|
+
log('message `%s` was prefixed with primus:: but not supported', msg);
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
log('processed a primus protocol message `%s`', msg);
|
|
393
|
+
return true;
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Send a new message to a given spark.
|
|
398
|
+
*
|
|
399
|
+
* @param {Mixed} data The data that needs to be written.
|
|
400
|
+
* @returns {Boolean} Always returns true.
|
|
401
|
+
* @api public
|
|
402
|
+
*/
|
|
403
|
+
Spark.readable('write', function write(data) {
|
|
404
|
+
var primus = this.primus;
|
|
405
|
+
|
|
406
|
+
//
|
|
407
|
+
// The connection is closed, return false.
|
|
408
|
+
//
|
|
409
|
+
if (Spark.CLOSED === this.readyState) {
|
|
410
|
+
log('attempted to write but readyState was already set to CLOSED for %s', this.id);
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
this.transforms(primus, this, 'outgoing', data);
|
|
415
|
+
|
|
416
|
+
return true;
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* The actual message writer.
|
|
421
|
+
*
|
|
422
|
+
* @param {Mixed} data The message that needs to be written.
|
|
423
|
+
* @returns {Boolean}
|
|
424
|
+
* @api private
|
|
425
|
+
*/
|
|
426
|
+
Spark.readable('_write', function _write(data) {
|
|
427
|
+
var primus = this.primus
|
|
428
|
+
, spark = this;
|
|
429
|
+
|
|
430
|
+
//
|
|
431
|
+
// The connection is closed, normally this would already be done in the
|
|
432
|
+
// `spark.write` method, but as `_write` is used internally, we should also
|
|
433
|
+
// add the same check here to prevent potential crashes by writing to a dead
|
|
434
|
+
// socket.
|
|
435
|
+
//
|
|
436
|
+
if (Spark.CLOSED === spark.readyState) {
|
|
437
|
+
log('attempted to _write but readyState was already set to CLOSED for %s', spark.id);
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
primus.encoder.call(spark, data, function encoded(err, packet) {
|
|
442
|
+
//
|
|
443
|
+
// Do a "safe" emit('error') when we fail to parse a message. We don't
|
|
444
|
+
// want to throw here as listening to errors should be optional.
|
|
445
|
+
//
|
|
446
|
+
if (err) return new ParserError('Failed to encode outgoing data: '+ err.message, spark, err);
|
|
447
|
+
if (!packet) return log('nothing to write, bailing out for %s', spark.id);
|
|
448
|
+
|
|
449
|
+
//
|
|
450
|
+
// Hack 1: \u2028 and \u2029 are allowed inside a JSON string, but JavaScript
|
|
451
|
+
// defines them as newline separators. Unescaped control characters are not
|
|
452
|
+
// allowed inside JSON strings, so this causes an error at parse time. We
|
|
453
|
+
// work around this issue by escaping these characters. This can cause
|
|
454
|
+
// errors with JSONP requests or if the string is just evaluated.
|
|
455
|
+
//
|
|
456
|
+
if ('string' === typeof packet) {
|
|
457
|
+
if (~packet.indexOf('\u2028')) packet = packet.replace(u2028, '\\u2028');
|
|
458
|
+
if (~packet.indexOf('\u2029')) packet = packet.replace(u2029, '\\u2029');
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
spark.emit('outgoing::data', packet);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
return true;
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* End the connection.
|
|
469
|
+
*
|
|
470
|
+
* Options:
|
|
471
|
+
* - reconnect (boolean) Trigger client-side reconnect.
|
|
472
|
+
*
|
|
473
|
+
* @param {Mixed} data Optional closing data.
|
|
474
|
+
* @param {Object} options End instructions.
|
|
475
|
+
* @api public
|
|
476
|
+
*/
|
|
477
|
+
Spark.readable('end', function end(data, options) {
|
|
478
|
+
if (Spark.CLOSED === this.readyState) return this;
|
|
479
|
+
|
|
480
|
+
options = options || {};
|
|
481
|
+
if (data !== undefined) this.write(data);
|
|
482
|
+
|
|
483
|
+
//
|
|
484
|
+
// If we want to trigger a reconnect do not send
|
|
485
|
+
// `primus::server::close`, otherwise bypass the .write method
|
|
486
|
+
// as this message should not be transformed.
|
|
487
|
+
//
|
|
488
|
+
if (!options.reconnect) this._write('primus::server::close');
|
|
489
|
+
|
|
490
|
+
//
|
|
491
|
+
// This seems redundant but there are cases where the above writes
|
|
492
|
+
// can trigger another `end` call. An example is with Engine.IO
|
|
493
|
+
// when calling `end` on the client and `end` on the spark right
|
|
494
|
+
// after. The `end` call on the spark comes before the `incoming::end`
|
|
495
|
+
// event and the result is an attempt of writing to a closed socket.
|
|
496
|
+
// When this happens Engine.IO closes the connection and without
|
|
497
|
+
// this check the following instructions could be executed twice.
|
|
498
|
+
//
|
|
499
|
+
if (Spark.CLOSED === this.readyState) return this;
|
|
500
|
+
|
|
501
|
+
log('emitting final events for spark %s', this.id);
|
|
502
|
+
|
|
503
|
+
this.readyState = Spark.CLOSED;
|
|
504
|
+
this.emit('outgoing::end');
|
|
505
|
+
this.emit('end');
|
|
506
|
+
this.ultron.destroy();
|
|
507
|
+
this.ultron = this.queue = null;
|
|
508
|
+
|
|
509
|
+
return this;
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
//
|
|
513
|
+
// Expose the module.
|
|
514
|
+
//
|
|
515
|
+
module.exports = Spark;
|