Introduction

Websocket client for browser platform. The client works best with the Regoch Websocket Server. Small, optimised and very powerful library made according to RFC6455 Standard for websocket version 13.

Features

  • RFC6455, websocket v.13
  • supported subprotocols: jsonRWS, raw
  • small, medium and large messages (up to 9,007,199,254 gigabytes or ~9 quadrillion bytes)
  • rooms - send group message to a subscribed clients
  • small file size, minified (*~7.5kB only*)
  • powerful API which saves your development time
  • use it in your browserify project
  • easy integration with RxJS

Installation

Install the websocket client in your project via npm:

$ npm install --save regoch-websocket


How to use

A short example how to use Browser Websocket Client after installation:

<script src="node_modules/regoch-websocket/clientBrowser/dist/client13jsonRWS/client13jsonRWS-min.js"></script>

<button onclick="testCB.connectMe()">Connect</button>
  

class TestClient extends window.regochWebsocket.Client13jsonRWS {
  constructor(wcOpts) { super(wcOpts); }

  async connectMe() {
    const wsocket = await this.connect();
    console.log('+++Connected', wsocket);
  }
}

const wcOpts = {
  wsURL: 'ws://localhost:3211?authkey=TRTmrt',
  questionTimeout: 3*1000, // wait 3 seconds for answer
  reconnectAttempts: 5, // try to reconnect 5 times
  reconnectDelay: 3000, // delay between reconnections is 3 seconds
  subprotocols: ['jsonRWS'],
  debug: false
};
const testCB = new TestClient(wcOpts);
  


or in the Browserify

const { RWClientBrowser } = require('regoch-websocket')
class TestClient extends RWClientBrowser { ... }
  

Exports in the npm package


module.exports = {
  RWServer,
  RWHttpServer,
  RWClientNodejs,
  RWClientBrowser,
  lib
};
  

License

The software is published under MIT License.
The MIT License

Copyright (C) 2021  Saša Mikodanić http://www.regoch.org

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to
whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

class RWClientBrowser

The websocket client for:
- websocket version 13
- subprotocol: jsonRWS (Regoch Router can be used on the client side)
- current file: Client13jsonRWS.js

Subprotocol jsonRWS the message fomat {id :number, from :number, to :number, cmd :string, payload :any}

Properties

Client13jsonRWS

PropertyDescriptionTypeDefault
wcOptswebsocket client options (see the table below)object
wsocketWebsocket instance https://developer.mozilla.org/en-US/docs/Web/API/WebSocketobject
socketIDsocket id (18 digits number)number
attemptreconnect attempt counternumber1


wcOpts

PropertyDescriptionTypeDefault
wsURLwebsocket URL: ws://localhost:3211/something?authkey=TRTmrtstring
questionTimeoutTimeout in ms when question to the server is sent and answer is not receivednumber
reconnectAttemptsthe number of recconnection attemptsnumber
reconnectDelaydelay in ms between two recconnection attemptsnumber
subprotocolswebsocket subprotocols: ['jsonRWS', 'raw']string[]
debugdebug incoming and outgoing messagesbooleanfalse

Methods

