sharedb 2.1.0 → 2.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 +15 -5
- package/lib/backend.js +18 -0
- package/package.json +1 -1
- package/test/backend.js +36 -14
- package/test/client/presence/presence.js +98 -0
package/lib/agent.js
CHANGED
|
@@ -736,17 +736,25 @@ Agent.prototype._src = function() {
|
|
|
736
736
|
|
|
737
737
|
Agent.prototype._broadcastPresence = function(presence, callback) {
|
|
738
738
|
var agent = this;
|
|
739
|
+
var backend = this.backend;
|
|
739
740
|
var requests = this.presenceRequests[presence.ch] || (this.presenceRequests[presence.ch] = {});
|
|
740
741
|
var previousRequest = requests[presence.id];
|
|
741
742
|
if (!previousRequest || previousRequest.pv < presence.pv) {
|
|
742
743
|
this.presenceRequests[presence.ch][presence.id] = presence;
|
|
743
744
|
}
|
|
744
|
-
|
|
745
|
+
var context = {
|
|
746
|
+
presence: presence,
|
|
747
|
+
collection: presence.c
|
|
748
|
+
};
|
|
749
|
+
backend.trigger(backend.MIDDLEWARE_ACTIONS.receivePresence, this, context, function(error) {
|
|
745
750
|
if (error) return callback(error);
|
|
746
|
-
|
|
747
|
-
agent.backend.pubsub.publish([channel], presence, function(error) {
|
|
751
|
+
backend.transformPresenceToLatestVersion(agent, presence, function(error, presence) {
|
|
748
752
|
if (error) return callback(error);
|
|
749
|
-
|
|
753
|
+
var channel = agent._getPresenceChannel(presence.ch);
|
|
754
|
+
agent.backend.pubsub.publish([channel], presence, function(error) {
|
|
755
|
+
if (error) return callback(error);
|
|
756
|
+
callback(null, presence);
|
|
757
|
+
});
|
|
750
758
|
});
|
|
751
759
|
});
|
|
752
760
|
};
|
|
@@ -815,7 +823,9 @@ Agent.prototype._handlePresenceData = function(presence) {
|
|
|
815
823
|
var agent = this;
|
|
816
824
|
backend.trigger(backend.MIDDLEWARE_ACTIONS.sendPresence, this, context, function(error) {
|
|
817
825
|
if (error) {
|
|
818
|
-
|
|
826
|
+
if (backend.doNotForwardSendPresenceErrorsToClient) backend.errorHandler(error, {agent: agent});
|
|
827
|
+
else agent.send({a: 'p', ch: presence.ch, id: presence.id, error: getReplyErrorObject(error)});
|
|
828
|
+
return;
|
|
819
829
|
}
|
|
820
830
|
agent.send(presence);
|
|
821
831
|
});
|
package/lib/backend.js
CHANGED
|
@@ -14,6 +14,7 @@ var StreamSocket = require('./stream-socket');
|
|
|
14
14
|
var SubmitRequest = require('./submit-request');
|
|
15
15
|
var ReadSnapshotsRequest = require('./read-snapshots-request');
|
|
16
16
|
var util = require('./util');
|
|
17
|
+
var logger = require('./logger');
|
|
17
18
|
|
|
18
19
|
var ERROR_CODE = ShareDBError.CODES;
|
|
19
20
|
|
|
@@ -34,6 +35,14 @@ function Backend(options) {
|
|
|
34
35
|
this.suppressPublish = !!options.suppressPublish;
|
|
35
36
|
this.maxSubmitRetries = options.maxSubmitRetries || null;
|
|
36
37
|
this.presenceEnabled = !!options.presence;
|
|
38
|
+
this.doNotForwardSendPresenceErrorsToClient = !!options.doNotForwardSendPresenceErrorsToClient;
|
|
39
|
+
if (!this.doNotForwardSendPresenceErrorsToClient) {
|
|
40
|
+
logger.warn(
|
|
41
|
+
'Broadcasting "sendPresence" middleware errors to clients is deprecated ' +
|
|
42
|
+
'and will be removed in a future release. Disable this behaviour with:\n\n' +
|
|
43
|
+
'new Backend({doNotForwardSendPresenceErrorsToClient: true})\n\n'
|
|
44
|
+
);
|
|
45
|
+
}
|
|
37
46
|
|
|
38
47
|
// Map from event name to a list of middleware
|
|
39
48
|
this.middleware = {};
|
|
@@ -41,6 +50,13 @@ function Backend(options) {
|
|
|
41
50
|
// The number of open agents for monitoring and testing memory leaks
|
|
42
51
|
this.agentsCount = 0;
|
|
43
52
|
this.remoteAgentsCount = 0;
|
|
53
|
+
|
|
54
|
+
this.errorHandler = typeof options.errorHandler === 'function' ?
|
|
55
|
+
options.errorHandler :
|
|
56
|
+
// eslint-disable-next-line no-unused-vars
|
|
57
|
+
function(error, context) {
|
|
58
|
+
logger.error(error);
|
|
59
|
+
};
|
|
44
60
|
}
|
|
45
61
|
module.exports = Backend;
|
|
46
62
|
emitter.mixin(Backend);
|
|
@@ -68,6 +84,8 @@ Backend.prototype.MIDDLEWARE_ACTIONS = {
|
|
|
68
84
|
// by design, changing existing reply properties can cause weird bugs, since
|
|
69
85
|
// the rest of ShareDB would be unaware of those changes.
|
|
70
86
|
reply: 'reply',
|
|
87
|
+
// The server received presence information
|
|
88
|
+
receivePresence: 'receivePresence',
|
|
71
89
|
// About to send presence information to a client
|
|
72
90
|
sendPresence: 'sendPresence',
|
|
73
91
|
// An operation is about to be submitted to the database
|
package/package.json
CHANGED
package/test/backend.js
CHANGED
|
@@ -1,29 +1,51 @@
|
|
|
1
1
|
var Backend = require('../lib/backend');
|
|
2
2
|
var expect = require('chai').expect;
|
|
3
3
|
var sinon = require('sinon');
|
|
4
|
+
var logger = require('../lib/logger');
|
|
4
5
|
|
|
5
6
|
describe('Backend', function() {
|
|
6
7
|
var backend;
|
|
7
|
-
var agent = {
|
|
8
|
-
custom: {
|
|
9
|
-
foo: 'bar'
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
var fetchOptions = {
|
|
13
|
-
snapshotOptions: {
|
|
14
|
-
fizz: 'buzz'
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
beforeEach(function() {
|
|
19
|
-
backend = new Backend();
|
|
20
|
-
});
|
|
21
8
|
|
|
22
9
|
afterEach(function(done) {
|
|
23
10
|
backend.close(done);
|
|
24
11
|
});
|
|
25
12
|
|
|
13
|
+
describe('options', function() {
|
|
14
|
+
describe('errorHandler', function() {
|
|
15
|
+
it('logs by default', function() {
|
|
16
|
+
backend = new Backend();
|
|
17
|
+
var error = new Error('foo');
|
|
18
|
+
sinon.spy(logger, 'error');
|
|
19
|
+
backend.errorHandler(error);
|
|
20
|
+
expect(logger.error.callCount).to.equal(1);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('overrides with another function', function() {
|
|
24
|
+
var handler = sinon.spy();
|
|
25
|
+
backend = new Backend({errorHandler: handler});
|
|
26
|
+
var error = new Error('foo');
|
|
27
|
+
backend.errorHandler(error);
|
|
28
|
+
expect(handler.callCount).to.equal(1);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
26
33
|
describe('a simple document', function() {
|
|
34
|
+
var agent = {
|
|
35
|
+
custom: {
|
|
36
|
+
foo: 'bar'
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var fetchOptions = {
|
|
40
|
+
snapshotOptions: {
|
|
41
|
+
fizz: 'buzz'
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
beforeEach(function() {
|
|
46
|
+
backend = new Backend();
|
|
47
|
+
});
|
|
48
|
+
|
|
27
49
|
beforeEach(function(done) {
|
|
28
50
|
var doc = backend.connect().get('books', '1984');
|
|
29
51
|
doc.create({title: '1984'}, function(error) {
|
|
@@ -487,4 +487,102 @@ describe('Presence', function() {
|
|
|
487
487
|
}
|
|
488
488
|
], done);
|
|
489
489
|
});
|
|
490
|
+
|
|
491
|
+
describe('middleware', function() {
|
|
492
|
+
describe('receivePresence', function() {
|
|
493
|
+
it('provides the presence in the middleware', function(done) {
|
|
494
|
+
backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context) {
|
|
495
|
+
expect(context.presence.p).to.eql({index: 5});
|
|
496
|
+
done();
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
var localPresence1 = presence1.create('presence-1');
|
|
500
|
+
localPresence1.submit({index: 5}, errorHandler(done));
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
it('can mutate the presence in the middleware', function(done) {
|
|
504
|
+
backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, next) {
|
|
505
|
+
context.presence.p.index++;
|
|
506
|
+
next();
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
var localPresence1 = presence1.create('presence-1');
|
|
510
|
+
|
|
511
|
+
async.series([
|
|
512
|
+
presence2.subscribe.bind(presence2),
|
|
513
|
+
function(next) {
|
|
514
|
+
presence2.on('receive', function(id, value) {
|
|
515
|
+
expect(value).to.eql({index: 6});
|
|
516
|
+
next();
|
|
517
|
+
});
|
|
518
|
+
localPresence1.submit({index: 5}, errorHandler(done));
|
|
519
|
+
}
|
|
520
|
+
], done);
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
it('can cancel a presence broadcast by erroring', function(done) {
|
|
524
|
+
backend.use(backend.MIDDLEWARE_ACTIONS.receivePresence, function(context, next) {
|
|
525
|
+
next(new Error('bad!'));
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
var localPresence1 = presence1.create('presence-1');
|
|
529
|
+
|
|
530
|
+
async.series([
|
|
531
|
+
presence2.subscribe.bind(presence2),
|
|
532
|
+
function(next) {
|
|
533
|
+
presence2.on('receive', function() {
|
|
534
|
+
done(new Error('should not have received presence'));
|
|
535
|
+
});
|
|
536
|
+
localPresence1.submit({index: 5}, function(error) {
|
|
537
|
+
expect(error.message).to.contain('bad!');
|
|
538
|
+
next();
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
], done);
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
describe('sendPresence', function() {
|
|
546
|
+
// TODO: This functionality is deprecated
|
|
547
|
+
it('sends an error to a subscribed client', function(done) {
|
|
548
|
+
var localPresence1 = presence1.create('presence-1');
|
|
549
|
+
|
|
550
|
+
backend.use(backend.MIDDLEWARE_ACTIONS.sendPresence, function(context, next) {
|
|
551
|
+
next(new Error('uh-oh!'));
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
async.series([
|
|
555
|
+
presence2.subscribe.bind(presence2),
|
|
556
|
+
function(next) {
|
|
557
|
+
localPresence1.submit({index: 3}, errorHandler(done));
|
|
558
|
+
presence2.once('error', function(error) {
|
|
559
|
+
expect(error.message).to.equal('uh-oh!');
|
|
560
|
+
next();
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
], done);
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
it('emits errors on the server instead of sending to the client', function(done) {
|
|
567
|
+
var localPresence1 = presence1.create('presence-1');
|
|
568
|
+
|
|
569
|
+
backend.doNotForwardSendPresenceErrorsToClient = true;
|
|
570
|
+
backend.use(backend.MIDDLEWARE_ACTIONS.sendPresence, function(context, next) {
|
|
571
|
+
next(new Error('uh-oh!'));
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
async.series([
|
|
575
|
+
presence2.subscribe.bind(presence2),
|
|
576
|
+
function(next) {
|
|
577
|
+
localPresence1.submit({index: 3}, errorHandler(done));
|
|
578
|
+
presence2.on('error', errorHandler(done));
|
|
579
|
+
backend.errorHandler = function(error) {
|
|
580
|
+
expect(error.message).to.equal('uh-oh!');
|
|
581
|
+
next();
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
], done);
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
});
|
|
490
588
|
});
|