A Promise-based API for WebSockets

Overview

websocket-as-promised

websocket-as-promised logo

Actions Status Known Vulnerabilities npm license

A WebSocket client library with Promise-based API for browser and Node.js.

Example

import WebSocketAsPromised from 'websocket-as-promised';

// create instance of WebSocket connection
const wsp = new WebSocketAsPromised('ws://example.com');

// wait for WebSocket connection to open
await wsp.open();

// send some data
wsp.send('data');

// wait for connection to close
await wsp.close();

Contents

Requirements

  • global Promise constructor

Installation

npm i websocket-as-promised --save

Usage in browser

import WebSocketAsPromised from 'websocket-as-promised';

const wsp = new WebSocketAsPromised('ws://example.com');

wsp.open()
  .then(() => wsp.send('message'))
  .then(() => wsp.close())
  .catch(e => console.error(e));

Or with ES7 async / await:

import WebSocketAsPromised from 'websocket-as-promised';

const wsp = new WebSocketAsPromised('ws://example.com');

(async () => {
  try {
    await wsp.open();
    wsp.send('message');
  } catch(e) {
    console.error(e);
  } finally {
    await wsp.close();
  }
})();

Usage in Node.js

As there is no built-in WebSocket client in Node.js, you should use a third-party WebSocket npm package.

Usage with websocket

Here you should use W3C compatible client - W3CWebSocket:

const WebSocketAsPromised = require('websocket-as-promised');
const W3CWebSocket = require('websocket').w3cwebsocket;

const wsp = new WebSocketAsPromised('ws://example.com', {
  createWebSocket: url => new W3CWebSocket(url)
});

wsp.open()
  .then(() => wsp.send('message'))
  .then(() => wsp.close())
  .catch(e => console.error(e));

Usage with ws

Here it is important to define extractMessageData option as event data are passed directly to onmessage handler, not as event.data by spec:

const WebSocketAsPromised = require('websocket-as-promised');
const WebSocket = require('ws');

const wsp = new WebSocketAsPromised('ws://example.com', {
  createWebSocket: url => new WebSocket(url),
  extractMessageData: event => event, // <- this is important
});

wsp.open()
  .then(() => wsp.send('message'))
  .then(() => wsp.close())
  .catch(e => console.error(e));

Sending raw data

To send raw data use .send() method:

wsp.send('foo');

To handle raw data from server use .onMessage channel:

wsp.onMessage.addListener(data => console.log(data));

Sending JSON

To send JSON you should define packMessage / unpackMessage options:

const wsp = new WebSocketAsPromised(wsUrl, {
  packMessage: data => JSON.stringify(data),
  unpackMessage: data => JSON.parse(data)
});

To send data use .sendPacked() method passing json as parameter:

wsp.sendPacked({foo: 'bar'});

To read unpacked data from received message you can subscribe to onUnpackedMessage channel:

wsp.onUnpackedMessage.addListener(data => console.log(data.status));

Sending binary

Example of sending Uint8Array:

const wsp = new WebSocketAsPromised(wsUrl, {
    packMessage: data => (new Uint8Array(data)).buffer,
    unpackMessage: data => new Uint8Array(data),
});

wsp.open()
  .then(() => wsp.sendPacked([1, 2, 3]))
  .then(() => wsp.close())
  .catch(e => console.error(e));

Sending requests

websocket-as-promised provides simple request-response mechanism (JSON RPC). Method .sendRequest() sends message with unique requestId and returns promise. That promise get resolved when response message with the same requestId comes. For reading/setting requestId from/to message there are two functions defined in options attachRequestId / extractRequestId:

const wsp = new WebSocketAsPromised(wsUrl, {
  packMessage: data => JSON.stringify(data),
  unpackMessage: data => JSON.parse(data),
  attachRequestId: (data, requestId) => Object.assign({id: requestId}, data), // attach requestId to message as `id` field
  extractRequestId: data => data && data.id,                                  // read requestId from message `id` field
});

