JSON-RPC 2.0 implementation over WebSockets for Node.js and JavaScript/TypeScript

Overview

WebSockets for Node.js and JavaScript/TypeScript with JSON RPC 2.0 support on top.




About

The rpc-websockets library enables developers to easily implement their business logic that includes messaging between users, machines or any devices. It provides a possibility to send and receive JSON data through the WebSocket communication protocol in order to support two-way notification push, running RPC methods and firing any types of event signalling. Only clients can call RPC methods and not vice versa at the moment. Both frontend (HTML/JS-based) and backend (Node.js-based) development environments are supported.

rpc-websockets is built on Node.js and supports both LTS and Current versions.

Use the free OSS edition in order to implement and manage your own WebSocket server instances, or subscribe for our Pro plan and have us manage your instances and provide you with management of your methods, events and notifications on an easy-to-use Web Management portal.

Quick start

Install our OSS library in your project:

npm install rpc-websockets

Write your source code using rpc-websockets:

var WebSocket = require('rpc-websockets').Client
var WebSocketServer = require('rpc-websockets').Server

// instantiate Server and start listening for requests
var server = new WebSocketServer({
  port: 8080,
  host: 'localhost'
})

// register an RPC method
server.register('sum', function(params) {
  return params[0] + params[1]
})

// ...and maybe a protected one also
server.register('account', function() {
  return ['confi1', 'confi2']
}).protected()

// create an event
server.event('feedUpdated')

// get events
console.log(server.eventList())

// emit an event to subscribers
server.emit('feedUpdated')

// close the server
server.close()

// instantiate Client and connect to an RPC server
var ws = new WebSocket('ws://localhost:8080')

ws.on('open', function() {
  // call an RPC method with parameters
  ws.call('sum', [5, 3]).then(function(result) {
    require('assert').equal(result, 8)
  })

  // send a notification to an RPC server
  ws.notify('openedNewsModule')

  // subscribe to receive an event
  ws.subscribe('feedUpdated')

  ws.on('feedUpdated', function() {
    updateLogic()
  })

  // unsubscribe from an event
  ws.unsubscribe('feedUpdated')

  // login your client to be able to use protected methods
  ws.login({'username': 'confi1', 'password':'foobar'}).then(function() {
    ws.call('account').then(function(result) {
      require('assert').equal(result, ['confi1', 'confi2'])
    })
  }).catch(function(error) {
    console.log('auth failed')
  })

  // close a websocket connection
  ws.close()
})

Documentation

Please consult our API documentation for both WebSocket server and client JavaScript and TypeScript classes.

OSS Features

Features of the free open-source edition.

OSS Features

All library's open-source features are documented in our API documentation and can be used free of charge. You are free to implement your solutions based on provided methods in any way you are comfortable with, as long as you use our work along our very permissive license conditions.

Pro Features

In order to support your production-ready environments, we can provide you with additional features built on top of our free OSS edition along with the skill set to turn your business case or a Proof-of-Concept idea into reality.

Pro Features

Describe us your use case by contacting us and we will swiftly get back to you with a proposed solution that meets your needs.

Professional support

We offer professional support for rpc-websockets and beyond. We have many years of expertise on building robust, scalable Node.js applications and can help you overcome issues and challenges preventing you to ship your great products. We excel in software architecture and implementation, being able to provide you with development, planning, consulting, training and customization services. Feel free to contact us so we can discuss how to help you finish your products!

Users

rpc-websockets is being actively used in production by multiple companies in a variety of different use cases.


ScratchboxLoom NetworkuniqCastLeapDAOKlika Tech, Inc.Kodebox, Inc.Hey-Group S.A./N.V.Hylo, Inc.Witnet FoundationScale LeapCodice Foundation, Inc.Holo Ltd.Solana Labs, Inc.Filecoin

Sponsors

Become a sponsor and get your logo on project's README on GitHub with a link to your site. Feel free to contact us for the arrangement!

License

This library is licensed under LGPLv3. Please see LICENSE for licensing details.

