websocket13-jsonrpc v2.0.1
websocket13-jsonrpc
This is a server implementation of JSON-RPC 2.0 over WebSockets.
A browser client implementation is available under browser.
If you want to write your own implementation, the only special consideration is that incoming connections must support
the subprotocol jsonrpc-2.0.
Please note that this server implementation does not support JSON-RPC batches, since that practically isn't useful over a transport like WebSocket.
Exports
The module exports the following:
ConnectionState- An enum indicating the state an individual connection is inJsonRpcErrorCode- An enum containing reserved JSON-RPC error codesWebSocketStatusCode- An enum containing WebSocket closure status codesRpcError- An extension toErrorused for responding to RPC calls with errorsWsRpcConnection- An object representing individual connectionsWsRpcServer- An object for running a serverWsRpcOutgoingConnection- An object representing outgoing connections
ConnectionState
JsonRpcErrorCode
Reserved JSON-RPC error codes are defined here.
WebSocketStatusCode
RpcError
Constructed with 3 parameters:
message- A string containing an error messagecode- A number containing an error code (MUST be an integer)data- An optional value of any type to be sent along with the error
Example
const {RpcError} = require('websocket13-jsonrpc2');
throw new RpcError('File not found', 100, {filename: '/root/example.txt'});WsRpcConnection
This class is not to be instantiated directly.
Properties
id
A string containing a UUIDv4 assigned to this connection.
remoteAddress
The remote IP address.
server
The WsRpcServer that spawned this connection.
state
The state of this connection. This is a value from ConnectionState
handshakeData
The data object from the handshake event for this connection.
groups
An array containing the string name of each group that this connection is a member of.
Methods
disconnect(statusCode, reason)
statusCode- A value fromWebSocketStatusCodereason- An optional string reason for the closure
Closes an active connection. If the connection is already closed, does nothing.
getPeerCertificate(detailed)
Same as tls.TLSSocket.getPeerCertificate.
Returns null if the current connection is not secure.
getSecurityProtocol()
Same as tls.TLSSocket.getProtocol.
Returns null if the current connection is not secure.
data(key, value)
key- Stringvalue- Any type
Associate any arbitrary data with this connection. If value is undefined, returns the current value of key.
If value is defined, sets key to that value and returns the previous value.
ping()
Sends a ping frame to the remote. Returns a Promise that is resolved with the time in milliseconds that it took to receive the reply.
Example
async function pingClient() {
let latency = await client.ping();
console.log(`Client ${client.id}'s latency is ${latency} milliseconds.`);
}joinGroup(group)
group- String group name
Joins this connection to a group. Groups are used to broadcast messages to groups of connections all at once. For example, you might put connections in a particular chat room into one group, or you might put connections authenticated to a given user ID in a dedicated group.
Groups are ad-hoc and are created or destroyed as needed.
Returns true if this connection was joined to the group successfully, or false if it was already in the given group.
leaveGroup(group)
group- String group name
Leaves this connection from a group. If this was the last member of the group, the group is destroyed.
Returns true if this connection left the group successfully, or false if it was not in the given group.
notify(method, params)
method- String method nameparams- Any data type
Sends a notification to the remote. JSON-RPC notifications are messages which may not be responded to.
Returns true if the notification was sent, or false if the connection was not open.
invoke(method, params)
method- String method nameparams- Any data type
Sends a request to the remote. Returns a Promise that will be resolved with the result of the request, or rejected with
a RpcError if the request fails.
Events
latency
pingTime- Round-trip latency in milliseconds
Emitted periodically (unless you've disabled pings in options) with the latency of the connection.
WsRpcServer
This class instantiates a WebSocket server.
The constructor takes a single options object:
requireObjectParams- See below- All other options from
WS13.WebSocketServerare allowed, exceptprotocols.
requireObjectParams
If requireObjectParams is set to true, then the following will happen:
- If the
paramsproperty of incoming messages is undefined or null, it will be converted to{}(empty object) - If the
paramsproperty of incoming messages is not an object, array, undefined, or null, then the message will be rejected with error code -32602 and message"Invalid params" - If the
paramsproperty of outgoing messages is undefined or null, it will be converted to{}(empty object)
This option is designed to allow you to do things like this without worrying about invalid incoming params causing a crash:
server.registerMethod('Add', (connection, [a, b]) => {
if (typeof a != 'number' || typeof b != 'number') {
throw new RpcError('An operand is not a number', JsonRpcErrorCode.InvalidParams);
}
return a + b;
});The module cannot validate that the incoming params object actually contains the keys you're expecting, so you still
need to check their types and values yourself.
Events
handshake
handshakeDatarejectaccept
Same as websocket13's handshake event, with these exceptions:
accept()returns aWsRpcConnectioninstead of aWebSocket- It is not possible to override
protocolinaccept()
This event must be handled or else all incoming connections will stall.
connect
connection- TheWsRpcConnectionthat connected
Emitted when a new connection is established.
disconnect
connection- TheWsRpcConnectionthat disconnectedcode- A value fromWebSocketStatusCodereason- A string, possibly empty, describing why they disconnectedinitiatedByUs- A boolean indicating whether the disconnection was initiated by the server (true) or by the client (false)
Emitted when a remote disconnects.
Properties
connections
An array containing all currently-active WsRpcConnection objects.
groups
An array containing strings of the names of all groups that currently have members.
Methods
http(server)
server- Either anhttp.Serveror anhttps.Server
Listen for WebSocket connections on this server. You can call this for more than one HTTP(S) server, but you shouldn't call it more than once per server. For example, if you're accepting both secure and insecure connections, you should call this once with an HTTP server, and once with an HTTPS server.
This binds to the server's upgrade event. If nothing else has bound to that event, then node-websocket13 will respond to bad handshakes with an HTTP 400 response. Otherwise, it will do nothing. Bad handshakes are those which match any of the following criteria:
Upgradeheader does not match the valuewebsocket(case-insensitively)Connectionheader does not contain the valueupgrade(case-insensitively, interpreting the header value as a comma-separated list)- For example,
Connection: keep-alive, upgradeis valid, butConnection: keep-alive upgradeis not
- For example,
- Client HTTP version is not at least 1.1
- Client request method is not
GET - Client request is missing
Sec-WebSocket-Keyheader or when base64-decoded, it is not 16 bytes in length - Client request is missing
Sec-WebSocket-Versionheader or the header's value is not13
groupMembers(group)
group- Either a group name or an array of group names
Returns an array of WsRpcConnection objects for the members in the given set of groups. If you
pass a single string, returns the list of members of that group. If you pass an array of strings, returns a de-duplicated
union of group members.
registerMethod(name, handler)
name- String method namehandler- A function to be invoked when the method is called
Registers a new method. When JSON-RPC messages invoking this method are received, the handler will be called with the
signature (WsRpcConnection connection, any params).
Please note that unless the requireObjectParams option is set, params can be any JSON type
(including null or undefined).
The handler function must return either a response value or a Promise which is resolved to the response value.
If an error occurs while processing this method, you must throw (or reject the Promise with) a RpcError,
which will be sent to the remote as an error response.
By default, if a method invocation is received that does not match any registered method, a method not found error will be sent back. If you want to process unregistered methods yourself, you can use the DEFAULT_HANDLER symbol.
Example
const {RpcError, JsonRpcErrorCode, DEFAULT_HANDLER} = require('websocket13-jsonrpc2');
server.registerMethod('Add', (connection, params) => {
if (typeof params != 'object' || !Array.isArray(params) || params.length != 2 || typeof params[0] != 'number' || typeof params[1] != 'number') {
throw new RpcError('Invalid params', JsonRpcErrorCode.InvalidParams);
}
return params[0] + params[1];
});
server.registerMethod('AddAsync', async (connection, params) => {
if (typeof params != 'object' || !Array.isArray(params) || params.length != 2 || typeof params[0] != 'number' || typeof params[1] != 'number') {
throw new RpcError('Invalid params', JsonRpcErrorCode.InvalidParams);
}
await new Promise((resolve) => setTimeout(resolve, 1000));
return params[0] + params[1];
});
// This is only safe if you've enabled requireObjectParams, otherwise an incoming params value that isn't an object or
// array will cause a crash.
server.registerMethod('Subtract', (connection, [a, b]) => {
if (typeof a != 'number' || typeof b != 'number') {
throw new RpcError('Invalid params', JsonRpcErrorCode.InvalidParams);
}
return a - b;
});
server.registerMethod(DEFAULT_HANDLER, (connection, method, params) => {
console.log(`Client ${connection.id} invoked unregistered method ${method} with params ${params}`);
return 1;
});registerNotification(name, handler)
name- String namehandler- A function to be invoked when the notification is received
Registers a new notification. When JSON-RPC messages containing this notification are received, the handler will be
called with the signature (WsRpcConnection connection, any params).
Please note that unless the requireObjectParams option is set, params can be any JSON type
(including null or undefined).
As a JSON-RPC notification requires no response, handler should not return anything.
You can also register a default handler for notifications in the same way as for methods.
notify(group, name, params)
group- String name of group or array of string names of groups to send notification to. Usenullto send a notification to all active clients.name- String name of notification to sendparams- Any data type
Sends a JSON-RPC notification to an entire group at once. You can also pass an array of groups to send a notification to all members of all specified groups.
Returns a number indicating how many clients received this notification.
notifyAll(name, params)
name- String name of notification to sendparams- Any data type
Sends a JSON-RPC notification to all connected clients. Returns a number indicating how many clients received this notification.
WsRpcOutgoingConnection
This class extends WsRpcConnection. Methods, properties, and events inherited from that class
are not listed below, so you should check those docs as well.
Used to establish outgoing connections. You should instantiate a new instance of this class to establish a new outgoing connection to a JSON-RPC server.
The constructor takes two arguments:
url- The WebSocket URL you want to connect to (e.g.ws://example.com/?some=query)options- Optional. An object with zero or more of these properties:requireObjectParams- SeerequireObjectParamsdocumentation forWsRpcServerAll other options from
WS13.WebSocketare allowed, exceptprotocols.
Example
const {WsRpcOutgoingConnection} = require('websocket13-jsonrpc');
let conn = new WsRpcOutgoingConnection('ws://127.0.0.1:8080', {pingInterval: 30000});Properties
server
Always null for outgoing connections.
groups
Always [] (empty array) for outgoing connections.
Methods
joinGroup()
Outgoing connections cannot be joined to groups, so this method throws an Error if invoked.
leaveGroup()
Outgoing connections cannot be joined to groups, so this method throws an Error if invoked.
registerMethod(name, handler)
name- Stringhandler- Function
Functionally identical to WsRpcServer#registerMethod(name, handler).
This is how you should register methods for outgoing connections.
registerNotification(name, handler)
name- Stringhandler- Function
Functionally identical to WsRpcServer#registerNotification(name, handler).
This is how you should register notifications for outgoing connections.
Events
connected
details- An object containing connection details. Identical toWS13.WebSocket#connected
Emitted when the connection is successfully established.
disconnected
code- A value fromWebSocketStatusCodereason- A string, possibly empty, describing why we disconnectedinitiatedByUs- A boolean indicating whether the disconnected was initiated by us/the client (true) or by the server (false)
Emitted when we disconnect from the server.
error
err- AnErrorobject
Emitted when a fatal error causes our connection to fail (while connecting) or be disconnected (while connected).
Under certain conditions, err may contain zero or more of these properties:
responseCode- The HTTP status code we received if the error occurred during the handshakeresponseText- The HTTP status text we received if the error occurred during the handshakehttpVersion- The HTTP version employed by the server if the error occurred during the handshakeheaders- An object containing the HTTP headers we received from the server if the error occurred during the handshakeexpected- A string containing theSec-WebSocket-Acceptvalue we expected to receive, if the error occurred because we didn'tactual- A string containing the actualSec-WebSocket-Acceptvalue we received, if the error occurred because it didn't match what we expectedstate- The connection state at the time of error. Always present.code- A value from theWS13.StatusCodeenum, if the error occurred after the WebSocket connection was established