wsp.open()
 .then(() => wsp.sendRequest({foo: 'bar'})) // actually sends {foo: 'bar', id: 'xxx'}, because `attachRequestId` defined above
 .then(response => console.log(response));  // waits server message with corresponding requestId: {id: 'xxx', ...}

By default requestId value is auto-generated, but you can set it manually:

wsp.sendRequest({foo: 'bar'}, {requestId: 42});

Note: you should implement yourself attaching requestId on server side.

API

Classes

WebSocketAsPromised

Typedefs

Options : Object

WebSocketAsPromised

Kind: global class

new WebSocketAsPromised(url, [options])

Constructor. Unlike original WebSocket it does not immediately open connection. Please call open() method to connect.

Param Type Description
url String WebSocket URL
[options] Options

wsp.ws ⇒ WebSocket

Returns original WebSocket instance created by options.createWebSocket.

Kind: instance property of WebSocketAsPromised

wsp.url ⇒ String

Returns WebSocket url.

Kind: instance property of WebSocketAsPromised

wsp.isOpening ⇒ Boolean

Is WebSocket connection in opening state.

Kind: instance property of WebSocketAsPromised

wsp.isOpened ⇒ Boolean

Is WebSocket connection opened.

Kind: instance property of WebSocketAsPromised

wsp.isClosing ⇒ Boolean

Is WebSocket connection in closing state.

Kind: instance property of WebSocketAsPromised

wsp.isClosed ⇒ Boolean

Is WebSocket connection closed.

Kind: instance property of WebSocketAsPromised

wsp.onOpen ⇒ Channel

Event channel triggered when connection is opened.

Kind: instance property of WebSocketAsPromised
See: https://vitalets.github.io/chnl/#channel
Example

wsp.onOpen.addListener(() => console.log('Connection opened'));

wsp.onSend ⇒ Channel

Event channel triggered every time when message is sent to server.

Kind: instance property of WebSocketAsPromised
See: https://vitalets.github.io/chnl/#channel
Example

wsp.onSend.addListener(data => console.log('Message sent', data));

wsp.onMessage ⇒ Channel

Event channel triggered every time when message received from server.

Kind: instance property of WebSocketAsPromised
See: https://vitalets.github.io/chnl/#channel
Example

wsp.onMessage.addListener(message => console.log(message));

wsp.onUnpackedMessage ⇒ Channel

Event channel triggered every time when received message is successfully unpacked. For example, if you are using JSON transport, the listener will receive already JSON parsed data.

Kind: instance property of WebSocketAsPromised
See: https://vitalets.github.io/chnl/#channel
Example

wsp.onUnpackedMessage.addListener(data => console.log(data.foo));

wsp.onResponse ⇒ Channel

Event channel triggered every time when response to some request comes. Received message considered a response if requestId is found in it.

Kind: instance property of WebSocketAsPromised
See: https://vitalets.github.io/chnl/#channel
Example

wsp.onResponse.addListener(data => console.log(data));

wsp.onClose ⇒ Channel

Event channel triggered when connection closed. Listener accepts single argument {code, reason}.

Kind: instance property of WebSocketAsPromised
See: https://vitalets.github.io/chnl/#channel
Example

wsp.onClose.addListener(event => console.log(`Connections closed: ${event.reason}`));

wsp.onError ⇒ Channel

Event channel triggered when by Websocket 'error' event.

Kind: instance property of WebSocketAsPromised
See: https://vitalets.github.io/chnl/#channel
Example

wsp.onError.addListener(event => console.error(event));

wsp.open() ⇒ Promise.<Event>

Opens WebSocket connection. If connection already opened, promise will be resolved with "open event".

Kind: instance method of WebSocketAsPromised

wsp.sendRequest(data, [options]) ⇒ Promise

Performs request and waits for response.

Kind: instance method of WebSocketAsPromised

Param Type Default
data *
[options] Object
[options.requestId] String | Number <auto-generated>
[options.timeout] Number 0

wsp.sendPacked(data)

Packs data with options.packMessage and sends to the server.

Kind: instance method of WebSocketAsPromised

Param Type
data *

