autobahn-react
Version:
Do realtime without headaches with Autobahn and React.
1,501 lines (1,203 loc) • 1.08 MB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.AutobahnReact = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _autobahn = require('autobahn');
var _autobahn2 = _interopRequireDefault(_autobahn);
var _ConnectionJs = require('./Connection.js');
var _ConnectionJs2 = _interopRequireDefault(_ConnectionJs);
var Auth = {
currentUser: null,
_signupRoute: 'com.auth.signup',
_createTokenRoute: 'com.auth.create_token',
setSignupRoute: function setSignupRoute(newRoute) {
this._signupRoute = newRoute;
},
setTokenCreationRoute: function setTokenCreationRoute(newRoute) {
this._createTokenRoute = newRoute;
},
_onOpened: function _onOpened(args) {
var session = args[0];
var details = args[1];
this.currentUser = {
session_id: session.id,
id: details.authid,
role: details.authrole,
provider: details.authprovider,
method: details.authmethod
};
return Promise.resolve([session, this.currentUser]);
},
_onClosed: function _onClosed() {
this.currentUser = null;
return Promise.reject(Array.prototype.slice.call(arguments));
},
signUp: function signUp(userPayload) {
var session = _ConnectionJs2['default'].currentConnection.session;
return session.call(this._signupRoute, [userPayload]);
},
logIn: function logIn(credentials) {
if (!credentials.username || !credentials.password) {
throw new Error('One of credentials can\'t be null!');
}
return _ConnectionJs2['default'].reconnectWithAuth(credentials.username, credentials.password).then(this._onOpened.bind(this))['catch'](this._onClosed.bind(this));
},
isLogged: function isLogged() {
return this.currentUser !== null;
},
createToken: function createToken() {
var session = _ConnectionJs2['default'].currentConnection.session;
return session.call(this._createTokenRoute, Array.prototype.slice.call(arguments), { disclose_me: true });
},
become: function become(token) {
return _ConnectionJs2['default'].reconnectWithToken(token).then(this._onOpened.bind(this))['catch'](this._onClosed.bind(this));
},
canAccess: function canAccess(route) {
var session = _ConnectionJs2['default'].currentConnection.session;
return session.call(route, []).then(function () {
return Promise.resolve(true);
})['catch'](function () {
return Promise.resolve(false);
});
}
};
exports.Auth = Auth;
},{"./Connection.js":2,"autobahn":5}],2:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var _autobahn = require("autobahn");
var _autobahn2 = _interopRequireDefault(_autobahn);
var Connection = {
_url: null,
_realm: null,
_unreachableHandlers: [],
_lostHandlers: [],
_errorHandlers: [],
_readyHandlers: [],
_currentConnection: null,
connect: function connect() {
var _this = this;
var promise = new Promise(function (resolve, reject) {
_this._currentConnection.onopen = (function (session, details) {
for (var i = 0; i < this._readyHandlers.length; i++) {
this._readyHandlers[i]([session, details]);
}
resolve([session, details]);
}).bind(_this);
_this._currentConnection.onclose = function (reason, details) {
if (reason === "unreachable") {
console.log("Server unreachable", details);
reject(details);
for (var i = 0; i < _this._unreachableHandlers.length; i++) {
_this._unreachableHandlers[i](details);
}
} else if (reason === "lost") {
console.log("Connection lost", details);
for (var i = 0; i < _this._lostHandlers.length; i++) {
_this._lostHandlers[i](details);
}
} else {
console.log("Connection closed", reason, details);
for (var i = 0; i < _this._errorHandlers.length; i++) {
_this._errorHandlers[i]([reason, details]);
}
}
};
_this._currentConnection.open();
});
return promise;
},
onUnreachable: function onUnreachable(callback) {
this._unreachableHandlers.push(callback);
return this;
},
onLost: function onLost(callback) {
this._lostHandlers.push(callback);
return this;
},
onReady: function onReady(callback) {
this._readyHandlers.push(callback);
return this;
},
onError: function onError(callback) {
this._errorHandlers.push(callback);
return this;
},
makeConnection: function makeConnection(params) {
if (this._currentConnection && this._currentConnection.isOpen) {
this._currentConnection.close();
}
this._currentConnection = new _autobahn2["default"].Connection(params);
},
initialize: function initialize(url, realm) {
this._url = url;
this._realm = realm;
this.makeConnection({ url: url, realm: realm });
},
reconnectAnonymously: function reconnectAnonymously() {
this.makeConnection({ url: this._url, realm: this._realm });
return this.connect();
},
reconnectWithToken: function reconnectWithToken(authid, token) {
function onchallenge(session, method, extra) {
if (method !== "ticket") {
throw new Error("Unknown authentication method: " + method + " ?!");
}
return token;
}
this.makeConnection({ url: this._url, realm: this._realm, authmethods: ["ticket"], authid: authid, onchallenge: onchallenge });
return this.connect();
},
reconnectWithAuth: function reconnectWithAuth(authid, secret) {
function onchallenge(session, method, extra) {
if (method !== "wampcra") {
throw new Error("Unknown authentication method: " + method + " ?!");
}
if ("salt" in extra) {
_autobahn2["default"].auth_cra.derive_key(secret, extra.salt);
}
return _autobahn2["default"].auth_cra.sign(secret, extra.challenge);
}
this.makeConnection({ url: this._url, realm: this._realm, authmethods: ["wampcra"], authid: authid, onchallenge: onchallenge });
return this.connect();
}
};
Object.defineProperty(Connection, "currentConnection", {
enumerable: true,
writeable: false,
get: function get() {
if (Connection._currentConnection && Connection._currentConnection.isOpen) {
return Connection._currentConnection;
} else {
throw new Error("Autobahn isn't initialized yet!");
}
}
});
exports["default"] = Connection;
module.exports = exports["default"];
},{"autobahn":5}],3:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _get = function get(_x2, _x3, _x4) { var _again = true; _function: while (_again) { var object = _x2, property = _x3, receiver = _x4; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x2 = parent; _x3 = property; _x4 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
exports.requireSubscriptions = requireSubscriptions;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _ConnectionJs = require('./Connection.js');
var _ConnectionJs2 = _interopRequireDefault(_ConnectionJs);
function requireSubscriptions(Component) {
var staticMethods = arguments[1] === undefined ? {} : arguments[1];
var highOrderComponent = (function (_React$Component) {
var _class = function highOrderComponent(props) {
_classCallCheck(this, _class);
_get(Object.getPrototypeOf(_class.prototype), 'constructor', this).call(this, props);
this.state = {
data: {}
};
this.subscriptions = [];
this.subscriptionsMeta = {};
};
_inherits(_class, _React$Component);
_createClass(_class, [{
key: 'onPublished',
value: function onPublished(variable, args, kwargs, details) {
var _this = this;
this.setState(function (previousState, curProps) {
if (_this.subscriptionsMeta[variable].store) {
previousState.data[variable].push({ args: args, kwargs: kwargs, details: details });
} else {
previousState.data[variable] = { args: args, kwargs: kwargs, details: details };
}
return previousState;
});
}
}, {
key: 'componentDidMount',
value: function componentDidMount() {
var _this2 = this;
var routes = Component.observeSubscriptions();
for (var variable in routes) {
_ConnectionJs2['default'].currentConnection.session.subscribe(routes[variable].route, this.onPublished.bind(this, variable)).then(function (subscription) {
_this2.subscriptions.push(subscription);
var isStore = routes[variable].store || false;
_this2.subscriptionsMeta[variable] = { store: isStore };
_this2.setState(function (previousState, curProps) {
if (isStore) {
previousState.data[variable] = [];
} else {
previousState.data[variable] = {};
}
});
})['catch'](function (error) {
console.error('Failed to auto-subscribe to a topic: ' + routes[variable] + ' !', error);
});
}
}
}, {
key: 'componentDidUnmount',
value: function componentDidUnmount() {
var routes = Component.observeSubscriptions();
this.subscriptions.foreach(function (subscription) {
_ConnectionJs2['default'].currentConnection.session.subscribe(subscription);
});
}
}, {
key: 'render',
value: function render() {
return _react2['default'].createElement(Component, _extends({ data: this.state.data }, this.props));
}
}]);
return _class;
})(_react2['default'].Component);
for (var functionName in staticMethods) {
highOrderComponent[functionName] = staticMethods[functionName];
}
return highOrderComponent;
}
},{"./Connection.js":2,"react":240}],4:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _ConnectionJs = require('./Connection.js');
var _ConnectionJs2 = _interopRequireDefault(_ConnectionJs);
var _AuthJs = require('./Auth.js');
var _DecoratorsJs = require('./Decorators.js');
var Decorators = _interopRequireWildcard(_DecoratorsJs);
var Autobahn = {
Auth: _AuthJs.Auth,
Connection: _ConnectionJs2['default'],
Decorators: Decorators,
initialize: function initialize(url, realm) {
if (_ConnectionJs2['default']._currentConnection) {
throw new Error('Autobahn is already initialized!');
}
_ConnectionJs2['default'].initialize(url, realm);
return _ConnectionJs2['default'].reconnectAnonymously();
},
browserInitialize: function browserInitialize(port, path, realm) {
return this.initialize('ws://' + document.location.hostname + ':' + port + '/' + path, realm);
},
isConnectionReady: function isConnectionReady() {
return _ConnectionJs2['default'].currentConnection && _ConnectionJs2['default'].currentConnection.isOpen;
},
publish: function publish() {
var _Connection$currentConnection$session;
return (_Connection$currentConnection$session = _ConnectionJs2['default'].currentConnection.session).publish.apply(_Connection$currentConnection$session, arguments);
},
subscribe: function subscribe() {
var _Connection$currentConnection$session2;
return (_Connection$currentConnection$session2 = _ConnectionJs2['default'].currentConnection.session).subscribe.apply(_Connection$currentConnection$session2, arguments);
},
unsubscribe: function unsubscribe() {
var _Connection$currentConnection$session3;
return (_Connection$currentConnection$session3 = _ConnectionJs2['default'].currentConnection.session).unsubscribe.apply(_Connection$currentConnection$session3, arguments);
},
call: function call() {
var _Connection$currentConnection$session4;
return (_Connection$currentConnection$session4 = _ConnectionJs2['default'].currentConnection.session).call.apply(_Connection$currentConnection$session4, arguments);
},
register: function register() {
var _Connection$currentConnection$session5;
return (_Connection$currentConnection$session5 = _ConnectionJs2['default'].currentConnection.session).register.apply(_Connection$currentConnection$session5, arguments);
}
};
exports['default'] = Autobahn;
module.exports = exports['default'];
},{"./Auth.js":1,"./Connection.js":2,"./Decorators.js":3}],5:[function(require,module,exports){
///////////////////////////////////////////////////////////////////////////////
//
// AutobahnJS - http://autobahn.ws, http://wamp.ws
//
// A JavaScript library for WAMP ("The Web Application Messaging Protocol").
//
// Copyright (C) 2011-2014 Tavendo GmbH, http://tavendo.com
//
// Licensed under the MIT License.
// http://www.opensource.org/licenses/mit-license.php
//
///////////////////////////////////////////////////////////////////////////////
module.exports = require('./lib/autobahn');
},{"./lib/autobahn":8}],6:[function(require,module,exports){
///////////////////////////////////////////////////////////////////////////////
//
// AutobahnJS - http://autobahn.ws, http://wamp.ws
//
// A JavaScript library for WAMP ("The Web Application Messaging Protocol").
//
// Copyright (C) 2011-2014 Tavendo GmbH, http://tavendo.com
//
// Licensed under the MIT License.
// http://www.opensource.org/licenses/mit-license.php
//
///////////////////////////////////////////////////////////////////////////////
// require('assert') would be nice .. but it does not
// work with Google Closure after Browserify
var crypto = require('crypto-js');
// PBKDF2-base key derivation function for salted WAMP-CRA
//
function derive_key (secret, salt, iterations, keylen) {
var iterations = iterations || 1000;
var keylen = keylen || 32;
var config = {
keySize: keylen / 4,
iterations: iterations,
hasher: crypto.algo.SHA256
}
var key = crypto.PBKDF2(secret, salt, config);
return key.toString(crypto.enc.Base64);
}
function sign (key, challenge) {
return crypto.HmacSHA256(challenge, key).toString(crypto.enc.Base64);
}
exports.sign = sign;
exports.derive_key = derive_key;
},{"crypto-js":32}],7:[function(require,module,exports){
///////////////////////////////////////////////////////////////////////////////
//
// AutobahnJS - http://autobahn.ws, http://wamp.ws
//
// A JavaScript library for WAMP ("The Web Application Messaging Protocol").
//
// Copyright (C) 2011-2014 Tavendo GmbH, http://tavendo.com
//
// Licensed under the MIT License.
// http://www.opensource.org/licenses/mit-license.php
//
///////////////////////////////////////////////////////////////////////////////
var when = require('when');
var when_fn = require("when/function");
function auth(session, user, extra) {
// Persona Issues:
//
// Chrome: https://github.com/mozilla/persona/issues/4083
// IE11: https://groups.google.com/forum/#!topic/mozilla.dev.identity/keEkVpvfLA8
var d = session.defer();
navigator.id.watch({
loggedInUser: user,
onlogin: function (assertion) {
// A user has logged in! Here you need to:
// 1. Send the assertion to your backend for verification and to create a session.
// 2. Update your UI.
d.resolve(assertion);
},
onlogout: function() {
// A user has logged out! Here you need to:
// Tear down the user's session by redirecting the user or making a call to your backend.
// Also, make sure loggedInUser will get set to null on the next page load.
// (That's a literal JavaScript null. Not false, 0, or undefined. null.)
session.leave("wamp.close.logout");
}
});
if (d.promise.then) {
// whenjs has the actual user promise in an attribute
return d.promise;
} else {
return d;
}
}
exports.auth = auth;
},{"when":82,"when/function":58}],8:[function(require,module,exports){
(function (global){
///////////////////////////////////////////////////////////////////////////////
//
// AutobahnJS - http://autobahn.ws, http://wamp.ws
//
// A JavaScript library for WAMP ("The Web Application Messaging Protocol").
//
// Copyright (C) 2011-2014 Tavendo GmbH, http://tavendo.com
//
// Licensed under the MIT License.
// http://www.opensource.org/licenses/mit-license.php
//
///////////////////////////////////////////////////////////////////////////////
// Polyfills for <= IE9
require('./polyfill.js');
var pjson = require('../package.json');
var when = require('when');
//var fn = require("when/function");
if ('AUTOBAHN_DEBUG' in global && AUTOBAHN_DEBUG) {
// https://github.com/cujojs/when/blob/master/docs/api.md#whenmonitor
require('when/monitor/console');
if ('console' in global) {
console.log("AutobahnJS debug enabled");
}
}
var util = require('./util.js');
var log = require('./log.js');
var session = require('./session.js');
var connection = require('./connection.js');
var configure = require('./configure.js');
var persona = require('./auth/persona.js');
var cra = require('./auth/cra.js');
exports.version = pjson.version;
exports.transports = configure.transports;
exports.Connection = connection.Connection;
exports.Session = session.Session;
exports.Invocation = session.Invocation;
exports.Event = session.Event;
exports.Result = session.Result;
exports.Error = session.Error;
exports.Subscription = session.Subscription;
exports.Registration = session.Registration;
exports.Publication = session.Publication;
exports.auth_persona = persona.auth;
exports.auth_cra = cra;
exports.when = when;
exports.util = util;
exports.log = log;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../package.json":84,"./auth/cra.js":6,"./auth/persona.js":7,"./configure.js":9,"./connection.js":10,"./log.js":11,"./polyfill.js":12,"./session.js":20,"./util.js":23,"when":82,"when/monitor/console":80}],9:[function(require,module,exports){
///////////////////////////////////////////////////////////////////////////////
//
// AutobahnJS - http://autobahn.ws, http://wamp.ws
//
// A JavaScript library for WAMP ("The Web Application Messaging Protocol").
//
// Copyright (C) 2011-2014 Tavendo GmbH, http://tavendo.com
//
// Licensed under the MIT License.
// http://www.opensource.org/licenses/mit-license.php
//
///////////////////////////////////////////////////////////////////////////////
function Transports() {
this._repository = {};
}
Transports.prototype.register = function (name, factory) {
this._repository[name] = factory;
};
Transports.prototype.isRegistered = function (name) {
return this._repository[name] ? true : false;
};
Transports.prototype.get = function (name) {
if (this._repository[name] !== undefined) {
return this._repository[name];
} else {
throw "no such transport: " + name;
}
}
Transports.prototype.list = function() {
var items = [];
for (var name in this._repository) {
items.push(name);
}
return items;
};
var _transports = new Transports();
// register default transports
var websocket = require('./transport/websocket.js');
_transports.register("websocket", websocket.Factory);
var longpoll = require('./transport/longpoll.js');
_transports.register("longpoll", longpoll.Factory);
exports.transports = _transports;
},{"./transport/longpoll.js":21,"./transport/websocket.js":22}],10:[function(require,module,exports){
(function (global){
///////////////////////////////////////////////////////////////////////////////
//
// AutobahnJS - http://autobahn.ws, http://wamp.ws
//
// A JavaScript library for WAMP ("The Web Application Messaging Protocol").
//
// Copyright (C) 2011-2014 Tavendo GmbH, http://tavendo.com
//
// Licensed under the MIT License.
// http://www.opensource.org/licenses/mit-license.php
//
///////////////////////////////////////////////////////////////////////////////
var when = require('when');
var session = require('./session.js');
var util = require('./util.js');
var log = require('./log.js');
var autobahn = require('./autobahn.js');
var Connection = function (options) {
var self = this;
self._options = options;
// Deferred factory
//
if (options && options.use_es6_promises) {
if ('Promise' in global) {
// ES6-based deferred factory
//
self._defer = function () {
var deferred = {};
deferred.promise = new Promise(function (resolve, reject) {
deferred.resolve = resolve;
deferred.reject = reject;
});
return deferred;
};
} else {
log.debug("Warning: ES6 promises requested, but not found! Falling back to whenjs.");
// whenjs-based deferred factory
//
self._defer = when.defer;
}
} else if (options && options.use_deferred) {
// use explicit deferred factory, e.g. jQuery.Deferred or Q.defer
//
self._defer = options.use_deferred;
} else {
// whenjs-based deferred factory
//
self._defer = when.defer;
}
// WAMP transport
//
// backward compatiblity
if (!self._options.transports) {
self._options.transports = [
{
type: 'websocket',
url: self._options.url
}
];
}
self._transport_factories = [];
self._init_transport_factories();
// WAMP session
//
self._session = null;
self._session_close_reason = null;
self._session_close_message = null;
// automatic reconnection configuration
//
// enable automatic reconnect if host is unreachable
if (self._options.retry_if_unreachable !== undefined) {
self._retry_if_unreachable = self._options.retry_if_unreachable;
} else {
self._retry_if_unreachable = true;
}
// maximum number of reconnection attempts
self._max_retries = self._options.max_retries || 15;
// initial retry delay in seconds
self._initial_retry_delay = self._options.initial_retry_delay || 1.5;
// maximum seconds between reconnection attempts
self._max_retry_delay = self._options.max_retry_delay || 300;
// the growth factor applied to the retry delay on each retry cycle
self._retry_delay_growth = self._options.retry_delay_growth || 1.5;
// the SD of a Gaussian to jitter the delay on each retry cycle
// as a fraction of the mean
self._retry_delay_jitter = self._options.retry_delay_jitter || 0.1;
// reconnection tracking
//
// total number of successful connections
self._connect_successes = 0;
// controls if we should try to reconnect
self._retry = false;
// current number of reconnect cycles we went through
self._retry_count = 0;
// the current retry delay
self._retry_delay = self._initial_retry_delay;
// flag indicating if we are currently in a reconnect cycle
self._is_retrying = false;
// when retrying, this is the timer object returned from window.setTimeout()
self._retry_timer = null;
};
Connection.prototype._create_transport = function () {
for (var i = 0; i < this._transport_factories.length; ++i) {
var transport_factory = this._transport_factories[i];
log.debug("trying to create WAMP transport of type: " + transport_factory.type);
try {
var transport = transport_factory.create();
if (transport) {
log.debug("using WAMP transport type: " + transport_factory.type);
return transport;
}
} catch (e) {
// ignore
log.debug("could not create WAMP transport '" + transport_factory.type + "': " + e);
}
}
// could not create any WAMP transport
return null;
};
Connection.prototype._init_transport_factories = function () {
// WAMP transport
//
var transports, transport_options, transport_factory, transport_factory_klass;
util.assert(this._options.transports, "No transport.factory specified");
transports = this._options.transports;
//if(typeof transports === "object") {
// this._options.transports = [transports];
//}
for(var i = 0; i < this._options.transports.length; ++i) {
// cascading transports until we find one which works
transport_options = this._options.transports[i];
if (!transport_options.url) {
// defaulting to options.url if none is provided
transport_options.url = this._options.url;
}
if (!transport_options.protocols) {
transport_options.protocols = this._options.protocols;
}
util.assert(transport_options.type, "No transport.type specified");
util.assert(typeof transport_options.type === "string", "transport.type must be a string");
try {
transport_factory_klass = autobahn.transports.get(transport_options.type);
if (transport_factory_klass) {
transport_factory = new transport_factory_klass(transport_options);
this._transport_factories.push(transport_factory);
}
} catch (exc) {
console.error(exc);
}
}
};
Connection.prototype._autoreconnect_reset_timer = function () {
var self = this;
if (self._retry_timer) {
clearTimeout(self._retry_timer);
}
self._retry_timer = null;
}
Connection.prototype._autoreconnect_reset = function () {
var self = this;
self._autoreconnect_reset_timer();
self._retry_count = 0;
self._retry_delay = self._initial_retry_delay;
self._is_retrying = false;
}
Connection.prototype._autoreconnect_advance = function () {
var self = this;
// jitter retry delay
if (self._retry_delay_jitter) {
self._retry_delay = util.rand_normal(self._retry_delay, self._retry_delay * self._retry_delay_jitter);
}
// cap the retry delay
if (self._retry_delay > self._max_retry_delay) {
self._retry_delay = self._max_retry_delay;
}
// count number of retries
self._retry_count += 1;
var res;
if (self._retry && self._retry_count <= self._max_retries) {
res = {
count: self._retry_count,
delay: self._retry_delay,
will_retry: true
};
} else {
res = {
count: null,
delay: null,
will_retry: false
}
}
// retry delay growth for next retry cycle
if (self._retry_delay_growth) {
self._retry_delay = self._retry_delay * self._retry_delay_growth;
}
return res;
}
Connection.prototype.open = function () {
var self = this;
if (self._transport) {
throw "connection already open (or opening)";
}
self._autoreconnect_reset();
self._retry = true;
function retry () {
// create a WAMP transport
self._transport = self._create_transport();
if (!self._transport) {
// failed to create a WAMP transport
self._retry = false;
if (self.onclose) {
var details = {
reason: null,
message: null,
retry_delay: null,
retry_count: null,
will_retry: false
};
self.onclose("unsupported", details);
}
return;
}
// create a new WAMP session using the WebSocket connection as transport
self._session = new session.Session(self._transport, self._defer, self._options.onchallenge);
self._session_close_reason = null;
self._session_close_message = null;
self._transport.onopen = function () {
// reset auto-reconnect timer and tracking
self._autoreconnect_reset();
// log successful connections
self._connect_successes += 1;
// start WAMP session
self._session.join(self._options.realm, self._options.authmethods, self._options.authid);
};
self._session.onjoin = function (details) {
if (self.onopen) {
try {
self.onopen(self._session, details);
} catch (e) {
log.debug("Exception raised from app code while firing Connection.onopen()", e);
}
}
};
//
// ... WAMP session is now attached to realm.
//
self._session.onleave = function (reason, details) {
self._session_close_reason = reason;
self._session_close_message = details.message || "";
self._retry = false;
self._transport.close(1000);
};
self._transport.onclose = function (evt) {
// remove any pending reconnect timer
self._autoreconnect_reset_timer();
self._transport = null;
var reason = null;
if (self._connect_successes === 0) {
reason = "unreachable";
if (!self._retry_if_unreachable) {
self._retry = false;
}
} else if (!evt.wasClean) {
reason = "lost";
} else {
reason = "closed";
}
var next_retry = self._autoreconnect_advance();
// fire app code handler
//
if (self.onclose) {
var details = {
reason: self._session_close_reason,
message: self._session_close_message,
retry_delay: next_retry.delay,
retry_count: next_retry.count,
will_retry: next_retry.will_retry
};
try {
// Connection.onclose() allows to cancel any subsequent retry attempt
var stop_retrying = self.onclose(reason, details);
} catch (e) {
log.debug("Exception raised from app code while firing Connection.onclose()", e);
}
}
// reset session info
//
if (self._session) {
self._session._id = null;
self._session = null;
self._session_close_reason = null;
self._session_close_message = null;
}
// automatic reconnection
//
if (self._retry && !stop_retrying) {
if (next_retry.will_retry) {
self._is_retrying = true;
log.debug("retrying in " + next_retry.delay + " s");
self._retry_timer = setTimeout(retry, next_retry.delay * 1000);
} else {
log.debug("giving up trying to reconnect");
}
}
}
}
retry();
};
Connection.prototype.close = function (reason, message) {
var self = this;
if (!self._transport && !self._is_retrying) {
throw "connection already closed";
}
// the app wants to close .. don't retry
self._retry = false;
if (self._session && self._session.isOpen) {
// if there is an open session, close that first.
self._session.leave(reason, message);
} else if (self._transport) {
// no session active: just close the transport
self._transport.close(1000);
}
};
Object.defineProperty(Connection.prototype, "defer", {
get: function () {
return this._defer;
}
});
Object.defineProperty(Connection.prototype, "session", {
get: function () {
return this._session;
}
});
Object.defineProperty(Connection.prototype, "isOpen", {
get: function () {
if (this._session && this._session.isOpen) {
return true;
} else {
return false;
}
}
});
Object.defineProperty(Connection.prototype, "isConnected", {
get: function () {
if (this._transport) {
return true;
} else {
return false;
}
}
});
Object.defineProperty(Connection.prototype, "transport", {
get: function () {
if (this._transport) {
return this._transport;
} else {
return {info: {type: 'none', url: null, protocol: null}};
}
}
});
Object.defineProperty(Connection.prototype, "isRetrying", {
get: function () {
return this._is_retrying;
}
});
exports.Connection = Connection;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./autobahn.js":8,"./log.js":11,"./session.js":20,"./util.js":23,"when":82}],11:[function(require,module,exports){
(function (global){
///////////////////////////////////////////////////////////////////////////////
//
// AutobahnJS - http://autobahn.ws, http://wamp.ws
//
// A JavaScript library for WAMP ("The Web Application Messaging Protocol").
//
// Copyright (C) 2011-2014 Tavendo GmbH, http://tavendo.com
//
// Licensed under the MIT License.
// http://www.opensource.org/licenses/mit-license.php
//
///////////////////////////////////////////////////////////////////////////////
var debug = function () {};
if ('AUTOBAHN_DEBUG' in global && AUTOBAHN_DEBUG && 'console' in global) {
debug = function () {
console.log.apply(console, arguments);
}
}
exports.debug = debug;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],12:[function(require,module,exports){
require('./polyfill/object');
require('./polyfill/array');
require('./polyfill/string');
require('./polyfill/function');
require('./polyfill/console');
require('./polyfill/typedarray');
require('./polyfill/json');
},{"./polyfill/array":13,"./polyfill/console":14,"./polyfill/function":15,"./polyfill/json":16,"./polyfill/object":17,"./polyfill/string":18,"./polyfill/typedarray":19}],13:[function(require,module,exports){
if ( 'function' !== typeof Array.prototype.reduce ) {
Array.prototype.reduce = function( callback /*, initialValue*/ ) {
'use strict';
var len, t, value, k;
if ( null === this || 'undefined' === typeof this ) {
throw new TypeError(
'Array.prototype.reduce called on null or undefined' );
}
if ( 'function' !== typeof callback ) {
throw new TypeError( callback + ' is not a function' );
}
t = Object( this );
len = t.length >>> 0;
k = 0;
if ( arguments.length >= 2 ) {
value = arguments[1];
} else {
while ( k < len && ! k in t ) k++;
if ( k >= len )
throw new TypeError('Reduce of empty array with no initial value');
value = t[ k++ ];
}
for ( ; k < len ; k++ ) {
if ( k in t ) {
value = callback( value, t[k], k, t );
}
}
return value;
};
}
// Add ECMA262-5 Array methods if not supported natively
//
if (!('indexOf' in Array.prototype)) {
Array.prototype.indexOf= function(find, i /*opt*/) {
if (i===undefined) i= 0;
if (i<0) i+= this.length;
if (i<0) i= 0;
for (var n= this.length; i<n; i++)
if (i in this && this[i]===find)
return i;
return -1;
};
}
if (!('lastIndexOf' in Array.prototype)) {
Array.prototype.lastIndexOf= function(find, i /*opt*/) {
if (i===undefined) i= this.length-1;
if (i<0) i+= this.length;
if (i>this.length-1) i= this.length-1;
for (i++; i-->0;) /* i++ because from-argument is sadly inclusive */
if (i in this && this[i]===find)
return i;
return -1;
};
}
if (!('forEach' in Array.prototype)) {
Array.prototype.forEach= function(action, that /*opt*/) {
for (var i= 0, n= this.length; i<n; i++)
if (i in this)
action.call(that, this[i], i, this);
};
}
if (!('map' in Array.prototype)) {
Array.prototype.map= function(mapper, that /*opt*/) {
var other= new Array(this.length);
for (var i= 0, n= this.length; i<n; i++)
if (i in this)
other[i]= mapper.call(that, this[i], i, this);
return other;
};
}
if (!('filter' in Array.prototype)) {
Array.prototype.filter= function(filter, that /*opt*/) {
var other= [], v;
for (var i=0, n= this.length; i<n; i++)
if (i in this && filter.call(that, v= this[i], i, this))
other.push(v);
return other;
};
}
if (!('every' in Array.prototype)) {
Array.prototype.every= function(tester, that /*opt*/) {
for (var i= 0, n= this.length; i<n; i++)
if (i in this && !tester.call(that, this[i], i, this))
return false;
return true;
};
}
if (!('some' in Array.prototype)) {
Array.prototype.some= function(tester, that /*opt*/) {
for (var i= 0, n= this.length; i<n; i++)
if (i in this && tester.call(that, this[i], i, this))
return true;
return false;
};
}
if ( 'function' !== typeof Array.prototype.reduceRight ) {
Array.prototype.reduceRight = function( callback /*, initialValue*/ ) {
'use strict';
if ( null === this || 'undefined' === typeof this ) {
throw new TypeError(
'Array.prototype.reduce called on null or undefined' );
}
if ( 'function' !== typeof callback ) {
throw new TypeError( callback + ' is not a function' );
}
var t = Object( this ), len = t.length >>> 0, k = len - 1, value;
if ( arguments.length >= 2 ) {
value = arguments[1];
} else {
while ( k >= 0 && ! k in t ) k--;
if ( k < 0 )
throw new TypeError('Reduce of empty array with no initial value');
value = t[ k-- ];
}
for ( ; k >= 0 ; k-- ) {
if ( k in t ) {
value = callback( value, t[k], k, t );
}
}
return value;
};
}
},{}],14:[function(require,module,exports){
(function (global){
(function(console) {
/*********************************************************************************************
* Make sure console exists because IE blows up if it's not open and you attempt to access it
* Create some dummy functions if we need to, so we don't have to if/else everything
*********************************************************************************************/
console||(console = window.console = {
// all this "a, b, c, d, e" garbage is to make the IDEs happy, since they can't do variable argument lists
/**
* @param a
* @param [b]
* @param [c]
* @param [d]
* @param [e]
*/
log: function(a, b, c, d, e) {},
/**
* @param a
* @param [b]
* @param [c]
* @param [d]
* @param [e]
*/
info: function(a, b, c, d, e) {},
/**
* @param a
* @param [b]
* @param [c]
* @param [d]
* @param [e]
*/
warn: function(a, b, c, d, e) {},
/**
* @param a
* @param [b]
* @param [c]
* @param [d]
* @param [e]
*/
error: function(a, b, c, d, e) {},
assert: function(test, message) {}
});
// IE 9 won't allow us to call console.log.apply (WTF IE!) It also reports typeof(console.log) as 'object' (UNH!)
// but together, those two errors can be useful in allowing us to fix stuff so it works right
if( typeof(console.log) === 'object' ) {
// Array.forEach doesn't work in IE 8 so don't try that :(
console.log = Function.prototype.call.bind(console.log, console);
console.info = Function.prototype.call.bind(console.info, console);
console.warn = Function.prototype.call.bind(console.warn, console);
console.error = Function.prototype.call.bind(console.error, console);
console.debug = Function.prototype.call.bind(console.info, console);
}
/**
* Support group and groupEnd functions
*/
('group' in console) ||
(console.group = function(msg) {
console.info("\n--- "+msg+" ---\n");
});
('groupEnd' in console) ||
(console.groupEnd = function() {
console.log("\n");
});
('assert' in console) ||
(console.assert = function(test, message) {
if (!test) {
try {
// attempt to preserve the stack
throw new Error("assertion failed: " + message);
} catch(error) {
setTimeout(function(){
throw error;
}, 0);
}
}
});
/**
* Support time and timeEnd functions
*/
('time' in console) ||
(function() {
var trackedTimes = {};
console.time = function(msg) {
trackedTimes[msg] = new Date().getTime();
};
console.timeEnd = function(msg) {
var end = new Date().getTime(), time = (msg in trackedTimes)? end - trackedTimes[msg] : 0;
console.info(msg+': '+time+'ms')
};
}());
})(global.console);
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],15:[function(require,module,exports){
if (!Function.prototype.bind) {
//credits: taken from bind_even_never in this discussion: https://prototype.lighthouseapp.com/projects/8886/tickets/215-optimize-bind-bindaseventlistener#ticket-215-9
Function.prototype.bind = function(context) {
var fn = this, args = Array.prototype.slice.call(arguments, 1);
return function(){
return fn.apply(context, Array.prototype.concat.apply(args, arguments));
};
};
}
},{}],16:[function(require,module,exports){
/*
json2.js
2014-02-04
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or ' '),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[k