Comments
  • Support for server request and client response

    Support for server request and client response

    We have a case when the server should make requests to the client. At this point this library do not have such functionality, while specification do not restrict regarding this.

    Do you interested in merging such PR if we will implement it?

    enhancement help wanted 
    opened by ScriptWorker 13
  • Server should check socket state before calling 'send' method

    Server should check socket state before calling 'send' method

    https://github.com/elpheria/rpc-websockets/blob/2f0f59e181e4b5338b878848a53198bcb199ee6f/src/lib/server.js#L417

    In case if client socket closes the connection - 'send' will cause an unhandled rejection, which in some production environments might lead to application crash!

    Mentioned problem is relevant to any other socket.send call.

    Steps to reproduce:

    1. Call some long running rpc task
    2. Close client connection
    3. After task has finished - unhandledRejection will be triggered
    opened by coderNeos 8
  • pass options into ws instance

    pass options into ws instance

    Not of all options are passed into ws instance now. For example, without my suggestion, ws-server does not receive custom headers: const Websocket = require('rpc-websockets').Client; const options = { autoconnect: true, reconnect: false, headers: { 'x-header1': 'x-header1', 'x-header2': 'x-header2' } }; const ws = new Websocket('ws://localhost:8080', options);

    opened by andrsyash 7
  • login middleware authenticates all clients

    login middleware authenticates all clients

    Hi, Trying to understand how login middlewere should work.

    Came across this code:

    // if login middleware returned true, set connection as authenticated
            if (message.method === "rpc.login" && response === true)
                this.authenticated = true
    

    Does it mean that after one client authenticates, all clients are authenticated automatically?

    bug help wanted 
    opened by sk91 7
  • Browser client

    Browser client

    Hi,

    Thanks for the great library! I've written a small Node JS server, and I want to use it from my frontend running in the browser. Can I do that? I saw a dist/index.browser-bundle.js file and included it in my index.html. How can I instantiate the client using this bundle? Normally I would do: var WebSocket = require('rpc-websockets').Client var ws = new WebSocket('ws://localhost:8080') What's the equivalent if using the browser-bundle?

    Thanks!

    Dinko

    opened by dinkoivanov 7
  • Add circular object support to emitted events

    Add circular object support to emitted events

    This is related to #12. When adding support for circular objects, only parameters for RPC methods were implemented. This update adds support for the data passed through events as well.

    opened by dstreet 7
  • Client 'on' params as an Object

    Client 'on' params as an Object

    https://github.com/qaap/rpc-websockets/blob/c335c872f8ea46df06848d21ac57df30457322d7/src/lib/client.js#L218

    I can't use notification parameters if it is an Object, only if it is an Array.

    opened by sir-go 7
  • Send notifications on next tick

    Send notifications on next tick

    Fixes: https://github.com/elpheria/rpc-websockets/issues/83

    This is a quick and dirty fix for the race condition. Feel free to go with another approach

    opened by jstarry 6
  • login promise should be rejected upon failed login

    login promise should be rejected upon failed login

    Greetings! Thanks for the great library, starting to put it to use in a new project.

    While experimenting w/ the authentication feature, I noticed the client 'login' promise will always result the 'resolve' callback being invoked even if setAuth returns false. The client can distinguish between successful and failed logins via the parameter specified to this callback (true for success, false for failure) but I feel it would be more inline w/ asynchronous javascript if the 'reject' callback was invoked on failure.

    eg in the current situation the client needs to be implemented like so:

    ws.login({username, password}).then(function(result) {
      if(result)
        ; // handle successful login
      else
        ; // handle failed login
    })
    

    If implemented via resolve/reject, the client could handle the two cases like so:

    ws.login({username, password}).then(function(result) {
      ; // handle success login
    
    }).catch(function(err){
      ; // handle failed login
    })
    

    Thoughts?

    opened by movitto 6
  • Need help: How work with this API, Add ID to JSON-RPC call

    Need help: How work with this API, Add ID to JSON-RPC call

    https://hitbtc.com/api#get-currencies
    How to add id to JSON-RPC call

    {
      "method": "getCurrency",
      "params": {
        "currency": "ETH"
      },
      "id": 123
    }
    
    opened by meotimdihia 6
  • No RPC exception is thrown when a received Response object does not contain both the

    No RPC exception is thrown when a received Response object does not contain both the "result" and "error" fields

    Hi, I was using the client in the library against a simple server that echoes the JSON message sent by the client, for example:

    {
      "jsonrpc":"2.0",
      "method":"runScript",
      "params":["test"],
      "id":4
    }
    

    Per JSON-RPC 2.0 spec, the server is required to respond with a Response object which contains a result property in case of success, or an error on in case of error. But, when my server responses with that JSON, both of them are absent. So I expected to receive an RPC exception when making a call() and getting this as response. Instead, the method simply resolves with an undefined result. Is this intended behavior?

    opened by debevv 5
  • The Map type cannot be returned using the Server registration method

    The Map type cannot be returned using the Server registration method

    issue

    I register a method by using the Server. The method returns a data body of Map type, but I get {} from the Client

    code template

    //Server
    server.register('getMap', function (params) {
      console.log(
        "---> {'method':'getMap','params':%0}", params
      );
      return new Map([['str', new Array(6).fill(0.0)]]);
    });
    //Client
    let result = await client.call('getMap', []);
    
    opened by ghostxbh 2
  • Help! Run ws on the same port as a http Express?

    Help! Run ws on the same port as a http Express?

    How to run ws on the same port as a http Express?

    I tried the example express-session-parse given by ws (link), and replace the const { WebSocketServer } = require('ws'); to const WebSocketServer = require('rpc-websockets').Server;, and add a hello remote function, but it didn't work. The client has no output, the server output is only Parsing session from request...

    What need I do?

    The source code of server and client are :

    server

    // server: index.json
    'use strict';
    
    const session = require('express-session');
    const express = require('express');
    const http = require('http');
    const uuid = require('uuid');
    
    const  WebSocketServer = require('rpc-websockets').Server;
    
    const app = express();
    const map = new Map();
    
    //
    // We need the same instance of the session parser in express and
    // WebSocket server.
    //
    const sessionParser = session({
      saveUninitialized: false,
      secret: '$eCuRiTy',
      resave: false
    });
    
    //
    // Serve static files from the 'public' folder.
    //
    app.use(express.static('public'));
    app.use(sessionParser);
    
    app.post('/login', function (req, res) {
      //
      // "Log in" user and set userId to session.
      //
      const id = uuid.v4();
    
      console.log(`Updating session for user ${id}`);
      req.session.userId = id;
      res.send({ result: 'OK', message: 'Session updated' });
    });
    
    app.delete('/logout', function (request, response) {
      const ws = map.get(request.session.userId);
    
      console.log('Destroying session');
      request.session.destroy(function () {
        if (ws) ws.close();
    
        response.send({ result: 'OK', message: 'Session destroyed' });
      });
    });
    
    //
    // Create an HTTP server.
    //
    const server = http.createServer(app);
    
    //
    // Create a WebSocket server completely detached from the HTTP server.
    //
    const wss = new WebSocketServer({ clientTracking: false, noServer: true });
    
    server.on('upgrade', function (request, socket, head) {
      console.log('Parsing session from request...');
    
      sessionParser(request, {}, () => {
        if (!request.session.userId) {
          socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
          socket.destroy();
          return;
        }
    
        console.log('Session is parsed!');
    
        wss.handleUpgrade(request, socket, head, function (ws) {
          wss.emit('connection', ws, request);
        });
      });
    });
    wss.on('listening',()=>{
    wss.register('hello',({index})=>{
      console.log(index);
      return `index:${index}`;
    })
    
    })
    wss.on('connection', function (ws, request) {
      const userId = request.session.userId;
    
      map.set(userId, ws);
    
      ws.on('message', function (message) {
        //
        // Here we can now use session parameters.
        //
        console.log(`Received message ${message} from user ${userId}`);
      });
    
      ws.on('close', function () {
        map.delete(userId);
      });
    });
    //
    // Start the server.
    //
    server.listen(8082, function () {
      console.log('Listening on http://localhost:8082');
    });
    
    

    client

    // client: rpc_client.js
    const WebSocket = require('rpc-websockets').Client;
    // instantiate Client and connect to an RPC server
    const ws = new WebSocket('ws://localhost:8082/');
    ws.on('open', function () {
        console.log("connected");
        ws.call("hello",{index},).then((ret)=>{
            console.log(ret);
        }).catch(err=>{
            console.trace(err);
        })
    
    });
    
    opened by m2kar 0
  • Ignore null in result/error

    Ignore null in result/error

    Hi! 👋

    Firstly, thanks for your work on this project! 🙂

    Today I used patch-package to patch [email protected] for the project I'm working on.

    whitebit.com sends "error: null" and I constantly get Server response malformed. Response must include either \"result\"" + " or \"error\", but not both.

    Here is the diff that solved my problem:

    diff --git a/node_modules/rpc-websockets/dist/lib/client.js b/node_modules/rpc-websockets/dist/lib/client.js
    index f07ce1d..2207e56 100644
    --- a/node_modules/rpc-websockets/dist/lib/client.js
    +++ b/node_modules/rpc-websockets/dist/lib/client.js
    @@ -451,6 +451,12 @@ var CommonClient = /*#__PURE__*/function (_EventEmitter) {
             } // reject early since server's response is invalid
     
     
    +        if (message.error === null) {
    +          delete message.error
    +        }if (message.result === null) {
    +          delete message.result
    +        }
    +
             if ("error" in message === "result" in message) _this4.queue[message.id].promise[1](new Error("Server response malformed. Response must include either \"result\"" + " or \"error\", but not both."));
             if (_this4.queue[message.id].timeout) clearTimeout(_this4.queue[message.id].timeout);
             if (message.error) _this4.queue[message.id].promise[1](message.error);else _this4.queue[message.id].promise[0](message.result);
    

    This issue body was partially generated by patch-package.

    opened by kakserpom 2
  • Rpc-websockets on heroku

    Rpc-websockets on heroku

    After i deployed my app on heroku i had an issue, if you can help me please

    
    const app = express()
    const port = process.env.PORT || 8080 // Heroku will need the PORT environment variable
    
    app.use(express.static(path.join(__dirname, 'build')));
    app.get('/*', function (req, res) {
      res.sendFile(path.join(__dirname, 'build', 'index.html'));
    });
    
    app.listen(port, () => console.log(`App is live on port ${port}!`))
    
    // instantiate Server and start listening for requests
    
    var server = new WebSocketServer({
      port: port,
      host: anaddress
    })
    
    

    how can i please pass the express server (as a param) to the websocket server?

    Thank you

    opened by mojitoo 0
  • How subscribe an event created inside a namespace.

    How subscribe an event created inside a namespace.

    Hi, I've created an event inside a namespace:

       [...]
       server.event(name, ns);
       [...]
    

    Then I use this command to emit a new event:

       [...]
       server.emit(name, state);
       [...]
    

    On the client I try to subscribe to the event in this way:

          ws.subscribe(name);
          ws.on(name, (param) => {
             console.log('new notify: ', param);
          });
    

    But I don't get any update. I can get it just when I don't use namespace.

    Thanks, Mirko

    opened by Free-Devel 3