wsp.send(data)

Sends data without packing.

Kind: instance method of WebSocketAsPromised

Param Type
data String | Blob | ArrayBuffer

wsp.waitUnpackedMessage(predicate, [options]) ⇒ Promise

Waits for particular message to come.

Kind: instance method of WebSocketAsPromised

Param Type Default Description
predicate function function to check incoming message.
[options] Object
[options.timeout] Number 0
[options.timeoutError] Error

Example

const response = await wsp.waitUnpackedMessage(data => data && data.foo === 'bar');

wsp.close([code], [reason]) ⇒ Promise.<Event>

Closes WebSocket connection. If connection already closed, promise will be resolved with "close event".

Kind: instance method of WebSocketAsPromised

Param Type Default Description
[code] number 1000 A numeric value indicating the status code.
[reason] string A human-readable reason for closing connection.

wsp.removeAllListeners()

Removes all listeners from WSP instance. Useful for cleanup.

Kind: instance method of WebSocketAsPromised

Options : Object

Kind: global typedef
Defaults: please see options.js
Properties

Name Type Default Description
[createWebSocket] function url => new WebSocket(url) custom function for WebSocket construction.
[packMessage] function noop packs message for sending. For example, data => JSON.stringify(data).
[unpackMessage] function noop unpacks received message. For example, data => JSON.parse(data).
[attachRequestId] function noop injects request id into data. For example, (data, requestId) => Object.assign({requestId}, data).
[extractRequestId] function noop extracts request id from received data. For example, data => data.requestId.
[extractMessageData] function event => event.data extracts data from event object.
timeout Number 0 timeout for opening connection and sending messages.
connectionTimeout Number 0 special timeout for opening connection, by default equals to timeout.

Changelog

Please see CHANGELOG.md.

License

MIT @ Vitaliy Potapov