Use this methods to connect the websocket client to the server and send the messages from the client to server.

  • constructor (wcOpts :object) :void

    Create the Client13jsonRWS class instance.

    
    const { RWClientBrowser, lib } = require('regoch-websocket');
    const wcOpts = {
      wsURL: 'ws://localhost:3211?authkey=TRTmrt',
      questionTimeout: 3*1000, // wait 3secs for answer
      reconnectAttempts: 5, // try to reconnect 5 times
      reconnectDelay: 3000, // delay between reconnections is 3 seconds
      subprotocols: ['jsonRWS'],
      debug: false
    };
    const client = new RWClientBrowser(wcOpts);
    const wsocket = await client.connect();
          



  • Connectors

  • connect () :Promise<WebSocket>

    Connect to the websocket server via wsURL. Returned value is the promise with the resolved WebSocket.

  • disconnect () :void

    Disconnect from the server by using wsocket.close().

  • async reconnect () :Promise<void>

    Try to reconnect the client when the socket is closed i.e. when server is restarted. This method is fired on every 'close' socket's event.

  • blockReconnect () :void

    Block reconnect. Use it after disconnect() method to prevent reconnection attempts.



  • Receivers

  • onMessage () :void

    Receive the message as string and convert it in the appropriate subprotocol format. Dispatch it as 'route', 'question', 'message', 'message-error' or 'error' event to the eventEmitter.
    This method is used internally and it's not recommended to use in your app. Use on() listeners instead.



  • Senders

  • async carryOut (to :number, cmd :string, payload :any) :Promise<void>

    Send message to the websocket server.
    This method is used internally and it's not recommended to use in your app.
    to the receiver socket id
    cmd the command in the message object {id, from, to, cmd, payload}
    payload the payload in the message object {id, from, to, cmd, payload}

  • async sendOne (to :number, msg :any) :Promise<void>

    Send message (payload) to one client.
    to the receiver socket id: 210205081923171300
    msg the payload in the message object {id, from, to, cmd, payload}

  • async send (to :number[], msg :any) :Promise<void>

    Send message (payload) to one or more clients.
    to array of the receiver socket ids: [210205081923171300, 210205082042463230]
    msg the payload in the message object {id, from, to, cmd, payload}

  • async broadcast (msg :any) :Promise<void>

    Send message (payload) to all clients except the sender.
    msg the payload in the message object {id, from, to, cmd, payload}

  • async sendAll (msg :any) :Promise<void>

    Send message (payload) to all clients and the sender.
    msg the payload in the message object {id, from, to, cmd, payload}



  • Questions

    Question is when client sends a request to server and wait for the answer. So the data is going in two directions client → server and then server → client. It's simmilar to HTTP request but on the websocket (TCP) level. The returned value is the info message like socket ID, list of socket IDs, room list ...etc.
  • question (cmd :string) :Promise<object>

    Send question and expect the answer. Returned value is the promise with the answered object.
    This method is used internally and it's not recommended to use in your app.
    cmd the command in the message object {id, from, to, cmd, payload}

  • async infoSocketId () :Promise<number>

    Send a question about the client's socket ID (cmd: 'question/socket/id').

  • async infoSocketList () :Promise<number[]>

    Send a question about all socket IDs connected to the server (cmd: 'question/socket/list').

  • async infoRoomList () :Promise<{name:string, socketIds:number[]}[]>

    Send a question about all rooms in the server (cmd: 'question/room/list').
    The returned value is object {name, socketIds} where name is the room name and socketIds is the list of sockets joined the room.

  • async infoRoomListmy () :Promise<{name:string, socketIds:number[]}[]>

    Send question about all rooms where the client was entered (cmd: 'question/room/listmy').



  • Rooms

  • async roomEnter (roomName :string) :Promise<void>

    Subscribe in the room cmd: 'room/enter'.
    roomName the room name: 'tech-chat'

  • async roomExit (roomName :string) :Promise<void>

    Unsubscribe in the room cmd: 'room/exit'.
    roomName the room name: 'tech-chat'

  • async roomExitAll () :Promise<void>

    Unsubscribe from the all rooms cmd: 'room/exitall'.

  • async roomSend (roomName :string, msg :any) :Promise<void>

    Send a message to the room. The sender doesn't need to be subscribed in the room cmd: 'room/send'.
    roomName the room name: 'tech-chat'
    msg the payload in the message object {id, from, to, cmd, payload}



  • Misc

  • async setNick (nickname :string) :Promise<void>

    Set a nick name on the server side socket.extension.nickname cmd: 'socket/nick'.
    nickname nick name

  • async route (uri :string, body :any) :Promise<void>

    Send route command to the server's router cmd: 'route'. Integrate regoch-router on thes erver side and create complex, real-time Websocket API.
    uri route URI, for example /shop/product/55?x=3 (the payload part in the message object {id, from, to, cmd, payload})
    body body data (the payload part in the message object {id, from, to, cmd, payload})



  • Listeners

  • on (eventName :string, listener :Function) :void

    Listen eventName and execute listener on every event.
    eventName event name: 'connected', 'message', 'message-error', 'question', 'route'
    listener the callback function

  • once (eventName :string, listener :Function) :void

    Listen eventName and execute the listener only once.
    eventName event name: 'connected', 'message', 'message-error', 'question', 'route'
    listener the callback function

  • off (eventName :string, listener :Function) :void

    Remove the event listener.
    Notice: The listener must be the same function as used in the on().
    eventName event name: 'connected', 'message', 'message-error', 'question', 'route'
    listener the callback function

Events

There are several events used in the client:
  1. connected - emitted by the connect() and if the client is succesfuly connected to the server
  2. disconnected - emitted when the socket is closed
  3. message - emitted when client received the valid message (valid means validated by the subprotocol)
  4. question - emitted when client received the message with cmd: 'question/...' from the server. This message is the response to the sent question.
  5. route - emitted when client received the message with cmd: 'route' from the server. This is used to separate the route messages (messages useful for regoch-router) from other ordinary messages./li>
  6. message-error - emitted when client received the invalid message (invalid means if the message doesn't conform the subprotocol rules)
  7. server-error - emitted when client received the message with cmd: 'error' from the server. This is the case when some error haeppend on the server side and server wants to announce the client. (see Datatransfer::sendError())

How to use listeners

  • on ('connected', (socket: Socket) => { ... }) :void

    When client is connected to the websocket server.
    socket - TCP Socket object https://nodejs.org/api/net.html#net_class_net_socket

  • on ('message', (msg :any, msgSTR :string) => { ... }) :void

    When client receive the message from the websocket server which is valid. It includes the all messages except route and questions.
    msg - the message after subprotocol is applied (jsonRWS)
    msgSTR - the message converted from buffer to string
    msgBUF - the message in buffer format (raw bytes)

  • once ('question', (msg :any, msgSTR :string) => { ... }) :void

    Used internally to get the answer. Not recommended to use in the app.

  • on ('route', (msg :any, msgSTR :string) => { ... }) :void

    When client received message from the server with the route command. For example: {"id":210408084514971400,"from":0,"to":210408084507407140,"cmd":"route","payload":{"uri":"/returned/back/21","body":{"x":"something","y":28}}}
    Useful to separate the messages which can be used in the regoch-router from ordinary messages.
    msg - the message after subprotocol is applied (jsonRWS)
    msgSTR - the message converted from buffer to string
    msgBUF - the message in buffer format (only in regoch-websocket-nodejs)

  • on ('message-error', (err :Error) => { ... }) :void

    When client receive the message from the websocket server which is invalid (usually not valid in the subprotocol). Useful to catch the invalid messages sent from the server.
    err - error which caused invalid message

  • on ('server-error', (msg :any, msgSTR :string) => { ... }) :void

    When error haeppend on the server-side and it's sent to the client.
    msg - the message after subprotocol is applied (jsonRWS)
    msgSTR - the message converted from buffer to string

Examples

HTML: 001client.html
JS: 001client.js

helper

The part of the "regoch-websocket" package is the lib library. It's consisted of: subprotocol, raw, jsonRWS, websocket13, helper, getMessageSize, getMessageSizeFromBlob, StringExt
The most important is helper and getMessageSize.

How to use


const { RWClientBrowser, lib } = require('regoch-websocket');
const helper = lib.helper;

helper.sleep(1300);
const bytes = lib.getMessageSize('AČ'); // gives 3 because Č is two bytes