Giter Club home page Giter Club logo

wampy.js's Introduction

Wampy.js

Wampy logo

About

Amazingly fast, feature-rich, lightweight and zero dependency (by default) WAMP (Web Application Messaging Protocol) Javascript client (for browser and node.js)

NPM version Build Status Code coverage MIT License Known Vulnerabilities

Table of Contents

Description

Wampy.js is javascript library, that runs both in browser and node.js environments, and even in react native environment. It implements WAMP v2 specification on top of WebSocket object, also provides additional features like auto-reconnecting. It has no external dependencies (by default) and is easy to use. Also, it provides (starting from v7.1) command line wamp client which can be extremely helpful in quick check/debug existing WAMP-based APIs.

Wampy.js supports the following WAMP roles and features:

  • Authentication:
    • Ticket-based Authentication
    • Challenge Response Authentication (wampcra method)
    • Cryptosign-based Authentication (cryptosign method)
  • publisher:
    • subscriber black-white listing
    • publisher exclusion
    • publisher identification
    • payload passthru mode
    • event retention
  • subscriber:
    • pattern-based subscription
    • publication trust levels
    • publisher identification
    • payload passthru mode
    • event retention
  • caller:
    • caller identification
    • progressive call results
    • call canceling
    • call timeout
    • payload passthru mode
  • callee:
    • caller identification
    • call trust levels
    • pattern-based registration
    • shared registration
    • payload passthru mode

Wampy supports the following serializers:

  • JSON (default, native)
  • MsgPack (See MessagePack Site for more info)
  • CBOR (See CBOR Site for more info)
  • Any new serializer can be added easily

In node.js environment Wampy is compatible with the following websocket clients:

  • WebSocket-Node. A WebSocket Implementation for Node.js (Draft-08 through the final RFC 6455)
  • ws. Simple to use, blazing fast and thoroughly tested WebSocket client and server for Node.js

For convenience, all API documentation is also available as a GitBook here.

Back to Table of Contents

Usage example

const wampy = new Wampy('/ws/', { realm: 'AppRealm' });

try {
    await wampy.connect();
} catch (e) {
    console.log('connection failed', e);
}

try {
    await wampy.subscribe('system.monitor.update', (eventData) => {
         console.log('Received event:', eventData);
    });
} catch (e) {
    console.log('subscription failed', e);
}

try {
    const res = await wampy.call('get.server.time');
    console.log('RPC called. Server time:', res.argsDict.serverTime);
} catch (e) {
    console.log('RPC call failed', e);
}

// Somewhere else for example
await wampy.publish('system.monitor.update');

// or just ignore promise if you don't need it
wampy.publish('client.message', 'Hi guys!');

Back to Table of Contents

Installation

Wampy.js can be installed using npm:

npm install -S wampy

For browser usage download the latest browser.zip archive and add wampy-all.min.js file to your page. It contains all auth plugins and serializers. They are available as global objects:

window.JsonSerializer = JsonSerializer;
window.MsgpackSerializer = MsgpackSerializer;
window.CborSerializer = CborSerializer;
// this is not available due to problem with browserify transforming await import('node:crypto')
// if someone really needs it - I would appreciate a PR with fix :)
//window.WampyCra = wampyCra;
window.WampyCryptosign = wampyCryptosign;
<script src="browser/wampy-all.min.js"></script>

If you don't plan to use other serializers then JSON or any auth plugins, just include wampy.min.js.

<script src="browser/wampy.min.js"></script>

Back to Table of Contents

Exported components

Wampy.js exports next components that you can import at your needs:

{
    "exports": {
        ".": {  // Main Wampy class
            "import": "./src/wampy.js",
            "require": "./dist/wampy.js"
        },
        "./JsonSerializer.js": {
            "import": "./src/serializers/json-serializer.js",
            "require": "./dist/serializers/json-serializer.js"
        },
        "./CborSerializer.js": {
            "import": "./src/serializers/cbor-serializer.js",
            "require": "./dist/serializers/cbor-serializer.js"
        },
        "./MsgpackSerializer.js": {
            "import": "./src/serializers/msgpack-serializer.js",
            "require": "./dist/serializers/msgpack-serializer.js"
        },
        "./cryptosign.js": {    // Cryptosign authentication plugin
            "import": "./src/auth/cryptosign/wampy-cryptosign.js",
            "require": "./dist/auth/cryptosign/wampy-cryptosign.js"
        },
        "./wampcra.js": {       // WAMP-CRA authentication plugin
            "import": "./src/auth/wampcra/wampy-cra.js",
            "require": "./dist/auth/wampcra/wampy-cra.js"
        }
    }
}

Back to Table of Contents

CLI tool

Wampy cli tool exposes almost the same API options to the command line interface. You can use all types of authorization, publish, subscribe, register and call any URI. Some WAMP Actions provides additional helper options (e.g. mirror option in register command that allows to return back the invocation payload to the caller).

Cli tool is charged with rich help descriptions, examples and even shell auto-completion script. All parameters may be passed as cmd args or via related ENV Vars for convenience. So you can for example export WAMP Router URI and realm to the environment and provide only wamp action parameters via cmd.

You can install wampy cli tool globally or call it by using npx:

npm install -g wampy
# After that you can invoke wampy
wampy -h
# or just run wampy with npx
npx wampy -h

Check the wampy -h or wampy --help for the available commands and global options and check the help for a specific command by issuing wampy <call|register|publish|subscribe> -h.

To make use of shell auto-completion features just add output of wampy completion to your shell config:

wampy completion >> ~/.zshrc
# or
wampy completion >> ~/.bashrc

The completion command is hidden from the wampy -h output to not pollute the main use flow as it is only needed once.

Migrating or Updating versions

Please refer to Migrating.md for instructions on upgrading major versions.

Back to Table of Contents

API

Below is a description of the exposed public API. Wampy also has type definitions available at DefinitelyTyped.org, but they are only for versions < 7.x for now. Feel free to update!)

Constructor([url[, options]])

Wampy constructor can take 2 parameters:

  • url to wamp server - optional. URL can be specified in the following forms:
    • Undefined/null. In-browser environment "page-scheme://page-server:page-port/ws" will be used in this case.
    • String, begins with a '/', for some path in "current-scheme://host:port."
    • Fully qualified URL, starting with the 'ws' or 'wss' schemes.
    • Host/domain without a scheme. In-browser environment "page-scheme" will be used.
  • options hash-table. The only required field is realm. For node.js environment it's also necessary to specify ws - websocket module. See description below.
// in browser
wampy = new Wampy();
wampy = new Wampy('/my-socket-path');
wampy = new Wampy('wss://socket.server.com:5000/ws', { autoReconnect: false });
wampy = new Wampy({ reconnectInterval: 1*1000 });

// in node.js
import { w3cwebsocket as w3cws } from 'websocket';
wampy = new Wampy(null, { ws: w3cws });
wampy = new Wampy('/my-socket-path', { ws: w3cws });
wampy = new Wampy('wss://socket.server.com:5000/ws', { autoReconnect: false, ws: w3cws });
wampy = new Wampy({ reconnectInterval: 1*1000, ws: w3cws });

// or using ws example
import WebSocket from 'ws';
wampy = new Wampy(null, { ws: WebSocket });
wampy = new Wampy('/my-socket-path', { ws: WebSocket });
wampy = new Wampy('wss://socket.server.com:5000/ws', { autoReconnect: false, ws: WebSocket });
wampy = new Wampy({ reconnectInterval: 1*1000, ws: WebSocket });

Json serializer will be used by default. If you want to use msgpack or cbor serializer, pass it through options. Also, you can use your own serializer if it is supported on the WAMP router side.

// in browser
wampy = new Wampy('wss://socket.server.com:5000/ws', {
    serializer: new MsgpackSerializer()
});
wampy = new Wampy({
    serializer: new CborSerializer()
});

// in node.js
import { Wampy } from 'wampy';
import { MsgpackSerializer } from 'wampy/MsgpackSerializer';
import { CborSerializer } from 'wampy/CborSerializer';
import WebSocket from 'ws';

