Skip to content

Commit 9ea3766

Browse files
committed
Proper end of stream signaling to rpcImpl, see #529
1 parent e4faf7f commit 9ea3766

File tree

9 files changed

+53
-23
lines changed

9 files changed

+53
-23
lines changed

dist/protobuf.js

Lines changed: 16 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/protobuf.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/protobuf.min.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/protobuf.min.js.gz

24 Bytes
Binary file not shown.

dist/protobuf.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,17 @@ var Greeter = root.lookup("Greeter"),
3535
Hello = root.lookup("Hello"),
3636
World = root.lookup("World");
3737

38+
var ended = false;
39+
40+
// Implement: Stream-aware RPC implementation
3841
function rpcImpl(method, requestData, callback) {
42+
if (ended)
43+
return;
44+
if (!requestData) {
45+
console.log("rpc ended client-side.");
46+
ended = true;
47+
return;
48+
}
3949
setTimeout(function() {
4050
try {
4151
// <exemplary server side code>
@@ -63,12 +73,14 @@ greeter.on("error", function(err, method) {
6373
console.log("error:", err);
6474
});
6575

66-
greeter.sayHello({ name: 'node' });
67-
greeter.sayHello({ name: 'protobuf' });
68-
greeter.sayHello({ name: 'paralin' });
76+
greeter.sayHello({ name: 'protocol' });
77+
greeter.sayHello({ name: 'buffers' });
78+
greeter.sayHello({ name: 'for' });
6979

7080
setTimeout(function() {
7181
greeter.end();
72-
greeter.sayHello({ name: 'dcode' }); // does nothing
82+
// ^ Signals rpcImpl that the service has been ended client-side by calling it with a null buffer.
83+
// Likewise, rpcImpl can end the stream by calling its callback with an explicit null buffer.
84+
85+
greeter.sayHello({ name: 'javascript' }); // does nothing
7386
}, 1000);
74-
// Likewise, the RPC impl can end the stream by calling its callback with an explicit null message

src/rpc/service.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ function Service(rpcImpl) {
1515
EventEmitter.call(this);
1616

1717
/**
18-
* RPC implementation.
19-
* @type {RPCImpl}
18+
* RPC implementation. Becomes `null` when the service is ended.
19+
* @type {?RPCImpl}
2020
*/
2121
this.$rpc = rpcImpl;
2222
}
@@ -27,8 +27,15 @@ ServicePrototype.constructor = Service;
2727

2828
/**
2929
* Ends this service and emits the `end` event.
30+
* @param {boolean} [endedByRPC=false] Whether the service has been ended by the RPC implementation.
3031
* @returns {rpc.Service} `this`
3132
*/
32-
ServicePrototype.end = function end() {
33-
return this.emit('end').off();
33+
ServicePrototype.end = function end(endedByRPC) {
34+
if (this.$rpc) {
35+
if (!endedByRPC) // signal end to rpcImpl
36+
this.$rpc(null, null, null);
37+
this.$rpc = null;
38+
this.emit('end').off();
39+
}
40+
return this;
3441
};

src/service.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ ServicePrototype.create = function create(rpcImpl, requestDelimited, responseDel
162162
this.getMethodsArray().forEach(function(method) {
163163
var lcName = method.name.substring(0, 1).toLowerCase() + method.name.substring(1);
164164
rpcService[lcName] = function(request, callback) {
165+
if (!rpcService.$rpc) // already ended?
166+
return;
165167
method.resolve();
166168
var requestData;
167169
try {
@@ -178,7 +180,7 @@ ServicePrototype.create = function create(rpcImpl, requestDelimited, responseDel
178180
return callback ? callback(err) : undefined;
179181
}
180182
if (responseData === null) {
181-
rpcService.emit('end', method);
183+
rpcService.end(/* endedByRPC */ true);
182184
return undefined;
183185
}
184186
var response;

src/util/eventemitter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ EventEmitterPrototype.off = function off(evt, fn) {
6060
};
6161

6262
/**
63-
* Emits an event.
63+
* Emits an event by calling its listeners with the specified arguments.
6464
* @param {string} evt Event name
6565
* @param {...*} args Arguments
6666
* @returns {util.EventEmitter} `this`

0 commit comments

Comments
 (0)