Releases(v7.4.16)
Owner
Elpheria
Smart, Connected and Cloud systems consulting services
Elpheria
simple chat app created with nextjs, express, tailwindcss, and WebSockets

This is a Next.js project bootstrapped with create-next-app. Getting Started First, run the development server: npm run dev # or yarn dev Open http://

Erfan Hanifezade 10 Sep 10, 2022
soketi is your simple, fast, and resilient open-source WebSockets server

soketi soketi is your simple, fast, and resilient open-source WebSockets server. ?? Blazing fast speed ⚡ The server is built on top of uWebSockets.js

Soketi 3.2k Jan 4, 2023
A Promise-based API for WebSockets

websocket-as-promised A WebSocket client library with Promise-based API for browser and Node.js. Example import WebSocketAsPromised from 'websocket-as

Vitaliy Potapov 547 Dec 18, 2022
Lightweight WebSocketServer wrapper lib using ws-wrapper to wrap connected WebSockets

ws-server-wrapper Lightweight WebSocketServer wrapper lib using ws-wrapper and ws to wrap connected WebSockets. The only dependency is ws-wrapper itse

Blake Miner 17 May 9, 2022
A WebSocket Implementation for Node.JS (Draft -08 through the final RFC 6455)

WebSocket Client & Server Implementation for Node Overview This is a (mostly) pure JavaScript implementation of the WebSocket protocol versions 8 and