wampy = new Wampy('wss://socket.server.com:5000/ws', {
    ws: WebSocket,
    serializer: new MsgpackSerializer()
});
wampy = new Wampy({
    ws: w3cws,
    serializer: new CborSerializer()
});

Back to Table of Contents

options([opts])

.options() method is now deprecated, so this is here only for documentation purposes. Please use getOptions()/setOptions() instead.

.options() can be called in two forms: -- without parameters it will behave the same as new method getOptions() -- with one parameter as a hash-table it will behave the same as new method setOptions()

wampy.options(); // same as wampy.getOptions

wampy.options({ // same as wampy.setOptions
    authPlugins: {
        ticket: ((userPassword) => (() => userPassword ))(),
        wampcra: wampyCra.sign(secret),
        cryptosign: wampyCryptosign.sign(privateKey)
    },
    authMode: 'auto'
});

getOptions()

Returns Wampy configuration options. See setOptions() down below for the full list of available options.

wampy.getOptions();

setOptions([newOptions])

Receives a newOptions object as a parameter, where each property is a new option to be set and returns a Wampy instance.

Options attributes description:

  • debug. Default value: false. Enable debug logging.
  • logger. Default value: null. User-provided logging function. If debug=true and no logger specified, console.log will be used.
  • autoReconnect. Default value: true. Enable auto reconnecting. In case of connection failure, Wampy will try to reconnect to WAMP server, and if you were subscribed to any topics, or had registered some procedures, Wampy will resubscribe to that topics and reregister procedures.
  • reconnectInterval. Default value: 2000 (ms). Reconnection Interval in ms.
  • maxRetries. Default value: 25. Max reconnection attempts. After reaching this value .disconnect() will be called. Set to 0 to disable limit.
  • realm. Default value: null. WAMP Realm to join on server. See WAMP spec for additional info.
  • helloCustomDetails. Default value: null. Custom attributes to send to router on hello.
  • uriValidation. Default value: strict. Can be changed to loose for less strict URI validation.
  • authid. Default value: null. Authentication (user) id to use in challenge.
  • authmethods. Default value: []. Array of strings of supported authentication methods.
  • authextra. Default value: {}. Additional authentication options for Cryptosign-based authentication. See Cryptosign-based Authentication section and WAMP Spec CS for more info.
  • authPlugins. Default value: {}. Authentication helpers for processing different authmethods flows. It's a hash-map, where key is an authentication method and value is a function, that takes the necessary user secrets/keys and returns a function which accepts authmethod and challenge info and returns signed challenge answer. You can provide your own signing functions or use existing helpers. Functions may be asynchronous.
import * as wampyCra from 'wampy/wampcra';
import * as wampyCS from 'wampy/cryptosign';

wampy.setOptions({
    authPlugins: {
        // No need to process challenge data in ticket flow, as it is empty
        ticket: ((userPassword) => (() => userPassword ))(),
        wampcra: wampyCra.sign(secret),
        cryptosign: wampyCS.sign(privateKey)
    },
    authMode: 'auto'
});
  • authMode. Default value: manual. Possible values: manual|auto. Mode of authorization flow. If it is set to manual - you also need to provide onChallenge callback, which will process authorization challenge. Or you can set it to auto and provide authPlugins (described above). In this case the necessary authorization flow will be chosen automatically. This allows to support few authorization methods simultaneously.
  • onChallenge. Default value: null. Callback function. It is fired when wamp server requests authentication during session establishment. This function receives two arguments: auth method and challenge details. Function should return computed signature, based on challenge details. See Challenge Response Authentication section, WAMP Spec CRA, Cryptosign-based Authentication section and WAMP Spec CS for more info. This function receives welcome details as an argument.
  • onClose. Default value: null. Callback function. Fired on closing connection to wamp server.
  • onError. Default value: null. Callback function. Fired on error in websocket communication or if error happens during auto reconnection flow (as it can not be bound to explicit API calls).
  • onReconnect. Default value: null. Callback function. Fired every time on reconnection attempt.
  • onReconnectSuccess. Default value: null. Callback function. Fired every time when reconnection succeeded. This function receives welcome details as an argument.
  • ws. Default value: null. User provided WebSocket class. Useful in node environment.
  • additionalHeaders. Default value: null. User provided additional HTTP headers (for use in Node.js environment)
  • wsRequestOptions. Default value: null. User provided WS Client Config Options (for use in Node.js environment). See docs for WebSocketClient, tls.connect options.
  • serializer. Default value: JsonSerializer. User provided serializer class. Useful if you plan to use other encoders instead of default json.
  • payloadSerializers. Default value: { json: jsonSerializer }. User provided hashmap of serializer instances for using in Payload Passthru Mode. Allows to specify a few serializers and use them on per message/call basis.
wampy.setOptions({
    reconnectInterval: 1000,
    maxRetries: 999,
    onClose: () => { console.log('See you next time!'); },
    onError: () => { console.log('Breakdown happened'); },
    onReconnect: () => { console.log('Reconnecting...'); },
    onReconnectSuccess: (welcomeDetails) => { console.log('Reconnection succeeded. Details:', welcomeDetails); }
});

Back to Table of Contents

getOpStatus()

Returns the status of last operation. This method returns an object with attributes:

  • code is integer, and value > 0 means error.
  • error is Error instance of last operation. Check errors types exposed by wampy.
  • reqId is a Request ID of last successful operation. It is useful in some cases (call canceling for example).
const defer = ws.publish('system.monitor.update');
console.log(ws.getOpStatus());
// may return
//    { code: 1, error: UriError instance }
// or { code: 2, error: NoBrokerError instance }
// or { code: 0, error: null }

Back to Table of Contents

getSessionId()

Returns the WAMP Session ID.

ws.getSessionId();

Back to Table of Contents

connect([url])

Connects to wamp server. url parameter is the same as specified in Constructor. Returns a Promise that's either:

  • Resolved with connection details provided by server (roles, features, authentication details)
  • Rejected with the thrown error
try {
    await wampy.connect();
} catch (e) {
    console.log('connection failed', e);
}

await ws.connect('/my-socket-path');

const defer = ws.connect('wss://socket.server.com:5000/ws');

Back to Table of Contents

disconnect()

Disconnects from wamp server. Clears all queues, subscription, calls. Returns a Promise that's either:

  • Resolved when wampy disconnects from WAMP server and closes websocket connection
  • Rejected with the thrown error (it probably never throws)
await ws.disconnect();

Back to Table of Contents

abort()

Aborts WAMP session and closes a websocket connection. If it is called on handshake stage - it sends the abort message to wamp server (as described in spec). Also clears all queues, subscription, calls. Returns wampy instance back.

ws.abort();

Back to Table of Contents

Ticket-based Authentication

With Ticket-based authentication, the client needs to present the server an authentication ticket - some magic value to authenticate itself to the server. It could be a user password, an authentication token or any other kind of client secret. To use it you need to provide "ticket" in "authmethods", "authid" and the "onChallenge" callback as wampy instance options.

'use strict';

// Ticket authentication
wampy = new Wampy('wss://wamp.router.url', {
    realm: 'realm1',
    authid: 'joe',
    authmethods: ['ticket'],
    onChallenge: (method, info) => {
        console.log('Requested challenge with ', method, info);
        return 'joe secret key or password';
    }
});

// Promise-based ticket authentication
wampy = new Wampy('wss://wamp.router.url', {
    realm: 'realm1',
    authid: 'micky',
    authmethods: ['ticket'],
    onChallenge: (method, info) => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('Requested challenge with ', method, info);
                resolve('micky secret key or password');
            }, 2000);
        });
    }
});

Challenge Response Authentication

Wampy.js supports challenge response authentication. To use it you need to provide the "authid" and the "onChallenge" callback as wampy instance options. Also, Wampy.js supports wampcra authentication method with a little helper plugin "wampy/wampcra". Just import wampy/wampcra and use provided methods as shown below.

'use strict';

import { Wampy } from 'wampy';
import * as wampyCra from 'wampy/wampcra';  // or import exact functions
import { w3cwebsocket as w3cws } from 'websocket';

