UNPKG

autobahn-react

Version:

Do realtime without headaches with Autobahn and React.

1,501 lines (1,203 loc) 1.08 MB
(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 '&nbsp;'), 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