Reference¶
Library¶
The library can be included
try {
// for Node.js
var autobahn = require('autobahn');
} catch (e) {
// for browsers (where AutobahnJS is available globally)
}
Autobahn bundles whenjs and cryptojs. These bundled libraries can be accessed like
try {
var autobahn = require('autobahn');
var when = require('when');
var crypto = require('crypto-js');
} catch (e) {
var when = autobahn.when;
var crypto = autobahn.crypto;
}
Library Version¶
Autobahn|JS library version is available (read-only):
autobahn.version()
which returns a string.
Debug Mode¶
To enable debug mode, define a global variable
AUTOBAHN_DEBUG = true;
before including Autobahn|JS. Debug mode works for use both in the browser and in Node.js. When using Autobahn|JS in a browser, you’d do e.g.
<!DOCTYPE html>
<html>
<body>
<script>
AUTOBAHN_DEBUG = true;
</script>
<script src="http://path_to_your_hosted_version_of_autobah/autobahn.min.jgz">
</script>
</body>
</html>
Connections¶
A new connection is created using
autobahn.Connection(options)
which returns an autobahn connection object.
Example: Create a new connection using WebSocket as a transport
var connection = new autobahn.Connection({
url: 'ws://127.0.0.1:9000/',
realm: 'realm1'
});
This is the brief syntax which uses the default WebSocket transport and just gives a single connection URL. You can alternatively define a list of transports to try successively - see connection-options.
Connection Methods¶
To open a connection:
autobahn.Connection.open()
This will establish an underlying transport and create a new session running over the transport. WebSocket is the default transport, but for environments which do not support WebSocket (like really old browsers) HTTP long-poll can be used as a fallback.
When the transport is lost, automatic reconnection will be attempted. This can be configured using the options provided to the constructor of the Connection (see Connection Options).
To close a connection:
autobahn.connection.close(reason, message)
where both arguments are optional.
reasonis a WAMP URI providing a closing reason e.g. ‘com.myapp.close.signout’ to the server side. If no reason is given, the default URIwamp.goodbye.normalis sent.messageis a string, to be used as a human-readable closing message
This returns a string on connection close error, else undefined.
When a connection has been closed explicitly, no automatic reconnection will happen.
Connection Callbacks¶
autobahn.Connection provides two callbacks:
autobahn.Connection.onopenautobahn.Connection.onclose
The connection open callback is fired when the connection has been established and a new session was created. This is the main callback which application code will hook into.
autobahn.Connection.onopen = function (session, details) {
// Underlying transport to WAMP router established and new WAMP session started.
// session is an instance of autobahn.Session
};
The connection open callback is passed the autobahn.Session object which has been created on opening the connection and a details object which contains further information about the session establishment such as the authentication role and ID assigned by the WAMP router.
The connection close callback is fired when the connection has been closed explicitly, was lost or could not be established in the first place.
autobahn.Connection.onclose = function (reason, details) {
// connection closed, lost or unable to connect
};
reason is a string with the possible values
"closed": The connection was closed explicitly (by the application or server). No automatic reconnection will be tried."lost": The connection had been formerly established at least once, but now was lost. Automatic reconnection will happen unless you return truthy from this callback."unreachable": The connection could not be established in the first place. No automatic reattempt will happen, since most often the cause is fatal (e.g. invalid server URL or server unreachable)"unsupported": No WebSocket transport could be created. For security reasons the WebSocket spec states that there should not be any specific errors for network-related issues, so no details are returned in this case either.
details is an object containing the reason and message passed to autobahn.Connection.close(), and thus does not apply in case of "lost" or "unreachable".
Connection Options¶
The constructor of autobahn.Connection() provides various options.
Required options:
realm: string - The WAMP realm to join, e.g.realm1a target to connect to, for which there are two options:
url: string - the WebSocket URL of the WAMP router to connect to, e.g.ws://myserver.com:8080/wsvia WebSocket, ora list of transports to try successively
Supported transports are WebSocket and HTTP long-poll.
As an example, with the options below, Autobahn|JS first attempts to establish a WebSocket connection and if this fails a HTTP long-poll connection to the respective URLs given.
var connection = new autobahn.Connection({
transports: [
{
'type': 'websocket',
'url': 'ws://127.0.0.1:9000/ws'
},
{
'type': 'longpoll',
'url': 'http://127.0.0.1:9000/lp'
}
],
realm: 'realm1'
});
Not all WAMP routers support all transports, so take a look at the documentation for your router. (The above configuration with both WebSocket and HTTP long-poll on the same port is something which Crossbar.io allows.)
note
We recommend that you use encrypted connections (using TLS). On the client side in Autobahn|JS, do this by setting the schema part of the connection URL to
wssinstead ofws.
note
When a Web page is served encrypted, then WebSocket connections from the page are also required to be encrypted. The WebSocket spec does intentionally not define any error message for this case, so Autobahn|JS returns
unsupported.
Optional options:
Options that control what kind of Deferreds to use:
use_es6_promises: boolean - use deferreds based on ES6 promisesuse_deferred: callable - if provided, use this deferred constructor, e.g.jQuery.DeferredorQ.defer, if omitted when.js is used (see their documentation for information on the full range of features)
note
Using ES6-based promises has certain restrictions. E.g. no progressive call results are supported. In general, unless there is a good technical reason, the default deferreds should be used.
Options that control automatic reconnection:
max_retries: integer - Maximum number of reconnection attempts. Unlimited if set to -1 (default: 15)initial_retry_delay: float - Initial delay for reconnection attempt in seconds (default: 1.5).max_retry_delay: float - Maximum delay for reconnection attempts in seconds (default: 300).retry_delay_growth: float - The growth factor applied to the retry delay between reconnection attempts (default: 1.5).retry_delay_jitter: float - The standard deviation of a Gaussian to jitter the delay on each retry cycle as a fraction of the mean (default: 0.1).
Options that control WebSocket subprotocol handling:
skip_subprotocol_check: Not yet implemented.skip_subprotocol_announce: Not yet implemented.
Options that control WebSocket heartbeat on NodeJS:
note
Below options only work when the transport is
websocketand the underlying platform is NodeJS/Electron.
autoping_interval: Seconds between automatic pingsautoping_timeout: Seconds until a ping is considered timed-outautoping_size: bytes of random data to send in ping messages (default: 4)
Options that define Custom error handlers:
on_user_error: function - This error handler is called in the following cases:an exception raised in
onopen,onclose,onchallengecallbacks,an exception raised in the event handler in the subscriber role,
an error occurred in the invocation handler in the callee role (the handler called in the client, before the error message is sent back to the Dealer.)
on_internal_error: function - This error handler is called in the following cases:not able to create a Wamp transport,
when a protocol violation is occurred,
when no
onchallengedefined, but a challenge request is received due to authenticate the client,
var connection = new autobahn.Connection({
on_user_error: function (error, customErrorMessage) {
// here comes your custom error handling, when a
// something went wrong in a user defined callback.
},
on_internal_error: function (error, customErrorMessage) {
// here comes your custom error handling, when a
// something went wrong in the autobahn core.
}
// ... other options
});
note
If no error handler is defined for these functions, an error level console log will be written.
note
In a case of error handling in the Callee role, when the invocation handler is executed, the error is reported on the Callee side (with the custom error handler or an error log), but despite that the error is sent back to the Dealer, and the Caller will receive a
runtime.errorwamp message.
Options that control tls connection:
tlsConfiguration: objectca: Buffer | String - CAcert: Buffer | String - Certificate Public Keykey: Buffer | String - Certificate Private Key
Options that define authentication settings
authid: string - If provided, this auth ID will be passed to the router when connecting. The router may issue a different challenge based on which auth ID is trying to connect.authextra: unknown - If provided, this data is passed to the router during the connection, which the router may use to further customize the challenge to the client.authmethods: string[] - An array of names of authentication methods supported by the client. The router SHOULD return challenge messages with methods only among those, or otherwise do what it would for unauthenticated connections (drop, continue anonymously, etc.).onchallenge: function(session: Session, method: string, extra: unknown?): string | [string, unknown] | Promise<string | [string, unknown] - A handler for challenge messages from the router. Return value should be a response to the challenge message. Either a string (“signature”), or an array with the response as the first value, and “extra” data that the router may need to verify that response as a second value. A promise resolving to those types may also be returned. If the function throws or the returned promise rejects, the connection will be aborted. The function is given the following arguments:session: Session - The session being challenged.method: string - Name of the authentication method the router is expecting a response to.extra: unknown? - Extra data that the router may provide the client in order to complete the challenge successfully.
Example:
var secret = 'top-secret-do-not-show-in-browser';
var connection = new autobahn.Connection({
authid: 'my-user',
authmethods: ['ticket', 'wampcra'],
onchallenge: function (session, method, extra) {
switch (method) {
case 'ticket':
// This authentication method requires the client to provide a value that the router can verify,
// even if it doesn't know the exact expected value in advance.
// We'll use JWT as our value.
/*
// For NodeJS, if the client can be trusted with the JWT signing key anyway,
// the token may be created at the client.
// See https://github.com/panva/jose for the JWT lib used below
return new jose.SignJWT({})
.setProtectedHeader({ alg: 'ES256' })
.setIssuedAt()
.setIssuer('urn:example:issuer')
.setAudience('urn:example:audience')
.setExpirationTime('2h')
.sign(secret);
*/
// For browser facing javascript, and untrusted NodeJS clients,
// the JWT should be generated on the server,
// and the result should be passed to the client.
// The browser should not be trusted with the JWT signing key, only the JWT itself. e.g.
return fetch('/my-jwt-generator').then(function (response) {
return response.text();
});
case 'wampcra':
// This authentication method is included in autobahn, and is supported by the crossbar router.
// It requires a secret known by both router and client,
// which makes it unsuitable for browser facing javascript.
// Use it only when running in NodeJS or at least ensure the "secret" is short lived
// and only shared with pre-authenticated users.
return autobahn.auth_cra.sign(secret, extra.challenge);
default:
throw new Error('Unknown auth method');
}
}
// ... other options
});
Connection Properties¶
To get the session object if there is a session currently running over the connection:
Connection.session
which returns an instance of autobahn.Session if there is a session currently running on the connection.
To check whether the connection (the underlying transport for the session) has been established:
Connection.isConnected
which returns true if the Connection is open.
A read-only property that signals if the underlying session is open and attached to a realm:
Connection.isOpen
which returns true if the underlying session is open.
To check whether the connection is currently in a “try to reconnect” cycle:
Connection.isRetrying
which returns true if reconnects are being attempted.
A property which holds a transport instance when connected
Connection.transport
which holds a transport instance when connected.
Connection.transport.info.type
which returns websocket, rawsocket or longpoll
Connection.transport.info.url
which returns the URL the transport is connected to
Connection.transport.info.protocol
the WAMP protocol in use, e.g. wamp.2.json
A property with the Deferred factory in use on this connection:
Connection.Deferred
returns the Deferred factory function used by the connection.
A Deferred factory for the type of Deferreds (whenjs, ES6, jQuery or Q) in use with the connection:
Connection.defer()
which returns a Deffered of the type specified in the call to the connection constructor.
Sessions¶
WAMP sessions are instances of autobahn.Session that are created by connections:
var connection = new autobahn.Connection({
url: 'ws://127.0.0.1:9000/',
realm: 'realm1'
});
connection.onopen = function (session) {
// session is an instance of autobahn.Session
};
connection.open();
Session Properties¶
Session objects provide a number of properties.
A read-only property with the WAMP session ID as an integer:
Session.id
A read-only property with the realm (as a string) the session is attached to:
Session.realm
A read-only property that signals if the session is open (as a boolean) and attached to a realm:
Session.isOpen
A read-only property with the features (as an object) from the WAMP Advanced Profile available on this session (supported by both peers):
Session.features
A read-only property with an array of all currently active subscriptions on this session:
Session.subscriptions
A read-only property with an array of all currently active registrations on this session:
Session.registrations
A property with the Deferred factory in use on this session:
Session.defer
A Deferred factory for the type of Deferreds (whenjs, ES6, jQuery or Q) in use with the session:
Session.defer()
Session Logging¶
Autobahn|JS includes a logging method for convenient logging from sessions.
Session.log(output)
This can be assigned as an event handler when no output argument is used.
session.log can be used without an output argument when it is assigned as an event handler.
For example:
connection.onopen = function (session) {
session.log("Session open.");
session.call('com.timeservice.now').then(
session.log;
);
};
which will log to the console:
WAMP session 2838853860563188 on 'realm1' at 3.902 ms
Session open.
WAMP session 2838853860563188 on 'realm1' at 4.679 ms
2014-03-13T14:09:07Z
where 2014-03-13T14:09:07Z is the return value of the call to com.timeservice.now.
The log method will log the WAMP session ID and the realm of the session, as well as a timestamp that provides the time elapsed since the construction of the autobahn.Session object.
URI Shortcuts¶
Establish an URI prefix to be used as a shortcut in WAMP interactions on session:
Session.prefix(shortcut, prefix)
where
shortcutis a stringprefixis an URI part
note
URI prefixes must only contain full URI components, i.e. stop at a ‘.’ separation of an URI. ‘com.myapp.topics’ is a valid prefix if it is to be used as part of full URI ‘com.myapp.topics.one’, but invalid if it is intended to be combined with a suffix to form ‘com.myapp.topicsnew’.
Example:
session.prefix('api', 'com.myapp.service');
You can then use CURIEs in addition to URIs:
session.call('api:add2').then(...);
which is equivalent to
session.call('com.myapp.service.add2').then(...);
To remove a prefix:
session.prefix('api', null);
To resolve a prefix (normally not needed in user code):
session.resolve('api:add2');
Session Meta-Events & Procedures¶
Some WAMP routers (such as Crossbar.io) provide the possibility to subscribe to events which are created by the router based on session lifecycle, as well as procedures which allow the retrieval of information about current sessions. For more information see the Crossbar.io documentation.
Subscribe¶
To subscribe to a topic on a session:
Session.subscribe(topic, handler, options)
where
topicis the URI of the topic to subscribe tohandleris the event handler which should consume eventsoptions- options object (see below)
The handler must be a callable
function (args, kwargs, details)
where
argsis an array with event payloadkwargsis an object with event payloaddetailsis an object which 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
}
);
or, differently notated, but functionally equivalent
var d = session.subscribe('com.myapp.topic1', on_event1);
d.then(
function (subscription) {
// subscription succeeded, subscription is an instance of autobahn.Subscription
},
function (error) {
// subscription failed, error is an instance of autobahn.Error
}
);
Complete Examples:
Pattern-Based Subscriptions¶
As a default, topic URIs in subscriptions are matched exactly.
It is possible to change the matching policy to either prefix or wildcard matching via an option when subscribing, e.g.
session.subscribe('com.myapp', on_event_all, { match: 'prefix' })
session.subscribe('com.myapp..update', on_event_update, { match: 'wildcard' })
In the first case, events for all publications where the topic contains the prefix com.myapp will be received, in the second events for all publications which match the wildcard pattern, e.g. com.myapp.user121.update and com.myapp.sensor_23.update.
Active Subscriptions¶
A list of subscriptions (in no particular order) currently active on a session may be accessed via :jsSession.subscriptions.
This returns an array 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);
}
note
Caution: This property and the subscription objects returned should be considered read-only. DO NOT MODIFY.
Unsubscribing¶
You can unsubscribe a previously established subscription
Session.unsubscribe(subscription)
where subscription is an instance of autobahn.Subscription and which returns a promise that resolves to a boolean when successful or rejects with an instance of autobahn.Error when unsuccessful.
note
If successful, the boolean returned indicates whether the underlying WAMP subscription was actually ended (
true) or not, since there still are application handlers in place due to multiple client-side subscriptions for the same WAMP subscription to the broker.
Example: Unsubscribing a subscription
var sub1;
session.subscribe('com.myapp.topic1', on_event1).then(
function (subscription) {
sub1 = subscription;
}
);
...
session.unsubscribe(sub1).then(
function (gone) {
// successfully unsubscribed sub1
},
function (error) {
// unsubscribe failed
}
);
Complete Examples:
Subscription Meta-Events and Procedures¶
Some WAMP routers (such as Crossbar.io) provide the possibility to subscribe to events which are created by the router based on subscription lifecycle, as well as procedures which allow the retrieval of information about current subscriptions. For more information see the Crossbar.io documentation.
Publish¶
To publish an event on a session:
Session.publish(topic, args, kwargs, options)
where
topicis the URI of the topic to publish toargsis an optional array as application event payloadkwargsis an optional object as application event payloadoptionsis an optional object which specifies options for publication (see below)
and which returns a promise if options.acknowledge is set, else nothing.
Examples: Publish an event
session.publish('com.myapp.hello', ['Hello, world!']);
session.publish('com.myapp.hello', [], { text: 'Hello, world' })
Complete Examples:
Acknowledgement¶
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 set to true.
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
};
);
Receiver Black-/Whitelisting¶
If the feature is supported by the Broker, a Publisher may restrict the actual receivers of an event beyond those subscribed via the options
excludeeligible
exclude is an array 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 an array 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.
Publisher Exclusion¶
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 set to false.
Example: Publish without excluding publisher
session.publish('com.myapp.hello', ['Hello, world!'], {}, {exclude_me: false});
Register¶
To register a procedure on a session for remoting:
Session.register(procedure, endpoint, options)
where
procedure is the URI of the procedure to register
endpoint is the function that provides the procedure implementation
options is an optional object which specifies options for registration (see below)
and which 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)
where
argsis an array with call argumentskwargsis an object with call argumentsdetailsis an object which 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 instance of autobahn.Error
}
);
When the procedure which you are registering works asynchronous, you can return a promise which is resolved when the asynchronous part has completed:
function myAsyncFunction(args, kwargs, details) {
var d = new autobahn.when.defer();
setTimeout(function() {
d.resolve("async finished");
}, 1000);
return d.promise;
}
The above example uses the default promises library for AutobahnJS, when. The syntax may vary for other libraries.
Complete Examples:
Pattern-Based Registrations¶
As a default, URIs in registrations are matched exactly.
It is possible to change the matching policy to either prefix or wildcard matching via an option when registering, e.g.
session.register('com.myapp', handle_all, { match: 'prefix' })
or
session.register('com.myapp..update', handle_updates, { match: 'wildcard' })
In the first case, calls for where the URI contains the prefix com.myapp will lead to the callee being invoked, while in the second calls where the URI matches the wildcard pattern will lead to the callee being invoked, e.g. com.myapp.user121.update and com.myapp.sensor_23.update.
Active Registrations¶
A list of registrations (in no particular order) currently active on a session may be accessed like via Session.registrations.
This returns an array of autobahn.Registration objects. E.g.
var regs = session.registrations;
for (var i = 0; i < regs.length; ++i) {
console.log("Active registration with ID " + regs[i].id);
}
note
Caution: This property and the registration objects returned should be considered read-only. DO NOT MODIFY.
Unregistering¶
You can unregister a previously established registration
Session.unregister(registration)
where registration is an instance of autobahn.Registration and which returns a promise that resolves with no value when successful or rejects with an instance of autobahn.Error when unsuccessful.
Example: Unregistering a registration
var reg1;
session.register('com.myapp.proc1', myproc1).then(
function (registration) {
reg1 = registration;
}
);
...
session.unregister(reg1).then(
function () {
// successfully unregistered reg1
},
function (error) {
// unregister failed
}
);
Registration Meta-Events and Procedures¶
Some WAMP routers (such as Crossbar.io) provide the possibility to subscribe to events which are created by the router based on registration lifecycle, as well as procedures which allow the retrieval of information about current registrations. For more information see the Crossbar.io documenation.
Call¶
To call a remote procedure from a session:
Session.call(procedure, args, kwargs, options)
where
procedureis the URI of the procedure to callargsis an optional optional array of call argumentskwargsis an optional object of call argumentsoptionsis an optional object with options for the call (see below)
and which 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:
Errors¶
On an error with a PRC call, a error object is passed to the error handler defined in the call. This has three properties:
error URI
an array of error arguments
an object with error arguments
Throwing an error in a registered procedure can happen in one of two ways:
by defining an array of error arguments
by creating a
autobahn.Errorobject
In the first case, the error URI is set to a default value, and the object of error arguments remains emtpy, i.e. if you do
throw ['this is just an error', 'with an array of arguments'];
logging this in the caller will come out something like
wamp.error.runtime_error ["this is just an error", "with an array of arguments"] Object {}
When defining an autobahn.Error object, all three properties can be defined. I.e. doing
throw new autobahn.Error('com.myapp.error', ['this is a more complex error'], {a: 23, b: 9});
and logging this in the caller will lead to something like
com.myapp.error ['this is a more complex error'] Object {a: 23, b: 9}
Complete Examples:
Progressive Results¶
Instead of returning just a single, final result, a remote procedure can return progressive results, if this is requested by the caller.
Progressive results are part of the advanced spec for WAMP, and may not be supported by all WAMP routers.
An example for a call requesting progressive call results would be
session.call('com.myapp.longop', [10], {}, {receive_progress: true}).then(
function (res) {
console.log("Final:", res);
connection.close();
},
function (err) {
},
function (progress) {
console.log(progress);
}
);
Here a third callback has been added, which is fired on each receipt of a progressive result event.
In the backend, the function for returning progressive results could be something like
if (details.progress) {
for (var i = 0; i < 5; i++) {
details.progress(i);
}
return "progressive result"
} else {
return "single result";
}
which would return 5 progressive result events (each with the current value of i as the payload) before returning "progressive result" as the final result.
Complete Examples:
Caller Identification¶
If the feature is supported by the Dealer, a Caller may request the disclosure of its identity (its WAMP session ID) to the invoked Callee via the option disclose_me set to true.
Example: Call with caller disclosure
session.call('com.myapp.procedure1', ['Hello, world!'], {}, {disclose_me: true});
If the Dealer allows the disclosure, the callee can consume the Caller’s session ID like this:
function on_call(args, kwargs, details) {
// details.caller provides the Publisher's WAMP session ID
}
session.register(on_call, 'com.myapp.procedure1');