// Manual authentication using signed message
wampy = new Wampy('wss://wamp.router.url', {
    ws: w3cws,  // just for example in node.js env
    realm: 'realm1',
    authid: 'joe',
    authmethods: ['wampcra'],
    onChallenge: (method, info) => {
        console.log('Requested challenge with ', method, info);
        return wampyCra.signManual('joe secret key or password', info.challenge);
    }
});

// Promise-based manual authentication using signed message
wampy = new Wampy('wss://wamp.router.url', {
    realm: 'realm1',
    authid: 'micky',
    authmethods: ['wampcra'],
    onChallenge: (method, info) => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('Requested challenge with ', method, info);
                resolve(wampyCra.signManual('micky secret key or password', info.challenge));
            }, 2000);
        });
    }
});

// Manual authentication using salted key and pbkdf2 scheme
wampy = new Wampy('wss://wamp.router.url', {
    realm: 'realm1',
    authid: 'peter',
    authmethods: ['wampcra'],
    onChallenge: (method, info) => {
        const iterations = 100;
        const keylen = 16;
        const salt = 'password salt for user peter';

        console.log('Requested challenge with ', method, info);
        return wampyCra.signManual(wampyCra.deriveKey('peter secret key or password', salt, iterations, keylen), info.challenge);
    }
});

// Automatic CRA authentication
wampy = new Wampy('wss://wamp.router.url', {
    realm: 'realm1',
    authid: 'patrik',
    authmethods: ['wampcra'],
    onChallenge: wampyCra.sign('patrik secret key or password')
});

Back to Table of Contents

Cryptosign-based Authentication

Wampy.js supports cryptosign-based authentication. To use it you need to provide authid, onChallenge callback and authextra as wampy instance options. Also, Wampy.js supports cryptosign authentication method with a little helper plugin "wampy/cryptosign". Just import wampy/cryptosign and use provided methods as shown below.

The authextra option may contain the following properties for WAMP-Cryptosign:

Field Type Required Description
pubkey string yes The client public key (32 bytes) as a Hex encoded string, e.g. 545efb0a2192db8d43f118e9bf9aee081466e1ef36c708b96ee6f62dddad9122
channel_binding* string no If TLS channel binding is in use, the TLS channel binding type, e.g. "tls-unique".
challenge string no A client chosen, random challenge (32 bytes) as a Hex encoded string, to be signed by the router.
trustroot string no When the client includes a client certificate, the Ethereum address of the trustroot of the certificate chain to be used, e.g. 0x72b3486d38E9f49215b487CeAaDF27D6acf22115, which can be a Standalone Trustroot or an On-chain Trustroot

*: channel_binding is not supported yet. And may be supported only in node.js environment.

'use strict';

import { Wampy } from 'wampy';
import * as wampyCS from 'wampy/cryptosign';
// or you can import only the "sign" method
// import { sign } from 'wampy/cryptosign';

// Manual authentication using signed message
wampy = new Wampy('wss://wamp.router.url', {
    realm: 'realm1',
    authid: 'joe',
    authmethods: ['cryptosign'],
    authextra: {
        pubkey: '545efb0a2192db8d43f118e9bf9aee081466e1ef36c708b96ee6f62dddad9122'
    },
    onChallenge: (method, info) => {
        console.log('Requested challenge with ', method, info);
        return wampyCS.sign('joe secret (private) key')(method, info);
    }
});

// Promise-based manual authentication using signed message
wampy = new Wampy('wss://wamp.router.url', {
    realm: 'realm1',
    authid: 'micky',
    authmethods: ['cryptosign'],
    authextra: {
        pubkey: '545efb0a2192db8d43f118e9bf9aee081466e1ef36c708b96ee6f62dddad9122'
    },
    onChallenge: (method, info) => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('Requested challenge with ', method, info);
                resolve(wampyCS.sign('micky secret (private) key')(method, info));
            }, 2000);
        });
    }
});

// Automatic CryptoSign authentication
wampy = new Wampy('wss://wamp.router.url', {
    realm: 'realm1',
    authid: 'patrik',
    authmethods: ['cryptosign'],
    authextra: {
        pubkey: '545efb0a2192db8d43f118e9bf9aee081466e1ef36c708b96ee6f62dddad9122'
    },
    onChallenge: wampyCS.sign('patrik secret (private) key')
});

Back to Table of Contents

Automatically chosen Authentication

If you server provides multiple options for authorization, you can configure wampy.js to automatically choose required authorization flow based on authmethod requested by server. For this flow you need to configure the following options:

  • authid. Authentication id to use in challenge
  • authmethods. Supported authentication methods
  • authextra. Additional authentication options
  • authPlugins. Authentication helpers for processing different authmethods challenge flows
  • authMode. Mode of authorization flow. Should be set to auto
  • onChallenge. onChallenge callback. Is not used when authMode=auto
import { Wampy } from 'wampy';
import { sign as CraSign } from 'wampy/wampcra';
import { sign as CryptoSign } from 'wampy/cryptosign';

wampy = new Wampy('wss://wamp.router.url', {
    realm: 'realm1',
    authid: 'patrik',
    authmethods: ['ticket', 'wampcra', 'cryptosign'],
    authextra: {    // User public key for Cryptosign-based Authentication
        pubkey: '545efb0a2192db8d43f118e9bf9aee081466e1ef36c708b96ee6f62dddad9122'
    },
    authPlugins: {
        ticket: ((userPassword) => (() => userPassword ))(),
        wampcra: CraSign(userSecret),
        cryptosign: CryptoSign(userPrivateKey)
    },
    authMode: 'auto',
    onChallenge: null
});

Back to Table of Contents

subscribe(topicURI, onEvent[, advancedOptions])

Subscribes for topicURI events.

Input Parameters:

  • topicURI. Required. A string that identifies the topic. Must meet a WAMP Spec URI requirements.
  • onEvent. Published event callback. Will be called on receiving published event with one hash-table parameter with following attributes:
    • argsList: array payload (maybe omitted)
    • argsDict: object payload (maybe omitted)
    • details: some publication options object.
  • advancedOptions. Optional parameters hash table. Must include any or all of the options:
    • match: string matching policy ("prefix"|"wildcard")
    • get_retained: bool request access to the Retained Event

Returns a Promise that's either:

  • Resolved with a hash-table parameter with following attributes:
    • topic
    • requestId
    • subscriptionId
    • subscriptionKey
  • Rejected with one of the Error instances
await ws.subscribe('chat.message.received', (eventData) => { console.log('Received new chat message!', eventData); });

try {
    const res = await ws.subscribe('some.another.topic',
        (eventData) => {
            console.log('Received topic event', eventData);
        }
    );
    console.log('Successfully subscribed to topic: ' + res.topic);

} catch (e) {
    console.log('Subscription error:' + e.error);
}

Back to Table of Contents

unsubscribe(subscriptionIdKey[, onEvent])

Unsubscribe subscription from receiving events.

Parameters:

  • subscriptionIdKey. Required. Subscription ID (number) or Key (string), received during .subscribe()
  • onEvent. Published event callback instance to remove, or it can be not specified, in this case all callbacks and subscription will be removed.

Returns a Promise that's either:

  • Resolved with one hash-table parameter with following attributes:
    • topic
    • requestId
  • Rejected with one of the Error instances
const f1 = (data) => { console.log('this was event handler for topic') };
await ws.unsubscribe('subscribed.topic', f1);

const defer = ws.unsubscribe('chat.message.received');

Back to Table of Contents

publish(topicURI[, payload[, advancedOptions]])

Publish a new event to topic.

