remotedev
Version:
Remote debugging for any flux implementation.
1,741 lines (1,454 loc) • 154 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["RemoteDev"] = factory();
else
root["RemoteDev"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
module.exports = __webpack_require__(9);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
var Emitter = __webpack_require__(11);
if (!Object.create) {
Object.create = __webpack_require__(23);
}
var SCEmitter = function () {
Emitter.call(this);
};
SCEmitter.prototype = Object.create(Emitter.prototype);
SCEmitter.prototype.emit = function (event) {
if (event == 'error' && this.domain) {
// Emit the error on the domain if it has one.
// See https://github.com/joyent/node/blob/ef4344311e19a4f73c031508252b21712b22fe8a/lib/events.js#L78-85
var err = arguments[1];
if (!err) {
err = new Error('Uncaught, unspecified "error" event.');
}
err.domainEmitter = this;
err.domain = this.domain;
err.domainThrown = false;
this.domain.emit('error', err);
}
Emitter.prototype.emit.apply(this, arguments);
};
module.exports.SCEmitter = SCEmitter;
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
var cycle = __webpack_require__(12);
var isStrict = (function () { return !this; })();
function AuthTokenExpiredError(message, expiry) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'AuthTokenExpiredError';
this.message = message;
this.expiry = expiry;
};
AuthTokenExpiredError.prototype = Object.create(Error.prototype);
function AuthTokenInvalidError(message) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'AuthTokenInvalidError';
this.message = message;
};
AuthTokenInvalidError.prototype = Object.create(Error.prototype);
function SilentMiddlewareBlockedError(message, type) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'SilentMiddlewareBlockedError';
this.message = message;
this.type = type;
};
SilentMiddlewareBlockedError.prototype = Object.create(Error.prototype);
function InvalidActionError(message) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'InvalidActionError';
this.message = message;
};
InvalidActionError.prototype = Object.create(Error.prototype);
function InvalidArgumentsError(message) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'InvalidArgumentsError';
this.message = message;
};
InvalidArgumentsError.prototype = Object.create(Error.prototype);
function InvalidOptionsError(message) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'InvalidOptionsError';
this.message = message;
};
InvalidOptionsError.prototype = Object.create(Error.prototype);
function InvalidMessageError(message) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'InvalidMessageError';
this.message = message;
};
InvalidMessageError.prototype = Object.create(Error.prototype);
function SocketProtocolError(message, code) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'SocketProtocolError';
this.message = message;
this.code = code;
};
SocketProtocolError.prototype = Object.create(Error.prototype);
function ServerProtocolError(message) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'ServerProtocolError';
this.message = message;
};
ServerProtocolError.prototype = Object.create(Error.prototype);
function HTTPServerError(message) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'HTTPServerError';
this.message = message;
};
HTTPServerError.prototype = Object.create(Error.prototype);
function ResourceLimitError(message) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'ResourceLimitError';
this.message = message;
};
ResourceLimitError.prototype = Object.create(Error.prototype);
function TimeoutError(message) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'TimeoutError';
this.message = message;
};
TimeoutError.prototype = Object.create(Error.prototype);
function BrokerError(message) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'BrokerError';
this.message = message;
};
BrokerError.prototype = Object.create(Error.prototype);
function ProcessExitError(message, code) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'ProcessExitError';
this.message = message;
this.code = code;
};
ProcessExitError.prototype = Object.create(Error.prototype);
function UnknownError(message) {
if (Error.captureStackTrace && !isStrict) {
Error.captureStackTrace(this, arguments.callee);
} else {
this.stack = (new Error()).stack;
}
this.name = 'UnknownError';
this.message = message;
};
UnknownError.prototype = Object.create(Error.prototype);
// Expose all error types
module.exports = {
AuthTokenExpiredError: AuthTokenExpiredError,
AuthTokenInvalidError: AuthTokenInvalidError,
SilentMiddlewareBlockedError: SilentMiddlewareBlockedError,
InvalidActionError: InvalidActionError,
InvalidArgumentsError: InvalidArgumentsError,
InvalidOptionsError: InvalidOptionsError,
InvalidMessageError: InvalidMessageError,
SocketProtocolError: SocketProtocolError,
ServerProtocolError: ServerProtocolError,
HTTPServerError: HTTPServerError,
ResourceLimitError: ResourceLimitError,
TimeoutError: TimeoutError,
BrokerError: BrokerError,
ProcessExitError: ProcessExitError,
UnknownError: UnknownError
};
module.exports.socketProtocolErrorStatuses = {
1001: 'Socket was disconnected',
1002: 'A WebSocket protocol error was encountered',
1003: 'Server terminated socket because it received invalid data',
1005: 'Socket closed without status code',
1006: 'Socket hung up',
1007: 'Message format was incorrect',
1008: 'Encountered a policy violation',
1009: 'Message was too big to process',
1010: 'Client ended the connection because the server did not comply with extension requirements',
1011: 'Server encountered an unexpected fatal condition',
4000: 'Server ping timed out',
4001: 'Client pong timed out',
4002: 'Server failed to sign auth token',
4003: 'Failed to complete handshake',
4004: 'Client failed to save auth token',
4005: 'Did not receive #handshake from client before timeout',
4006: 'Failed to bind socket to message broker',
4007: 'Client connection establishment timed out'
};
module.exports.socketProtocolIgnoreStatuses = {
1000: 'Socket closed normally',
1001: 'Socket hung up'
};
// Properties related to error domains cannot be serialized.
var unserializableErrorProperties = {
domain: 1,
domainEmitter: 1,
domainThrown: 1
};
module.exports.dehydrateError = function (error, includeStackTrace) {
var dehydratedError;
if (typeof error == 'string') {
dehydratedError = error;
} else {
dehydratedError = {
message: error.message
};
if (includeStackTrace) {
dehydratedError.stack = error.stack;
}
for (var i in error) {
if (!unserializableErrorProperties[i]) {
dehydratedError[i] = error[i];
}
}
}
return cycle.decycle(dehydratedError);
};
module.exports.hydrateError = function (error) {
var hydratedError = null;
if (error != null) {
if (typeof error == 'string') {
hydratedError = error;
} else {
hydratedError = new Error(error.message);
for (var i in error) {
if (error.hasOwnProperty(i)) {
hydratedError[i] = error[i];
}
}
}
}
return hydratedError;
};
/***/ },
/* 3 */
/***/ function(module, exports) {
module.exports = pathGetter;
function pathGetter(obj, path) {
if (path !== '$') {
var paths = getPaths(path);
for (var i = 0; i < paths.length; i++) {
path = paths[i].toString().replace(/\\"/g, '"');
obj = obj[path];
}
}
return obj;
}
function getPaths(pathString) {
var regex = /(?:\.(\w+))|(?:\[(\d+)\])|(?:\["((?:[^\\"]|\\.)*)"\])/g;
var matches = [];
var match;
while (match = regex.exec(pathString)) {
matches.push( match[1] || match[2] || match[3] );
}
return matches;
}
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.decode = exports.parse = __webpack_require__(19);
exports.encode = exports.stringify = __webpack_require__(20);
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
var scErrors = __webpack_require__(2);
var InvalidActionError = scErrors.InvalidActionError;
var Response = function (socket, id) {
this.socket = socket;
this.id = id;
this.sent = false;
};
Response.prototype._respond = function (responseData) {
if (this.sent) {
throw new InvalidActionError('Response ' + this.id + ' has already been sent');
} else {
this.sent = true;
this.socket.send(this.socket.stringify(responseData));
}
};
Response.prototype.end = function (data) {
if (this.id) {
var responseData = {
rid: this.id
};
if (data !== undefined) {
responseData.data = data;
}
this._respond(responseData);
}
};
Response.prototype.error = function (error, data) {
if (this.id) {
var err = scErrors.dehydrateError(error);
var responseData = {
rid: this.id,
error: err
};
if (data !== undefined) {
responseData.data = data;
}
this._respond(responseData);
}
};
Response.prototype.callback = function (error, data) {
if (error) {
this.error(error, data);
} else {
this.end(data);
}
};
module.exports.Response = Response;
/***/ },
/* 6 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global, Buffer) {var SCEmitter = __webpack_require__(1).SCEmitter;
var SCChannel = __webpack_require__(22).SCChannel;
var Response = __webpack_require__(5).Response;
var AuthEngine = __webpack_require__(26).AuthEngine;
var SCTransport = __webpack_require__(28).SCTransport;
var querystring = __webpack_require__(4);
var LinkedList = __webpack_require__(18);
var base64 = __webpack_require__(10);
var scErrors = __webpack_require__(2);
var InvalidArgumentsError = scErrors.InvalidArgumentsError;
var InvalidMessageError = scErrors.InvalidMessageError;
var SocketProtocolError = scErrors.SocketProtocolError;
var TimeoutError = scErrors.TimeoutError;
var isBrowser = typeof window != 'undefined';
var SCSocket = function (opts) {
var self = this;
SCEmitter.call(this);
this.id = null;
this.state = this.CLOSED;
this.authState = this.PENDING;
this.signedAuthToken = null;
this.authToken = null;
this.pendingReconnect = false;
this.pendingReconnectTimeout = null;
this.pendingConnectCallback = false;
this.connectTimeout = opts.connectTimeout;
this.ackTimeout = opts.ackTimeout;
this.channelPrefix = opts.channelPrefix || null;
// pingTimeout will be ackTimeout at the start, but it will
// be updated with values provided by the 'connect' event
this.pingTimeout = this.ackTimeout;
var maxTimeout = Math.pow(2, 31) - 1;
var verifyDuration = function (propertyName) {
if (self[propertyName] > maxTimeout) {
throw new InvalidArgumentsError('The ' + propertyName +
' value provided exceeded the maximum amount allowed');
}
};
verifyDuration('connectTimeout');
verifyDuration('ackTimeout');
verifyDuration('pingTimeout');
this._localEvents = {
'connect': 1,
'connectAbort': 1,
'disconnect': 1,
'message': 1,
'error': 1,
'raw': 1,
'fail': 1,
'kickOut': 1,
'subscribe': 1,
'unsubscribe': 1,
'subscribeStateChange': 1,
'authStateChange': 1,
'authenticate': 1,
'deauthenticate': 1,
'removeAuthToken': 1,
'subscribeRequest': 1
};
this.connectAttempts = 0;
this._emitBuffer = new LinkedList();
this._channels = {};
this.options = opts;
this._cid = 1;
this.options.callIdGenerator = function () {
return self._callIdGenerator();
};
if (this.options.autoReconnect) {
if (this.options.autoReconnectOptions == null) {
this.options.autoReconnectOptions = {};
}
// Add properties to the this.options.autoReconnectOptions object.
// We assign the reference to a reconnectOptions variable to avoid repetition.
var reconnectOptions = this.options.autoReconnectOptions;
if (reconnectOptions.initialDelay == null) {
reconnectOptions.initialDelay = 10000;
}
if (reconnectOptions.randomness == null) {
reconnectOptions.randomness = 10000;
}
if (reconnectOptions.multiplier == null) {
reconnectOptions.multiplier = 1.5;
}
if (reconnectOptions.maxDelay == null) {
reconnectOptions.maxDelay = 60000;
}
}
if (this.options.subscriptionRetryOptions == null) {
this.options.subscriptionRetryOptions = {};
}
if (this.options.authEngine) {
this.auth = this.options.authEngine;
} else {
this.auth = new AuthEngine();
}
this.options.path = this.options.path.replace(/\/$/, '') + '/';
this.options.query = opts.query || {};
if (typeof this.options.query == 'string') {
this.options.query = querystring.parse(this.options.query);
}
this.connect();
this._channelEmitter = new SCEmitter();
if (isBrowser) {
var unloadHandler = function () {
self.disconnect();
};
if (global.attachEvent) {
global.attachEvent('onunload', unloadHandler);
} else if (global.addEventListener) {
global.addEventListener('beforeunload', unloadHandler, false);
}
}
};
SCSocket.prototype = Object.create(SCEmitter.prototype);
SCSocket.CONNECTING = SCSocket.prototype.CONNECTING = SCTransport.prototype.CONNECTING;
SCSocket.OPEN = SCSocket.prototype.OPEN = SCTransport.prototype.OPEN;
SCSocket.CLOSED = SCSocket.prototype.CLOSED = SCTransport.prototype.CLOSED;
SCSocket.AUTHENTICATED = SCSocket.prototype.AUTHENTICATED = 'authenticated';
SCSocket.UNAUTHENTICATED = SCSocket.prototype.UNAUTHENTICATED = 'unauthenticated';
SCSocket.PENDING = SCSocket.prototype.PENDING = 'pending';
SCSocket.ignoreStatuses = scErrors.socketProtocolIgnoreStatuses;
SCSocket.errorStatuses = scErrors.socketProtocolErrorStatuses;
SCSocket.prototype._privateEventHandlerMap = {
'#publish': function (data) {
var undecoratedChannelName = this._undecorateChannelName(data.channel);
var isSubscribed = this.isSubscribed(undecoratedChannelName, true);
if (isSubscribed) {
this._channelEmitter.emit(undecoratedChannelName, data.data);
}
},
'#kickOut': function (data) {
var undecoratedChannelName = this._undecorateChannelName(data.channel);
var channel = this._channels[undecoratedChannelName];
if (channel) {
SCEmitter.prototype.emit.call(this, 'kickOut', data.message, undecoratedChannelName);
channel.emit('kickOut', data.message, undecoratedChannelName);
this._triggerChannelUnsubscribe(channel);
}
},
'#setAuthToken': function (data, response) {
var self = this;
if (data) {
var triggerAuthenticate = function (err) {
if (err) {
// This is a non-fatal error, we don't want to close the connection
// because of this but we do want to notify the server and throw an error
// on the client.
response.error(err);
self._onSCError(err);
} else {
self._changeToAuthenticatedState(data.token);
response.end();
}
};
this.auth.saveToken(this.options.authTokenName, data.token, {}, triggerAuthenticate);
} else {
response.error(new InvalidMessageError('No token data provided by #setAuthToken event'));
}
},
'#removeAuthToken': function (data, response) {
var self = this;
this.auth.removeToken(this.options.authTokenName, function (err, oldToken) {
if (err) {
// Non-fatal error - Do not close the connection
response.error(err);
self._onSCError(err);
} else {
SCEmitter.prototype.emit.call(self, 'removeAuthToken', oldToken);
self._changeToUnauthenticatedState();
response.end();
}
});
},
'#disconnect': function (data) {
this.transport.close(data.code, data.data);
}
};
SCSocket.prototype._callIdGenerator = function () {
return this._cid++;
};
SCSocket.prototype.getState = function () {
return this.state;
};
SCSocket.prototype.getBytesReceived = function () {
return this.transport.getBytesReceived();
};
SCSocket.prototype.deauthenticate = function (callback) {
var self = this;
this.auth.removeToken(this.options.authTokenName, function (err, oldToken) {
self.emit('#removeAuthToken');
callback && callback(err);
if (err) {
// Non-fatal error - Do not close the connection
self._onSCError(err);
} else {
SCEmitter.prototype.emit.call(self, 'removeAuthToken', oldToken);
self._changeToUnauthenticatedState();
}
});
};
SCSocket.prototype.connect = SCSocket.prototype.open = function () {
var self = this;
if (this.state == this.CLOSED) {
this.pendingReconnect = false;
this.pendingReconnectTimeout = null;
clearTimeout(this._reconnectTimeoutRef);
this.state = this.CONNECTING;
this._changeToPendingAuthState();
if (this.transport) {
this.transport.off();
}
this.transport = new SCTransport(this.auth, this.options);
this.transport.on('open', function (status) {
self.state = self.OPEN;
self._onSCOpen(status);
});
this.transport.on('error', function (err) {
self._onSCError(err);
});
this.transport.on('close', function (code, data) {
self.state = self.CLOSED;
self._onSCClose(code, data);
});
this.transport.on('openAbort', function (code, data) {
self.state = self.CLOSED;
self._onSCClose(code, data, true);
});
this.transport.on('event', function (event, data, res) {
self._onSCEvent(event, data, res);
});
}
};
SCSocket.prototype.reconnect = function () {
this.disconnect();
this.connect();
};
SCSocket.prototype.disconnect = function (code, data) {
code = code || 1000;
if (this.state == this.OPEN) {
var packet = {
code: code,
data: data
};
this.transport.emit('#disconnect', packet);
this.transport.close(code, data);
} else if (this.state == this.CONNECTING) {
this.transport.close(code, data);
} else {
this.pendingReconnect = false;
this.pendingReconnectTimeout = null;
clearTimeout(this._reconnectTimeoutRef);
}
};
SCSocket.prototype._changeToPendingAuthState = function () {
if (this.authState != this.PENDING) {
var oldState = this.authState;
this.authState = this.PENDING;
var stateChangeData = {
oldState: oldState,
newState: this.authState
};
SCEmitter.prototype.emit.call(this, 'authStateChange', stateChangeData);
}
};
SCSocket.prototype._changeToUnauthenticatedState = function () {
if (this.authState != this.UNAUTHENTICATED) {
var oldState = this.authState;
this.authState = this.UNAUTHENTICATED;
this.signedAuthToken = null;
this.authToken = null;
var stateChangeData = {
oldState: oldState,
newState: this.authState
};
SCEmitter.prototype.emit.call(this, 'authStateChange', stateChangeData);
if (oldState == this.AUTHENTICATED) {
SCEmitter.prototype.emit.call(this, 'deauthenticate');
}
SCEmitter.prototype.emit.call(this, 'authTokenChange', this.signedAuthToken);
}
};
SCSocket.prototype._changeToAuthenticatedState = function (signedAuthToken) {
this.signedAuthToken = signedAuthToken;
this.authToken = this._extractAuthTokenData(signedAuthToken);
if (this.authState != this.AUTHENTICATED) {
var oldState = this.authState;
this.authState = this.AUTHENTICATED;
var stateChangeData = {
oldState: oldState,
newState: this.authState,
signedAuthToken: signedAuthToken,
authToken: this.authToken
};
this.processPendingSubscriptions();
SCEmitter.prototype.emit.call(this, 'authStateChange', stateChangeData);
SCEmitter.prototype.emit.call(this, 'authenticate', signedAuthToken);
}
SCEmitter.prototype.emit.call(this, 'authTokenChange', signedAuthToken);
};
SCSocket.prototype.decodeBase64 = function (encodedString) {
var decodedString;
if (typeof Buffer == 'undefined') {
if (global.atob) {
decodedString = global.atob(encodedString);
} else {
decodedString = base64.decode(encodedString);
}
} else {
var buffer = new Buffer(encodedString, 'base64');
decodedString = buffer.toString('utf8');
}
return decodedString;
};
SCSocket.prototype.encodeBase64 = function (decodedString) {
var encodedString;
if (typeof Buffer == 'undefined') {
if (global.btoa) {
encodedString = global.btoa(decodedString);
} else {
encodedString = base64.encode(decodedString);
}
} else {
var buffer = new Buffer(decodedString, 'utf8');
encodedString = buffer.toString('base64');
}
return encodedString;
};
SCSocket.prototype._extractAuthTokenData = function (signedAuthToken) {
var tokenParts = (signedAuthToken || '').split('.');
var encodedTokenData = tokenParts[1];
if (encodedTokenData != null) {
var tokenData = encodedTokenData;
try {
tokenData = this.decodeBase64(tokenData);
return JSON.parse(tokenData);
} catch (e) {
return tokenData;
}
}
return null;
};
SCSocket.prototype.getAuthToken = function () {
return this.authToken;
};
SCSocket.prototype.getSignedAuthToken = function () {
return this.signedAuthToken;
};
// Perform client-initiated authentication by providing an encrypted token string
SCSocket.prototype.authenticate = function (signedAuthToken, callback) {
var self = this;
this._changeToPendingAuthState();
this.emit('#authenticate', signedAuthToken, function (err, authStatus) {
if (authStatus && authStatus.authError) {
authStatus.authError = scErrors.hydrateError(authStatus.authError);
}
if (err) {
self._changeToUnauthenticatedState();
callback && callback(err, authStatus);
} else {
self.auth.saveToken(self.options.authTokenName, signedAuthToken, {}, function (err) {
callback && callback(err, authStatus);
if (err) {
self._changeToUnauthenticatedState();
self._onSCError(err);
} else {
if (authStatus.isAuthenticated) {
self._changeToAuthenticatedState(signedAuthToken);
} else {
self._changeToUnauthenticatedState();
}
}
});
}
});
};
SCSocket.prototype._tryReconnect = function (initialDelay) {
var self = this;
var exponent = this.connectAttempts++;
var reconnectOptions = this.options.autoReconnectOptions;
var timeout;
if (initialDelay == null || exponent > 0) {
var initialTimeout = Math.round(reconnectOptions.initialDelay + (reconnectOptions.randomness || 0) * Math.random());
timeout = Math.round(initialTimeout * Math.pow(reconnectOptions.multiplier, exponent));
} else {
timeout = initialDelay;
}
if (timeout > reconnectOptions.maxDelay) {
timeout = reconnectOptions.maxDelay;
}
clearTimeout(this._reconnectTimeoutRef);
this.pendingReconnect = true;
this.pendingReconnectTimeout = timeout;
this._reconnectTimeoutRef = setTimeout(function () {
self.connect();
}, timeout);
};
SCSocket.prototype._onSCOpen = function (status) {
var self = this;
if (status) {
this.id = status.id;
this.pingTimeout = status.pingTimeout;
this.transport.pingTimeout = this.pingTimeout;
if (status.isAuthenticated) {
this._changeToAuthenticatedState(status.authToken);
} else {
this._changeToUnauthenticatedState();
}
} else {
this._changeToUnauthenticatedState();
}
this.connectAttempts = 0;
if (this.options.autoProcessSubscriptions) {
this.processPendingSubscriptions();
} else {
this.pendingConnectCallback = true;
}
// If the user invokes the callback while in autoProcessSubscriptions mode, it
// won't break anything - The processPendingSubscriptions() call will be a no-op.
SCEmitter.prototype.emit.call(this, 'connect', status, function () {
self.processPendingSubscriptions();
});
this._flushEmitBuffer();
};
SCSocket.prototype._onSCError = function (err) {
var self = this;
// Throw error in different stack frame so that error handling
// cannot interfere with a reconnect action.
setTimeout(function () {
if (self.listeners('error').length < 1) {
throw err;
} else {
SCEmitter.prototype.emit.call(self, 'error', err);
}
}, 0);
};
SCSocket.prototype._suspendSubscriptions = function () {
var channel, newState;
for (var channelName in this._channels) {
if (this._channels.hasOwnProperty(channelName)) {
channel = this._channels[channelName];
if (channel.state == channel.SUBSCRIBED ||
channel.state == channel.PENDING) {
newState = channel.PENDING;
} else {
newState = channel.UNSUBSCRIBED;
}
this._triggerChannelUnsubscribe(channel, newState);
}
}
};
SCSocket.prototype._onSCClose = function (code, data, openAbort) {
var self = this;
this.id = null;
if (this.transport) {
this.transport.off();
}
this.pendingReconnect = false;
this.pendingReconnectTimeout = null;
clearTimeout(this._reconnectTimeoutRef);
this._changeToPendingAuthState();
this._suspendSubscriptions();
// Try to reconnect
// on server ping timeout (4000)
// or on client pong timeout (4001)
// or on close without status (1005)
// or on handshake failure (4003)
// or on socket hung up (1006)
if (this.options.autoReconnect) {
if (code == 4000 || code == 4001 || code == 1005) {
// If there is a ping or pong timeout or socket closes without
// status, don't wait before trying to reconnect - These could happen
// if the client wakes up after a period of inactivity and in this case we
// want to re-establish the connection as soon as possible.
this._tryReconnect(0);
// Codes 4500 and above will be treated as permanent disconnects.
// Socket will not try to auto-reconnect.
} else if (code != 1000 && code < 4500) {
this._tryReconnect();
}
}
if (openAbort) {
SCEmitter.prototype.emit.call(self, 'connectAbort', code, data);
} else {
SCEmitter.prototype.emit.call(self, 'disconnect', code, data);
}
if (!SCSocket.ignoreStatuses[code]) {
var failureMessage;
if (data) {
failureMessage = 'Socket connection failed: ' + data;
} else {
failureMessage = 'Socket connection failed for unknown reasons';
}
var err = new SocketProtocolError(SCSocket.errorStatuses[code] || failureMessage, code);
this._onSCError(err);
}
};
SCSocket.prototype._onSCEvent = function (event, data, res) {
var handler = this._privateEventHandlerMap[event];
if (handler) {
handler.call(this, data, res);
} else {
SCEmitter.prototype.emit.call(this, event, data, function () {
res && res.callback.apply(res, arguments);
});
}
};
SCSocket.prototype.parse = function (message) {
return this.transport.parse(message);
};
SCSocket.prototype.stringify = function (object) {
return this.transport.stringify(object);
};
SCSocket.prototype._flushEmitBuffer = function () {
var currentNode = this._emitBuffer.head;
var nextNode;
while (currentNode) {
nextNode = currentNode.next;
var eventObject = currentNode.data;
currentNode.detach();
this.transport.emitRaw(eventObject);
currentNode = nextNode;
}
};
SCSocket.prototype._handleEventAckTimeout = function (eventObject, eventNode) {
if (eventNode) {
eventNode.detach();
}
var error = new TimeoutError("Event response for '" + eventObject.event + "' timed out");
var callback = eventObject.callback;
if (callback) {
delete eventObject.callback;
callback.call(eventObject, error, eventObject);
}
};
SCSocket.prototype._emit = function (event, data, callback) {
var self = this;
if (this.state == this.CLOSED) {
this.connect();
}
var eventObject = {
event: event,
data: data,
callback: callback
};
var eventNode = new LinkedList.Item();
eventNode.data = eventObject;
eventObject.timeout = setTimeout(function () {
self._handleEventAckTimeout(eventObject, eventNode);
}, this.ackTimeout);
this._emitBuffer.append(eventNode);
if (this.state == this.OPEN) {
this._flushEmitBuffer();
}
};
SCSocket.prototype.send = function (data) {
this.transport.send(data);
};
SCSocket.prototype.emit = function (event, data, callback) {
if (this._localEvents[event] == null) {
this._emit(event, data, callback);
} else {
SCEmitter.prototype.emit.call(this, event, data);
}
};
SCSocket.prototype.publish = function (channelName, data, callback) {
var pubData = {
channel: this._decorateChannelName(channelName),
data: data
};
this.emit('#publish', pubData, callback);
};
SCSocket.prototype._triggerChannelSubscribe = function (channel, subscriptionOptions) {
var channelName = channel.name;
if (channel.state != channel.SUBSCRIBED) {
var oldState = channel.state;
channel.state = channel.SUBSCRIBED;
var stateChangeData = {
channel: channelName,
oldState: oldState,
newState: channel.state,
subscriptionOptions: subscriptionOptions
};
channel.emit('subscribeStateChange', stateChangeData);
channel.emit('subscribe', channelName, subscriptionOptions);
SCEmitter.prototype.emit.call(this, 'subscribeStateChange', stateChangeData);
SCEmitter.prototype.emit.call(this, 'subscribe', channelName, subscriptionOptions);
}
};
SCSocket.prototype._triggerChannelSubscribeFail = function (err, channel, subscriptionOptions) {
var channelName = channel.name;
var meetsAuthRequirements = !channel.waitForAuth || this.authState == this.AUTHENTICATED;
if (channel.state != channel.UNSUBSCRIBED && meetsAuthRequirements) {
channel.state = channel.UNSUBSCRIBED;
channel.emit('subscribeFail', err, channelName, subscriptionOptions);
SCEmitter.prototype.emit.call(this, 'subscribeFail', err, channelName, subscriptionOptions);
}
};
// Cancel any pending subscribe callback
SCSocket.prototype._cancelPendingSubscribeCallback = function (channel) {
if (channel._pendingSubscriptionCid != null) {
this.transport.cancelPendingResponse(channel._pendingSubscriptionCid);
delete channel._pendingSubscriptionCid;
}
};
SCSocket.prototype._decorateChannelName = function (channelName) {
if (this.channelPrefix) {
channelName = this.channelPrefix + channelName;
}
return channelName;
};
SCSocket.prototype._undecorateChannelName = function (decoratedChannelName) {
if (this.channelPrefix && decoratedChannelName.indexOf(this.channelPrefix) == 0) {
return decoratedChannelName.replace(this.channelPrefix, '');
}
return decoratedChannelName;
};
SCSocket.prototype._trySubscribe = function (channel) {
var self = this;
var meetsAuthRequirements = !channel.waitForAuth || this.authState == this.AUTHENTICATED;
// We can only ever have one pending subscribe action at any given time on a channel
if (this.state == this.OPEN && !this.pendingConnectCallback &&
channel._pendingSubscriptionCid == null && meetsAuthRequirements) {
var options = {
noTimeout: true
};
var subscriptionOptions = {
channel: this._decorateChannelName(channel.name)
};
if (channel.waitForAuth) {
options.waitForAuth = true;
subscriptionOptions.waitForAuth = options.waitForAuth;
}
if (channel.data) {
subscriptionOptions.data = channel.data;
}
channel._pendingSubscriptionCid = this.transport.emit(
'#subscribe', subscriptionOptions, options,
function (err) {
delete channel._pendingSubscriptionCid;
if (err) {
self._triggerChannelSubscribeFail(err, channel, subscriptionOptions);
} else {
self._triggerChannelSubscribe(channel, subscriptionOptions);
}
}
);
SCEmitter.prototype.emit.call(this, 'subscribeRequest', channel.name, subscriptionOptions);
}
};
SCSocket.prototype.subscribe = function (channelName, options) {
var channel = this._channels[channelName];
if (!channel) {
channel = new SCChannel(channelName, this, options);
this._channels[channelName] = channel;
} else if (options) {
channel.setOptions(options);
}
if (channel.state == channel.UNSUBSCRIBED) {
channel.state = channel.PENDING;
this._trySubscribe(channel);
}
return channel;
};
SCSocket.prototype._triggerChannelUnsubscribe = function (channel, newState) {
var channelName = channel.name;
var oldState = channel.state;
if (newState) {
channel.state = newState;
} else {
channel.state = channel.UNSUBSCRIBED;
}
this._cancelPendingSubscribeCallback(channel);
if (oldState == channel.SUBSCRIBED) {
var stateChangeData = {
channel: channelName,
oldState: oldState,
newState: channel.state
};
channel.emit('subscribeStateChange', stateChangeData);
channel.emit('unsubscribe', channelName);
SCEmitter.prototype.emit.call(this, 'subscribeStateChange', stateChangeData);
SCEmitter.prototype.emit.call(this, 'unsubscribe', channelName);
}
};
SCSocket.prototype._tryUnsubscribe = function (channel) {
var self = this;
if (this.state == this.OPEN) {
var options = {
noTimeout: true
};
// If there is a pending subscribe action, cancel the callback
this._cancelPendingSubscribeCallback(channel);
// This operation cannot fail because the TCP protocol guarantees delivery
// so long as the connection remains open. If the connection closes,
// the server will automatically unsubscribe the socket and thus complete
// the operation on the server side.
var decoratedChannelName = this._decorateChannelName(channel.name);
this.transport.emit('#unsubscribe', decoratedChannelName, options);
}
};
SCSocket.prototype.unsubscribe = function (channelName) {
var channel = this._channels[channelName];
if (channel) {
if (channel.state != channel.UNSUBSCRIBED) {
this._triggerChannelUnsubscribe(channel);
this._tryUnsubscribe(channel);
}
}
};
SCSocket.prototype.channel = function (channelName, options) {
var currentChannel = this._channels[channelName];
if (!currentChannel) {
currentChannel = new SCChannel(channelName, this, options);
this._channels[channelName] = currentChannel;
}
return currentChannel;
};
SCSocket.prototype.destroyChannel = function (channelName) {
var channel = this._channels[channelName];
channel.unwatch();
channel.unsubscribe();
delete this._channels[channelName];
};
SCSocket.prototype.subscriptions = function (includePending) {
var subs = [];
var channel, includeChannel;
for (var channelName in this._channels) {
if (this._channels.hasOwnProperty(channelName)) {
channel = this._channels[channelName];
if (includePending) {
includeChannel = channel && (channel.state == channel.SUBSCRIBED ||
channel.state == channel.PENDING);
} else {
includeChannel = channel && channel.state == channel.SUBSCRIBED;
}
if (includeChannel) {
subs.push(channelName);
}
}
}
return subs;
};
SCSocket.prototype.isSubscribed = function (channelName, includePending) {
var channel = this._channels[channelName];
if (includePending) {
return !!channel && (channel.state == channel.SUBSCRIBED ||
channel.state == channel.PENDING);
}
return !!channel && channel.state == channel.SUBSCRIBED;
};
SCSocket.prototype.processPendingSubscriptions = function () {
var self = this;
this.pendingConnectCallback = false;
for (var i in this._channels) {
if (this._channels.hasOwnProperty(i)) {
(function (channel) {
if (channel.state == channel.PENDING) {
self._trySubscribe(channel);
}
})(this._channels[i]);
}
}
};
SCSocket.prototype.watch = function (channelName, handler) {
if (typeof handler != 'function') {
throw new InvalidArgumentsError('No handler function was provided');
}
this._channelEmitter.on(channelName, handler);
};
SCSocket.prototype.unwatch = function (channelName, handler) {
if (handler) {
this._channelEmitter.removeListener(channelName, handler);
} else {
this._channelEmitter.removeAllListeners(channelName);
}
};
SCSocket.prototype.watchers = function (channelName) {
return this._channelEmitter.listeners(channelName);
};
module.exports = SCSocket;
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(7).Buffer))
/***/ },
/* 7 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(Buffer, global) {/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
* @license MIT
*/
/* eslint-disable no-proto */
'use strict'
var base64 = __webpack_require__(31)
var ieee754 = __webpack_require__(32)
var isArray = __webpack_require__(33)
exports.Buffer = Buffer
exports.SlowBuffer = SlowBuffer
exports.INSPECT_MAX_BYTES = 50
Buffer.poolSize = 8192 // not used by this implementation
var rootParent = {}
/**
* If `Buffer.TYPED_ARRAY_SUPPORT`:
* === true Use Uint8Array implementation (fastest)
* === false Use Object implementation (most compatible, even IE6)
*
* Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
* Opera 11.6+, iOS 4.2+.
*
* Due to various browser bugs, sometimes the Object implementation will be used even
* when the browser supports typed arrays.
*
* Note:
*
* - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
* See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
*
* - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property
* on objects.
*
* - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
*
* - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
* incorrect length in some situations.
* We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they
* get the Object implementation, which is slower but behaves correctly.
*/
Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined
? global.TYPED_ARRAY_SUPPORT
: typedArraySupport()
function typedArraySupport () {
function Bar () {}
try {
var arr = new Uint8Array(1)
arr.foo = function () { return 42 }
arr.constructor = Bar
return arr.foo() === 42 && // typed array instances can be augmented
arr.constructor === Bar && // constructor can be set
typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
} catch (e) {
return false
}
}
function kMaxLength () {
return Buffer.TYPED_ARRAY_SUPPORT
? 0x7fffffff
: 0x3fffffff
}
/**
* Class: Buffer
* =============
*
* The Buffer constructor returns instances of `Uint8Array` that are augmented
* with function properties for all the node `Buffer` API functions. We use
* `Uint8Array` so that square bracket notation works as expected -- it returns
* a single octet.
*
* By augmenting the instances, we can avoid modifying the `Uint8Array`
* prototype.
*/
function Buffer (arg) {
if (!(this instanceof Buffer)) {
// Avoid going through an ArgumentsAdaptorTrampoline in the common case.
if (arguments.length > 1) return new Buffer(arg, arguments[1])
return new Buffer(arg)
}
if (!Buffer.TYPED_ARRAY_SUPPORT) {
this.length = 0
this.parent = undefined
}
// Common case.
if (typeof arg === 'number') {
return fromNumber(this, arg)
}
// Slightly less common case.
if (typeof arg === 'string') {
return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')
}
// Unusual.
return fromObject(this, arg)
}
function fromNumber (that, length) {
that = allocate(that, length < 0 ? 0 : checked(length) | 0)
if (!Buffer.TYPED_ARRAY_SUPPORT) {
for (var i = 0; i < length; i++) {
that[i] = 0
}
}
return that
}
function fromString (that, string, encoding) {
if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'
// Assumption: byteLength() return value is always < kMaxLength.
var length = byteLength(string, encoding) | 0
that = allocate(that, length)
that.write(string, encoding)
return that
}
function fromObject (that, object) {
if (Buffer.isBuffer(object)) return fromBuffer(that, object)
if (isArray(object)) return fromArray(that, object)
if (object == null) {
throw new TypeError('must start with number, buffer, array or string')
}
if (typeof ArrayBuffer !== 'undefined') {
if (object.buffer instanceof ArrayBuffer) {
return fromTypedArray(that, object)
}
if (object instanceof ArrayBuffer) {
return fromArrayBuffer(that, object)
}
}
if (object.length) return fromArrayLike(that, object)
return fromJsonObject(that, object)
}
function fromBuffer (that, buffer) {
var length = checked(buffer.length) | 0
that = allocate(that, length)
buffer.copy(that, 0, 0, length)
return that
}
function fromArray (that, array) {
var length = checked(array.length) | 0
that = allocate(that, length)
for (var i = 0; i < length; i += 1) {
that[i] = array[i] & 255
}
return that
}
// Duplicate of fromArray() to keep fromArray() monomorphic.
function fromTypedArray (that, array) {
var length = checked(array.length) | 0
that = allocate(that, length)
// Truncating the elements is probably not what people expect from typed
// arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior
// of the old Buffer constructor.
for (var i = 0; i < length; i += 1) {
that[i] = array[i] & 255
}
return that
}
function fromArrayBuffer (that, array) {
if (Buffer.TYPED_ARRAY_SUPPORT) {
// Return an augmented `Uint8Array` instance, for best performance
array.byteLength
that = Buffer._augment(new Uint8Array(array))
} else {
// Fallback: Return an object instance of the Buffer class
that = fromTypedArray(that, new Uint8Array(array))
}
return that
}
function fromArrayLike (that, array) {
var length = checked(array.length) | 0
that = allocate(that, length)
for (var i = 0; i < length; i += 1) {
that[i] = array[i] & 255
}
return that
}
// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.
// Returns a zero-length buffer for inputs that don't conform to the spec.
function fromJsonObject (that, object) {
var array
var length = 0
if (object.type === 'Buffer' && isArray(object.data)) {
array = object.data
length = checked(array.length) | 0
}
that = allocate(that, length)
for (var i = 0; i < length; i += 1) {
that[i] = array[i] & 255
}
return that
}
if (Buffer.TYPED_ARRAY_SUPPORT) {
Buffer.prototype.__proto__ = Uint8Array.prototype
Buffer.__proto__ = Uint8Array
} else {
// pre-set for values that may exist in the future
Buffer.prototype.length = undefined
Buffer.prototype.parent = undefined
}
function allocate (that, length) {
if (Buffer.TYPED_ARRAY_SUPPORT) {
// Return an augmented `Uint8Array` instance, for best performance
that = Buffer._augment(new Uint8Array(length))
that.__proto__ = Buffer.prototype
} else {
// Fallback: Return an object instance of the Buffer class
that.length = length
that._isBuffer = true
}
var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1
if (fromPool) that.parent = rootParent
return that
}
function checked (length) {
// Note: cannot use `length < kMaxLength` here because that fails when
// length is NaN (which is otherwise coerced to zero.)
if (length >= kMaxLength()) {
throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
'size: 0x' + kMaxLength().toString(16) + ' bytes')
}
return length | 0
}
function SlowBuffer (subject, encoding) {
if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)
var buf = new Buffer(subject, encoding)
delete buf.parent
return buf
}
Buffer.isBuffer = function isBuffer (b) {
return !!(b != null && b._isBuffer)
}
Buffer.compare = function compare (a, b) {
if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
throw new TypeError('Arguments must be Buffers')
}
if (a === b) return 0
var x = a.length
var y = b.length
var i = 0
var len = Math.min(x, y)
while (i < len) {
if (a[i] !== b[i]) break
++i
}
if (i !== len) {
x = a[i]
y = b[i]
}
if (x < y) return -1
if (y < x) return 1
return 0
}
Buffer.isEncoding = function isEncoding (encoding) {
switch (String(encoding).toLowerCase()) {
case 'hex':
case 'utf8':
case 'utf-8':
case 'ascii':
case 'binary':
case 'base64':
case 'raw':
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return true
default:
return false
}
}
Buffer.concat = function concat (list, length) {
if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')
if (list.leng