Skip to content

Commit

Permalink
Create .notify(), remove useless timers (fixes #6)
Browse files Browse the repository at this point in the history
  • Loading branch information
vphantom committed Apr 22, 2016
1 parent 40aa0d7 commit a787cae
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 31 deletions.
18 changes: 12 additions & 6 deletions README.md
@@ -1,6 +1,6 @@
# jrpc v3.0.1-beta
# jrpc v3.0.2-beta

[![Build Status](https://travis-ci.org/vphantom/js-jrpc.svg?branch=v3.0.1-beta)](https://travis-ci.org/vphantom/js-jrpc) [![Coverage Status](https://coveralls.io/repos/github/vphantom/js-jrpc/badge.svg?branch=v3.0.1-beta)](https://coveralls.io/github/vphantom/js-jrpc?branch=v3.0.1-beta)
[![Build Status](https://travis-ci.org/vphantom/js-jrpc.svg?branch=v3.0.2-beta)](https://travis-ci.org/vphantom/js-jrpc) [![Coverage Status](https://coveralls.io/repos/github/vphantom/js-jrpc/badge.svg?branch=v3.0.2-beta)](https://coveralls.io/github/vphantom/js-jrpc?branch=v3.0.2-beta)

Streaming bidirectional backwards-compatible extended JSON-RPC 2.0 in JavaScript

Expand Down Expand Up @@ -167,6 +167,8 @@ remote.expose('foo.bar', function(params, next) {
});
```
Due to the nature of JSON-RPC, even methods intended to be used as notification receivers need to call `next()` with at least one parameter, so that if the method is accidentally called requesting a value, one will reach the caller. A simple `next(true)` suffices.
### remote.expose(*object*)
Add many declarations at once:
Expand All @@ -190,18 +192,18 @@ If you are using JRPC on the client side and know in advance that the remote ser
Note that it is important to handshake _after_ having exposed your service methods, because afterwards the other end will be limited to calling method names which have been already exposed at this point. (See `remote.call()` below.)
### remote.call(*methodName*, *params*, *callback*)
### remote.call(*methodName*[, *params*][, *callback*]])
##### Bluebird: remote.callAsync(*methodName*, *params*)
Queue a call to the other end's method `methodName` with `params` as a single argument. Your callback is _guaranteed_ to be invoked even if the server never responds, in which case it would be in error, after a timeout.
Queue a call to the other end's method `methodName` with `params` as a single argument. If you supplied a callback, it is _guaranteed_ to be invoked even if the server never responds, in which case it would be in error, after a timeout. Note that omitting a callback prevents your application from detecting errors, so it should usually be reserved for methods which return no value (called "notifications" in JSON-RPC 2.0).
Note that after a successful `remote.upgrade()`, any attempts to call a `methodName` not disclosed by the remote end during capability handshake will immediately fail. This is to save on useless network round-trips.
While it is up to implementations to decide what to do with `params`: either an Array or an object (alas, no bare values per the specification). I recommend an object so that properties can be named and future changes have less risk of breaking anything.
While it is up to implementations to decide what to do with `params`: either an Array or an object (alas, no bare values per the specification). Specifying `null` is equivalent to omitting it entirely. I recommend an object so that properties can be named and future changes have less risk of breaking anything.
```js
remote._call('foo', [], function(err, result) {
remote.call('foo', {}, function(err, result) {
if (err) {
// Something went wrong...
} else {
Expand All @@ -228,6 +230,10 @@ var fooResult = yield remote.callAsync('foo', {});
It is **strongly recommended** to keep a non-zero remoteTimeout when using co-routines!
### remote.notify(*methodName*[, *params*])
Convenience shortcut to `remote.call()` so that your code can more clearly distinguish between method calls expecting a return value and one-way notifications.
### remote.receive(*message*)
Parse `message` as a JSON-RPC 2.0 request or response. If it's a request, responses will be created and transmitted back (or queued). If it's a response, callers will receive what they were waiting for.
Expand Down
31 changes: 22 additions & 9 deletions jrpc.browser.js
@@ -1,6 +1,6 @@
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.JRPC = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
(function (global){
/*! JRPC v3.0.1-beta
/*! JRPC v3.0.2-beta
* <https://github.com/vphantom/js-jrpc>
* Copyright 2016 Stéphane Lavergne
* Free software under MIT License: <https://opensource.org/licenses/MIT> */
Expand Down Expand Up @@ -261,8 +261,8 @@ function upgrade() {
* Queue up a remote method call
*
* @param {string} methodName Name of method to call
* @param {(Object|Array|null)} params Parameters
* @param {JRPC~receiveCallback} next Callback to receive result
* @param {(Object|Array|null)} [params] Parameters
* @param {JRPC~receiveCallback} [next] Callback to receive result
*
* @return {JRPC} This instance, for chaining
*/
Expand All @@ -272,15 +272,22 @@ function call(methodName, params, next) {
method : methodName
};

if (typeof params === 'function') {
next = params;
params = null;
}

if (
'system._upgraded' in this.remoteComponents
&& !(methodName in this.remoteComponents)
) {
// We're upgraded, yet method name isn't found, immediate error!
setImmediate(next, {
code : -32601,
message: 'Unknown remote method'
});
if (typeof next === 'function') {
setImmediate(next, {
code : -32601,
message: 'Unknown remote method'
});
}
return this;
}

Expand All @@ -290,12 +297,17 @@ function call(methodName, params, next) {
request.params = params;
}

this.inbox[this.serial] = next;
if (typeof next === 'function') {
this.inbox[this.serial] = next;
}
this.outbox.requests.push(request);

// If we're interactive, send the new request
this.transmit();

if (typeof next !== 'function') {
return this;
}
if (this.remoteTimeout > 0) {
this.outTimers[this.serial] = setTimeout(
deliverResponse.bind(
Expand Down Expand Up @@ -476,7 +488,7 @@ function serveRequest(request) {
setImmediate(
this.exposed[request.method],
params,
sendResponse.bind(this, id)
sendResponse.bind(this, id) // id will be unknown, thus will be silent
);

return;
Expand Down Expand Up @@ -556,6 +568,7 @@ function sendResponse(id, err, result, timeout) {
// Public methods

JRPC.prototype.call = call;
JRPC.prototype.notify = call;
JRPC.prototype.expose = expose;
JRPC.prototype.upgrade = upgrade;
JRPC.prototype.receive = receive;
Expand Down
31 changes: 22 additions & 9 deletions jrpc.js
@@ -1,4 +1,4 @@
/*! JRPC v3.0.1-beta
/*! JRPC v3.0.2-beta
* <https://github.com/vphantom/js-jrpc>
* Copyright 2016 Stéphane Lavergne
* Free software under MIT License: <https://opensource.org/licenses/MIT> */
Expand Down Expand Up @@ -259,8 +259,8 @@ function upgrade() {
* Queue up a remote method call
*
* @param {string} methodName Name of method to call
* @param {(Object|Array|null)} params Parameters
* @param {JRPC~receiveCallback} next Callback to receive result
* @param {(Object|Array|null)} [params] Parameters
* @param {JRPC~receiveCallback} [next] Callback to receive result
*
* @return {JRPC} This instance, for chaining
*/
Expand All @@ -270,15 +270,22 @@ function call(methodName, params, next) {
method : methodName
};

if (typeof params === 'function') {
next = params;
params = null;
}

if (
'system._upgraded' in this.remoteComponents
&& !(methodName in this.remoteComponents)
) {
// We're upgraded, yet method name isn't found, immediate error!
setImmediate(next, {
code : -32601,
message: 'Unknown remote method'
});
if (typeof next === 'function') {
setImmediate(next, {
code : -32601,
message: 'Unknown remote method'
});
}
return this;
}

Expand All @@ -288,12 +295,17 @@ function call(methodName, params, next) {
request.params = params;
}

this.inbox[this.serial] = next;
if (typeof next === 'function') {
this.inbox[this.serial] = next;
}
this.outbox.requests.push(request);

// If we're interactive, send the new request
this.transmit();

if (typeof next !== 'function') {
return this;
}
if (this.remoteTimeout > 0) {
this.outTimers[this.serial] = setTimeout(
deliverResponse.bind(
Expand Down Expand Up @@ -474,7 +486,7 @@ function serveRequest(request) {
setImmediate(
this.exposed[request.method],
params,
sendResponse.bind(this, id)
sendResponse.bind(this, id) // id will be unknown, thus will be silent
);

return;
Expand Down Expand Up @@ -554,6 +566,7 @@ function sendResponse(id, err, result, timeout) {
// Public methods

JRPC.prototype.call = call;
JRPC.prototype.notify = call;
JRPC.prototype.expose = expose;
JRPC.prototype.upgrade = upgrade;
JRPC.prototype.receive = receive;
Expand Down

0 comments on commit a787cae

Please sign in to comment.