Parameters:

  • topicURI. Required. A string that identifies the topic. Must meet a WAMP Spec URI requirements.
  • payload. Publishing event data. Optional. Maybe any single value or array or hash-table object or null:
    • If it is an array - it is sent as is as WAMP positional arguments attribute
    • If it is a single object (without argsList and argsDict keys) - it is sent as is as WAMP key-value arguments attribute
    • If it is a single Number/String/Boolean/Null value - it is packed into one-item array and is sent as WAMP positional arguments attribute. Be aware: receiver will get it in argsList as one-item array and not as single value!
    • It is possible to pass array and object-like data simultaneously. In this case pass a hash-table with next attributes:
      • argsList: array payload (maybe omitted)
      • argsDict: object payload (maybe omitted)
  • advancedOptions. Optional parameters hash table. Must include any or all of the options:
    • exclude: integer|array WAMP session id(s) that won't receive a published event, even though they may be subscribed
    • exclude_authid: string|array Authentication id(s) that won't receive a published event, even though they may be subscribed
    • exclude_authrole: string|array Authentication role(s) that won't receive a published event, even though they may be subscribed
    • eligible: integer|array WAMP session id(s) that are allowed to receive a published event
    • eligible_authid: string|array Authentication id(s) that are allowed to receive a published event
    • eligible_authrole: string|array Authentication role(s) that are allowed to receive a published event
    • exclude_me: bool flag of receiving publishing event by initiator (if it is subscribed to this topic)
    • disclose_me: bool flag of disclosure of publisher identity (its WAMP session ID) to receivers of a published event
    • ppt_scheme: string Identifies the Payload Schema for Payload Passthru Mode
    • ppt_serializer: string Specifies what serializer was used to encode the payload
    • ppt_cipher: string Specifies the cryptographic algorithm that was used to encrypt the payload
    • ppt_keyid: string Contains the encryption key id that was used to encrypt the payload
    • retain: bool Ask broker to mark this event as retained

Returns a Promise that's either:

  • Resolved with one hash-table parameter with following attributes:
    • topic
    • requestId
    • publicationId
  • Rejected with one of the Error instances
await ws.publish('user.logged.in');
await ws.publish('chat.message.received', 'user message');  // will be sent as ['user message1']
await ws.publish('chat.message.received', ['user message1', 'user message2']);
await ws.publish('user.modified', { field1: 'field1', field2: true, field3: 123 });
await ws.publish('chat.message.received', ['Private message'], { eligible: 123456789 });

try {
    await ws.publish('user.modified', { field1: 'field1', field2: true, field3: 123 });
    console.log('User successfully modified');
} catch (e) {
    console.log('User modification failed', e.error, e.details);
}

Back to Table of Contents

call(topicURI[, payload[, advancedOptions]])

Make an RPC call to topicURI.

Parameters:

  • topicURI. Required. A string that identifies the remote procedure to be called. Must meet a WAMP Spec URI requirements.
  • payload. RPC data. Optional. Maybe any single value or array or hash-table object or null:
    • If it is an array - it is sent as is as WAMP positional arguments attribute
    • If it is a single object (without argsList and argsDict keys) - it is sent as is as WAMP key-value arguments attribute
    • If it is a single Number/String/Boolean/Null value - it is packed into one-item array and is sent as WAMP positional arguments attribute. Be aware: receiver will get it in argsList as one-item array and not as single value!
    • It is possible to pass array and object-like data simultaneously. In this case pass a hash-table with next attributes:
      • argsList: array payload (maybe omitted)
      • argsDict: object payload (maybe omitted)
  • advancedOptions. Optional parameters hash table. Must include any or all of the options:
    • disclose_me: bool flag of disclosure of Caller identity (WAMP session ID) to endpoints of a routed call
    • progress_callback: function for handling intermediate progressive call results
    • timeout: integer timeout (in ms) for the call to finish
    • ppt_scheme: string Identifies the Payload Schema for Payload Passthru Mode
    • ppt_serializer: string Specifies what serializer was used to encode the payload
    • ppt_cipher: string Specifies the cryptographic algorithm that was used to encrypt the payload
    • ppt_keyid: string Contains the encryption key id that was used to encrypt the payload

Returns a Promise that's either:

  • Resolved with one hash-table parameter with following attributes:
    • details: hash-table with some additional details
    • argsList: optional array containing the original list of positional result elements as returned by the Callee
    • argsDict: optional hash-table containing the original dictionary of keyword result elements as returned by the Callee
  • Rejected with one of the Error instances

Important note on progressive call results:

For getting a progressive call results you need to specify progress_callback in advancedOptions. This callback will be fired on every intermediate result. But the last one result or error will be processed on promise returned from the .call(). That means that final call result will be received by call promise resolve handler.

const result = await ws.call('server.time');
console.log('Server time is ' + result.argsList[0]);

try {
    await ws.call('start.migration');
    console.log('RPC successfully called');
} catch (e) {
    console.log('RPC call failed!', e.error);
}

try {
    await ws.call('restore.backup', { backupFile: 'backup.zip' });
    console.log('Backup successfully restored');
} catch (e) {
    console.log('Restore failed!', e.error, e.details);
}

Back to Table of Contents

cancel(reqId[, advancedOptions])

RPC invocation cancelling.

Parameters:

  • reqId. Required. Request ID of RPC call that need to be canceled.
  • advancedOptions. Optional parameters hash table. Must include any or all of the options:
    • mode: string|one of the possible modes: "skip" | "kill" | "killnowait". Skip is default.

Returns a Boolean or throws an Error:

  • true if successfully sent canceling message
  • Error if some error occurred
const defer = ws.call('start.migration');
defer
    .then((result) => console.log('RPC successfully called'))
    .catch((e) => console.log('RPC call failed!', e));

status = ws.getOpStatus();

ws.cancel(status.reqId);

Back to Table of Contents

register(topicURI, rpc[, advancedOptions])

RPC registration for invocation.

Parameters:

  • topicURI. Required. A string that identifies the remote procedure to be called. Must meet a WAMP Spec URI requirements.
  • rpc. Required. registered procedure.
  • advancedOptions. Optional parameters hash table. Must include any or all of the options:
    • match: string matching policy ("prefix"|"wildcard")
    • invoke: string invocation policy ("single"|"roundrobin"|"random"|"first"|"last")

Returns a Promise that's either:

  • Resolved with one hash-table parameter with following attributes:
    • topic
    • requestId
    • registrationId
  • Rejected with one of the Error instances

Registered PRC during invocation will receive one hash-table argument with following attributes:

  • argsList: array payload (maybe omitted)
  • argsDict: object payload (maybe omitted)
  • details: some invocation options object. One attribute of interest in options is "receive_progress" (boolean), which indicates, that caller is willing to receive progressive results, if possible. Another one is "trustlevel", which indicates the call trust level, assigned by dealer (of course if it is configured accordingly).
  • result_handler: result handler for case when you want to send progressive results. Just call it with one parameter, same as you return from simple invocation. Also, do not forget to set options: { progress: true } for intermediate results.
  • error_handler: error handler for case when you want to send progressive results and caught some exception or error.

RPC can return no result (undefined), any single value, array or hash-table object:

  • If it is an array - it is sent as is as WAMP positional arguments attribute
  • If it is a single object (without argsList and argsDict keys) - it is sent as is as WAMP key-value arguments attribute
  • If it is a single Number/String/Boolean/Null value - it is packed into one-item array and is sent as WAMP positional arguments attribute. Be aware: receiver will get it in argsList as one-item array and not as single value!
  • It is possible to pass array and object-like data simultaneously. In this case pass a hash-table with next attributes:
    • argsList: array payload (maybe omitted)
    • argsDict: object payload (maybe omitted)
    • options: some result options object. Possible attribute of options is "progress": true, which indicates, that it's a progressive result, so there will be more results in the future. Be sure to unset "progress" on last result message.
const sqrt_f = function (data) { return { result: data.argsList[0]*data.argsList[0] } };

await ws.register('sqrt.value', sqrt_f);

try {
    await ws.register('sqrt.value', sqrt_f);
    console.log('RPC successfully registered');
} catch (e) {
    console.log('RPC registration failed!', e);
}

Also, wampy supports rpc with asynchronous code, such as some user interactions or xhr, using promises. For using this functionality in old browsers you should use polyfills, like es6-promise. Check browser support at can i use site.

const getUserName = () => {
    return new Promise((resolve, reject) => {
        /* Ask user to input his username somehow,
           and resolve promise with user input at the end */
        resolve({ argsList: userInput });
    });
};

ws.register('get.user.name', getUserName);

Also, it is possible to abort rpc processing and throw error with custom application specific data. This data will be passed to caller onError callback.

Exception object with custom data may have the following attributes:

  • error. String with custom error uri. Must meet a WAMP Spec URI requirements.
  • details. Custom details dictionary object.
  • argsList. Custom arguments array, this will be forwarded to the caller by the WAMP router's dealer role. In most cases this attribute is used to pass the human-readable message to the client.
  • argsDict. Custom arguments object, this will be forwarded to the caller by the WAMP router's dealer role.