Brian McKelvey 3.6k Dec 30, 2022
Simple to use, blazing fast and thoroughly tested WebSocket client and server for Node.js

ws: a Node.js WebSocket library ws is a simple to use, blazing fast, and thoroughly tested WebSocket client and server implementation. Passes the quit

WebSockets 19.2k Jan 4, 2023
A node.js module for websocket server and client

Nodejs Websocket A nodejs module for websocket server and client How to use it Install with npm install nodejs-websocket or put all files in a folder

Guilherme Souza 719 Dec 13, 2022
Node.js library to receive live stream chat events like comments and gifts in realtime from TikTok LIVE.

TikTok-Live-Connector A Node.js library to receive live stream events such as comments and gifts in realtime from TikTok LIVE by connecting to TikTok'

David 399 Jan 4, 2023
WebSocket emulation - Node.js server

SockJS-node SockJS for enterprise Available as part of the Tidelift Subscription. The maintainers of SockJS and thousands of other packages are workin

SockJS 2.1k Dec 29, 2022
μWebSockets for Node.js back-ends :metal:

Simple, secure[1] & standards compliant[2] web server for the most demanding[3] of applications. Read more... A note on NPM drama ⚡ Simple performance

uNetworking AB 5.7k Jan 8, 2023
ONG-Node JS

