Autobahn|JS implements The Web Application Messaging Protocol V2 in JavaScript.
WAMP provides asynchronous Remote Procedure Calls and Publish & Subscribe for applications in one protocol running over WebSocket.
Autobahn|JS runs on both Web browsers and Node.js, and implements the following WAMP roles:
- Caller
- Callee
- Publisher
- Subscriber
Autobahn|JS is part of the Autobahn project, MIT licensed, and full source code can be found on GitHub.
Here is how programming with Autobahn|JS looks like (identical code runs in browsers and on NodeJS):
var autobahn = require('autobahn');
var connection = new autobahn.Connection({url: 'ws://127.0.0.1:9000/', realm: 'realm1'});
connection.onopen = function (session) {
// 1) subscribe to a topic
function onevent(args) {
console.log("Event:", args[0]);
}
session.subscribe('com.myapp.hello', onevent);
// 2) publish an event
session.publish('com.myapp.hello', ['Hello, world!']);
// 3) register a procedure for remoting
function add2(args) {
return args[0] + args[1];
}
session.register('com.myapp.add2', add2);
// 4) call a remote procedure
session.call('com.myapp.add2', [2, 3]).then(
function (res) {
console.log("Result:", res);
}
);
};
connection.open();
To use Autobahn|JS in your application, you need a WAMP v2 compatible application router.
The application router is responsible for call and event routing between your application's components. The router itself will not run any application code.
With Autobahn|JS, you can program application components in JavaScript, and those components can be hosted in browsers or NodeJS.
WAMP implementations need to catch up with V2 of WAMP, and currently, the only WAMP v2 compatible router is included with Autobahn|Python.
You can find complete examples here.
You can get Autobahn|JS for NodeJS using the Node Package Manager:
npm install autobahn
and then, in your code
var autobahn = require('autobahn')
You can get the latest (= WAMPv2 only) prebuilt Autobahn|JS release from here:
and use in your HTML
<!DOCTYPE html>
<html>
<body>
<script src="https://autobahn.s3.amazonaws.com/autobahnjs/latest/autobahn.min.jgz"></script>
</body>
</html>
You can use above via direct linking for development purposes, but please do not hotlink for production. It won't work anyway, since we restrictions on HTTP referer.
The old Autobahn|JS for WAMPv1 is still available from here:
The library can be included
try {
// for NodeJS
var autobahn = require('autobahn');
} catch (e) {
// for browsers (where AutobahnJS is available globally)
}
Autobahn bundles whenjs and cryptojs, and the bundled libraries can be accessed like this
try {
var autobahn = require('autobahn');
var when = require('when');
var crypto = require('crypto-js');
} catch (e) {
var when = autobahn.when;
var crypto = autobahn.crypto;
}
Autobahn|JS library version is available (read-only):
autobahn.version
A new connection is created by
var connection = new autobahn.Connection(<options|dict>);
Here, options
provides additional connection options:
url|string
(required): the WebSocket URL of the WAMP router to connect torealm|string
(required): the WAMP realm to joinuse_es6_promises|bool
(optional): use deferreds based on ES6 promises *use_deferred|callable
(optional): if provided, use this deferred constructor, e.g.jQuery.Deferred
orQ.defer
max_retries
: Not yet implemented.retry_delay
: Not yet implemented.skip_subprotocol_check
: Not yet implemented.skip_subprotocol_announce
: Not yet implemented.
*: Using ES6-based promises has certain restrictions. E.g. no progressive call results are supported.
Example: Create a connection
try {
// for NodeJS
var autobahn = require('autobahn');
} catch (e) {
// for browsers (where AutobahnJS is available globally)
}
var connection = new autobahn.Connection({url: 'ws://127.0.0.1:9000/', realm: 'realm1'});
autobahn.Connection
provides two callbacks:
autobahn.Connection.onopen
autobahn.Connection.onclose
where
autobahn.Connection.onopen = function (session) {
// Underlying connection to WAMP router established
// and new WAMP session started.
// session is an instance of autobahn.Session
};
and
autobahn.Connection.onclose = function () {
// underlying connection to WAMP router closed
};
To open a connection:
autobahn.Connection.open();
To close a connection:
autobahn.Connection.close();
To check if a session is open (that is, successfully joined to a realm):
Session.isOpen
A Session's ID is available (read-only) when the session is open:
Session.id
A Session's realm is available (read-only) when the session is open:
Session.realm
All roles and features supported by both peers of a session can be accessed:
Session.features
Create a new Deferred of the same class as used by the library itself:
Session.defer()
This returns a new deferred, e.g. a whenjs deferred or a deferred based on ES6 promises.
To subscribe to a topic on a session
:
var d = session.subscribe(<topic|uri>, <handler|callable>, <options|dict>);
where
topic
(required): is the URI of the topic to subscribe tohandler
(required): is the event handler that should consume eventsoptions
(optional) specifies options for subscription (see below).
and returns a promise that resolves to an instance of autobahn.Subscription
when successful, or rejects with an instance of autobahn.Error
when unsuccessful.
The handler
must be a callable
function (args, kwargs, details)
where
args
is the (positional) event payloadkwargs
is the (keyword) event payloaddetails
provides event metadata
Example: Subscribe to a topic
function on_event1(args, kwargs, details) {
// event received, do something ..
}
session.subscribe('com.myapp.topic1', on_event1).then(
function (subscription) {
// subscription succeeded, subscription is an instance of autobahn.Subscription
},
function (error) {
// subscription failed, error is an instance of autobahn.Error
}
);
A list of subscriptions (in no particular order) currently active on a session
may be accessed like this:
<autobahn.Session>.subscriptions
This returns a list of autobahn.Subscription
objects. E.g.
var subs = session.subscriptions;
for (var i = 0; i < subs.length; ++i) {
console.log("Active subscription with ID " + subs[i].id);
}
Caution: This property should be considered read-only. DO NOT MODIFY.
You can unsubscribe a previously established subscription
var d = <autobahn.Subscription>.unsubscribe();
which returns a promise that resolves (with no result value) when successful, or rejects with an instance of autobahn.Error
when unsuccessful.
Example: Unsubscribing a subscription
var sub1;
session.subscribe('com.myapp.topic1', on_event1).then(
function (subscription) {
sub1 = subscription;
}
);
...
sub1.unsubscribe().then(
function () {
// successfully unsubscribed sub1
},
function (error) {
// unsubscribe failed
}
);
Complete Examples:
To publish an event on a session
:
var d = session.publish(<topic|uri>, <args|list>, <kwargs|dict>, <options|dict>);
where
topic
(required): is the URI of the topic to publish toargs
(optional): is application event payload (a list giving the positional arguments)kwargs
(optional): is application event payload (a dictionary giving the keyword arguments)options
(optional) specifies options for publication (see below).
and returns either nothing or a promise if options.acknowledge
is set.
Example: Publish an event
session.publish('com.myapp.hello', ['Hello, world!']);
Complete Examples:
By default, a publish is not acknowledged by the Broker, and the Publisher receives no feedback whether the publish was indeed successful or not.
If supported by the Broker, a Publisher may request acknowledgement of a publish via the option acknowledge|bool
.
With acknowledged publish, the publish method will return a promise that will resolve to an instance of autobahn.Publication
when the publish was successful, or reject with an autobahn.Error
when the publish was unsuccessful.
Example: Publish with acknowledge
session.publish('com.myapp.hello', ['Hello, world!'], {}, {acknowledge: true}).then(
function (publication) {
// publish was successful
},
function (error) {
// publish failed
};
);
If the feature is supported by the Broker, a Publisher may restrict the actual receivers of an event beyond those subscribed via the options
exclude|list
eligible|list
exclude
is a list of WAMP session IDs providing an explicit list of (potential) Subscribers that won't receive a published event, even though they might be subscribed. In other words, exclude
is a blacklist of (potential) Subscribers.
eligible
is a list of WAMP session IDs providing an explicit list of (potential) Subscribers that are allowed to receive a published event. In other words, eligible
is a whitelist of (potential) Subscribers.
The Broker will dispatch events published only to *Subscribers+ that are not explicitly excluded via exclude
and which are explicitly eligible via eligible
.
Example: Publish with exclude
session.publish('com.myapp.hello', ['Hello, world!'], {}, {exclude: [123, 456]});
The event will be received by all Subscribers to topic com.myapp.hello
, but not the sessions with IDs 123
and 456
(if those sessions are subscribed anyway).
Example: Publish with eligible
session.publish('com.myapp.hello', ['Hello, world!'], {}, {eligible: [123, 456]});
The event will be received by the sessions with IDs 123
and 456
, if those sessions are subscribed to topic com.myapp.hello
.
By default, a Publisher of an event will not itself receive an event published, even when subscribed to the topic the Publisher is publishing to.
If supported by the Broker, this behavior can be overridden via the option exclude_me|bool
.
Example: Publish without excluding publisher
session.publish('com.myapp.hello', ['Hello, world!'], {}, {exclude_me: false});
If the feature is supported by the Broker, a Publisher may request the disclosure of it's identity (it's WAMP session ID) to receivers of a published event via the option disclose_me|bool
.
Example: Publish with publisher disclosure
session.publish('com.myapp.hello', ['Hello, world!'], {}, {disclose_me: true});
If the Broker allows the disclosure, receivers can consume the Publisher's session ID like this:
function on_event(args, kwargs, details) {
// details.publisher provides the Publisher's WAMP session ID
// details.publication provides the event ID
}
session.subscribe(on_event, 'com.myapp.topic1');
To register a procedure on a session
for remoting:
var d = session.register(<procedure|uri>, <endpoint|callable>, <options|dict>);
where
procedure
(required): the URI of the procedure to registerendpoint
(required): the function that provides the procedure implementationoptions
(optional): specifies options for registration (see below)
and returns a promise that resolves to an instance of autobahn.Registration
when successful, or rejects with an instance of autobahn.Error
when unsuccessful.
The endpoint
must be a callable
function (args, kwargs, details) => result
where
args
are the (positional) call argumentskwargs
are the (keyword) call argumentsdetails
provides call metadata
and which returns either a plain value or a promise, and the value is serializable or an instance of autobahn.Result
.
The autobahn.Result
wrapper is used when returning a complex value (multiple positional return values and/or keyword return values).
Example: Register a procedure
function myproc1(args, kwargs, details) {
// invocation .. do something and return a plain value or a promise ..
}
session.register('com.myapp.proc1', myproc1).then(
function (registration) {
// registration succeeded, registration is an instance of autobahn.Registration
},
function (error) {
// registration failed, error is an isntance of autobahn.Error
}
);
Complete Examples:
A list of registrations (in no particular order) currently active on a session
may be accessed like this:
autobahn.Session.registrations
This returns a list of autobahn.Registration
objects.
Caution: this should be considered read-only. DO NOT MODIFY.
Write me.
To call a remote procedure from a session
:
var d = session.call(<procedure|uri>, <args|list>, <kwargs|dict>, <options|dict>);
where
topic
(required): is the URI of the procedure to callargs
(optional): are (positional) call argumentskwargs
(optional): are (keyword) call argumentsoptions
(optional) specifies options for the call (see below).
and returns a promise that will resolve to the call result if successful (either a plain value or an instance of autobahn.Result
) or reject with an instance of autobahn.Error
.
Example: Call a procedure
session.call('com.arguments.add2', [2, 3]).then(
function (result) {
// call was successful
},
function (error) {
// call failed
}
);
Complete Examples:
Write me.
Complete Examples:
Write me.
Complete Examples:
To build Autobahn|JS for use in browsers, you will need
SCons is a Python based build tool, so you will need Python as well. Taschenmesser is an SCons toolbelt also written in Python.
Set environment variables:
-
JAVA_HOME
pointing to your Java run-timeC:\Program Files\Java\jre7
-
Add Python and Python script to
PATH
C:\Python27;C:\Python27\Scripts;
-
Set
JS_COMPILER
pointing to the Google Closurecompiler.jar
C:\Program Files\Google Closure\compiler.jar
Now clone the repo:
git clone [email protected]:tavendo/AutobahnJS.git
cd autobahnjs
Then start the build:
scons
This will produce 3 files inside the build
directory:
build/autobahn.js
build/autobahn.min.js
build/autobahn.min.jgz
To clean up your build:
scons -uc
For more information, including getting started, tutorials and reference documentation, please visit the project's homepage.
Get in touch on IRC #autobahn
on chat.freenode.net
or the mailing list.
Autobahn|JS includes code from the following open-source projects
Special thanks to the Coders with an Unhealthy Javascript Obsession for creating when.js - A lightweight Promise and when() implementation, plus other async goodies.