Note: Any other type of errors (like built in Javascript runtime TypeErrors, ReferenceErrors) and exceptions are caught by wampy and sent back to the client's side, not just this type of custom errors. In this case the details of the error can be lost.

const getSystemInfo = () => {

    // Application logic

    // for example, if you need to get data from db
    // and at this time you can't connect to db
    // you can throw exception with some details for client application

    const UserException = () => {
        this.error = 'app.error.no_database_connection';
        this.details = {
         errorCode: 'ECONNREFUSED',
         errorMessage: 'Connection refused by a remote host.',
         database: 'db',
         host: '1.2.3.4',
         port: 5432,
         dbtype: 'postgres'
       };
        this.argsList = ['Not able to connect to the database.'];
        this.argsDict = {};
    };

    throw new UserException();
};

await wampy.register('get.system.info', getSystemInfo);

try {
    await wampy.call('get.system.info');
} catch (error) {
    console.log('Error happened', error);
}

Back to Table of Contents

unregister(topicURI)

RPC unregistration from invocations.

Parameters:

  • topicURI. Required. A string that identifies the remote procedure to be unregistered. Must meet a WAMP Spec URI requirements.

Returns a Promise that's either:

  • Resolved with one hash-table parameter with following attributes:
    • topic
    • requestId
  • Rejected with one of the Error instances
await ws.unregister('sqrt.value');

try {
    ws.unregister('sqrt.value');
    console.log('RPC successfully unregistered');
} catch (e) {
    console.log('RPC unregistration failed!', e);
}

Error handling

During wampy instance lifetime there can be many cases when error happens: some made by developer mistake, some are bound to WAMP protocol violation, some came from other peers. Errors that can be caught by wampy instance itself are stored in opStatus.error, while others are just thrown.

This allows, for example, convenient handling of different types of errors:

import {Wampy, Errors} from 'wampy';
const wampy = new Wampy('/ws/', { realm: 'AppRealm' });

try {
    await wampy.call('start.migration');
    console.log('RPC successfully called');
} catch (error) {
    console.log('Error happened!');
    if (error instanceof Errors.UriError) {
        // statements to handle UriError exceptions
    } else if (error instanceof Errors.InvalidParamError) {
        // statements to handle InvalidParamError exceptions
    } else if (error instanceof Errors.NoSerializerAvailableError) {
        // statements to handle NoSerializerAvailableError exceptions
    } else {
        // statements to handle any unspecified exceptions
    }
}

Wampy package exposes the following Error classes:

  • UriError
  • NoBrokerError
  • NoCallbackError
  • InvalidParamError
  • NoSerializerAvailableError
  • NonExistUnsubscribeError
  • NoDealerError
  • RPCAlreadyRegisteredError
  • NonExistRPCUnregistrationError
  • NonExistRPCInvocationError
  • NonExistRPCReqIdError
  • NoRealmError
  • NoWsOrUrlError
  • NoCRACallbackOrIdError
  • ChallengeExceptionError
  • PPTNotSupportedError
  • PPTInvalidSchemeError
  • PPTSerializerInvalidError
  • PPTSerializationError
  • ProtocolViolationError
  • AbortError
  • WampError
  • SubscribeError
  • UnsubscribeError
  • PublishError
  • RegisterError
  • UnregisterError
  • CallError
  • WebsocketError

For errors attributes look at src/errors.js file.

Back to Table of Contents

Using custom serializer

From v5.0 version there is option to provide custom serializer.

Custom serializer instance must meet a few requirements:

  • Have a encode (data) method, that returns encoded data
  • Have a decode (data) method, that returns decoded data
  • Have a protocol string property, that contains a protocol name. This name is concatenated with "wamp.2." string and is then passed as websocket subprotocol http header.
  • Have a isBinary boolean property, that indicates, is this a binary protocol or not.

Take a look at json-serializer.js or msgpack-serializer.js as examples.

Back to Table of Contents

Connecting through TLS in node environment

Starting from v6.2.0 version you can pass additional HTTP Headers and TLS parameters to underlying socket connection in node.js environment (thnx websocket library). See example below. For wsRequestOptions you can pass any option, described in tls.connect options documentation.

const Wampy = require('wampy').Wampy;
const w3cws = require('websocket').w3cwebsocket;

wampy = new Wampy('wss://wamp.router.url:8888/wamp-router', {
    ws: w3cws,
    realm: 'realm1',
    additionalHeaders: {
        'X-ACL-custom-token': 'dkfjhsdkjfhdkjs',
        'X-another-custom-header': 'header-value'
    },
    wsRequestOptions: {
        ca: fs.readFileSync('ca-crt.pem'),
        key: fs.readFileSync('client1-key.pem'),
        cert: fs.readFileSync('client1-crt.pem'),
        host: 'wamp.router.url',
        port: 8888,
        rejectUnauthorized: false,   // this setting allow to connect to untrusted (or self signed) TLS certificate,
        checkServerIdentity: (servername, cert) => {
            // A callback function to be used (instead of the builtin tls.checkServerIdentity() function)
            // when checking the server's hostname (or the provided servername when explicitly set)
            // against the certificate. This should return an <Error> if verification fails.
            // The method should return undefined if the servername and cert are verified.
            if (servername !== 'MyTrustedServerName') {
                return new Error('Bad server!');
            }
        }
    }
});

Back to Table of Contents

Tests and code coverage

Wampy.js uses mocha and chai for tests and c8/istanbul for code coverage. Wampy sources are mostly all covered with tests! :)

# use standard npm test command
> npm test
# or only some tests
> npm run test:node
> npm run test:node-no-crossbar
> npm run test:browser

# for code coverage report run
> npm run cover
# and then open coverage/lcov-report/index.html

Back to Table of Contents

Copyright and License

Wampy.js library is licensed under the MIT License (MIT).

Copyright (c) 2014 Konstantin Burkalev

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.

Back to Table of Contents

See Also

  • WAMP specification
  • wampy/wampcra - WAMP Challenge Response Authentication plugin for Wampy.js
  • wampy/cryptosign - WAMP Cryptosign-based Authentication plugin for Wampy.js
  • Wiola - WAMP Router in Lua on top of nginx/openresty
  • Loowy - LUA WAMP client
  • msgpackr - Ultra-fast MessagePack implementation with extension for record and structural cloning.
  • cbor-x - Ultra-fast CBOR encoder/decoder with extensions for records and structural cloning.

Back to Table of Contents

Thanks JetBrains for support! Best IDEs for every language!

jetbrains logo

wampy.js's People

Contributors

421p avatar azamat-sharapov avatar bjartebore avatar cameron-elliott avatar danelowe avatar dependabot[bot] avatar elliottsj avatar greenkeeper[bot] avatar ksdaemon avatar lucasrmendonca avatar mavrin avatar samson84 avatar snyk-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wampy.js's Issues

Inconsistent return values from RPC

When making RPCs using Wampy#call(), I am getting inconsistent onSuccess callback parameters. In some cases, I get just the returned data from the function (i.e. if the RPC handler returns an object, just that object is given in the callback); in other cases, I also get an empty array as first parameter to the callback, and then the data I want as the second parameter.

As a workaround I have made my wrapper detect if the first parameter is an empty array, in that case using the second parameter, but I'd like to know what is actually going on. Is this a bug, or am I just using the library wrong? I couldn't find anything in the documentation that helped.

depending on window makes wampy unusable for webworkers

this logic

scheme = window.location.protocol === 'https:' ? 'wss://' : 'ws://';

in getServerUrlBrowser

set implicit requirement that window must exists which is not the case if code executed within WebWorker, there should be way to explicitly specify scheme or connection URI, to avoid requirement for window to exist.

Installation issues

Hi,

I'm having issues installing Wampy. I'm using Node v5.10.1 and npm v 3.8.3

When i do
npm install wampy
in an empty folder with no package.json file, I get a whole heap of errors in red.

If i do have a package.json file, and do
npm install wampy --save i still get a whole heap of errors.

