PHP WebShell
Текущая директория: /usr/lib/node_modules/bitgo-express/node_modules/ripple-lib/dist/npm/common
Просмотр файла: connection.js
'use strict'; // eslint-disable-line strict
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; }; }();
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
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) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _ = require('lodash');
var _require = require('events'),
EventEmitter = _require.EventEmitter;
var WebSocket = require('ws');
var parseURL = require('url').parse;
var RangeSet = require('./rangeset').RangeSet;
var _require2 = require('./errors'),
RippledError = _require2.RippledError,
DisconnectedError = _require2.DisconnectedError,
NotConnectedError = _require2.NotConnectedError,
TimeoutError = _require2.TimeoutError,
ResponseFormatError = _require2.ResponseFormatError,
ConnectionError = _require2.ConnectionError,
RippledNotInitializedError = _require2.RippledNotInitializedError;
function isStreamMessageType(type) {
return type === 'ledgerClosed' || type === 'transaction' || type === 'path_find';
}
var Connection = function (_EventEmitter) {
_inherits(Connection, _EventEmitter);
function Connection(url) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, Connection);
var _this = _possibleConstructorReturn(this, (Connection.__proto__ || Object.getPrototypeOf(Connection)).call(this));
_this.setMaxListeners(Infinity);
_this._url = url;
_this._trace = options.trace;
if (_this._trace) {
// for easier unit testing
_this._console = console;
}
_this._proxyURL = options.proxy;
_this._proxyAuthorization = options.proxyAuthorization;
_this._authorization = options.authorization;
_this._trustedCertificates = options.trustedCertificates;
_this._key = options.key;
_this._passphrase = options.passphrase;
_this._certificate = options.certificate;
_this._timeout = options.timeout || 20 * 1000;
_this._isReady = false;
_this._ws = null;
_this._ledgerVersion = null;
_this._availableLedgerVersions = new RangeSet();
_this._nextRequestID = 1;
_this._retry = 0;
_this._retryTimer = null;
_this._onOpenErrorBound = null;
_this._onUnexpectedCloseBound = null;
_this._fee_base = null;
_this._fee_ref = null;
return _this;
}
_createClass(Connection, [{
key: '_updateLedgerVersions',
value: function _updateLedgerVersions(data) {
this._ledgerVersion = Number(data.ledger_index);
if (data.validated_ledgers) {
this._availableLedgerVersions.reset();
this._availableLedgerVersions.parseAndAddRanges(data.validated_ledgers);
} else {
this._availableLedgerVersions.addValue(this._ledgerVersion);
}
}
}, {
key: '_updateFees',
value: function _updateFees(data) {
this._fee_base = Number(data.fee_base);
this._fee_ref = Number(data.fee_ref);
}
// return value is array of arguments to Connection.emit
}, {
key: '_parseMessage',
value: function _parseMessage(message) {
var data = JSON.parse(message);
if (data.type === 'response') {
if (!(Number.isInteger(data.id) && data.id >= 0)) {
throw new ResponseFormatError('valid id not found in response');
}
return [data.id.toString(), data];
} else if (isStreamMessageType(data.type)) {
if (data.type === 'ledgerClosed') {
this._updateLedgerVersions(data);
this._updateFees(data);
}
return [data.type, data];
} else if (data.type === undefined && data.error) {
return ['error', data.error, data.error_message, data]; // e.g. slowDown
}
throw new ResponseFormatError('unrecognized message type: ' + data.type);
}
}, {
key: '_onMessage',
value: function _onMessage(message) {
var parameters = void 0;
if (this._trace) {
this._console.log(message);
}
try {
parameters = this._parseMessage(message);
} catch (error) {
this.emit('error', 'badMessage', error.message, message);
return;
}
// we don't want this inside the try/catch or exceptions in listener
// will be caught
this.emit.apply(this, _toConsumableArray(parameters));
}
}, {
key: 'isConnected',
value: function isConnected() {
return this._state === WebSocket.OPEN && this._isReady;
}
}, {
key: '_onUnexpectedClose',
value: function _onUnexpectedClose(beforeOpen, resolve, reject, code) {
if (this._onOpenErrorBound) {
this._ws.removeListener('error', this._onOpenErrorBound);
this._onOpenErrorBound = null;
}
// just in case
this._ws.removeAllListeners('open');
this._ws = null;
this._isReady = false;
if (beforeOpen) {
// connection was closed before it was properly opened, so we must return
// error to connect's caller
this.connect().then(resolve, reject);
} else {
// if first parameter ws lib sends close code,
// but sometimes it forgots about it, so default to 1006 - CLOSE_ABNORMAL
this.emit('disconnected', code || 1006);
this._retryConnect();
}
}
}, {
key: '_calculateTimeout',
value: function _calculateTimeout(retriesCount) {
return retriesCount < 40 ?
// First, for 2 seconds: 20 times per second
1000 / 20 : retriesCount < 40 + 60 ?
// Then, for 1 minute: once per second
1000 : retriesCount < 40 + 60 + 60 ?
// Then, for 10 minutes: once every 10 seconds
10 * 1000 :
// Then: once every 30 seconds
30 * 1000;
}
}, {
key: '_retryConnect',
value: function _retryConnect() {
var _this2 = this;
this._retry += 1;
var retryTimeout = this._calculateTimeout(this._retry);
this._retryTimer = setTimeout(function () {
_this2.emit('reconnecting', _this2._retry);
_this2.connect().catch(_this2._retryConnect.bind(_this2));
}, retryTimeout);
}
}, {
key: '_clearReconnectTimer',
value: function _clearReconnectTimer() {
clearTimeout(this._retryTimer);
this._retryTimer = null;
}
}, {
key: '_onOpen',
value: function _onOpen() {
var _this3 = this;
if (!this._ws) {
return Promise.reject(new DisconnectedError());
}
if (this._onOpenErrorBound) {
this._ws.removeListener('error', this._onOpenErrorBound);
this._onOpenErrorBound = null;
}
var request = {
command: 'subscribe',
streams: ['ledger']
};
return this.request(request).then(function (data) {
if (_.isEmpty(data) || !data.ledger_index) {
// rippled instance doesn't have validated ledgers
return _this3._disconnect(false).then(function () {
throw new RippledNotInitializedError('Rippled not initialized');
});
}
_this3._updateLedgerVersions(data);
_this3._updateFees(data);
_this3._rebindOnUnxpectedClose();
_this3._retry = 0;
_this3._ws.on('error', function (error) {
if (process.browser && error && error.type === 'error') {
// we are in browser, ignore error - `close` event will be fired
// after error
return;
}
_this3.emit('error', 'websocket', error.message, error);
});
_this3._isReady = true;
_this3.emit('connected');
return undefined;
});
}
}, {
key: '_rebindOnUnxpectedClose',
value: function _rebindOnUnxpectedClose() {
if (this._onUnexpectedCloseBound) {
this._ws.removeListener('close', this._onUnexpectedCloseBound);
}
this._onUnexpectedCloseBound = this._onUnexpectedClose.bind(this, false, null, null);
this._ws.once('close', this._onUnexpectedCloseBound);
}
}, {
key: '_unbindOnUnxpectedClose',
value: function _unbindOnUnxpectedClose() {
if (this._onUnexpectedCloseBound) {
this._ws.removeListener('close', this._onUnexpectedCloseBound);
}
this._onUnexpectedCloseBound = null;
}
}, {
key: '_onOpenError',
value: function _onOpenError(reject, error) {
this._onOpenErrorBound = null;
this._unbindOnUnxpectedClose();
reject(new NotConnectedError(error && error.message));
}
}, {
key: '_createWebSocket',
value: function _createWebSocket() {
var options = {};
if (this._proxyURL !== undefined) {
var parsedURL = parseURL(this._url);
var parsedProxyURL = parseURL(this._proxyURL);
var proxyOverrides = _.omitBy({
secureEndpoint: parsedURL.protocol === 'wss:',
secureProxy: parsedProxyURL.protocol === 'https:',
auth: this._proxyAuthorization,
ca: this._trustedCertificates,
key: this._key,
passphrase: this._passphrase,
cert: this._certificate
}, _.isUndefined);
var proxyOptions = _.assign({}, parsedProxyURL, proxyOverrides);
var HttpsProxyAgent = void 0;
try {
HttpsProxyAgent = require('https-proxy-agent');
} catch (error) {
throw new Error('"proxy" option is not supported in the browser');
}
options.agent = new HttpsProxyAgent(proxyOptions);
}
if (this._authorization !== undefined) {
var base64 = new Buffer(this._authorization).toString('base64');
options.headers = { Authorization: 'Basic ' + base64 };
}
var optionsOverrides = _.omitBy({
ca: this._trustedCertificates,
key: this._key,
passphrase: this._passphrase,
cert: this._certificate
}, _.isUndefined);
var websocketOptions = _.assign({}, options, optionsOverrides);
var websocket = new WebSocket(this._url, null, websocketOptions);
// we will have a listener for each outstanding request,
// so we have to raise the limit (the default is 10)
if (typeof websocket.setMaxListeners === 'function') {
websocket.setMaxListeners(Infinity);
}
return websocket;
}
}, {
key: 'connect',
value: function connect() {
var _this4 = this;
this._clearReconnectTimer();
return new Promise(function (resolve, reject) {
if (!_this4._url) {
reject(new ConnectionError('Cannot connect because no server was specified'));
}
if (_this4._state === WebSocket.OPEN) {
resolve();
} else if (_this4._state === WebSocket.CONNECTING) {
_this4._ws.once('open', resolve);
} else {
_this4._ws = _this4._createWebSocket();
// when an error causes the connection to close, the close event
// should still be emitted; the "ws" documentation says: "The close
// event is also emitted when then underlying net.Socket closes the
// connection (end or close)."
// In case if there is connection error (say, server is not responding)
// we must return this error to connection's caller. After successful
// opening, we will forward all errors to main api object.
_this4._onOpenErrorBound = _this4._onOpenError.bind(_this4, reject);
_this4._ws.once('error', _this4._onOpenErrorBound);
_this4._ws.on('message', _this4._onMessage.bind(_this4));
// in browser close event can came before open event, so we must
// resolve connect's promise after reconnect in that case.
// after open event we will rebound _onUnexpectedCloseBound
// without resolve and reject functions
_this4._onUnexpectedCloseBound = _this4._onUnexpectedClose.bind(_this4, true, resolve, reject);
_this4._ws.once('close', _this4._onUnexpectedCloseBound);
_this4._ws.once('open', function () {
return _this4._onOpen().then(resolve, reject);
});
}
});
}
}, {
key: 'disconnect',
value: function disconnect() {
return this._disconnect(true);
}
}, {
key: '_disconnect',
value: function _disconnect(calledByUser) {
var _this5 = this;
if (calledByUser) {
this._clearReconnectTimer();
this._retry = 0;
}
return new Promise(function (resolve) {
if (_this5._state === WebSocket.CLOSED) {
resolve();
} else if (_this5._state === WebSocket.CLOSING) {
_this5._ws.once('close', resolve);
} else {
if (_this5._onUnexpectedCloseBound) {
_this5._ws.removeListener('close', _this5._onUnexpectedCloseBound);
_this5._onUnexpectedCloseBound = null;
}
_this5._ws.once('close', function (code) {
_this5._ws = null;
_this5._isReady = false;
if (calledByUser) {
_this5.emit('disconnected', code || 1000); // 1000 - CLOSE_NORMAL
}
resolve();
});
_this5._ws.close();
}
});
}
}, {
key: 'reconnect',
value: function reconnect() {
var _this6 = this;
return this.disconnect().then(function () {
return _this6.connect();
});
}
}, {
key: '_whenReady',
value: function _whenReady(promise) {
var _this7 = this;
return new Promise(function (resolve, reject) {
if (!_this7._shouldBeConnected) {
reject(new NotConnectedError());
} else if (_this7._state === WebSocket.OPEN && _this7._isReady) {
promise.then(resolve, reject);
} else {
_this7.once('connected', function () {
return promise.then(resolve, reject);
});
}
});
}
}, {
key: 'getLedgerVersion',
value: function getLedgerVersion() {
return this._whenReady(Promise.resolve(this._ledgerVersion));
}
}, {
key: 'hasLedgerVersions',
value: function hasLedgerVersions(lowLedgerVersion, highLedgerVersion) {
return this._whenReady(Promise.resolve(this._availableLedgerVersions.containsRange(lowLedgerVersion, highLedgerVersion || this._ledgerVersion)));
}
}, {
key: 'hasLedgerVersion',
value: function hasLedgerVersion(ledgerVersion) {
return this.hasLedgerVersions(ledgerVersion, ledgerVersion);
}
}, {
key: 'getFeeBase',
value: function getFeeBase() {
return this._whenReady(Promise.resolve(Number(this._fee_base)));
}
}, {
key: 'getFeeRef',
value: function getFeeRef() {
return this._whenReady(Promise.resolve(Number(this._fee_ref)));
}
}, {
key: '_send',
value: function _send(message) {
var _this8 = this;
if (this._trace) {
this._console.log(message);
}
return new Promise(function (resolve, reject) {
_this8._ws.send(message, undefined, function (error, result) {
if (error) {
reject(new DisconnectedError(error.message));
} else {
resolve(result);
}
});
});
}
}, {
key: 'request',
value: function request(_request, timeout) {
var _this9 = this;
return new Promise(function (resolve, reject) {
if (!_this9._shouldBeConnected) {
reject(new NotConnectedError());
}
var timer = null;
var self = _this9;
var id = _this9._nextRequestID;
_this9._nextRequestID += 1;
var eventName = id.toString();
function onDisconnect() {
clearTimeout(timer);
self.removeAllListeners(eventName);
reject(new DisconnectedError());
}
function cleanup() {
clearTimeout(timer);
self.removeAllListeners(eventName);
if (self._ws !== null) {
self._ws.removeListener('close', onDisconnect);
}
}
function _resolve(response) {
cleanup();
resolve(response);
}
function _reject(error) {
cleanup();
reject(error);
}
_this9.once(eventName, function (response) {
if (response.status === 'error') {
_reject(new RippledError(response.error));
} else if (response.status === 'success') {
_resolve(response.result);
} else {
_reject(new ResponseFormatError('unrecognized status: ' + response.status));
}
});
_this9._ws.once('close', onDisconnect);
// JSON.stringify automatically removes keys with value of 'undefined'
var message = JSON.stringify(Object.assign({}, _request, { id: id }));
_this9._whenReady(_this9._send(message)).then(function () {
var delay = timeout || _this9._timeout;
timer = setTimeout(function () {
return _reject(new TimeoutError());
}, delay);
}).catch(_reject);
});
}
}, {
key: '_state',
get: function get() {
return this._ws ? this._ws.readyState : WebSocket.CLOSED;
}
}, {
key: '_shouldBeConnected',
get: function get() {
return this._ws !== null;
}
}]);
return Connection;
}(EventEmitter);
module.exports = Connection;Выполнить команду
Для локальной разработки. Не используйте в интернете!