@fruitsjs/core
Version:
Principal package with functions and models for building Fruits Eco-Blockchain applications.
127 lines • 6.29 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChainService = void 0;
const http_1 = require("@fruitsjs/http");
const util_1 = require("@fruitsjs/util");
const constants_1 = require("../constants");
class SettingsImpl {
constructor(settings) {
this.apiRootUrl = settings.apiRootUrl || constants_1.DefaultApiEndpoint;
this.nodeHost = settings.nodeHost;
this.httpClient = settings.httpClient || http_1.HttpClientFactory.createHttpClient(settings.nodeHost, settings.httpClientOptions);
this.reliableNodeHosts = settings.reliableNodeHosts || [];
}
}
class ChainService {
constructor(settings) {
this._relPath = constants_1.DefaultApiEndpoint;
this.settings = new SettingsImpl(settings);
const { apiRootUrl } = this.settings;
if (apiRootUrl) {
this._relPath = apiRootUrl.endsWith('/') ? apiRootUrl.substr(0, apiRootUrl.length - 1) : apiRootUrl;
}
}
static throwAsHttpError(url, apiError) {
const errorCode = apiError.errorCode && ` (Code: ${apiError.errorCode})` || '';
throw new http_1.HttpError(url, 400, `${apiError.errorDescription || apiError.error}${errorCode}`, apiError);
}
toApiEndpoint(method, data = {}) {
const request = `${this._relPath}?requestType=${method}`;
const params = Object.keys(data)
.filter(k => data[k] !== undefined)
.map(k => `${k}=${encodeURIComponent(data[k])}`)
.join('&');
return params ? `${request}&${params}` : request;
}
query(method, args = {}, options) {
return __awaiter(this, void 0, void 0, function* () {
const endpoint = this.toApiEndpoint(method, args);
const { response } = yield this.faultTolerantRequest(() => this.settings.httpClient.get(endpoint, options));
if (response.errorCode || response.error || response.errorDescription) {
ChainService.throwAsHttpError(endpoint, response);
}
return response;
});
}
send(method, args = {}, body = {}, options) {
return __awaiter(this, void 0, void 0, function* () {
const endpoint = this.toApiEndpoint(method, args);
const { response } = yield this.faultTolerantRequest(() => this.settings.httpClient.post(endpoint, body, options));
if (response.errorCode || response.error || response.errorDescription) {
ChainService.throwAsHttpError(endpoint, response);
}
return response;
});
}
sendBodyString(method, args = {}, body, options) {
return __awaiter(this, void 0, void 0, function* () {
const endpoint = this.toApiEndpoint(method, args);
const { response } = yield this.faultTolerantRequest(() => this.settings.httpClient.post(endpoint, body, options));
if (response.errorCode || response.error || response.errorDescription) {
ChainService.throwAsHttpError(endpoint, response);
}
return response;
});
}
faultTolerantRequest(requestFn) {
return __awaiter(this, void 0, void 0, function* () {
const onFailureAsync = (e, retrialCount) => __awaiter(this, void 0, void 0, function* () {
const shouldRetry = this.settings.reliableNodeHosts.length && retrialCount < this.settings.reliableNodeHosts.length;
if (shouldRetry) {
yield this.selectBestHost(true);
}
return shouldRetry;
});
return yield (0, util_1.asyncRetry)({
asyncFn: requestFn,
onFailureAsync
});
});
}
selectBestHost(reconfigure = false, checkMethod = 'getBlockchainStatus') {
return __awaiter(this, void 0, void 0, function* () {
if (!this.settings.reliableNodeHosts.length) {
throw new Error('No reliableNodeHosts configured');
}
const checkEndpoint = this.toApiEndpoint(checkMethod);
let timeout = null;
const requests = this.settings.reliableNodeHosts.map(host => {
const absoluteUrl = `${host}${checkEndpoint}`;
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
try {
yield this.settings.httpClient.get(absoluteUrl);
resolve(host);
}
catch (e) {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
reject(null);
}, 10 * 1000);
}
}));
});
const bestHost = yield Promise.race(requests);
clearTimeout(timeout);
if (!bestHost) {
throw new Error('All reliableNodeHosts failed');
}
if (reconfigure) {
this.settings = new SettingsImpl(Object.assign(Object.assign({}, this.settings), { httpClient: http_1.HttpClientFactory.createHttpClient(bestHost, this.settings.httpClientOptions), nodeHost: bestHost }));
}
return bestHost;
});
}
}
exports.ChainService = ChainService;
//# sourceMappingURL=chainService.js.map