npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

wamprx

v2.0.0

Published

Simple WAMP client library heavily relying on rxjs and TypeScript

Downloads

65

Readme

wamprx.js

Simple WAMP (WebSocket Application Messaging Protocol) TypeScript client-side implementation (of course also usable in JavaScript).

It heavily relies on RxJS.

Usage examples

Creating a channel and call an RPC

connectWampChannel('ws://my.wamp.url/ws', 'realm1').pipe(
    switchMap(channel => channel.call('add', [1, 2])))
    .subscribe(([[answer]]) => answer !== 3
        ? console.error(`${answer} is the wrong answer!`)
        : console.log('Answer 3 is correct'));

Or imperatively:

const channel = await toPromise(connectWampChannel('ws://my.wamp.url/ws', 'realm1'));

const [[answer]] = await channel.call('add', [1, 2]).toPromise();

if (answer !== 3) {
    console.error(`${answer} is the wrong answer!`);
} else {
    console.log('Answer 3 is correct');
}

Or any combination of it.

Helper to call functions in a more natural way

To call simple WAMP functions in a more natural way, you can use wampCall() like this:

const answer = await wampCall(channel, 'add', 1, 2).toPromise();

Or turn it into a normal method first to call it later:

const add = (a: number, b: number): Promise<number> =>
    wampCall(channel, 'add', a, b).toPromise();

const answer = await add(1, 2);

Imperative way

Note that when you want to use the imperative way, you can't simply use connectWampChannel(...).toPromise(), but you have to use the toPromise() method from wamprx. That is because the channel$ observable returned from connectWampChannel(...) should be treated as a resource. Which is to say, it connects when it is subscribed, and it disconnects when it is unsubscribed. So when you use .toPromise(), it will unsubscribe and hence disconnect the channel once it returns.

When you use the imperative method, a channel can be closed again by calling:

channel.unsubscribe();

Destructuring

Note the strange looking [[answer]]. This is actually destructuring the WAMP response which is of type ArgsAndDict. ArgsAndDict is a tuple of an array (Args) and a dictionary (object) (Dict), which in WAMP is the usual way to pass arguments or return values. [[answer]] is hence selecting the first argument of the Args.

If you can't (or don't want to) use destructuring for some reason, you can achieve the same result like this:

const argsAndDict = await channel.call('add', [1, 2]).toPromise();
const answer = argsAndDict[0][0]; // First [0] selecting args, second for selecting first arg

or simply use wampCall(). See above.

Registering a function

const channel = await toPromise(connectWampChannel('ws://my.wamp.url/ws', 'realm1'));

const registration = channel.register('add', ([a, b]) => of([[a + b]]);

Most of the time, you will probably only register simple functions with a list of arguments and a simple return value. In those cases you don't need to bother with WAMP's ArgsAndDict type, and you can use toWampFunc() for that like this:

// simple function to be registered:
const add = (a, b) => of(a + b);

// Using toWampFunc() to turn it into a registerable function.
const registration = channel.register('add', toWampFunc(add));

To unregister:

registration.unsubscribe();

With authentication

const auth = {
    authid: 'myId',
    authmethods: ['ticket'],
    challenge: (method, extra) => 'some ticket'
};
const channel = await toPromise(connectWampChannel('ws://my.wamp.url/ws', 'realm1', auth));

Using it in node.js

Because the library is primarily used in the browser, it defaults to using the browsers WebSocket implementation. You can however use it in node.js too like this:

import * as WebSocket from 'ws';
//...
const useWs = makeObservableWebSocket(
    (url, protocol) => new WebSocket(url, protocol));

const channel = await toPromise(connectWampChannel('ws://my.wamp.url/ws', 'realm1', undefined, useWs));

Reconnect on lost connection

wamprx.js doesn't support autoreconnect natively. However, since it is based on RxJS, it is accomplished easily by using RxJS operators.

When the wamp channel disconnects, or is not able to connect, it will emit an error. To reconnect simply use retryWhen() like this:

connectWampChannel('ws://my.wamp.url/ws', 'realm1').pipe(
    // Retry every 5 seconds...
    retryWhen(errors => errors.pipe(delay(5000)))
    .subscribe(connectedChannel => ...);

WAMP features support

See following interface for what is supported:

interface WampChannel {
    call(uri: string, args?: Args, dict?: Dict): Observable<ArgsAndDict>;
    register(uri: string, func: RegisteredFunc): Promise<Subscription>;
    publish(uri: string, args?: Args, dict?: Dict): Promise<number>;
    subscribe(uri: string): Observable<ArgsAndDict>;
}

Serialization

Currently the only serialization method supported is JSON (wamp.2.json).

RPC caller

For all RPC calls, it uses the receive_progress=true option. Also, the Observable<ArgsAndDict> returned by call is cold. Hence the method is called only once it is subscribed, and it is called twice (with the same arguments) when it is subscribed twice.

When you don't want that, simply turn it into a promise via .toPromise().

RPC callee

When a registered function is called with option receive_progress=true, all payload is sent to the caller with option progress=true. When the returned observable emits complete, it will emit the final result without progress=true and without any payload.

When a registered function is called without option receive_progress=true, it will only send the last emitted payload to the caller when the returned observable completes, (or no payload when it completes without emitting any payload). This is the behavior as if .toPromise() was called on the observable.