JSONBird-WebSocket makes it easy to establish a JSON-RPC 2.0 client connection over WebSocket so that you can send and receive Remote Procedure Calls. It works in node.js and web browsers. If the connection closes or is unresponsive, an automatic reconnection will occur after a delay. This delay will slowly increase to avoid spamming the server.
This library uses the JSONBird module, which is a more generic JSON-RPC 2.0 library, which can be used to create any kind of client or server over different transports.
Almost all behaviour is configurable, examples include:
ws
module, such as TLS options and HTTP headersHowever the default options should be good enough in most situations.
And some events are available that can be used to hook up logging or provide additional behaviour:
Support for HTML WebSocket in web browsers is provided thanks to the isomorphic-ws
module. You can use browserify or webpack to generate a javascript bundle containing this library and the rest of your own code.
npm install --save jsonbird-websocket ws
The ws
package does not have to be installed if you are only going to use this library for web browsers.
This library sends out ping messages as JSON-RPC method calls (NOT WebSocket pings), the other end is expected to reply to this method call as soon as possible (however the return value is ignored). The default name of this method is "jsonbird.ping"
.
This is an example of the message which will be sent out over the WebSocket connection periodically:
{"jsonrpc":"2.0","id":"10350 HJRolp3jG","method":"jsonbird.ping","params":[]}
The server is then expected to reply with:
{"jsonrpc":"2.0","id":"10350 HJRolp3jG","result":true}
These ping messages are used to ensure that the connection is healthy. If the server does not reply to pings the connection will eventually be closed (and then a new connection will be made).
const {WebSocketClient} = require('jsonbird-websocket');
async function example() {
const rpc = new WebSocketClient({
url: `ws://127.0.0.1:1234/`,
});
rpc.defaultTimeout = 5000;
rpc.on('webSocketError', ({error}) => console.error('Connection failed', error));
rpc.on('webSocketClose', ({code, reason}) => {
console.log('Connection has been closed', code, reason);
if (code === 1008) {
// stop reconnecting when we receive this specific
// close code from the server
rpc.stop();
}
});
// no connection will be made until .start()
rpc.start();
// Send an JSON-RPC 2.0 method call to the server:
const result = await rpc.call('foo', 123, 456);
console.log('result', result);
// Start listening for method calls sent from the server to our client:
rpc.method('sum', async (a, b) => a + b);
};
example().catch(console.error);
Kind: global class
string
boolean
number
number
number
number
function
function
number
boolean
boolean
number
number
number
boolean
boolean
Promise
function
Promise
function
boolean
Param | Type | Default | Description |
---|---|---|---|
[opts] | object |
The effect of these options are documented at the getter/setter with the same name | |
opts.url | string |
||
[opts.createConnectionCallback] | function |
({WebSocket, url}) => new (require('isomorphic-ws'))(url) |
|
[opts.reconnect] | boolean |
true |
|
[opts.reconnectDelayCallback] | function |
x => 2*x 100 * (Math.random() + 0.5) |
|
[opts.reconnectCounterMax] | number |
8 |
|
[opts.connectTimeout] | number |
10000 |
|
[opts.consecutivePingFailClose] | number |
4 |
|
[opts.timeoutCloseCode] | number |
4100 |
|
[opts.internalErrorCloseCode] | number |
4101 |
|
[opts.jsonbird] | object |
Options passed to the JSONBird constructor | |
[opts.jsonbird.receiveErrorStack] | boolean |
false |
|
[opts.jsonbird.sendErrorStack] | boolean |
false |
|
[opts.jsonbird.firstRequestId] | number |
0 |
The first request id to use |
[opts.jsonbird.sessionId] | string |
"randomString()" |
|
[opts.jsonbird.endOfJSONWhitespace=] | string |
||
[opts.jsonbird.endOnFinish] | boolean |
true |
|
[opts.jsonbird.finishOnEnd] | boolean |
true |
|
[opts.jsonbird.pingReceive] | boolean |
true |
|
[opts.jsonbird.pingMethod] | string |
"'jsonbird.ping'" |
|
[opts.jsonbird.pingInterval] | number |
2000 |
|
[opts.jsonbird.pingTimeout] | number |
1000 |
|
[opts.jsonbird.pingNow] | number |
Date.now |
Timer function used to figure out ping delays |
[opts.jsonbird.setTimeout] | function |
global.setTimeout |
|
[opts.jsonbird.clearTimeout] | function |
global.clearTimeout |
The URL to which to connect; this should be the URL to which the WebSocket server will respond.
Kind: instance property of WebSocketClient
Param | Type |
---|---|
value | string |
string
The URL to which to connect; this should be the URL to which the WebSocket server will respond.
Kind: instance property of WebSocketClient
If true, a new connection will be made (after a delay) if the connection closes for any reason (error, timeouts, explicit close)
Kind: instance property of WebSocketClient
Param | Type |
---|---|
value | boolean |
boolean
If true
, a new connection will be made (after a delay) if the connection closes for any reason (error, timeouts, explicit close)
Kind: instance property of WebSocketClient
If this amount of pings fail consecutively, the connection will be automatically closed. If reconnect
is true
a new connection
will be established.
Kind: instance property of WebSocketClient
Param | Type |
---|---|
value | number |
number
If this amount of pings fail consecutively, the connection will be automatically closed. If reconnect
is true
a new connection
will be established.
Kind: instance property of WebSocketClient
Abort the connection if it takes longer than this many milliseconds to complete the connection attempt.
This is the maximum amount of time that we will wait for the WebSocket readyState
to transition from CONNECTING
to OPEN
Kind: instance property of WebSocketClient
Param | Type | Description |
---|---|---|
value | number |
milliseconds |
number
Abort the connection if it takes longer than this many milliseconds to complete the connection attempt.
This is the maximum amount of time that we will wait for the WebSocket readyState
to transition from CONNECTING
to OPEN
Kind: instance property of WebSocketClient
Returns: number
- milliseconds
The close code to send to the server when the connection is going to be closed because of a timeout
Kind: instance property of WebSocketClient
Param | Type | Description |
---|---|---|
value | number |
1000 or in the range 3000 and 4999 inclusive |
number
The close code to send to the server when the connection is going to be closed because of a timeout
Kind: instance property of WebSocketClient
Returns: number
- 1000
or integer in the range 3000
and 4999
inclusive
The close code to send to the server when the connection is going to be closed because an error
event was raised
by the node.js stream api or jsonbird.
Kind: instance property of WebSocketClient
Param | Type | Description |
---|---|---|
value | number |
1000 or in the range 3000 and 4999 inclusive |
number
The close code to send to the server when the connection is going to be closed because an error
event was raised
by the node.js stream api or jsonbird.
Kind: instance property of WebSocketClient
Returns: number
- 1000
or in the range 3000
and 4999
inclusive
A callback which is called whenever this library wants to establish a new WebSocket connection. The callback is called with a single argument, an object containing the following properties:
this.url
window.WebSocket
. Otherwise this value
will be equal to the NPM "ws" package.Kind: instance property of WebSocketClient
Param | Type |
---|---|
value | function |
function
A callback which is called whenever this library wants to establish a new WebSocket connection. The callback is called with a single argument, an object containing the following properties:
this.url
window.WebSocket
. Otherwise this value
will be equal to the NPM "ws" package.Kind: instance property of WebSocketClient
A callback which is called after a failed connection to determine the delay before the next connection attempt.
The callback is called with a single argument, a number specifying the current reconnectCounter
. This counter
is increased by 1
whenever a connection attempt fails, and it is slowly decreased while the connection is healthy
The reconnectCounter is always a value between 0
and this.reconnectCounterMax
inclusive.
The callback must return the reconnect delay as a number in milliseconds.
Kind: instance property of WebSocketClient
Param | Type |
---|---|
value | function |
function
A callback which is called after a failed connection to determine the delay before the next connection attempt.
The callback is called with a single argument, a number specifying the current reconnectCounter
. This counter
is increased by 1
whenever a connection attempt fails, and it is slowly decreased while the connection is healthy
The reconnectCounter is always a value between 0
and this.reconnectCounterMax
inclusive.
The callback must return the reconnect delay as a number in milliseconds.
Kind: instance property of WebSocketClient
The maximum value for the reconnectCounter
(see reconnectDelayCallback). This can be used to easily set a maximum reconnect delay.
For example if reconnectCounterMax
is set to 8
, and reconnectDelayCallback
is set to the default value, the highest reconnect
delay is: 2**8 * 100 * (Math.random() + 0.5)
= random between 12800 and 38400
Kind: instance property of WebSocketClient
Param | Type |
---|---|
value | number |
number
The maximum value for the reconnectCounter
(see reconnectDelayCallback). This can be used to easily set a maximum reconnect delay.
For example if reconnectCounterMax
is set to 8
, and reconnectDelayCallback
is set to the default value, the highest reconnect
delay is: 2**8 * 100 * (Math.random() + 0.5)
= random between 12800 and 38400
Kind: instance property of WebSocketClient
boolean
If true and a remote method throws, attempt to read stack trace information from the JSON-RPC error.data
property. This stack
trace information is then used to set the fileName
, lineNumber
, columnNumber
and stack
properties of our local Error
object (the Error object that the .call()
function will reject with).
Kind: instance property of WebSocketClient
If true and a remote method throws, attempt to read stack trace information from the JSON-RPC error.data
property. This stack
trace information is then used to set the fileName
, lineNumber
, columnNumber
and stack
properties of our local Error
object (the Error object that the .call()
function will reject with).
Kind: instance property of WebSocketClient
Param | Type |
---|---|
value | boolean |
boolean
If true, the fileName
, lineNumber
, columnNumber
and stack
of an Error
thrown during a method is sent to the client
using the JSON-RPC error.data
property.
Kind: instance property of WebSocketClient
If true, the fileName
, lineNumber
, columnNumber
and stack
of an Error
thrown during a method is sent to the client
using the JSON-RPC error.data
property.
Kind: instance property of WebSocketClient
Param | Type |
---|---|
value | boolean |
number
The timeout to use for an outgoing method call unless a different timeout was explicitly specified to call()
.
Kind: instance property of WebSocketClient
The timeout to use for an outgoing method call unless a different timeout was explicitly specified to call()
.
Kind: instance property of WebSocketClient
Param | Type |
---|---|
value | number |
number
The time (in milliseconds) between each ping if isSendingPings
is true.
This time is in addition to the time spent waiting for the previous ping to settle.
Kind: instance property of WebSocketClient
Returns: number
- milliseconds
The time (in milliseconds) between each ping if isSendingPings
is true.
This time is in addition to the time spent waiting for the previous ping to settle.
Kind: instance property of WebSocketClient
Param | Type | Description |
---|---|---|
value | number |
milliseconds |
number
The maximum amount of time (in milliseconds) to wait for a ping method call to resolve.
Kind: instance property of WebSocketClient
Returns: number
- milliseconds
The maximum amount of time (in milliseconds) to wait for a ping method call to resolve.
Kind: instance property of WebSocketClient
Param | Type | Description |
---|---|---|
value | number |
milliseconds |
boolean
Returns true
if this instance has been started. Which means that we are either setting up a connection, connected or waiting for a
reconnect.
Kind: instance property of WebSocketClient
boolean
Returns true
if there is an active WebSocket connection, in which case all RPC calls will be flushed out immediately and at which
point we might receive RPC calls directed to us.
If this property returns false
, all outgoing RPC calls will be queued until we have a connection again
Kind: instance property of WebSocketClient
Registers a new method with the given name.
If the same method name is registered multiple times, earlier definitions will be overridden
Kind: instance method of WebSocketClient
Param | Type | Description |
---|---|---|
name | string |
The method name |
func | function |
Registers multiple methods using an object or Map.
Each key->value pair is registered as a method.
Values that are not a function are ignored.
The this
object during a method call is set to the objectOrMap
(unless a Map was used)
If the same method name is registered multiple times, earlier definitions will be overridden
Kind: instance method of WebSocketClient
Param | Type |
---|---|
objectOrMap | Object | Map |
Registers a notification with the given name.
A notification is a method for which the return value or thrown Error is ignored. A response object is never sent.
If the same method name is registered multiple times, all functions handlers will be called (in the same order as they were registered)
Kind: instance method of WebSocketClient
Param | Type | Description |
---|---|---|
name | string |
The method name |
func | function |
Registers multiple notifications using an object or Map.
A notification is a method for which the return value or thrown Error is ignored. A response object is never sent.
If the same method name is registered multiple times, all functions handlers will be called (in the same order as they were registered)
Each key->value pair is registered as a notification.
Values that are not a "function" are ignored.
The this
object during a method call is set to the objectOrMap
(unless a Map was used)
If the same method name is registered multiple times, earlier definitions will be overridden
Kind: instance method of WebSocketClient
Param | Type |
---|---|
objectOrMap | Object | Map |
Promise
Call a method on the remote instance, by sending a JSON-RPC request object to our write stream.
If no write stream has been set, the method call will be buffered until a write stream is set (setWriteStream). Note: if a read stream is never set, any call() will also never resolve.
Kind: instance method of WebSocketClient
Returns: Promise
- A Promise which will resole with the return value of the remote method
Param | Type | Description |
---|---|---|
nameOrOptions | string | Object |
The method name or an options object |
nameOrOptions.name | string |
The method name |
nameOrOptions.timeout | number |
A maximum time (in milliseconds) to wait for a response. The returned promise will reject after this time. |
...args | * |
function
Returns a new function which calls the given method name by binding the function to this RPC instance and the given method name (or options object).
For example:
const subtract = rpc.bindCall('subtract');
subtract(10, 3).then(result => console.log(result)) // 7
Kind: instance method of WebSocketClient
Param | Type | Description |
---|---|---|
nameOrOptions | string | Object |
The method name or an options object |
nameOrOptions.name | string |
The method name |
nameOrOptions.timeout | number |
A maximum time (in milliseconds) to wait for a response. The returned promise will reject after this time. |
Promise
Execute a notification on the remote instance, by sending a JSON-RPC request object to our write stream.
If no write stream has been set, the method call will be buffered until a write stream is set (setWriteStream).
This function resolves as soon as the request object has been buffered, but does not wait for the remote instance to have actually received the request object.
Kind: instance method of WebSocketClient
Param | Type | Description |
---|---|---|
nameOrOptions | string | Object |
The method name or an options object |
nameOrOptions.name | string |
The method name |
...args | * |
function
Returns a new function which sends a notification with the given method name by binding the function to this RPC instance and the given method name (or options object).
For example:
const userDeleted = rpc.bindNotify('userDeleted');
userDeleted(123)
Kind: instance method of WebSocketClient
Param | Type | Description |
---|---|---|
nameOrOptions | string | Object |
The method name or an options object |
nameOrOptions.name | string |
The method name |
nameOrOptions.timeout | number |
A maximum time (in milliseconds) to wait for a response. The returned promise will reject after this time. |
Establish the WebSocket connection, and automatically reconnect after an network error or timeout.
Kind: instance method of WebSocketClient
Close the active WebSocket connection, and stop reconnecting.
If there is no active connection the code
and reason
params are ignored.
Kind: instance method of WebSocketClient
Param | Type | Default | Description |
---|---|---|---|
code | number |
Must be equal to 1000 or in the range 3000 to 4999 inclusive | |
reason | string |
"Normal Closure" |
Must be 123 bytes or less (utf8) |
boolean
Close the active WebSocket connection and reconnect if reconnects are enabled.
If there is no active connection the code
and reason
params are ignored.
Kind: instance method of WebSocketClient
Param | Type | Description |
---|---|---|
code | number |
Must be equal to 1000 or in the range 3000 to 4999 inclusive |
reason | string |
Must be 123 bytes or less (utf8) |
This event is fired if an uncaught error occurred
Most errors end up at the caller of our functions or at the remote peer, instead of this event. Note that if you do not listen for this event on node.js, your process might exit.
Kind: event emitted by WebSocketClient
Param | Type |
---|---|
error | Error |
This event is fired if our peer sent us something that we were unable to parse.
These kind of errors do not end up at the 'error' event
Kind: event emitted by WebSocketClient
Param | Type |
---|---|
error | Error |
The most recent ping sent to our peer succeeded
Kind: event emitted by WebSocketClient
Param | Type | Description |
---|---|---|
delay | number |
How long the ping took to resolve (in milliseconds) |
The most recent ping sent to our peer timed out or resulted in an error
Kind: event emitted by WebSocketClient
Param | Type | Description |
---|---|---|
consecutiveFails | number |
The amount of consecutive pings that failed |
error | Error |
The WebSocket connection is being established but is not yet open.
Kind: event emitted by WebSocketClient
The WebSocket connection is now open and all pending RPC calls will be flushed to the server
Kind: event emitted by WebSocketClient
The WebSocket API raised an error.
Kind: event emitted by WebSocketClient
Param | Type | Description |
---|---|---|
error | window.Event | ws.ErrorEvent |
When running in node.js this contains an ErrorEvent from the "ws" library, interesting properties include message (string) and error (Error) However when run in a browser, this will contain a plain Event without any useful error information. |
The WebSocket connection has been (half) closed by either side.
Kind: event emitted by WebSocketClient
Type |
---|
Object |
This event is fired if the WebSocket connection has been closed.
A new connection might be established after this event if the reconnect
option is enabled.
Kind: event emitted by WebSocketClient
Param | Type |
---|---|
info | Object |
Example
rpc = new WebSocketClient(...);
rpc.on('webSocketClose', ({code, reason}) => {
if (reason === closeCodes.POLICY_VIOLATION) {
rpc.stop(); // stop reconnecting
}
});