* * *
If you love ❤️ JavaScript and would like to track new trending repositories,
have a look on vitalets/github-trending-repos.
Comments
  • Feature Suggestion: await new messages

    Feature Suggestion: await new messages

    I hope this package can enable us to do the following:

    await ws.open();
    
    while (true) {
      data = await ws.recv();
      ws.send(data);
    }
    

    This is actually not that trivial if we need to handle connection error without a wrapper.

    opened by hanayashiki 19
  • Tolerate already extracted data coming from on message handler from underlying websocket

    Tolerate already extracted data coming from on message handler from underlying websocket

    Hi there, I have to use ws package because it supports setting custom headers when opening a websocket, but it turns out that it doesn't cooperate well with the websocket-as-promised. ws implements all the needed methods but in the on('message', ... handler it doesn't pass the full event, but it passes the already extracted data property. Would you mind adding a little check of the incoming parameter? It's just a matter of changing

      _handleMessage(event) {
        const message = event.data;
    

    to

      _handleMessage(event) {
        const message = typeof event === 'string' ? event : event.data;
    

    in the index.js. It stays compatible with the already supported websocket implementations and, at the same time, tolerates the use of ws. I will be happy to send PR for this if you're willing to accept such a hack.

    opened by gpolakow 7
  • v0.10.0 causes runtime error when building with Create React App

    v0.10.0 causes runtime error when building with Create React App

    I'm using websocket-as-promised in an ejected version of "create-react-app". When testing using the dev server, everything works fine. But when I build the project and then run it, I get an error "Uncaught TypeError: Super expression must either be null or a function, not undefined" and the websocket code fails to run.

    Downgrading to version 0.9.0 fixes the problem.

    I have not had a chance to try much debugging. I tried to change the Terser minification plugin option in my app to keep_fnames: true, going on advice from various Stack Overflow posts. This did not resolve the issue. I also tried disabled the Terser plugin in my app, and that resolved the issue.

    opened by pangolingo 6
  • Support async operations in unpackMessage()

    Support async operations in unpackMessage()

    I've been experimenting with this library in the browser, but run into one issue I am not sure how to resolve.

    const wsp = new WebSocketAsPromised(wsUrl, {
      packMessage: data => JSON.stringify(data),
     unpackMessage: data => JSON.parse(data)
    });
    

    For the unpackMessage function, in the browser, I receive a Blob, but I don't think I can get the Blob data before returning from the function. When I tried JSON.parse it just returned undefined. Maybe data is not a blob in Node, but it seems to be in Chrome. Let me know if an example would help.

    opened by cameronelliott 4
  • Add support for auto reconnect

    Add support for auto reconnect

    It would be nice of websocket-as-promised had a support for auto-reconnect in case of the underlying websocket disconnect. There are actually two use cases:

    • Reconnect after the underlying websocket got disconnected
    • Keep trying reconnect if the first initial connect attempt failed

    I envision a need for the following configuration options:

    • reconnectInterval [ms]
    • reconnectAttempts
    • reconnectDecay (eventually)
    opened by ivosh 4
  • Error: TS2345: Argument of type W3CWebSocket is not assignable to parameter of type 'Options'

    Error: TS2345: Argument of type W3CWebSocket is not assignable to parameter of type 'Options'

    Thanks for the library it's really helpful. But I got an error on the built typescript project. The problem is that I use W3CWebSocket in the createWebSocket property but in the Options interface I should return WebSocket type.

    const wspParams = {
      createWebSocket: (url: string) => new W3CWebSocket(url),
    }
    
    declare interface Options {
        createWebSocket?: (url: string) => WebSocket;
    }
    

    https://github.com/vitalets/websocket-as-promised/blob/master/types/options.d.ts#L5

    TS2345: Argument of type '{ createWebSocket: (url: string) => W3CWebSocket; packMessage: (data: object) => string; unpackMessage: (data: string) => any; attachRequestId: (data: object, requestId: string) => { id: string; }; extractRequestId: (data: { id: string;}) => string; timeout: number; }' is not assignable to parameter of type 'Options'.

    opened by igrzhukovich 3
  • Self-signed certs

    Self-signed certs

    Getting connection errors due to self-signed certs. Is their an option similar to ws that allows you to bypass the connection error?

    const WebSocket = require('ws');
    const ws = new WebSocket('wss://url',{rejectUnauthorized: false});
    
    opened by narsariusv 3
  • ReferenceError: WebSocket is not defined

    ReferenceError: WebSocket is not defined

    I am getting following error while using this library on nodejs, I am new to this can help me to resolve this.

    ReferenceError: WebSocket is not defined at Object.createWebSocket (/node_modules/websocket-as-promised/dist/webpack:/src/options.js:34:20) at WebSocketAsPromised._createWS (/node_modules/websocket-as-promised/dist/webpack:/src/index.js:291:30) at /node_modules/websocket-as-promised/dist/webpack:/src/index.js:205:12 at PromiseController._callFn (/node_modules/websocket-as-promised/dist/webpack:/node_modules/promise-controller/lib/index.js:187:1) at PromiseController.call (/node_modules/websocket-as-promised/dist/webpack:/node_modules/promise-controller/lib/index.js:62:1) at WebSocketAsPromised.open (/node_modules/websocket-as-promised/dist/webpack:/src/index.js:203:26)

    opened by sameer49 3
  • [Question] As a server usage or how to pass PORT to listen to?

    [Question] As a server usage or how to pass PORT to listen to?

    Hello @vitalets,

    Just out of curiosity, is it possible to use websocket-as-promised as a websocket server akin to ws module?

    For example: https://github.com/websockets/ws#simple-server

    const WebSocket = require('ws');
    const wss = new WebSocket.Server({ port: 8080 });
    
    wss.on('connection', function connection(ws) {
      ws.on('message', function incoming(message) {
        console.log('received: %s', message);
      });
      ws.send('something');
    });
    

    If it's not can I submit PR that will introduce this functionality? Thanks!

    opened by ArturJS 2
  • How to set header of the ws connection

    How to set header of the ws connection

    I'm adding authentication to ws.

    In original websocket: new WebSocket("ws://www.example.com/socketserver", ["access_token", "3gn11Ft0Me8lkqqW2/5uFQ="]);

    I'v searched the APIs of README page but found nothing. How to use websocket-as-promised to pass params to ws connection.

    opened by cd-yang 1
  • How to use CBOR to pack/unpack messages?

    How to use CBOR to pack/unpack messages?

    I would like to use CBOR to pack/unpack messages in a plain HTML/JS application.

    I use spaceify/cbor-js (a fork of paroga/cbor-js)

    <script src="https://cdn.jsdelivr.net/gh/spaceify/cbor-js@master/cbor.js"></script>
    

    then in my JS code:

    this.websocket = new WebSocketAsPromised(
        `ws://${this.host}:${this.port}`,
        {
            packMessage: data => CBOR.encode(data),
            unpackMessage: data => CBOR.decode(data),
            // attach requestId to message as `id` field
            attachRequestId: (data, requestId) => Object.assign({id: requestId}, data),
            // read requestId from message `id` field
            extractRequestId: data => data && data.id,
        }
    );
    

    but I have an error (TypeError: First argument to DataView constructor must be an ArrayBuffer) because unpackMessage calls CBOR.decode(data) with data being an object of type Blob.

    I tried to change unpackMessage to use Blob.arrayBuffer():

    unpackMessage: data => CBOR.encode(data.arrayBuffer())
    

    but data.arrayBuffer() returns a Promise, however this:

    unpackMessage: data => CBOR.encode(await data.arrayBuffer())
    

    is a syntax error (Uncaught SyntaxError: missing ) after argument list).

    Any idea how to fix this?

    opened by fferri 1
  • failed to get response from server

    failed to get response from server

    Hi, I am using sendRequest() API, and always failed to get response even though I send it from server with same request id.

    Here is the detailed code.

    const ws = new WebSocketAsPromised('ws://127.0.0.1:8000/ws', {
              packMessage: data => JSON.stringify(data),
              unpackMessage: data => JSON.parse(data),
             attachRequestId: (data, requestId) => Object.assign({id: requestId}, data), // attach requestId to message as `id` field
             extractRequestId: data => data && data.id, 
          });
    ws.onMessage.addListener(message => console.log("received ", message));
    ws.open();
    
    // send request 
    await ws.sendRequest({ task: 'move_ptp' }, { requestId: 1 })
    .then((response) => { console.log("responsed"); console.log(response) });
    
    console.log("finished");
    

    I have a server running behind, sending response with same message after 1 second receiving request.

    When I run the code I only see the log in onMessage, but not in promise, and I didn't see "finished".

    I wonder, did I configure something wrong ? Or I didn't extract requestID from received message correctly ?

    opened by XDinEuro 4
  • Help with transitioning from different library

    Help with transitioning from different library

    I am having a hard time coming from react-use-websocket. Do I need to keep this connection open as I am doing previously? Or is that where the async part comes into play? I am not sure on how to do this. It would be great if someone could help me transition my logic to use this library.

    `
    import useWebSocket, { ReadyState } from 'react-use-websocket';
    
    const SOCKET_URL = '';
    
    let timestamp = new Date().getTime();
    const UseWebSocket = ({ webSocketRef }: { webSocketRef: any }) => {
      webSocketRef.current = useWebSocket(SOCKET_URL, {
        retryOnError: true,
        reconnectInterval: 100000,
      });
    
      const { sendJsonMessage, lastJsonMessage, readyState } = webSocketRef.current;
      const data = useSelector(getEditForecastJSONSelector);
    
      const prevData = React.useRef<any>();
    
      const dispatch = useDispatch();
    
      const onSetDataReceived = (response: any) => {
        const currentTimestamp = new Date().getTime();
        const diff = currentTimestamp - timestamp;
        if (diff > 200) {
          dispatch(actions.onForeCastDataReceived(response));
          dispatch(actions.onIsLoading(false));
          timestamp = new Date().getTime();
        }
      };
    
      React.useEffect(() => {
        if (readyState === ReadyState.OPEN) {
          if (!isEqual(prevData.current, data) && data.length > 0) {
            data.forEach((item) => {
              if (item.data) {
                item.data.forEach((x) => {
                  x.forecasts.forEach((f) => {
                    const payload: SocketPayload = getSocketPayload({ item, f });
                    sendJsonMessage(payload, false);
                  });
                });
              }
            });
          }
          prevData.current = data;
        }
      }, [
        dispatch,
        data,
        sendJsonMessage,
        readyState,
      ]);
    
      React.useEffect(() => {
        if (lastJsonMessage !== null) {
          onSetDataReceived(lastJsonMessage);
        } else dispatch(actions.onIsLoading(false));
      }, [lastJsonMessage, onSetDataReceived]);
    
      return webSocketRef.current;
    };
    
    export default UseWebSocket;
    `
    

    Current Logic I am trying to get to work.

    `const SOCKET_URL = '';
    
    let timestamp = new Date().getTime();
    const UseWebSocket = ({ webSocketRef }: { webSocketRef: any }) => {
      webSocketRef.current = new WebSocketAsPromised(SOCKET_URL, {
        packMessage: data => JSON.stringify(data),
        unpackMessage: data => JSON.parse(String(data)),
      });
    
      const data = useSelector(getEditForecastJSONSelector);
    
      const prevData = React.useRef<any>();
    
      const dispatch = useDispatch();
    
      const onSetDataReceived = (response: any) => {
        const currentTimestamp = new Date().getTime();
        const diff = currentTimestamp - timestamp;
        if (diff > 200) {
          dispatch(actions.onForeCastDataReceived(response));
          dispatch(actions.onIsLoading(false));
          timestamp = new Date().getTime();
        }
      };
    
      React.useEffect(() => {
        // (async () => {
        //   try {
        //     await webSocketRef.current.open();
        //   } catch (e) {
        //     console.error(e);
        //   }
        // })();
      }, []);
    
      React.useEffect(() => {
        const run = async () => {
          if (!isEqual(prevData.current, data) && data.length > 0) {
            for (const item of data) {
              if (item.data) {
                for (const x of item.data) {
                  for (const f of x.forecasts) {
                    const payload: SocketPayload = getSocketPayload({ item, f });
                    try {
                      webSocketRef.current.onError.addListener((event: any) => console.error(event));
                      webSocketRef.current.onUnpackedMessage.addListener((res: any) => {
                        console.log(res);
                        onSetDataReceived(res);
                      });
                      await webSocketRef.current.open();
                      await webSocketRef.current.sendPacked(payload);
                    } catch (e) {
                      console.error(e);
                    } finally {
                      // await webSocketRef.current.close();
                    }
                  }
                }
              }
            }
          }
          prevData.current = data;
        };
        run();
      }, [
        dispatch,
        data,
        onSetDataReceived,
      ]);
    
      React.useEffect(() => {
        // if (lastJsonMessage !== null) {
        //   onSetDataReceived(lastJsonMessage);
        // } else dispatch(actions.onIsLoading(false));
      }, [onSetDataReceived]);
    
      return webSocketRef.current;
    };
    
    export default UseWebSocket;`
    
    opened by texas697 0
  • bug: build in typescript Found 4 errors.

    bug: build in typescript Found 4 errors.

    used in typescript:

      import WebSocketAsPromised from 'websocket-as-promised';
      
      const wsp = new WebSocketAsPromised(this.options.address, {
                  createWebSocket: url => new WebSocket(url),
                  extractMessageData: event => event, // <- this is important
                  packMessage: data => JSON.stringify(data),
                  unpackMessage: data => {
                      if (Helper.isJSONStr(<string>data)) {
                          return JSON.parse(<string>data);
                      } else {
                          return data;
                      }
                  },
                  attachRequestId: (data, requestId) => Object.assign({ id: requestId }, data), // attach requestId to message as `id` field
                  extractRequestId: data => data && data.id,
              });
    
            return wsp.open().then(() => {
                this.service = wsp;
                return wsp;
            });
    
    

    run build tsc throw errors:

      node_modules/websocket-as-promised/types/index.d.ts:9:9 - error TS2304: Cannot find name 'WebSocket'.
      
      9     ws: WebSocket;
                ~~~~~~~~~
      
      node_modules/websocket-as-promised/types/index.d.ts:21:25 - error TS2304: Cannot find name 'Event'.
      
      21     open: () => Promise<Event>;
                                 ~~~~~
      
      node_modules/websocket-as-promised/types/index.d.ts:26:26 - error TS2304: Cannot find name 'CloseEvent'.
      
      26     close: () => Promise<CloseEvent>;
                                  ~~~~~~~~~~
      
      node_modules/websocket-as-promised/types/options.d.ts:5:40 - error TS2304: Cannot find name 'WebSocket'.
      
      5     createWebSocket?: (url: string) => WebSocket;
                                               ~~~~~~~~~
    
    
    opened by richenlin 0
  • add support for unexpected-response

    add support for unexpected-response

    I'm almost certain this isn't the right way to handle this but it works.

    Without this when my server disconnects my client the client doesn't have any way of reacting to the statusCode and/or reason.

    opened by OmgImAlexis 0
  • Support subprotocols without synchronized sequence ID

    Support subprotocols without synchronized sequence ID

    I want to use this library with a subprotocol where the client and server have their own sequence ID. Both peers should be able to send requests and receive corresponding responses.

    The problem I encounter: The subprotocol is based on request-response pattern. Imagine both peers use their own sequenceId to number their requests and both peers start with sequenceId = 1. So it is possible, that both peers send a request with the same sequence ID at the same time. Now the client considers the request of the server as the response of its request and the real response of the server is dismissed.

    This happens because the assignment of messages is only based on the sequence ID.

    Feature Request: Give the caller the opportunity to save additional data to every request so the assignment of messages is not only based on the sequence ID but on additional data.

    Example:

    Request opcode | Possible response opcodes ------------------ | ------------------------------ login | ack, nak getProperties | properties, nak ... | ...

    If I send a login command and it gets the sequenceId = 34, I can save the possible response opcodes as additional data for that request and when I get a response matched by the sequenceId I can validate the response by checking if the response opcode matches ack or nak.

    const wsp = new WebSocketAsPromised(wsUrl, {
      packMessage: data => JSON.stringify(data),
      unpackMessage: data => JSON.parse(data),
      attachRequestId: (data, requestId) => Object.assign({id: requestId}, data), // attach requestId to message as `id` field
      extractRequestId: data => data && data.id,                                  // read requestId from message `id` field
      isPossibleResponse: (data, additionalData) => additionalData.possibleResponses.includes(data.opcode) // <--- new parameter
    });
    
    wsp.sendRequest({foo: 'bar'},{requestId: 42, additionalData: {possibleResponses: ['ack', 'nak']}});
    

    I worked a bit on this idea in the following fork: https://github.com/PMalte/websocket-as-promised/tree/feature/bidirectional-subprotocols

    opened by PMalte 0
  • Bug: createWebSocker option prevents from using custom WebSocket types

    Bug: createWebSocker option prevents from using custom WebSocket types

    When trying to create a new WebSocketAsPromised using TypeScript, compiler throws an error if your WebSocket object is coming from some library such WebSocket-Node

    Code:

    import WebSocketAsPromised from 'websocket-as-promised' 
    import websocket from 'websocket'
    
    const W3CWebSocket = websocket.w3cwebsocket
    
    const ws = new WebSocketAsPromised('xxxx', {
      createWebSocket: url => new W3CWebSocket(url)
    })
    

    Error:

    Type '(url: string) => w3cwebsocket' is not assignable to type '(url: string) => WebSocket'.
      Type 'w3cwebsocket' is missing the following properties from type 'WebSocket': addEventListener, removeEventListener, dispatchEvent
    

    Cause (type/options.d.ts):

    export = Options;
    
    declare interface Options {
        createWebSocket?: (url: string) => WebSocket; <------------ maybe add | any (?)
        packMessage?: (data: any) => string | ArrayBuffer | Blob;
        unpackMessage?: (data: string | ArrayBuffer | Blob) => any;
        attachRequestId?: (data: any, requestId: string | number) => any;
        extractRequestId?: (data: any) => string | number | undefined;
        extractMessageData?: (event: any) => any;
        timeout?: number;
        connectionTimeout?: number;
    }
    

    Solution from client code

    import WebSocketAsPromised from 'websocket-as-promised' 
    import websocket from 'websocket'
    
    const W3CWebSocket = websocket.w3cwebsocket
    
    const ws = new WebSocketAsPromised('xxxx', {
      createWebSocket: url => new W3CWebSocket(url) as any
    })
    
    opened by JulioMh 0
Owner
Vitaliy Potapov
Vitaliy Potapov
JSON-RPC 2.0 implementation over WebSockets for Node.js and JavaScript/TypeScript

WebSockets for Node.js and JavaScript/TypeScript with JSON RPC 2.0 support on top. About The rpc-websockets library enables developers to easily imple

Elpheria 482 Dec 21, 2022
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
Next-JS interface for 🤖 Open-AI based 🕷 spider-man conversation simulator ⚡️

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://

Mohit Yadav 12 Dec 12, 2022
WebRTC based peer to peer video calling and messaging web app build with MERN stack.

talkhouse WebRTC based peer to peer video calling and messaging web app build with MERN stack. Demo Libraries used React for frontend Socket.io as sig

Saalik Mubeen 70 Nov 26, 2022
A websocket-based reverse shell for XSS attacks.

CrossSiteShell A javascript/nodejs "reverse shell" that makes it easier to interact with the victim's browser during XSS attacks. Usage Run the follow

Rafael 13 Oct 7, 2022
🔄 iola: Socket client with REST API

?? iola: Socket client with REST API

Pavel Varentsov 113 Jan 3, 2023
A Develop Tool to Test WebSocket, Socket.IO, Stomp, Bayeux, HTTP, TCP, UDP, WebRTC, DNS API.

A Develop Tool to Test WebSocket, Socket.IO, Stomp, Bayeux, HTTP, TCP, UDP, WebRTC, DNS API.

York Yao 24 Sep 6, 2022
How to build a chat using Lambda + WebSocket + API Gateway? (nodejs)

Description Source code for the lambda function from the screencast How to build a chat using Lambda + WebSocket + API Gateway? (nodejs) The reactjs c

Alex 21 Dec 28, 2022
Um bot feito utilizando a API baileys em WebSocket para o Whatsapp Multi-Devices.

Informação ?? O BaileysBot foi feito utilzando a API Baileys Caso encontre algum BUG, faça um Novo Issue! Requisitos ?? NodeJS Git Instalação ?? Para

null 12 Dec 3, 2022
Inside-out promise; lets you call resolve and reject from outside the Promise constructor function.

Inside-out promise; lets you call resolve and reject from outside the Promise constructor function.

Lily Scott 3 Feb 28, 2022
Adds promise support (rejects(), doesNotReject()) to tape by decorating it using tape-promise.

Tape With Promises Adds promise support (rejects(), doesNotReject()) to tape by decorating it using tape-promise. Install npm install --save-dev @smal

Small Technology Foundation 3 Mar 21, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Blaze is a file sharing progressive web app built using WebTorrent and WebSockets

Blaze is a file sharing progressive web app(PWA) that allows users to transfer files between multiple devices. I

Akash Hamirwasia 1.6k Jan 4, 2023
A template for WebSockets powered Cloudflare Worker project using graphql-ws

?? graphql-ws on Cloudflare Workers A template for WebSockets powered Cloudflare Worker project using graphql-ws. The worker serves the following rout

Denis Badurina 26 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
JSON-RPC 2.0 implementation over WebSockets for Node.js and JavaScript/TypeScript

WebSockets for Node.js and JavaScript/TypeScript with JSON RPC 2.0 support on top. About The rpc-websockets library enables developers to easily imple

Elpheria 482 Dec 21, 2022
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