Server Base - Proyecto ONG Envinroment setup Create database Copy .env.example to .env and fill with database credentials.

Alkemy 2 Dec 30, 2021
Sse-example - SSE (server-sent events) example using Node.js

sse-example SSE (server-sent events) example using Node.js SSE is a easy way to commutate with the client side in a single direction. it has loss cost

Jack 2 Mar 11, 2022
Mini Projeto de um chat-app usando o protocolo WebSocket através da lib 'ws' do node.js

CHAT-APP-WEBSOCKET Mini Projeto de um chat-app usando o protocolo WebSocket através da lib 'ws' do node.js Obs o intuito deste projeto não é o fronten

Vinicius dos Santos Rodrigues 4 Jul 14, 2022
Unix dgram, seqpacket, etc binding for Node.js.

node-unix-socket node-unix-socket allows you to use some nonblocking unix sockets that are currently not supported by Node.js native modules, includin

Bytedance Inc. 31 Dec 27, 2022
This Repository implements an Authenticated Websocket Server built in Node Js along ws library.

websockets-authentication-server This Repository implements an Authenticated Websocket Server built in Node Js along ws library. Features Authenticate

M.Abdullah Ch 7 May 5, 2023
Simple realtime chat application made by NodeJS, Express, Socket.io and Vanilla Javascript. This project is made to discover socket.io and understand its basic features.

LearnByChat App Simple realtime chat application made with NodeJS, Express, Socket.io and Vanilla Javascript. This project is made to discover socket.

Ayoub Saouidi 1 Dec 19, 2021
JavaScript library that adds a 'read more' functionality on the text blocks that is applied to.

ReadMore.js JavaScript library that adds a 'Read more/less' functionality on the text blocks that is applied to. API & Usage // Initialise var destroy

George Raptis 29 Oct 14, 2022
Standards-compliant WebSocket client and server

faye-websocket This is a general-purpose WebSocket implementation extracted from the Faye project. It provides classes for easily building WebSocket s

null 588 Dec 23, 2022
Lightweight WebSocket lib with socket.io-like event handling, requests, and channels

ws-wrapper Lightweight and isomorphic Web Socket lib with socket.io-like event handling, Promise-based requests, and channels. What? Much like Socket.

Blake Miner 70 Dec 23, 2022