The first 3 errors (out of about 100) are:
C:\Users\Brad\.node-gyp\5.10.1\include\node\v8.h(336): error C2988: unrecognizable template declaration/definition [C:\DEV\testwampyinstall\node_modules\websoc ket\build\bufferutil.vcxproj] C:\Users\Brad\.node-gyp\5.10.1\include\node\v8.h(336): error C2059: syntax error : 'using' [C:\DEV\testwampyinstall\node_modules\websocket\build\bufferutil.vcx proj] C:\Users\Brad\.node-gyp\5.10.1\include\node\v8.h(469): error C2988: unrecognizable template declaration/definition [C:\DEV\testwampyinstall\node_modules\websoc ket\build\bufferutil.vcxproj]

I have installed Wampy before just fine with previous versions, but not this latest one.

Can anyone please help ?!?

Symbol undefined

On IE and android based Fully kiosk

Symbol undefined && invalidStateError

An in-range update of webpack is breaking the build 🚨

Version 2.5.0 of webpack just got published.

Branch Build failing 🚨
Dependency webpack
Current Version 2.4.1
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

As webpack is “only” a devDependency of this project it might not break production or downstream projects, but “only” your build or test tools – preventing new deploys or publishes.

I recommend you give this issue a high priority. I’m sure you can resolve this 💪

