Skip to content

Instantly share code, notes, and snippets.

@stevro
Forked from Maclay74/autobanh.js
Created February 17, 2023 21:44
Show Gist options
  • Save stevro/59e8863e9e9a1b87369beeab09c2fb61 to your computer and use it in GitHub Desktop.
Save stevro/59e8863e9e9a1b87369beeab09c2fb61 to your computer and use it in GitHub Desktop.
autobanh
import * as when from 'when';
/** @license MIT License (c) 2011-2013 Copyright Tavendo GmbH. */
/**
* AutobahnJS - http://autobahn.ws
*
* A lightweight implementation of
*
* WAMP (The WebSocket Application Messaging Protocol) - http://wamp.ws
*
* Provides asynchronous RPC/PubSub over WebSocket.
*
* Copyright (C) 2011-2014 Tavendo GmbH. Licensed under the MIT License.
* See license text at http://www.opensource.org/licenses/mit-license.php
*/
/* global console: false, MozWebSocket: false, when: false, CryptoJS: false */
/**
* @define {string}
*/
var AUTOBAHNJS_VERSION = '?.?.?';
var global = this;
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['when'], function (when) {
// Also create a global in case some scripts
// that are loaded still are looking for
// a global even when an AMD loader is in use.
return (root.ab = factory(root, when));
});
} else if (typeof exports !== 'undefined') {
// Support Node.js specific `module.exports` (which can be a function)
if (typeof module != 'undefined' && module.exports) {
exports = module.exports = factory(root, root.when);
}
// But always support CommonJS module 1.1.1 spec (`exports` cannot be a function)
//exports.ab = exports;
} else {
// Browser globals
root.ab = factory(root, root.when);
}
})(global, function (root, when) {
'use strict';
var ab = {};
ab._version = AUTOBAHNJS_VERSION;
// Helper to slice out browser / version from userAgent
ab._sliceUserAgent = function (str, delim, delim2) {
var ver = [];
var ua = navigator.userAgent;
var i = ua.indexOf(str);
var j = ua.indexOf(delim, i);
if (j < 0) {
j = ua.length;
}
var agent = ua.slice(i, j).split(delim2);
var v = agent[1].split('.');
for (var k = 0; k < v.length; ++k) {
ver.push(parseInt(v[k], 10));
}
return {name: agent[0], version: ver};
};
/**
* Detect browser and browser version.
*/
ab.getBrowser = function () {
var ua = navigator.userAgent;
if (ua.indexOf('Chrome') > -1) {
return ab._sliceUserAgent('Chrome', ' ', '/');
} else if (ua.indexOf('Safari') > -1) {
return ab._sliceUserAgent('Safari', ' ', '/');
} else if (ua.indexOf('Firefox') > -1) {
return ab._sliceUserAgent('Firefox', ' ', '/');
} else if (ua.indexOf('MSIE') > -1) {
return ab._sliceUserAgent('MSIE', ';', ' ');
} else {
return null;
}
};
ab.getServerUrl = function (wsPath, fallbackUrl) {
if (root.location.protocol === 'file:') {
if (fallbackUrl) {
return fallbackUrl;
} else {
return 'ws://127.0.0.1/ws';
}
} else {
var scheme = root.location.protocol === 'https:' ? 'wss://' : 'ws://';
var port = root.location.port !== '' ? ':' + root.location.port : '';
var path = wsPath ? wsPath : 'ws';
return scheme + root.location.hostname + port + '/' + path;
}
};
// Logging message for unsupported browser.
ab.browserNotSupportedMessage = 'Browser does not support WebSockets (RFC6455)';
// PBKDF2-base key derivation function for salted WAMP-CRA
ab.deriveKey = function (secret, extra) {
if (extra && extra.salt) {
var salt = extra.salt;
var keylen = extra.keylen || 32;
var iterations = extra.iterations || 10000;
var key = CryptoJS.PBKDF2(secret, salt, {
keySize: keylen / 4,
iterations: iterations,
hasher: CryptoJS.algo.SHA256,
});
return key.toString(CryptoJS.enc.Base64);
} else {
return secret;
}
};
ab._idchars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
ab._idlen = 16;
ab._subprotocol = 'wamp';
ab._newid = function () {
var id = '';
for (var i = 0; i < ab._idlen; i += 1) {
id += ab._idchars.charAt(Math.floor(Math.random() * ab._idchars.length));
}
return id;
};
ab._newidFast = function () {
return Math.random().toString(36);
};
ab.log = function () {
//console.log.apply(console, !!arguments.length ? arguments : [this]);
if (arguments.length > 1) {
console.group('Log Item');
for (var i = 0; i < arguments.length; i += 1) {
console.log(arguments[i]);
}
console.groupEnd();
} else {
console.log(arguments[0]);
}
};
ab._debugrpc = false;
ab._debugpubsub = false;
ab._debugws = false;
ab._debugconnect = false;
ab.debug = function (debugWamp, debugWs, debugConnect) {
if ('console' in root) {
ab._debugrpc = debugWamp;
ab._debugpubsub = debugWamp;
ab._debugws = debugWs;
ab._debugconnect = debugConnect;
} else {
throw 'browser does not support console object';
}
};
ab.version = function () {
return ab._version;
};
ab.PrefixMap = function () {
var self = this;
self._index = {};
self._rindex = {};
};
ab.PrefixMap.prototype.get = function (prefix) {
var self = this;
return self._index[prefix];
};
ab.PrefixMap.prototype.set = function (prefix, uri) {
var self = this;
self._index[prefix] = uri;
self._rindex[uri] = prefix;
};
ab.PrefixMap.prototype.setDefault = function (uri) {
var self = this;
self._index[''] = uri;
self._rindex[uri] = '';
};
ab.PrefixMap.prototype.remove = function (prefix) {
var self = this;
var uri = self._index[prefix];
if (uri) {
delete self._index[prefix];
delete self._rindex[uri];
}
};
ab.PrefixMap.prototype.resolve = function (curie, pass) {
var self = this;
// skip if not a CURIE
var i = curie.indexOf(':');
if (i >= 0) {
var prefix = curie.substring(0, i);
if (self._index[prefix]) {
return self._index[prefix] + curie.substring(i + 1);
}
}
// either pass-through or null
if (pass === true) {
return curie;
} else {
return null;
}
};
ab.PrefixMap.prototype.shrink = function (uri, pass) {
var self = this;
for (var i = uri.length; i > 0; i -= 1) {
var u = uri.substring(0, i);
var p = self._rindex[u];
if (p) {
return p + ':' + uri.substring(i);
}
}
// either pass-through or null
if (pass === true) {
return uri;
} else {
return null;
}
};
ab._MESSAGE_TYPEID_WELCOME = 0;
ab._MESSAGE_TYPEID_PREFIX = 1;
ab._MESSAGE_TYPEID_CALL = 2;
ab._MESSAGE_TYPEID_CALL_RESULT = 3;
ab._MESSAGE_TYPEID_CALL_ERROR = 4;
ab._MESSAGE_TYPEID_SUBSCRIBE = 5;
ab._MESSAGE_TYPEID_UNSUBSCRIBE = 6;
ab._MESSAGE_TYPEID_PUBLISH = 7;
ab._MESSAGE_TYPEID_EVENT = 8;
ab.CONNECTION_CLOSED = 0;
ab.CONNECTION_LOST = 1;
ab.CONNECTION_RETRIES_EXCEEDED = 2;
ab.CONNECTION_UNREACHABLE = 3;
ab.CONNECTION_UNSUPPORTED = 4;
ab.CONNECTION_UNREACHABLE_SCHEDULED_RECONNECT = 5;
ab.CONNECTION_LOST_SCHEDULED_RECONNECT = 6;
//ab.Deferred = when.defer;
//ab.Deferred = jQuery.Deferred;
ab.Deferred = () => {
const deferred = {};
const promise = new Promise(function (resolve, reject) {
deferred.resolve = resolve;
deferred.reject = reject;
});
deferred.promise = promise;
return deferred;
};
ab._construct = function (url, protocols, token) {
return new WebSocket(url, protocols, {headers: {Authorization: token}});
};
ab.Session = function (wsuri, onopen, onclose, options) {
var self = this;
self._wsuri = wsuri;
self._options = options;
self._websocket_onopen = onopen;
self._websocket_onclose = onclose;
self._websocket = null;
self._websocket_connected = false;
self._session_id = null;
self._wamp_version = null;
self._server = null;
self._calls = {};
self._subscriptions = {};
self._prefixes = new ab.PrefixMap();
self._txcnt = 0;
self._rxcnt = 0;
if (self._options && self._options.skipSubprotocolAnnounce) {
self._websocket = ab._construct(self._wsuri, null, options.token);
} else {
self._websocket = ab._construct(self._wsuri, [ab._subprotocol], options.token);
}
if (!self._websocket) {
if (onclose !== undefined) {
onclose(ab.CONNECTION_UNSUPPORTED);
return;
} else {
throw ab.browserNotSupportedMessage;
}
}
self._websocket.onmessage = function (e) {
if (ab._debugws) {
self._rxcnt += 1;
console.group('WS Receive');
console.info(self._wsuri + ' [' + self._session_id + ']');
console.log(self._rxcnt);
console.log(e.data);
console.groupEnd();
}
var o = JSON.parse(e.data);
if (o[1] in self._calls) {
if (o[0] === ab._MESSAGE_TYPEID_CALL_RESULT) {
var dr = self._calls[o[1]];
var r = o[2];
if (ab._debugrpc && dr._ab_callobj !== undefined) {
console.group('WAMP Call', dr._ab_callobj[2]);
console.timeEnd(dr._ab_tid);
console.group('Arguments');
for (var i = 3; i < dr._ab_callobj.length; i += 1) {
var arg = dr._ab_callobj[i];
if (arg !== undefined) {
console.log(arg);
} else {
break;
}
}
console.groupEnd();
console.group('Result');
console.log(r);
console.groupEnd();
console.groupEnd();
}
dr.resolve(r);
} else if (o[0] === ab._MESSAGE_TYPEID_CALL_ERROR) {
var de = self._calls[o[1]];
var uri_ = o[2];
var desc_ = o[3];
var detail_ = o[4];
if (ab._debugrpc && de._ab_callobj !== undefined) {
console.group('WAMP Call', de._ab_callobj[2]);
console.timeEnd(de._ab_tid);
console.group('Arguments');
for (var j = 3; j < de._ab_callobj.length; j += 1) {
var arg2 = de._ab_callobj[j];
if (arg2 !== undefined) {
console.log(arg2);
} else {
break;
}
}
console.groupEnd();
console.group('Error');
console.log(uri_);
console.log(desc_);
if (detail_ !== undefined) {
console.log(detail_);
}
console.groupEnd();
console.groupEnd();
}
if (detail_ !== undefined) {
de.reject({uri: uri_, desc: desc_, detail: detail_});
} else {
de.reject({uri: uri_, desc: desc_});
}
}
delete self._calls[o[1]];
} else if (o[0] === ab._MESSAGE_TYPEID_EVENT) {
var subid = self._prefixes.resolve(o[1], true);
if (subid in self._subscriptions) {
var uri2 = o[1];
var val = o[2];
if (ab._debugpubsub) {
console.group('WAMP Event');
console.info(self._wsuri + ' [' + self._session_id + ']');
console.log(uri2);
console.log(val);
console.groupEnd();
}
self._subscriptions[subid].forEach(function (callback) {
callback(uri2, val);
});
} else {
// ignore unsolicited event!
}
} else if (o[0] === ab._MESSAGE_TYPEID_WELCOME) {
if (self._session_id === null) {
self._session_id = o[1];
self._wamp_version = o[2];
self._server = o[3];
if (ab._debugrpc || ab._debugpubsub) {
console.group('WAMP Welcome');
console.info(self._wsuri + ' [' + self._session_id + ']');
console.log(self._wamp_version);
console.log(self._server);
console.groupEnd();
}
// only now that we have received the initial server-to-client
// welcome message, fire application onopen() hook
if (self._websocket_onopen !== null) {
self._websocket_onopen();
}
} else {
throw 'protocol error (welcome message received more than once)';
}
}
};
self._websocket.onopen = function (e) {
// check if we can speak WAMP!
if (self._websocket.protocol !== ab._subprotocol) {
if (typeof self._websocket.protocol === 'undefined') {
// i.e. Safari does subprotocol negotiation (broken), but then
// does NOT set the protocol attribute of the websocket object (broken)
//
if (ab._debugws) {
console.group('WS Warning');
console.info(self._wsuri);
console.log('WebSocket object has no protocol attribute: WAMP subprotocol check skipped!');
console.groupEnd();
}
} else if (self._options && self._options.skipSubprotocolCheck) {
// WAMP subprotocol check disabled by session option
//
if (ab._debugws) {
console.group('WS Warning');
console.info(self._wsuri);
console.log('Server does not speak WAMP, but subprotocol check disabled by option!');
console.log(self._websocket.protocol);
console.groupEnd();
}
} else {
// we only speak WAMP .. if the server denied us this, we bail out.
//
self._websocket.close(1000, 'server does not speak WAMP');
throw "server does not speak WAMP (but '" + self._websocket.protocol + "' !)";
}
}
if (ab._debugws) {
console.group('WAMP Connect');
console.info(self._wsuri);
console.log(self._websocket.protocol);
console.groupEnd();
}
self._websocket_connected = true;
};
self._websocket.onerror = function (e) {
// FF fires this upon unclean closes
// Chrome does not fire this
};
self._websocket.onclose = function (e) {
if (ab._debugws) {
if (self._websocket_connected) {
console.log(
'Autobahn connection to ' +
self._wsuri +
' lost (code ' +
e.code +
", reason '" +
e.reason +
"', wasClean " +
e.wasClean +
').',
);
} else {
console.log(
'Autobahn could not connect to ' +
self._wsuri +
' (code ' +
e.code +
", reason '" +
e.reason +
"', wasClean " +
e.wasClean +
').',
);
}
}
// fire app callback
if (self._websocket_onclose !== undefined) {
if (self._websocket_connected) {
if (e.wasClean) {
// connection was closed cleanly (closing HS was performed)
self._websocket_onclose(ab.CONNECTION_CLOSED, 'WS-' + e.code + ': ' + e.reason);
} else {
// connection was closed uncleanly (lost without closing HS)
self._websocket_onclose(ab.CONNECTION_LOST);
}
} else {
// connection could not be established in the first place
self._websocket_onclose(ab.CONNECTION_UNREACHABLE);
}
}
// cleanup - reconnect requires a new session object!
self._websocket_connected = false;
self._wsuri = null;
self._websocket_onopen = null;
self._websocket_onclose = null;
self._websocket = null;
};
self.log = function () {
if (self._options && 'sessionIdent' in self._options) {
console.group("WAMP Session '" + self._options.sessionIdent + "' [" + self._session_id + ']');
} else {
console.group('WAMP Session ' + '[' + self._session_id + ']');
}
for (var i = 0; i < arguments.length; ++i) {
console.log(arguments[i]);
}
console.groupEnd();
};
};
ab.Session.prototype._send = function (msg) {
var self = this;
if (!self._websocket_connected) {
throw 'Autobahn not connected';
}
var rmsg;
switch (true) {
// In the event that prototype library is in existance run the toJSON method prototype provides
// else run the standard JSON.stringify
// this is a very clever problem that causes json to be double-quote-encoded.
case root.Prototype && typeof top.root.__prototype_deleted === 'undefined':
case typeof msg.toJSON === 'function':
rmsg = msg.toJSON();
break;
// we could do instead
// msg.toJSON = function(){return msg};
// rmsg = JSON.stringify(msg);
default:
rmsg = JSON.stringify(msg);
}
self._websocket.send(rmsg);
self._txcnt += 1;
if (ab._debugws) {
console.group('WS Send');
console.info(self._wsuri + ' [' + self._session_id + ']');
console.log(self._txcnt);
console.log(rmsg);
console.groupEnd();
}
};
ab.Session.prototype.close = function () {
var self = this;
if (self._websocket_connected) {
self._websocket.close();
} else {
//throw "Autobahn not connected";
}
};
ab.Session.prototype.sessionid = function () {
var self = this;
return self._session_id;
};
ab.Session.prototype.wsuri = function () {
var self = this;
return self._wsuri;
};
ab.Session.prototype.shrink = function (uri, pass) {
var self = this;
if (pass === undefined) pass = true;
return self._prefixes.shrink(uri, pass);
};
ab.Session.prototype.resolve = function (curie, pass) {
var self = this;
if (pass === undefined) pass = true;
return self._prefixes.resolve(curie, pass);
};
ab.Session.prototype.prefix = function (prefix, uri) {
var self = this;
/*
if (self._prefixes.get(prefix) !== undefined) {
throw "prefix '" + prefix + "' already defined";
}
*/
self._prefixes.set(prefix, uri);
if (ab._debugrpc || ab._debugpubsub) {
console.group('WAMP Prefix');
console.info(self._wsuri + ' [' + self._session_id + ']');
console.log(prefix);
console.log(uri);
console.groupEnd();
}
var msg = [ab._MESSAGE_TYPEID_PREFIX, prefix, uri];
self._send(msg);
};
ab.Session.prototype.call = function () {
var self = this;
var d = new ab.Deferred();
var callid;
while (true) {
callid = ab._newidFast();
if (!(callid in self._calls)) {
break;
}
}
self._calls[callid] = d;
var procuri = self._prefixes.shrink(arguments[0], true);
var obj = [ab._MESSAGE_TYPEID_CALL, callid, procuri];
for (var i = 1; i < arguments.length; i += 1) {
obj.push(arguments[i]);
}
self._send(obj);
if (ab._debugrpc) {
d._ab_callobj = obj;
d._ab_tid = self._wsuri + ' [' + self._session_id + '][' + callid + ']';
console.time(d._ab_tid);
console.info();
}
if (d.promise.then) {
// whenjs has the actual user promise in an attribute
return d.promise;
} else {
return d;
}
};
ab.Session.prototype.subscribe = function (topicuri, callback) {
var self = this;
// subscribe by sending WAMP message when topic not already subscribed
//
var rtopicuri = self._prefixes.resolve(topicuri, true);
if (!(rtopicuri in self._subscriptions)) {
if (ab._debugpubsub) {
console.group('WAMP Subscribe');
console.info(self._wsuri + ' [' + self._session_id + ']');
console.log(topicuri);
console.log(callback);
console.groupEnd();
}
var msg = [ab._MESSAGE_TYPEID_SUBSCRIBE, topicuri];
self._send(msg);
self._subscriptions[rtopicuri] = [];
}
// add callback to event listeners list if not already in list
//
var i = self._subscriptions[rtopicuri].indexOf(callback);
if (i === -1) {
self._subscriptions[rtopicuri].push(callback);
} else {
throw 'callback ' + callback + ' already subscribed for topic ' + rtopicuri;
}
};
ab.Session.prototype.unsubscribe = function (topicuri, callback) {
var self = this;
var rtopicuri = self._prefixes.resolve(topicuri, true);
if (!(rtopicuri in self._subscriptions)) {
throw 'not subscribed to topic ' + rtopicuri;
} else {
var removed;
if (callback !== undefined) {
var idx = self._subscriptions[rtopicuri].indexOf(callback);
if (idx !== -1) {
removed = callback;
self._subscriptions[rtopicuri].splice(idx, 1);
} else {
throw 'no callback ' + callback + ' subscribed on topic ' + rtopicuri;
}
} else {
removed = self._subscriptions[rtopicuri].slice();
self._subscriptions[rtopicuri] = [];
}
if (self._subscriptions[rtopicuri].length === 0) {
delete self._subscriptions[rtopicuri];
if (ab._debugpubsub) {
console.group('WAMP Unsubscribe');
console.info(self._wsuri + ' [' + self._session_id + ']');
console.log(topicuri);
console.log(removed);
console.groupEnd();
}
var msg = [ab._MESSAGE_TYPEID_UNSUBSCRIBE, topicuri];
self._send(msg);
}
}
};
ab.Session.prototype.publish = function () {
var self = this;
var topicuri = arguments[0];
var event = arguments[1];
var excludeMe = null;
var exclude = null;
var eligible = null;
var msg = null;
if (arguments.length > 3) {
if (!(arguments[2] instanceof Array)) {
throw 'invalid argument type(s)';
}
if (!(arguments[3] instanceof Array)) {
throw 'invalid argument type(s)';
}
exclude = arguments[2];
eligible = arguments[3];
msg = [ab._MESSAGE_TYPEID_PUBLISH, topicuri, event, exclude, eligible];
} else if (arguments.length > 2) {
if (typeof arguments[2] === 'boolean') {
excludeMe = arguments[2];
msg = [ab._MESSAGE_TYPEID_PUBLISH, topicuri, event, excludeMe];
} else if (arguments[2] instanceof Array) {
exclude = arguments[2];
msg = [ab._MESSAGE_TYPEID_PUBLISH, topicuri, event, exclude];
} else {
throw 'invalid argument type(s)';
}
} else {
msg = [ab._MESSAGE_TYPEID_PUBLISH, topicuri, event];
}
if (ab._debugpubsub) {
console.group('WAMP Publish');
console.info(self._wsuri + ' [' + self._session_id + ']');
console.log(topicuri);
console.log(event);
if (excludeMe !== null) {
console.log(excludeMe);
} else {
if (exclude !== null) {
console.log(exclude);
if (eligible !== null) {
console.log(eligible);
}
}
}
console.groupEnd();
}
self._send(msg);
};
// allow both 2-party and 3-party authentication/authorization
// for 3-party: let C sign, but let both the B and C party authorize
ab.Session.prototype.authreq = function (appkey, extra) {
return this.call('http://api.wamp.ws/procedure#authreq', appkey, extra);
};
ab.Session.prototype.authsign = function (challenge, secret) {
if (!secret) {
secret = '';
}
return CryptoJS.HmacSHA256(challenge, secret).toString(CryptoJS.enc.Base64);
};
ab.Session.prototype.auth = function (signature) {
return this.call('http://api.wamp.ws/procedure#auth', signature);
};
ab._connect = function (peer) {
// establish session to WAMP server
var sess = new ab.Session(
peer.wsuri,
// fired when session has been opened
function () {
peer.connects += 1;
peer.retryCount = 0;
// we are connected .. do awesome stuff!
peer.onConnect(sess);
},
// fired when session has been closed
function (code, reason) {
var stop = null;
switch (code) {
case ab.CONNECTION_CLOSED:
// the session was closed by the app
peer.onHangup(code, 'Connection was closed properly [' + reason + ']');
break;
case ab.CONNECTION_UNSUPPORTED:
// fatal: we miss our WebSocket object!
peer.onHangup(code, 'Browser does not support WebSocket.');
break;
case ab.CONNECTION_UNREACHABLE:
peer.retryCount += 1;
if (peer.connects === 0) {
// the connection could not be established in the first place
// which likely means invalid server WS URI or such things
peer.onHangup(code, 'Connection could not be established.');
} else {
// the connection was established at least once successfully,
// but now lost .. sane thing is to try automatic reconnects
if (peer.retryCount <= peer.options.maxRetries) {
// notify the app of scheduled reconnect
stop = peer.onHangup(
ab.CONNECTION_UNREACHABLE_SCHEDULED_RECONNECT,
'Connection unreachable - scheduled reconnect to occur in ' +
peer.options.retryDelay / 1000 +
' second(s) - attempt ' +
peer.retryCount +
' of ' +
peer.options.maxRetries +
'.',
{
delay: peer.options.retryDelay,
retries: peer.retryCount,
maxretries: peer.options.maxRetries,
},
);
if (!stop) {
if (ab._debugconnect) {
console.log('Connection unreachable - retrying (' + peer.retryCount + ') ..');
}
root.setTimeout(function () {
ab._connect(peer);
}, peer.options.retryDelay);
} else {
if (ab._debugconnect) {
console.log('Connection unreachable - retrying stopped by app');
}
peer.onHangup(ab.CONNECTION_RETRIES_EXCEEDED, 'Number of connection retries exceeded.');
}
} else {
peer.onHangup(ab.CONNECTION_RETRIES_EXCEEDED, 'Number of connection retries exceeded.');
}
}
break;
case ab.CONNECTION_LOST:
peer.retryCount += 1;
if (peer.retryCount <= peer.options.maxRetries) {
// notify the app of scheduled reconnect
stop = peer.onHangup(
ab.CONNECTION_LOST_SCHEDULED_RECONNECT,
'Connection lost - scheduled ' +
peer.retryCount +
'th reconnect to occur in ' +
peer.options.retryDelay / 1000 +
' second(s).',
{
delay: peer.options.retryDelay,
retries: peer.retryCount,
maxretries: peer.options.maxRetries,
},
);
if (!stop) {
if (ab._debugconnect) {
console.log('Connection lost - retrying (' + peer.retryCount + ') ..');
}
root.setTimeout(function () {
ab._connect(peer);
}, peer.options.retryDelay);
} else {
if (ab._debugconnect) {
console.log('Connection lost - retrying stopped by app');
}
peer.onHangup(ab.CONNECTION_RETRIES_EXCEEDED, 'Connection lost.');
}
} else {
peer.onHangup(ab.CONNECTION_RETRIES_EXCEEDED, 'Connection lost.');
}
break;
default:
throw 'unhandled close code in ab._connect';
}
},
peer.options, // forward options to session class for specific WS/WAMP options
);
};
ab.connect = function (wsuri, onconnect, onhangup, options) {
var peer = {};
peer.wsuri = wsuri;
if (!options) {
peer.options = {};
} else {
peer.options = options;
}
if (peer.options.retryDelay === undefined) {
peer.options.retryDelay = 5000;
}
if (peer.options.maxRetries === undefined) {
peer.options.maxRetries = 10;
}
if (peer.options.skipSubprotocolCheck === undefined) {
peer.options.skipSubprotocolCheck = false;
}
if (peer.options.skipSubprotocolAnnounce === undefined) {
peer.options.skipSubprotocolAnnounce = false;
}
if (!onconnect) {
throw 'onConnect handler required!';
} else {
peer.onConnect = onconnect;
}
if (!onhangup) {
peer.onHangup = function (code, reason, detail) {
if (ab._debugconnect) {
console.log(code, reason, detail);
}
};
} else {
peer.onHangup = onhangup;
}
peer.connects = 0; // total number of successful connects
peer.retryCount = 0; // number of retries since last successful connect
ab._connect(peer);
};
ab.launch = function (appConfig, onOpen, onClose) {
function Rpc(session, uri) {
return function () {
var args = [uri];
for (var j = 0; j < arguments.length; ++j) {
args.push(arguments[j]);
}
//arguments.unshift(uri);
return ab.Session.prototype.call.apply(session, args);
};
}
function createApi(session, perms) {
session.api = {};
for (var i = 0; i < perms.rpc.length; ++i) {
var uri = perms.rpc[i].uri;
var _method = uri.split('#')[1];
var _class = uri.split('#')[0].split('/');
_class = _class[_class.length - 1];
if (!(_class in session.api)) {
session.api[_class] = {};
}
session.api[_class][_method] = new Rpc(session, uri);
}
}
ab.connect(
appConfig.wsuri,
// connection established handler
function (session) {
if (!appConfig.appkey || appConfig.appkey === '') {
// Authenticate as anonymous ..
session.authreq().then(function () {
session.auth().then(function (permissions) {
//createApi(session, permissions);
if (onOpen) {
onOpen(session);
} else if (ab._debugconnect) {
session.log('Session opened.');
}
}, session.log);
}, session.log);
} else {
// Authenticate as appkey ..
session.authreq(appConfig.appkey, appConfig.appextra).then(function (challenge) {
var signature = null;
if (typeof appConfig.appsecret === 'function') {
signature = appConfig.appsecret(challenge);
} else {
// derive secret if salted WAMP-CRA
var secret = ab.deriveKey(appConfig.appsecret, JSON.parse(challenge).authextra);
// direct sign
signature = session.authsign(challenge, secret);
}
session.auth(signature).then(function (permissions) {
//createApi(session, permissions);
if (onOpen) {
onOpen(session);
} else if (ab._debugconnect) {
session.log('Session opened.');
}
}, session.log);
}, session.log);
}
},
// connection lost handler
function (code, reason, detail) {
if (onClose) {
onClose(code, reason, detail);
} else if (ab._debugconnect) {
ab.log('Session closed.', code, reason, detail);
}
},
// WAMP session config
appConfig.sessionConfig,
);
};
return ab;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment