metaapi.cloud-metastats-sdk
Version:
Javascript SDK for MetaStats forex trading statistics API. Can calculate metrics for MetaTrader accounts added to MetaApi. Supports both MetaTrader 5 (MT5) and MetaTrader 4 (MT4). (https://metaapi.cloud)
158 lines (157 loc) • 15.5 kB
JavaScript
;
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _async_to_generator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
import { ValidationError } from './errorHandler';
let DomainClient = class DomainClient {
/**
* Returns domain client token
* @returns {String} client token
*/ get token() {
return this._token;
}
/**
* Sends a MetaStats API request
* @param {Function} getOpts function to get request options
* @param {String} accountId account id
* @returns {Object|String|any} request result
*/ requestMetastats(getOpts, accountId) {
var _this = this;
return _async_to_generator(function*() {
yield _this._updateHost();
yield _this._updateAccountHost(accountId);
const accountCache = _this._accountCache[accountId];
try {
const regionSettings = accountCache.regions[accountCache.regionIndex];
const opts = getOpts(`https://metastats-api-v1.${regionSettings.region}.${_this._urlCache.domain}`, regionSettings.id);
return yield _this._httpClient.request(opts);
} catch (err) {
if (![
'ConflictError',
'InternalError',
'ApiError',
'TimeoutError'
].includes(err.name)) {
throw err;
} else {
if (accountCache.regions.length === accountCache.regionIndex + 1) {
accountCache.regionIndex = 0;
throw err;
} else {
accountCache.regionIndex++;
return yield _this.requestMetastats(getOpts, accountId);
}
}
}
})();
}
_updateHost() {
var _this = this;
return _async_to_generator(function*() {
if (!_this._urlCache || _this._urlCache.lastUpdated < Date.now() - 1000 * 60 * 10) {
const urlSettings = yield _this._httpClient.requestWithFailover({
url: `https://mt-provisioning-api-v1.${_this._domain}/users/current/servers/mt-client-api`,
method: 'GET',
headers: {
'auth-token': _this._token
},
json: true
});
_this._urlCache = {
domain: urlSettings.domain,
lastUpdated: Date.now()
};
}
})();
}
_updateAccountHost(accountId) {
var _this = this;
return _async_to_generator(function*() {
if (!_this._accountCache[accountId] || _this._accountCache[accountId].lastUpdated < Date.now() - 1000 * 60 * 10) {
const getAccount = function() {
var _ref = _async_to_generator(function*(id) {
const accountOpts = {
url: `https://mt-provisioning-api-v1.${_this._domain}/users/current/accounts/${id}`,
method: 'GET',
headers: {
'auth-token': _this._token
},
json: true
};
return yield _this._httpClient.requestWithFailover(accountOpts);
});
return function getAccount(id) {
return _ref.apply(this, arguments);
};
}();
let accounts = [];
let accountData = yield getAccount(accountId);
if (accountData.primaryAccountId) {
accountData = yield getAccount(accountData.primaryAccountId);
}
accounts = [
{
_id: accountData._id,
region: accountData.region,
state: accountData.state
}
].concat(accountData.accountReplicas || []);
accounts = accounts.filter((account)=>account.state === 'DEPLOYED');
if (!accounts.length) {
throw new ValidationError('There are no replicas deployed yet. Please make sure at least ' + 'one of the replicas is deployed.');
}
let regions = accounts.map((account)=>({
region: account.region,
id: account._id
}));
_this._accountCache[accountId] = {
regions,
regionIndex: 0,
lastUpdated: Date.now()
};
}
})();
}
/**
* Constructs domain client instance
* @param {HttpClient} httpClient HTTP client
* @param {String} token authorization token
* @param {String} domain domain to connect to, default is agiliumtrade.agiliumtrade.ai
*/ constructor(httpClient, token, domain = 'agiliumtrade.agiliumtrade.ai'){
this._httpClient = httpClient;
this._domain = domain;
this._token = token;
this._urlCache = null;
this._accountCache = {};
}
};
/**
* Connection URL and request managing client
*/ export { DomainClient as default };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCB7IFZhbGlkYXRpb25FcnJvciB9IGZyb20gJy4vZXJyb3JIYW5kbGVyJztcblxuLyoqXG4gKiBDb25uZWN0aW9uIFVSTCBhbmQgcmVxdWVzdCBtYW5hZ2luZyBjbGllbnRcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRG9tYWluQ2xpZW50IHtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBkb21haW4gY2xpZW50IGluc3RhbmNlXG4gICAqIEBwYXJhbSB7SHR0cENsaWVudH0gaHR0cENsaWVudCBIVFRQIGNsaWVudFxuICAgKiBAcGFyYW0ge1N0cmluZ30gdG9rZW4gYXV0aG9yaXphdGlvbiB0b2tlblxuICAgKiBAcGFyYW0ge1N0cmluZ30gZG9tYWluIGRvbWFpbiB0byBjb25uZWN0IHRvLCBkZWZhdWx0IGlzIGFnaWxpdW10cmFkZS5hZ2lsaXVtdHJhZGUuYWlcbiAgICovXG4gIGNvbnN0cnVjdG9yKGh0dHBDbGllbnQsIHRva2VuLCBkb21haW4gPSAnYWdpbGl1bXRyYWRlLmFnaWxpdW10cmFkZS5haScpIHtcbiAgICB0aGlzLl9odHRwQ2xpZW50ID0gaHR0cENsaWVudDtcbiAgICB0aGlzLl9kb21haW4gPSBkb21haW47XG4gICAgdGhpcy5fdG9rZW4gPSB0b2tlbjtcbiAgICB0aGlzLl91cmxDYWNoZSA9IG51bGw7XG4gICAgdGhpcy5fYWNjb3VudENhY2hlID0ge307XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBkb21haW4gY2xpZW50IHRva2VuXG4gICAqIEByZXR1cm5zIHtTdHJpbmd9IGNsaWVudCB0b2tlblxuICAgKi9cbiAgZ2V0IHRva2VuKCkge1xuICAgIHJldHVybiB0aGlzLl90b2tlbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kcyBhIE1ldGFTdGF0cyBBUEkgcmVxdWVzdFxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBnZXRPcHRzIGZ1bmN0aW9uIHRvIGdldCByZXF1ZXN0IG9wdGlvbnNcbiAgICogQHBhcmFtIHtTdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkXG4gICAqIEByZXR1cm5zIHtPYmplY3R8U3RyaW5nfGFueX0gcmVxdWVzdCByZXN1bHRcbiAgICovXG4gIGFzeW5jIHJlcXVlc3RNZXRhc3RhdHMoZ2V0T3B0cywgYWNjb3VudElkKSB7XG4gICAgYXdhaXQgdGhpcy5fdXBkYXRlSG9zdCgpO1xuICAgIGF3YWl0IHRoaXMuX3VwZGF0ZUFjY291bnRIb3N0KGFjY291bnRJZCk7XG4gICAgY29uc3QgYWNjb3VudENhY2hlID0gdGhpcy5fYWNjb3VudENhY2hlW2FjY291bnRJZF07XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlZ2lvblNldHRpbmdzID0gYWNjb3VudENhY2hlLnJlZ2lvbnNbYWNjb3VudENhY2hlLnJlZ2lvbkluZGV4XTtcbiAgICAgIGNvbnN0IG9wdHMgPSBnZXRPcHRzKGBodHRwczovL21ldGFzdGF0cy1hcGktdjEuJHtyZWdpb25TZXR0aW5ncy5yZWdpb259LiR7dGhpcy5fdXJsQ2FjaGUuZG9tYWlufWAsIFxuICAgICAgICByZWdpb25TZXR0aW5ncy5pZCk7XG5cbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLl9odHRwQ2xpZW50LnJlcXVlc3Qob3B0cyk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoIVsnQ29uZmxpY3RFcnJvcicsICdJbnRlcm5hbEVycm9yJywgJ0FwaUVycm9yJywgJ1RpbWVvdXRFcnJvciddLmluY2x1ZGVzKGVyci5uYW1lKSkge1xuICAgICAgICB0aHJvdyBlcnI7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoYWNjb3VudENhY2hlLnJlZ2lvbnMubGVuZ3RoID09PSBhY2NvdW50Q2FjaGUucmVnaW9uSW5kZXggKyAxKSB7XG4gICAgICAgICAgYWNjb3VudENhY2hlLnJlZ2lvbkluZGV4ID0gMDtcbiAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYWNjb3VudENhY2hlLnJlZ2lvbkluZGV4Kys7XG4gICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucmVxdWVzdE1ldGFzdGF0cyhnZXRPcHRzLCBhY2NvdW50SWQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gIH1cblxuICBhc3luYyBfdXBkYXRlSG9zdCgpIHtcbiAgICBpZiAoIXRoaXMuX3VybENhY2hlIHx8IHRoaXMuX3VybENhY2hlLmxhc3RVcGRhdGVkIDwgRGF0ZS5ub3coKSAtIDEwMDAgKiA2MCAqIDEwKSB7XG4gICAgICBjb25zdCB1cmxTZXR0aW5ncyA9IGF3YWl0IHRoaXMuX2h0dHBDbGllbnQucmVxdWVzdFdpdGhGYWlsb3Zlcih7XG4gICAgICAgIHVybDogYGh0dHBzOi8vbXQtcHJvdmlzaW9uaW5nLWFwaS12MS4ke3RoaXMuX2RvbWFpbn0vdXNlcnMvY3VycmVudC9zZXJ2ZXJzL210LWNsaWVudC1hcGlgLFxuICAgICAgICBtZXRob2Q6ICdHRVQnLFxuICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlblxuICAgICAgICB9LFxuICAgICAgICBqc29uOiB0cnVlLFxuICAgICAgfSk7XG4gICAgICB0aGlzLl91cmxDYWNoZSA9IHtcbiAgICAgICAgZG9tYWluOiB1cmxTZXR0aW5ncy5kb21haW4sXG4gICAgICAgIGxhc3RVcGRhdGVkOiBEYXRlLm5vdygpXG4gICAgICB9OyBcbiAgICB9XG4gIH1cbiAgXG4gIGFzeW5jIF91cGRhdGVBY2NvdW50SG9zdChhY2NvdW50SWQpIHtcbiAgICBpZiAoIXRoaXMuX2FjY291bnRDYWNoZVthY2NvdW50SWRdIHx8IHRoaXMuX2FjY291bnRDYWNoZVthY2NvdW50SWRdLmxhc3RVcGRhdGVkIDwgRGF0ZS5ub3coKSAtIDEwMDAgKiA2MCAqIDEwKSB7XG5cbiAgICAgIGNvbnN0IGdldEFjY291bnQgPSBhc3luYyAoaWQpID0+IHtcbiAgICAgICAgY29uc3QgYWNjb3VudE9wdHMgPSB7XG4gICAgICAgICAgdXJsOiBgaHR0cHM6Ly9tdC1wcm92aXNpb25pbmctYXBpLXYxLiR7dGhpcy5fZG9tYWlufS91c2Vycy9jdXJyZW50L2FjY291bnRzLyR7aWR9YCxcbiAgICAgICAgICBtZXRob2Q6ICdHRVQnLFxuICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICdhdXRoLXRva2VuJzogdGhpcy5fdG9rZW5cbiAgICAgICAgICB9LFxuICAgICAgICAgIGpzb246IHRydWVcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5faHR0cENsaWVudC5yZXF1ZXN0V2l0aEZhaWxvdmVyKGFjY291bnRPcHRzKTtcbiAgICAgIH07XG5cbiAgICAgIGxldCBhY2NvdW50cyA9IFtdO1xuICAgICAgbGV0IGFjY291bnREYXRhID0gYXdhaXQgZ2V0QWNjb3VudChhY2NvdW50SWQpO1xuICAgICAgaWYgKGFjY291bnREYXRhLnByaW1hcnlBY2NvdW50SWQpIHtcbiAgICAgICAgYWNjb3VudERhdGEgPSBhd2FpdCBnZXRBY2NvdW50KGFjY291bnREYXRhLnByaW1hcnlBY2NvdW50SWQpO1xuICAgICAgfVxuICAgICAgYWNjb3VudHMgPSBbe19pZDogYWNjb3VudERhdGEuX2lkLCByZWdpb246IGFjY291bnREYXRhLnJlZ2lvbiwgc3RhdGU6IGFjY291bnREYXRhLnN0YXRlfV1cbiAgICAgICAgLmNvbmNhdCgoYWNjb3VudERhdGEuYWNjb3VudFJlcGxpY2FzIHx8IFtdKSk7XG4gICAgICBhY2NvdW50cyA9IGFjY291bnRzLmZpbHRlcihhY2NvdW50ID0+IGFjY291bnQuc3RhdGUgPT09ICdERVBMT1lFRCcpO1xuICAgICAgaWYgKCFhY2NvdW50cy5sZW5ndGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcignVGhlcmUgYXJlIG5vIHJlcGxpY2FzIGRlcGxveWVkIHlldC4gUGxlYXNlIG1ha2Ugc3VyZSBhdCBsZWFzdCAnICtcbiAgICAgICAgJ29uZSBvZiB0aGUgcmVwbGljYXMgaXMgZGVwbG95ZWQuJyk7XG4gICAgICB9XG5cbiAgICAgIGxldCByZWdpb25zID0gYWNjb3VudHMubWFwKGFjY291bnQgPT4gKHtyZWdpb246IGFjY291bnQucmVnaW9uLCBpZDogYWNjb3VudC5faWR9KSk7XG5cbiAgICAgIHRoaXMuX2FjY291bnRDYWNoZVthY2NvdW50SWRdID0ge1xuICAgICAgICByZWdpb25zLFxuICAgICAgICByZWdpb25JbmRleDogMCxcbiAgICAgICAgbGFzdFVwZGF0ZWQ6IERhdGUubm93KClcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbn1cbiJdLCJuYW1lcyI6WyJWYWxpZGF0aW9uRXJyb3IiLCJEb21haW5DbGllbnQiLCJ0b2tlbiIsIl90b2tlbiIsInJlcXVlc3RNZXRhc3RhdHMiLCJnZXRPcHRzIiwiYWNjb3VudElkIiwiX3VwZGF0ZUhvc3QiLCJfdXBkYXRlQWNjb3VudEhvc3QiLCJhY2NvdW50Q2FjaGUiLCJfYWNjb3VudENhY2hlIiwicmVnaW9uU2V0dGluZ3MiLCJyZWdpb25zIiwicmVnaW9uSW5kZXgiLCJvcHRzIiwicmVnaW9uIiwiX3VybENhY2hlIiwiZG9tYWluIiwiaWQiLCJfaHR0cENsaWVudCIsInJlcXVlc3QiLCJlcnIiLCJpbmNsdWRlcyIsIm5hbWUiLCJsZW5ndGgiLCJsYXN0VXBkYXRlZCIsIkRhdGUiLCJub3ciLCJ1cmxTZXR0aW5ncyIsInJlcXVlc3RXaXRoRmFpbG92ZXIiLCJ1cmwiLCJfZG9tYWluIiwibWV0aG9kIiwiaGVhZGVycyIsImpzb24iLCJnZXRBY2NvdW50IiwiYWNjb3VudE9wdHMiLCJhY2NvdW50cyIsImFjY291bnREYXRhIiwicHJpbWFyeUFjY291bnRJZCIsIl9pZCIsInN0YXRlIiwiY29uY2F0IiwiYWNjb3VudFJlcGxpY2FzIiwiZmlsdGVyIiwiYWNjb3VudCIsIm1hcCIsImNvbnN0cnVjdG9yIiwiaHR0cENsaWVudCJdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7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