Status Details - ❌ **continuous-integration/travis-ci/push** The Travis CI build could not complete due to an error [Details](https://travis-ci.org/KSDaemon/wampy.js/builds/228681354?utm_source=github_status&utm_medium=notification)

Release Notes v2.5.0

Bugfixes:

  • add hashSalt to schema
  • webpack's source code no longer contains sourceMappingURL, which caused issues with some tools
  • Added missing semicolon in dll-imported modules
  • DllPlugin manifest is smaller (not pretty printed)
  • CommonsChunkPlugin in async mode doesn't extract from initial chunks

Features:

  • allow placeholders in the BannerPlugin
  • add option to disable the module trace in stats
Commits

The new version differs by 81 commits0.

  • bf3652b 2.5.0
  • cd1cd29 Merge pull request #4815 from webpack/bugfix/extract-async-initial
  • b45588b CommonsChunkPlugin in async mode doesn't select initial chunks
  • 8bab88c Merge pull request #4814 from webpack/test/move-entry
  • a244879 add testcase for moving entry modules into the commons chunk
  • 85dc98f Merge pull request #4813 from JLHwung/perf/date-now
  • 6afc397 perf: use Date.now() instead of new Date().getTime()
  • 94d0641 perf: use Date.now() instead of +new Date()
  • c91ba49 Merge pull request #4791 from deificx/master
  • 94ba75f Merge pull request #4794 from ndresx/disable-manifest-json-pretty-print
  • 84ea1ff added error to stats.moduleTrace test name to trigger test cases corretly
  • 8ad4386 test cases for stats.moduleTrace option
  • 958156a moduleTrace added to webpackOptionsSchema.json
  • de87f93 Disable manifest.json pretty print
  • 4131013 rename stats.stackTrace to stats.moduleTrace

There are 81 commits in total.

See the full diff

Not sure how things should work exactly?

There is a collection of frequently asked questions and of course you may always ask my humans.


Your Greenkeeper Bot 🌴

ReferenceError: exports is not defined

my entry point is dist/wampy.js which is already transpiled to "es2015" preset
but I always get the next error message on Javascript console:
ReferenceError: exports is not defined

Tutorials/Help for node

Hi,
You mention WAMPY is a 'browser-only' lib, but you've got example code for node:

// in node.js
w3cws = require('websocket').w3cwebsocket;
ws = new Wampy(null, { ws: w3cws });
ws = new Wampy('/my-socket-path', { ws: w3cws });
ws = new Wampy('ws://socket.server.com:5000/ws', { autoReconnect: false, ws: w3cws });
ws = new Wampy({ reconnectInterval: 1*1000, ws: w3cws });

Are you able to please provide a basic example (possibly with a package.json) to get WAMPY working with Node (i.e. installation of WebSocket, WAMPY, etc) ?

I'm unable to get this going in Node. (running in Browser is fine, though!)

(Ideally, I'm trying to get this working with Typescript in Node, but lets just get the JavaScript version working for me: one step at a time. I have it working with Typescript in the Browser just fine.)

Cheers.

Something wrong in the wampy.js file (browser.zip release 6.1.0)?

Did you look into the file (under browser - seemingly combined from a number of files from the src directory) itself?

There are lines very very long, and the top comment section from the original src/wampy.js goes way way to the far right (huge indentation) somewhere in the middle (vertically) of now browser/wampy.js.

Noticed it after running 'pdoc` (generating documentation from the source) on the file, which failed.

Connection to server is stuck most of the time

I am connecting to WampSharp server implementation and connection to the server most of the time stuck. If I connect though wampsharp client it is always successful, any thoughts. Same thing with autobahn client.

image

Add progress callback

Can we add a progress callback when using receive_progress = true or add the progress flag to the onSuccess callback?

Use with React Native

When I use wampy.js with ReactNative with crossbar.io router, have a problem:

Failed to connect to /127.0.0.1:8080

I don't use authorization, and other options

new Wampy('ws://127.0.0.1:8080', { 
            realm: config.server.realm,
            ws: WebSocket,
            onConnect: () => {
                console.log('Connected to Router!');
            },
            reconnectInterval: 1000,
            maxRetries: 999,
            onClose: function () { console.log('See you next time!'); },
            onError: function (error) { console.log('Breakdown happened', error.message, error); },
            onReconnect: function () { console.log('Reconnecting...'); },
            onReconnectSuccess: function () { console.log('Reconnection succeeded...'); }
        })

Can I use wampy with ReactNative. Autobahn don't work with RN. I want use wampy
ws: WebSocket
This options I try enabled and disabled, have same result

on reconnect

Does the on reconnect auto subscribe to the old topics? Seems to bug out.
Trying to figure out where its going wrong.

It is suppose to reconnect on all the topics?

Typo in wampy.js:509

Hi, I think this._options._authmethods needs to be changed to this._options.authmethods (excess underscore before authmethods).

508:        if (this._options.authid) {
509:            options.authmethods = this._options._authmethods;
                                                    ^^^^^^^^^^^^
510:            options.authid = this._options.authid;
511:        }

Progressive call results

Hi,

I have a question about the progressive call results.
From the docs, I understand that wampy supports progressive call results with registered procedures.
It says:

Possible attribute of options is "progress": true, which indicates, that it's a progressive result, so there will be more results in future. Be sure to unset "progress" on last result message.

But, I can't find a way how to return more than one result. The docs say how you can delay a return with a promise, but I can't find a way to return a second value after the first one.
It would be nice when the RPC callback can return an rx Observable in addition to a value or a promise. Or is there somehow a different way I missed?

Greetings
Johan

Can't import Wampy

How to properly import wampy into TypeScript project?

Wampy.js installed with

typings install dt~wampy --global --save && npm install wampy --save

Trying to import Wampy:

import {Wampy} from "wampy";

npm start produces this error:

error TS2305: Module '"wampy"' has no exported member 'Wampy'.

Next I tried to import as I have seen here:

import * as Wampy from "wampy";

Getting

error TS2304: Cannot find name 'Wampy'.

UPD: Trying

import {wampy} from "wampy";
// some code
this.ws = new wampy('ws://127.0.0.1:9000', {
    realm: 'realm1',
    onConnect: () => {
        console.log('Connected to Router!');
    }
});

Getting

error TS2305: Module '"wampy"' has no exported member 'wampy'.

Migrate typings to 6.x.x version

Hi there!

Would love to use wampy.js in my current (angular 5.x.x) project as a wamp client - I've just reviewed the current typings, which seem to be a little bit outdated. Are you planning to migrate them to the latest version 6.x.x?

Wampy > 2.0 does not work in Browser

Wampy 2.0.1, running in Chrome gives the following Error.
Also tested with Edge-Browser.
Seems to be a regression of commit 493dbe.

ReferenceError: root is not defined
at getWebSocket (wampy.js:190)
at Wampy.connect (wampy.js:1135)
at new Wampy (wampy.js:450)

question about "HELLO" message

Hi, I have one question.

Are there any options to set 'Details'(or payload) when send the HELLO message?

below quotation is taken from WAMP v2 draft.

After the underlying transport has been established, the opening of a
WAMP session is initiated by the Client sending a "HELLO" message
to the Router.
"Details" is a dictionary that allows to provide additional
opening information

   [HELLO, Realm|uri, Details|dict]

As I know, HELLO message will be sent to the router automatically when wampy's constructor is created. but I can not find any options to set 'Details' in case of using constructor and connection( ) method.

If there is no way now, do you have plan to support that feature?

Thank you.

clarification of error usage in a documentation

Hi,

I made some experiments with the error handling, and have a docs update recommendation:

in readme.md:

Also it is possible to abort rpc processing and throw error with custom application specific data. This data will be passed to caller onError callback. Exception object with custom data may have next attributes:

uri. String with custom error uri.
details. Custom details object.
argsList. Custom arguments array.
argsDict. Custom arguments object.

According to the standard the details object is used by the router not by the original caller or publisher . The main reason of this object to extend the protocol for the further features. It is not really guaranteed that this object will be passed back to the caller / publisher (and the crossbar.io router implementation actually working this way). However it is not said explicitly.
https://tools.ietf.org/html/draft-oberstet-hybi-tavendo-wamp-02#section-6.1

According to the INVOCATION ERROR message definition of the standard argList and argDict objects sends back to the caller / subscriber, even it is said explicitly.
https://tools.ietf.org/html/draft-oberstet-hybi-tavendo-wamp-02#section-9.2.5

If you agree, I am happy to contribute of the correction.

Thanks for the answer,
Daniel

URI validation does not meet WAMP v2 spec

According to the WAMP v2 spec URI's must only have numbers, letters and underscore, with a minimum of size of one for each URI component. (https://tools.ietf.org/html/draft-oberstet-hybi-tavendo-wamp-02#section-5.1.1.2). The sample regex in the spec is

re.compile(r"^([0-9a-z_]+.)*([0-9a-z_]+)$")

Wampy however enforces at a minimum size of two for the length of each component.

_validateURI (uri) {
    const re = /^([0-9a-zA-Z_]{2,}\.)*([0-9a-zA-Z_]{2,})$/;
    return !(!re.test(uri) || uri.indexOf('wamp') === 0);
}

This is a mismatch from the spec.

wampy-all.min.js missed

Hi there,

I just installed your library using bower and from the ZIP package but I didn't find the file called wampy-all.min.js that you mention in the documentation.

Regards.

Error: Cannot read property 'split' of undefined

On React Native, this error occurs after successfully connecting to the server:

Error: Cannot read property 'split' of undefined
 stack: 
  Wampy._wsOnOpen                              index.ios.bundle:58797
  WebSocket.Wampy._initWsCallbacks._ws.onopen  index.ios.bundle:58785
  WebSocket.<anonymous>                        index.ios.bundle:13888
  Object.ErrorUtils.applyWithGuard             index.ios.bundle:1202
  EventEmitter.emit                            index.ios.bundle:9702
  MessageQueue.__callFunction                  index.ios.bundle:7157
  <unknown>                                    index.ios.bundle:7093
  guard                                        index.ios.bundle:7046
  <unknown>                                    index.ios.bundle:7093
 URL: undefined
 line: undefined
 message: Cannot read property 'split' of undefined

This is because the React Native WebSocket iOS implementation does not currently support passing the 'protocols' option in the constructor, so this._ws.protocol ends up being undefined.

Is it possible to call RPC with two payloads?

The Wampy documentation says that register RPC function is called with two payloads:

rpc. Registered PRC during invocation will receive three arguments: array
payload (may be undefined), object payload (may be undefined) and options
object.

However, the call function allows to call RPC with only one payload:

call(topicURI[, payload[, callbacks[, advancedOptions]]])

payload. RPC data. Optional. May be any single value or array or hash-
table object or null.

The WAMP specification 9.2.1 has an example:

[48, 7814135, {}, "com.myapp.user.new", ["johnny"],
       {"firstname": "John", "surname": "Doe"}]

In this example, RPC is called with two payloads (array and hash-table object). Is it implemented in Wampy?

Authorization?

What about using authorization with wampy? wamp-cra or jwt, its possible? thanks

support of wss with self-signed certificate

Hi, I'm trying to deploy your module into our solution and I'm not able to make it working with wss://. My websocket server is using self-signed certificate. I guess it is the issue because ws:// works fine. Can you advice what is wrong? Or is there any further flag to be turned on in order to accept such certificate? Thx, Jaro.

[SERIOUS] Where to get "wampy.min.js" ?

In the readme, you say :

"For simple browser usage just download latest browser.zip archive and add wampy-all.min.js file to your page. It contains msgpack encoder plus wampy itself."

But it's not the case : no minimized version (and no usable non minimized) in the ZIP, at least for the v6 version ....

So it's very difficult to test the lib, without grunt/gulp/bower knowledge ;-)

wildcard in topic

Using crossbar.

Want to subscribe with wildcard like topic.uri..live
as described in crossbar docs. Yes, the double dots are the wildcard.

Is this possible?

Welcome details on connect

Can we have "welcome details" as an argument to onConnect() and onReconnectSuccess()? It's useful to get some session details once client connects. My current workaround to this is calling wamp.session.get, but I would like to avoid odd call, when all needed info is in "welcome".

If you accept PR for this, I could make one.

Thanks!

reconnected callback

hi,

I've been using this library and I feel this is very good for me.
I would like to ask you to add a callback that is invoked when reconnection is done successfully.

thank you:)

Losing PUBLISH.Arguments|list when PUBLISH.ArgumentKw|dict is available

I am attempting to parse messages from the Poloniex API order book/trade feed, and I am only able to access the PUBLISH.ArgumentKw portion of the event.

The API uses the arguments list portion to include (potentially multiple) order updates or trades, and the kw section to include a sequence number. A (formatted) WS frame is as follows:

[
   36,
   3284491188904719,
   4402815269786502,
   {

   },
   [
      {
         "type":"orderBookRemove",
         "data":{
            "type":"ask",
            "rate":"0.02006601"
         }
      },
      {
         "type":"newTrade",
         "data":{
            "amount":"0.03000000",
            "date":"2016-07-27 21:30:06",
            "rate":"0.02006601",
            "total":"0.00060198",
            "tradeID":"14774276",
            "type":"buy"
         }
      }
   ],
   {
      "seq":78362665
   }
]

In the event parsing code it selects only one of the three argument sets depending on how many are included:

                case WAMP_MSG_SPEC.EVENT:
                    if (this._subscriptions[data[1]]) {

                        switch (data.length) {
                            case 4:
                                // WAMP SPEC: [EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id, Details|dict]
                                d = null;
                                break;
                            case 5:
                                // WAMP SPEC: [EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id,
                                //             Details|dict, PUBLISH.Arguments|list]
                                d = data[4];
                                break;
                            case 6:
                                // WAMP SPEC: [EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id,
                                //             Details|dict, PUBLISH.Arguments|list, PUBLISH.ArgumentKw|dict]
                                d = data[5];
                                break;
                        }

                        i = this._subscriptions[data[1]].callbacks.length;
                        while (i--) {
                            this._subscriptions[data[1]].callbacks[i](d);
                        }

                    }
                    break;

This results in only receiving {seq: ######} and being unable to access the trade information.

A different library specifies the callback could match this signature:

function (args, kwargs, details)

or data[4], data[5], data[3]
This would break backwards compatibility. I'm changing my code to that cause I'm in a hurry. Want me to PR the edit?

Angular 2 implementation won't connect

Hi there,

I'm trying to connect my NotificationService (within Angular2) to my Wamp server and so far I've had no feedback from the callbacks. No error or anything.
Basic websocket connection is established when using var ws = new WebSocket("ws://127.0.0.1:8080");
Here is my code:

import { Wampy } from 'wampy';

...
export class NotificationService {
   init(){
      this.openWsConnection('ws://127.0.0.1:8080');
   }

   openWsConnection(url): void{
      var ws = new Wampy(url,{
         onConnect: ()=>{
            console.log("connected");
         },
         onClose: ()=>{
            console.log("close");
         },
         onError: ()=>{
            console.log("error");
         },
      });
     console.log(ws);  //ws exists
   }
}

Am I missing anything ?

Help in file transfer between clients

hello,

I know the "ISSUE" is not a right forum to post questions, but unfortunately I did not find your email address, thus I just choosed this way.

So I am using your wampy project and I would like to do file transfer between two wamp clients. In the README, I can see an example for wamp.call where a backup file is transfered(?)

ws.call('restore.backup', { backupFile: 'backup.zip' }, {...

I would like to ask you, do I understood right, the call method is the way how file can be transfered?

Thanks for your help.
/Robi

Events are lost after a reconnect

When Wampy reconnects after connection-loss with autoReconnect, it re-subscribes to previous subscriptions; So far ok.
But after re-connect no events will come through anymore.

Tested in Chrome & Edge with Wampy 2.0.1.

WampyMsgpackSerializer not defined

Hi!

I'm using last version of wampy-all.min.js from browser.zip and trying to define new instance of wampy with msgpack serializer.
Following the instructions in README.md, I do this:

// in browser
ws = new Wampy('ws://mycoolserver.watever:6789/myroute', {
    realm: 'awesome.realm',
    serializer: new WampyMsgpackSerializer(msgpack5)
});

So, browser throws error: Uncaught ReferenceError: WampyMsgpackSerializer is not defined

Noob question - am I doing it wrong, or miss something?
Best regards

null value in argList causes crossbar.io router exception

Hi,

  1. register a callee function
  2. callee function throws a custom error with argsDict but without argsList property
  3. wampy.js handle this that, adds null to the argsList: https://github.com/KSDaemon/wampy.js/blob/dev/src/wampy.js#L999
  4. wamp router throws protocol error and immediately close the connection because of type of the argList is None instead of Dict.

The wampy sends the following ERROR message:
"[8,68,1,{},\"custom.error\",null,{\"message\":\"This error should be thrown\"}]"

Causes the following error in crossbar.io router:

crossbar-service_1  | [Router         15 crossbar.router.protocol.WampWebSocketServerProtocol] Traceback (most recent call last):
crossbar-service_1  |   File "/usr/local/lib/python3.5/site-packages/autobahn/wamp/websocket.py", line 88, in onMessage
crossbar-service_1  |     for msg in self._serializer.unserialize(payload, isBinary):
crossbar-service_1  |   File "/usr/local/lib/python3.5/site-packages/autobahn/wamp/serializer.py", line 131, in unserialize
crossbar-service_1  |     msg = Klass.parse(raw_msg)
crossbar-service_1  |   File "/usr/local/lib/python3.5/site-packages/autobahn/wamp/message.py", line 1036, in parse
crossbar-service_1  |     raise ProtocolError("invalid type {0} for 'args' in ERROR".format(type(args)))
crossbar-service_1  | autobahn.wamp.exception.ProtocolError: invalid type <class 'NoneType'> for 'args' in ERROR

My custom error definition in node.js:

function WampError(uri, message) {
    Error.captureStackTrace(this, this.constructor);
    this.uri = uri || 'wamp.error';
    this.details = {};
    //this.argsList = [];
    this.argsDict = {
        message,
    };
}
require('util').inherits(WampError, Error);

The WAMP standard is a little bit ambiguous on this topic:
https://tools.ietf.org/html/draft-oberstet-hybi-tavendo-wamp-02#section-6.7
Recommends, that not pass empty arrays, simple skip them. --> this causes also a same type of error.

On the other hand the https://tools.ietf.org/html/draft-oberstet-hybi-tavendo-wamp-02#section-9.2.5
refers to a position based argument passing.

A better solution can be to pass an empty array instead of null to the mentioned line.

msgpack transportEncoding issue

hi,
I am using the latest wampy.js with backend crossbar.io 0.9.12 router. Everything worked as expected when using json transportEncoding, but when I switch over to msgpack, crossbar.io complaint about ProtocolError during the initial handshaking:

...
2014-12-26 18:08:48+0000 [Router         15] RX WAMP HELLO Message (realm = test.realm.wecount, roles = [, , , ], authmethods = None, authid = None)
2014-12-26 18:08:48+0000 [Router         15] TX WAMP WELCOME Message (session = 149574515, roles = [, ], authid = yYI1wcFwlPx74I8X4Cjv06JX, authrole = anonymous, authmethod = anonymous, authprovider = None)
2014-12-26 18:08:48+0000 [Router         15] TX Frame to tcp4:192.168.59.3:51705 : fin = True, rsv = 0, opcode = 2, mask = -, length = 250, repeat_length = None, chopsize = None, sync = False, payload = 9302ce08ea537384a861757468726f6c65a9616e6f6e796d6f7573aa617574686d6574686f64a9616e6f6e796d6f7573a5726f6c657382a662726f6b657281a8666561747572657383b87075626c69736865725f6964656e74696669636174696f6ec3b37075626c69736865725f6578636c7573696f6ec3bd737562736372696265725f626c61636b77686974655f6c697374696e67c3a66465616c657281a8666561747572657382b870726f67726573736976655f63616c6c5f726573756c7473c3b563616c6c65725f6964656e74696669636174696f6ec3a6617574686964b879594931776346776c5078373449385834436a7630364a58
2014-12-26 18:08:48+0000 [Router         15] TX Octets to tcp4:192.168.59.3:51705 : sync = False, octets = 827e00fa9302ce08ea537384a861757468726f6c65a9616e6f6e796d6f7573aa617574686d6574686f64a9616e6f6e796d6f7573a5726f6c657382a662726f6b657281a8666561747572657383b87075626c69736865725f6964656e74696669636174696f6ec3b37075626c69736865725f6578636c7573696f6ec3bd737562736372696265725f626c61636b77686974655f6c697374696e67c3a66465616c657281a8666561747572657382b870726f67726573736976655f63616c6c5f726573756c7473c3b563616c6c65725f6964656e74696669636174696f6ec3a6617574686964b879594931776346776c5078373449385834436a7630364a58
2014-12-26 18:08:48+0000 [Router         15] RX Octets from tcp4:192.168.59.3:51705 : octets = 82b742bd1157d69dde5742f639e1b7525bd79bbd72382f9372382cd3743436d97e2338937c3636cf782f6cca74342dc87f236cd27f0830dc7f3c2bd376
2014-12-26 18:08:48+0000 [Router         15] RX Frame from tcp4:192.168.59.3:51705 : fin = True, rsv = 0, opcode = 2, mask = 42bd1157, length = 55, payload = 9420cf00004b28b6f5ef4a80d900636f6d2e636f6e6e656374646f747a2e6d61747269782e7765636f756e742e6f6e5f72616e6b696e67
2014-12-26 18:08:48+0000 [Router         15] Traceback (most recent call last):
2014-12-26 18:08:48+0000 [Router         15] File "/usr/local/lib/python2.7/dist-packages/autobahn/wamp/websocket.py", line 88, in onMessage
2014-12-26 18:08:48+0000 [Router         15] for msg in self._serializer.unserialize(payload, isBinary):
2014-12-26 18:08:48+0000 [Router         15] File "/usr/local/lib/python2.7/dist-packages/autobahn/wamp/serializer.py", line 106, in unserialize
2014-12-26 18:08:48+0000 [Router         15] raise ProtocolError("invalid serialization of WAMP message ({0})".format(e))
2014-12-26 18:08:48+0000 [Router         15] ProtocolError: invalid serialization of WAMP message (unpack(b) received extra data.)
2014-12-26 18:08:48+0000 [Router         15] Failing WAMP-over-WebSocket transport: code = 1002, reason = 'WAMP Protocol Error (invalid serialization of WAMP message (unpack(b) received extra data.))'
201

there is no warning on the wampy.js side. The failed message seems to be from the subscribe() call.
I am not sure if it is a crossbar.io or or wampy.js issue, but giving crossbar.io is one of the most popular/mature WAMP router implementation, I would think it is important to make sure wampy.js is compatible.

Please let me know if there is anything I can provide to help track down this issue. Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.