sharedb 3.0.0 → 3.2.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/lib/agent.js +54 -31
- package/lib/client/connection.js +48 -27
- package/lib/client/presence/local-presence.js +2 -1
- package/lib/client/presence/presence.js +2 -1
- package/lib/client/query.js +3 -2
- package/lib/client/snapshot-request/snapshot-timestamp-request.js +2 -1
- package/lib/client/snapshot-request/snapshot-version-request.js +2 -1
- package/lib/error.js +1 -0
- package/lib/index.js +1 -0
- package/lib/message-actions.js +22 -0
- package/package.json +2 -2
- package/test/client/connection.js +39 -0
package/lib/agent.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
var hat = require('hat');
|
|
2
|
+
var ShareDBError = require('./error');
|
|
3
|
+
var logger = require('./logger');
|
|
4
|
+
var ACTIONS = require('./message-actions').ACTIONS;
|
|
2
5
|
var types = require('./types');
|
|
3
6
|
var util = require('./util');
|
|
4
|
-
var logger = require('./logger');
|
|
5
|
-
var ShareDBError = require('./error');
|
|
6
7
|
|
|
7
8
|
var ERROR_CODE = ShareDBError.CODES;
|
|
8
9
|
|
|
@@ -58,7 +59,7 @@ function Agent(backend, stream) {
|
|
|
58
59
|
this.custom = {};
|
|
59
60
|
|
|
60
61
|
// Send the legacy message to initialize old clients with the random agent Id
|
|
61
|
-
this.send(this._initMessage(
|
|
62
|
+
this.send(this._initMessage(ACTIONS.initLegacy));
|
|
62
63
|
}
|
|
63
64
|
module.exports = Agent;
|
|
64
65
|
|
|
@@ -174,7 +175,7 @@ Agent.prototype._subscribeToQuery = function(emitter, queryId, collection, query
|
|
|
174
175
|
|
|
175
176
|
var agent = this;
|
|
176
177
|
emitter.onExtra = function(extra) {
|
|
177
|
-
agent.send({a:
|
|
178
|
+
agent.send({a: ACTIONS.queryUpdate, id: queryId, extra: extra});
|
|
178
179
|
};
|
|
179
180
|
|
|
180
181
|
emitter.onDiff = function(diff) {
|
|
@@ -186,7 +187,7 @@ Agent.prototype._subscribeToQuery = function(emitter, queryId, collection, query
|
|
|
186
187
|
}
|
|
187
188
|
// Consider stripping the collection out of the data we send here
|
|
188
189
|
// if it matches the query's collection.
|
|
189
|
-
agent.send({a:
|
|
190
|
+
agent.send({a: ACTIONS.queryUpdate, id: queryId, diff: diff});
|
|
190
191
|
};
|
|
191
192
|
|
|
192
193
|
emitter.onError = function(err) {
|
|
@@ -250,7 +251,7 @@ Agent.prototype.send = function(message) {
|
|
|
250
251
|
|
|
251
252
|
Agent.prototype._sendOp = function(collection, id, op) {
|
|
252
253
|
var message = {
|
|
253
|
-
a:
|
|
254
|
+
a: ACTIONS.op,
|
|
254
255
|
c: collection,
|
|
255
256
|
d: id,
|
|
256
257
|
v: op.v,
|
|
@@ -354,22 +355,34 @@ Agent.prototype._open = function() {
|
|
|
354
355
|
|
|
355
356
|
// Check a request to see if its valid. Returns an error if there's a problem.
|
|
356
357
|
Agent.prototype._checkRequest = function(request) {
|
|
357
|
-
if (
|
|
358
|
+
if (
|
|
359
|
+
request.a === ACTIONS.queryFetch ||
|
|
360
|
+
request.a === ACTIONS.querySubscribe ||
|
|
361
|
+
request.a === ACTIONS.queryUnsubscribe
|
|
362
|
+
) {
|
|
358
363
|
// Query messages need an ID property.
|
|
359
364
|
if (typeof request.id !== 'number') return 'Missing query ID';
|
|
360
|
-
} else if (request.a ===
|
|
365
|
+
} else if (request.a === ACTIONS.op ||
|
|
366
|
+
request.a === ACTIONS.fetch ||
|
|
367
|
+
request.a === ACTIONS.subscribe ||
|
|
368
|
+
request.a === ACTIONS.unsubscribe ||
|
|
369
|
+
request.a === ACTIONS.presence) {
|
|
361
370
|
// Doc-based request.
|
|
362
371
|
if (request.c != null && typeof request.c !== 'string') return 'Invalid collection';
|
|
363
372
|
if (request.d != null && typeof request.d !== 'string') return 'Invalid id';
|
|
364
373
|
|
|
365
|
-
if (request.a ===
|
|
374
|
+
if (request.a === ACTIONS.op || request.a === ACTIONS.presence) {
|
|
366
375
|
if (request.v != null && (typeof request.v !== 'number' || request.v < 0)) return 'Invalid version';
|
|
367
376
|
}
|
|
368
377
|
|
|
369
|
-
if (request.a ===
|
|
378
|
+
if (request.a === ACTIONS.presence) {
|
|
370
379
|
if (typeof request.id !== 'string') return 'Missing presence ID';
|
|
371
380
|
}
|
|
372
|
-
} else if (
|
|
381
|
+
} else if (
|
|
382
|
+
request.a === ACTIONS.bulkFetch ||
|
|
383
|
+
request.a === ACTIONS.bulkSubscribe ||
|
|
384
|
+
request.a === ACTIONS.bulkUnsubscribe
|
|
385
|
+
) {
|
|
373
386
|
// Bulk request
|
|
374
387
|
if (request.c != null && typeof request.c !== 'string') return 'Invalid collection';
|
|
375
388
|
if (typeof request.b !== 'object') return 'Invalid bulk subscribe data';
|
|
@@ -383,28 +396,28 @@ Agent.prototype._handleMessage = function(request, callback) {
|
|
|
383
396
|
if (errMessage) return callback(new ShareDBError(ERROR_CODE.ERR_MESSAGE_BADLY_FORMED, errMessage));
|
|
384
397
|
|
|
385
398
|
switch (request.a) {
|
|
386
|
-
case
|
|
399
|
+
case ACTIONS.handshake:
|
|
387
400
|
if (request.id) this.src = request.id;
|
|
388
|
-
return callback(null, this._initMessage(
|
|
389
|
-
case
|
|
401
|
+
return callback(null, this._initMessage(ACTIONS.handshake));
|
|
402
|
+
case ACTIONS.queryFetch:
|
|
390
403
|
return this._queryFetch(request.id, request.c, request.q, getQueryOptions(request), callback);
|
|
391
|
-
case
|
|
404
|
+
case ACTIONS.querySubscribe:
|
|
392
405
|
return this._querySubscribe(request.id, request.c, request.q, getQueryOptions(request), callback);
|
|
393
|
-
case
|
|
406
|
+
case ACTIONS.queryUnsubscribe:
|
|
394
407
|
return this._queryUnsubscribe(request.id, callback);
|
|
395
|
-
case
|
|
408
|
+
case ACTIONS.bulkFetch:
|
|
396
409
|
return this._fetchBulk(request.c, request.b, callback);
|
|
397
|
-
case
|
|
410
|
+
case ACTIONS.bulkSubscribe:
|
|
398
411
|
return this._subscribeBulk(request.c, request.b, callback);
|
|
399
|
-
case
|
|
412
|
+
case ACTIONS.bulkUnsubscribe:
|
|
400
413
|
return this._unsubscribeBulk(request.c, request.b, callback);
|
|
401
|
-
case
|
|
414
|
+
case ACTIONS.fetch:
|
|
402
415
|
return this._fetch(request.c, request.d, request.v, callback);
|
|
403
|
-
case
|
|
416
|
+
case ACTIONS.subscribe:
|
|
404
417
|
return this._subscribe(request.c, request.d, request.v, callback);
|
|
405
|
-
case
|
|
418
|
+
case ACTIONS.unsubscribe:
|
|
406
419
|
return this._unsubscribe(request.c, request.d, callback);
|
|
407
|
-
case
|
|
420
|
+
case ACTIONS.op:
|
|
408
421
|
// Normalize the properties submitted
|
|
409
422
|
var op = createClientOp(request, this._src());
|
|
410
423
|
if (op.seq >= util.MAX_SAFE_INTEGER) {
|
|
@@ -415,11 +428,11 @@ Agent.prototype._handleMessage = function(request, callback) {
|
|
|
415
428
|
}
|
|
416
429
|
if (!op) return callback(new ShareDBError(ERROR_CODE.ERR_MESSAGE_BADLY_FORMED, 'Invalid op message'));
|
|
417
430
|
return this._submit(request.c, request.d, op, callback);
|
|
418
|
-
case
|
|
431
|
+
case ACTIONS.snapshotFetch:
|
|
419
432
|
return this._fetchSnapshot(request.c, request.d, request.v, callback);
|
|
420
|
-
case
|
|
433
|
+
case ACTIONS.snapshotFetchByTimestamp:
|
|
421
434
|
return this._fetchSnapshotByTimestamp(request.c, request.d, request.ts, callback);
|
|
422
|
-
case
|
|
435
|
+
case ACTIONS.presence:
|
|
423
436
|
if (!this.backend.presenceEnabled) return;
|
|
424
437
|
var presence = this._createPresence(request);
|
|
425
438
|
if (presence.t && !util.supportsPresence(types.map[presence.t])) {
|
|
@@ -429,11 +442,13 @@ Agent.prototype._handleMessage = function(request, callback) {
|
|
|
429
442
|
});
|
|
430
443
|
}
|
|
431
444
|
return this._broadcastPresence(presence, callback);
|
|
432
|
-
case
|
|
445
|
+
case ACTIONS.presenceSubscribe:
|
|
433
446
|
if (!this.backend.presenceEnabled) return;
|
|
434
447
|
return this._subscribePresence(request.ch, request.seq, callback);
|
|
435
|
-
case
|
|
448
|
+
case ACTIONS.presenceUnsubscribe:
|
|
436
449
|
return this._unsubscribePresence(request.ch, request.seq, callback);
|
|
450
|
+
case ACTIONS.pingPong:
|
|
451
|
+
return this._pingPong(callback);
|
|
437
452
|
default:
|
|
438
453
|
callback(new ShareDBError(ERROR_CODE.ERR_MESSAGE_BADLY_FORMED, 'Invalid or unknown message'));
|
|
439
454
|
}
|
|
@@ -527,6 +542,14 @@ Agent.prototype._querySubscribe = function(queryId, collection, query, options,
|
|
|
527
542
|
});
|
|
528
543
|
};
|
|
529
544
|
|
|
545
|
+
Agent.prototype._pingPong = function(callback) {
|
|
546
|
+
var error = null;
|
|
547
|
+
var message = {
|
|
548
|
+
a: ACTIONS.pingPong
|
|
549
|
+
};
|
|
550
|
+
callback(error, message);
|
|
551
|
+
};
|
|
552
|
+
|
|
530
553
|
function getResultsData(results) {
|
|
531
554
|
var items = [];
|
|
532
555
|
for (var i = 0; i < results.length; i++) {
|
|
@@ -761,7 +784,7 @@ Agent.prototype._broadcastPresence = function(presence, callback) {
|
|
|
761
784
|
|
|
762
785
|
Agent.prototype._createPresence = function(request) {
|
|
763
786
|
return {
|
|
764
|
-
a:
|
|
787
|
+
a: ACTIONS.presence,
|
|
765
788
|
ch: request.ch,
|
|
766
789
|
src: this._src(),
|
|
767
790
|
id: request.id, // Presence ID, not Doc ID (which is 'd')
|
|
@@ -813,7 +836,7 @@ Agent.prototype._requestPresence = function(channel, callback) {
|
|
|
813
836
|
Agent.prototype._handlePresenceData = function(presence) {
|
|
814
837
|
if (presence.src === this._src()) return;
|
|
815
838
|
|
|
816
|
-
if (presence.r) return this.send({a:
|
|
839
|
+
if (presence.r) return this.send({a: ACTIONS.presenceRequest, ch: presence.ch});
|
|
817
840
|
|
|
818
841
|
var backend = this.backend;
|
|
819
842
|
var context = {
|
|
@@ -824,7 +847,7 @@ Agent.prototype._handlePresenceData = function(presence) {
|
|
|
824
847
|
backend.trigger(backend.MIDDLEWARE_ACTIONS.sendPresence, this, context, function(error) {
|
|
825
848
|
if (error) {
|
|
826
849
|
if (backend.doNotForwardSendPresenceErrorsToClient) backend.errorHandler(error, {agent: agent});
|
|
827
|
-
else agent.send({a:
|
|
850
|
+
else agent.send({a: ACTIONS.presence, ch: presence.ch, id: presence.id, error: getReplyErrorObject(error)});
|
|
828
851
|
return;
|
|
829
852
|
}
|
|
830
853
|
agent.send(presence);
|
package/lib/client/connection.js
CHANGED
|
@@ -6,6 +6,7 @@ var SnapshotVersionRequest = require('./snapshot-request/snapshot-version-reques
|
|
|
6
6
|
var SnapshotTimestampRequest = require('./snapshot-request/snapshot-timestamp-request');
|
|
7
7
|
var emitter = require('../emitter');
|
|
8
8
|
var ShareDBError = require('../error');
|
|
9
|
+
var ACTIONS = require('../message-actions').ACTIONS;
|
|
9
10
|
var types = require('../types');
|
|
10
11
|
var util = require('../util');
|
|
11
12
|
var logger = require('../logger');
|
|
@@ -194,25 +195,25 @@ Connection.prototype.handleMessage = function(message) {
|
|
|
194
195
|
// Switch on the message action. Most messages are for documents and are
|
|
195
196
|
// handled in the doc class.
|
|
196
197
|
switch (message.a) {
|
|
197
|
-
case
|
|
198
|
+
case ACTIONS.initLegacy:
|
|
198
199
|
// Client initialization packet
|
|
199
200
|
return this._handleLegacyInit(message);
|
|
200
|
-
case
|
|
201
|
+
case ACTIONS.handshake:
|
|
201
202
|
return this._handleHandshake(err, message);
|
|
202
|
-
case
|
|
203
|
+
case ACTIONS.queryFetch:
|
|
203
204
|
var query = this.queries[message.id];
|
|
204
205
|
if (query) query._handleFetch(err, message.data, message.extra);
|
|
205
206
|
return;
|
|
206
|
-
case
|
|
207
|
+
case ACTIONS.querySubscribe:
|
|
207
208
|
var query = this.queries[message.id];
|
|
208
209
|
if (query) query._handleSubscribe(err, message.data, message.extra);
|
|
209
210
|
return;
|
|
210
|
-
case
|
|
211
|
+
case ACTIONS.queryUnsubscribe:
|
|
211
212
|
// Queries are removed immediately on calls to destroy, so we ignore
|
|
212
213
|
// replies to query unsubscribes. Perhaps there should be a callback for
|
|
213
214
|
// destroy, but this is currently unimplemented
|
|
214
215
|
return;
|
|
215
|
-
case
|
|
216
|
+
case ACTIONS.queryUpdate:
|
|
216
217
|
// Query message. Pass this to the appropriate query object.
|
|
217
218
|
var query = this.queries[message.id];
|
|
218
219
|
if (!query) return;
|
|
@@ -221,37 +222,39 @@ Connection.prototype.handleMessage = function(message) {
|
|
|
221
222
|
if (message.hasOwnProperty('extra')) query._handleExtra(message.extra);
|
|
222
223
|
return;
|
|
223
224
|
|
|
224
|
-
case
|
|
225
|
+
case ACTIONS.bulkFetch:
|
|
225
226
|
return this._handleBulkMessage(err, message, '_handleFetch');
|
|
226
|
-
case
|
|
227
|
-
case
|
|
227
|
+
case ACTIONS.bulkSubscribe:
|
|
228
|
+
case ACTIONS.bulkUnsubscribe:
|
|
228
229
|
return this._handleBulkMessage(err, message, '_handleSubscribe');
|
|
229
230
|
|
|
230
|
-
case
|
|
231
|
-
case
|
|
231
|
+
case ACTIONS.snapshotFetch:
|
|
232
|
+
case ACTIONS.snapshotFetchByTimestamp:
|
|
232
233
|
return this._handleSnapshotFetch(err, message);
|
|
233
234
|
|
|
234
|
-
case
|
|
235
|
+
case ACTIONS.fetch:
|
|
235
236
|
var doc = this.getExisting(message.c, message.d);
|
|
236
237
|
if (doc) doc._handleFetch(err, message.data);
|
|
237
238
|
return;
|
|
238
|
-
case
|
|
239
|
-
case
|
|
239
|
+
case ACTIONS.subscribe:
|
|
240
|
+
case ACTIONS.unsubscribe:
|
|
240
241
|
var doc = this.getExisting(message.c, message.d);
|
|
241
242
|
if (doc) doc._handleSubscribe(err, message.data);
|
|
242
243
|
return;
|
|
243
|
-
case
|
|
244
|
+
case ACTIONS.op:
|
|
244
245
|
var doc = this.getExisting(message.c, message.d);
|
|
245
246
|
if (doc) doc._handleOp(err, message);
|
|
246
247
|
return;
|
|
247
|
-
case
|
|
248
|
+
case ACTIONS.presence:
|
|
248
249
|
return this._handlePresence(err, message);
|
|
249
|
-
case
|
|
250
|
+
case ACTIONS.presenceSubscribe:
|
|
250
251
|
return this._handlePresenceSubscribe(err, message);
|
|
251
|
-
case
|
|
252
|
+
case ACTIONS.presenceUnsubscribe:
|
|
252
253
|
return this._handlePresenceUnsubscribe(err, message);
|
|
253
|
-
case
|
|
254
|
+
case ACTIONS.presenceRequest:
|
|
254
255
|
return this._handlePresenceRequest(err, message);
|
|
256
|
+
case ACTIONS.pingPong:
|
|
257
|
+
return this._handlePingPong(err);
|
|
255
258
|
|
|
256
259
|
default:
|
|
257
260
|
logger.warn('Ignoring unrecognized message', message);
|
|
@@ -416,7 +419,7 @@ Connection.prototype._sendBulk = function(action, collection, values) {
|
|
|
416
419
|
}
|
|
417
420
|
};
|
|
418
421
|
|
|
419
|
-
Connection.prototype.
|
|
422
|
+
Connection.prototype._sendActions = function(action, doc, version) {
|
|
420
423
|
// Ensure the doc is registered so that it receives the reply message
|
|
421
424
|
this._addDoc(doc);
|
|
422
425
|
if (this.bulk) {
|
|
@@ -434,22 +437,22 @@ Connection.prototype._sendAction = function(action, doc, version) {
|
|
|
434
437
|
};
|
|
435
438
|
|
|
436
439
|
Connection.prototype.sendFetch = function(doc) {
|
|
437
|
-
return this.
|
|
440
|
+
return this._sendActions(ACTIONS.fetch, doc, doc.version);
|
|
438
441
|
};
|
|
439
442
|
|
|
440
443
|
Connection.prototype.sendSubscribe = function(doc) {
|
|
441
|
-
return this.
|
|
444
|
+
return this._sendActions(ACTIONS.subscribe, doc, doc.version);
|
|
442
445
|
};
|
|
443
446
|
|
|
444
447
|
Connection.prototype.sendUnsubscribe = function(doc) {
|
|
445
|
-
return this.
|
|
448
|
+
return this._sendActions(ACTIONS.unsubscribe, doc);
|
|
446
449
|
};
|
|
447
450
|
|
|
448
451
|
Connection.prototype.sendOp = function(doc, op) {
|
|
449
452
|
// Ensure the doc is registered so that it receives the reply message
|
|
450
453
|
this._addDoc(doc);
|
|
451
454
|
var message = {
|
|
452
|
-
a:
|
|
455
|
+
a: ACTIONS.op,
|
|
453
456
|
c: doc.collection,
|
|
454
457
|
d: doc.id,
|
|
455
458
|
v: doc.version,
|
|
@@ -475,6 +478,19 @@ Connection.prototype.send = function(message) {
|
|
|
475
478
|
this.socket.send(JSON.stringify(message));
|
|
476
479
|
};
|
|
477
480
|
|
|
481
|
+
Connection.prototype.ping = function() {
|
|
482
|
+
if (!this.canSend) {
|
|
483
|
+
throw new ShareDBError(
|
|
484
|
+
ERROR_CODE.ERR_CANNOT_PING_OFFLINE,
|
|
485
|
+
'Socket must be CONNECTED to ping'
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
var message = {
|
|
490
|
+
a: ACTIONS.pingPong
|
|
491
|
+
};
|
|
492
|
+
this.send(message);
|
|
493
|
+
};
|
|
478
494
|
|
|
479
495
|
/**
|
|
480
496
|
* Closes the socket and emits 'closed'
|
|
@@ -553,7 +569,7 @@ Connection.prototype._destroyQuery = function(query) {
|
|
|
553
569
|
// The callback should have the signature function(error, results, extra)
|
|
554
570
|
// where results is a list of Doc objects.
|
|
555
571
|
Connection.prototype.createFetchQuery = function(collection, q, options, callback) {
|
|
556
|
-
return this._createQuery(
|
|
572
|
+
return this._createQuery(ACTIONS.queryFetch, collection, q, options, callback);
|
|
557
573
|
};
|
|
558
574
|
|
|
559
575
|
// Create a subscribe query. Subscribe queries return with the initial data
|
|
@@ -563,7 +579,7 @@ Connection.prototype.createFetchQuery = function(collection, q, options, callbac
|
|
|
563
579
|
// If present, the callback should have the signature function(error, results, extra)
|
|
564
580
|
// where results is a list of Doc objects.
|
|
565
581
|
Connection.prototype.createSubscribeQuery = function(collection, q, options, callback) {
|
|
566
|
-
return this._createQuery(
|
|
582
|
+
return this._createQuery(ACTIONS.querySubscribe, collection, q, options, callback);
|
|
567
583
|
};
|
|
568
584
|
|
|
569
585
|
Connection.prototype.hasPending = function() {
|
|
@@ -716,7 +732,7 @@ Connection.prototype._handleLegacyInit = function(message) {
|
|
|
716
732
|
};
|
|
717
733
|
|
|
718
734
|
Connection.prototype._initializeHandshake = function() {
|
|
719
|
-
this.send({a:
|
|
735
|
+
this.send({a: ACTIONS.handshake, id: this.id});
|
|
720
736
|
};
|
|
721
737
|
|
|
722
738
|
Connection.prototype._handleHandshake = function(error, message) {
|
|
@@ -724,6 +740,11 @@ Connection.prototype._handleHandshake = function(error, message) {
|
|
|
724
740
|
this._initialize(message);
|
|
725
741
|
};
|
|
726
742
|
|
|
743
|
+
Connection.prototype._handlePingPong = function(error) {
|
|
744
|
+
if (error) return this.emit('error', error);
|
|
745
|
+
this.emit('pong');
|
|
746
|
+
};
|
|
747
|
+
|
|
727
748
|
Connection.prototype._initialize = function(message) {
|
|
728
749
|
if (this.state !== 'connecting') return;
|
|
729
750
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
var emitter = require('../../emitter');
|
|
2
|
+
var ACTIONS = require('../../message-actions').ACTIONS;
|
|
2
3
|
var util = require('../../util');
|
|
3
4
|
|
|
4
5
|
module.exports = LocalPresence;
|
|
@@ -59,7 +60,7 @@ LocalPresence.prototype._ack = function(error, presenceVersion) {
|
|
|
59
60
|
|
|
60
61
|
LocalPresence.prototype._message = function() {
|
|
61
62
|
return {
|
|
62
|
-
a:
|
|
63
|
+
a: ACTIONS.presence,
|
|
63
64
|
ch: this.presence.channel,
|
|
64
65
|
id: this.presenceId,
|
|
65
66
|
p: this.value,
|
|
@@ -4,6 +4,7 @@ var RemotePresence = require('./remote-presence');
|
|
|
4
4
|
var util = require('../../util');
|
|
5
5
|
var async = require('async');
|
|
6
6
|
var hat = require('hat');
|
|
7
|
+
var ACTIONS = require('../../message-actions').ACTIONS;
|
|
7
8
|
|
|
8
9
|
module.exports = Presence;
|
|
9
10
|
function Presence(connection, channel) {
|
|
@@ -70,7 +71,7 @@ Presence.prototype.destroy = function(callback) {
|
|
|
70
71
|
|
|
71
72
|
Presence.prototype._sendSubscriptionAction = function(wantSubscribe, callback) {
|
|
72
73
|
this.wantSubscribe = !!wantSubscribe;
|
|
73
|
-
var action = this.wantSubscribe ?
|
|
74
|
+
var action = this.wantSubscribe ? ACTIONS.presenceSubscribe : ACTIONS.presenceUnsubscribe;
|
|
74
75
|
var seq = this.connection._presenceSeq++;
|
|
75
76
|
this._subscriptionCallbacksBySeq[seq] = callback;
|
|
76
77
|
if (this.connection.canSend) {
|
package/lib/client/query.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
var emitter = require('../emitter');
|
|
2
|
+
var ACTIONS = require('../message-actions').ACTIONS;
|
|
2
3
|
var util = require('../util');
|
|
3
4
|
|
|
4
5
|
// Queries are live requests to the database for particular sets of fields.
|
|
@@ -75,8 +76,8 @@ Query.prototype.send = function() {
|
|
|
75
76
|
// Destroy the query object. Any subsequent messages for the query will be
|
|
76
77
|
// ignored by the connection.
|
|
77
78
|
Query.prototype.destroy = function(callback) {
|
|
78
|
-
if (this.connection.canSend && this.action ===
|
|
79
|
-
this.connection.send({a:
|
|
79
|
+
if (this.connection.canSend && this.action === ACTIONS.querySubscribe) {
|
|
80
|
+
this.connection.send({a: ACTIONS.queryUnsubscribe, id: this.id});
|
|
80
81
|
}
|
|
81
82
|
this.connection._destroyQuery(this);
|
|
82
83
|
// There is a callback for consistency, but we don't actually wait for the
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
var SnapshotRequest = require('./snapshot-request');
|
|
2
2
|
var util = require('../../util');
|
|
3
|
+
var ACTIONS = require('../../message-actions').ACTIONS;
|
|
3
4
|
|
|
4
5
|
module.exports = SnapshotTimestampRequest;
|
|
5
6
|
|
|
@@ -17,7 +18,7 @@ SnapshotTimestampRequest.prototype = Object.create(SnapshotRequest.prototype);
|
|
|
17
18
|
|
|
18
19
|
SnapshotTimestampRequest.prototype._message = function() {
|
|
19
20
|
return {
|
|
20
|
-
a:
|
|
21
|
+
a: ACTIONS.snapshotFetchByTimestamp,
|
|
21
22
|
id: this.requestId,
|
|
22
23
|
c: this.collection,
|
|
23
24
|
d: this.id,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
var SnapshotRequest = require('./snapshot-request');
|
|
2
2
|
var util = require('../../util');
|
|
3
|
+
var ACTIONS = require('../../message-actions').ACTIONS;
|
|
3
4
|
|
|
4
5
|
module.exports = SnapshotVersionRequest;
|
|
5
6
|
|
|
@@ -17,7 +18,7 @@ SnapshotVersionRequest.prototype = Object.create(SnapshotRequest.prototype);
|
|
|
17
18
|
|
|
18
19
|
SnapshotVersionRequest.prototype._message = function() {
|
|
19
20
|
return {
|
|
20
|
-
a:
|
|
21
|
+
a: ACTIONS.snapshotFetch,
|
|
21
22
|
id: this.requestId,
|
|
22
23
|
c: this.collection,
|
|
23
24
|
d: this.id,
|
package/lib/error.js
CHANGED
|
@@ -16,6 +16,7 @@ ShareDBError.CODES = {
|
|
|
16
16
|
ERR_APPLY_OP_VERSION_DOES_NOT_MATCH_SNAPSHOT: 'ERR_APPLY_OP_VERSION_DOES_NOT_MATCH_SNAPSHOT',
|
|
17
17
|
ERR_APPLY_SNAPSHOT_NOT_PROVIDED: 'ERR_APPLY_SNAPSHOT_NOT_PROVIDED',
|
|
18
18
|
ERR_CLIENT_ID_BADLY_FORMED: 'ERR_CLIENT_ID_BADLY_FORMED',
|
|
19
|
+
ERR_CANNOT_PING_OFFLINE: 'ERR_CANNOT_PING_OFFLINE',
|
|
19
20
|
ERR_CONNECTION_SEQ_INTEGER_OVERFLOW: 'ERR_CONNECTION_SEQ_INTEGER_OVERFLOW',
|
|
20
21
|
ERR_CONNECTION_STATE_TRANSITION_INVALID: 'ERR_CONNECTION_STATE_TRANSITION_INVALID',
|
|
21
22
|
ERR_DATABASE_ADAPTER_NOT_FOUND: 'ERR_DATABASE_ADAPTER_NOT_FOUND',
|
package/lib/index.js
CHANGED
|
@@ -9,6 +9,7 @@ Backend.logger = require('./logger');
|
|
|
9
9
|
Backend.MemoryDB = require('./db/memory');
|
|
10
10
|
Backend.MemoryMilestoneDB = require('./milestone-db/memory');
|
|
11
11
|
Backend.MemoryPubSub = require('./pubsub/memory');
|
|
12
|
+
Backend.MESSAGE_ACTIONS = require('./message-actions').ACTIONS;
|
|
12
13
|
Backend.MilestoneDB = require('./milestone-db');
|
|
13
14
|
Backend.ot = require('./ot');
|
|
14
15
|
Backend.projections = require('./projections');
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
exports.ACTIONS = {
|
|
2
|
+
initLegacy: 'init',
|
|
3
|
+
handshake: 'hs',
|
|
4
|
+
queryFetch: 'qf',
|
|
5
|
+
querySubscribe: 'qs',
|
|
6
|
+
queryUnsubscribe: 'qu',
|
|
7
|
+
queryUpdate: 'q',
|
|
8
|
+
bulkFetch: 'bf',
|
|
9
|
+
bulkSubscribe: 'bs',
|
|
10
|
+
bulkUnsubscribe: 'bu',
|
|
11
|
+
fetch: 'f',
|
|
12
|
+
subscribe: 's',
|
|
13
|
+
unsubscribe: 'u',
|
|
14
|
+
op: 'op',
|
|
15
|
+
snapshotFetch: 'nf',
|
|
16
|
+
snapshotFetchByTimestamp: 'nt',
|
|
17
|
+
pingPong: 'pp',
|
|
18
|
+
presence: 'p',
|
|
19
|
+
presenceSubscribe: 'ps',
|
|
20
|
+
presenceUnsubscribe: 'pu',
|
|
21
|
+
presenceRequest: 'pr'
|
|
22
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sharedb",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "JSON OT database backend",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"dependencies": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"lolex": "^5.1.1",
|
|
19
19
|
"mocha": "^8.2.1",
|
|
20
20
|
"nyc": "^14.1.1",
|
|
21
|
-
"ot-json0-v2": "ottypes/json0",
|
|
21
|
+
"ot-json0-v2": "https://github.com/ottypes/json0#90a3ae26364c4fa3b19b6df34dad46707a704421",
|
|
22
22
|
"ot-json1": "^0.3.0",
|
|
23
23
|
"rich-text": "^4.1.0",
|
|
24
24
|
"sharedb-legacy": "npm:sharedb@=1.1.0",
|
|
@@ -124,6 +124,45 @@ describe('client connection', function() {
|
|
|
124
124
|
});
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
+
describe('ping/pong', function() {
|
|
128
|
+
it('pings the backend', function(done) {
|
|
129
|
+
var connection = this.backend.connect();
|
|
130
|
+
|
|
131
|
+
connection.on('pong', function() {
|
|
132
|
+
done();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
connection.on('connected', function() {
|
|
136
|
+
connection.ping();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('handles errors', function(done) {
|
|
141
|
+
this.backend.use('receive', function(request, next) {
|
|
142
|
+
var error = request.data.a === 'pp' && new Error('bad');
|
|
143
|
+
next(error);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
var connection = this.backend.connect();
|
|
147
|
+
|
|
148
|
+
connection.on('error', function(error) {
|
|
149
|
+
expect(error.message).to.equal('bad');
|
|
150
|
+
done();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
connection.on('connected', function() {
|
|
154
|
+
connection.ping();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('throws if pinging offline', function() {
|
|
159
|
+
var connection = this.backend.connect();
|
|
160
|
+
expect(function() {
|
|
161
|
+
connection.ping();
|
|
162
|
+
}).to.throw('Socket must be CONNECTED to ping');
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
127
166
|
describe('backend.agentsCount', function() {
|
|
128
167
|
it('updates after connect and connection.close()', function(done) {
|
|
129
168
|
var backend = this.backend;
|