UNPKG

postchain-client

Version:

Client library for accessing a Postchain node through REST.

202 lines 10.3 kB
"use strict"; 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()); }); }; import { Buffer } from "buffer"; import { ResponseStatus, } from "./types"; import * as logger from "../logger"; import { EmptyListOfUrlsException, LostMessageError, SerializedTransactionFormatException, TxRejectedError, UnexpectedResponseError, UnexpectedStatusError, InvalidTxRidException, } from "./errors"; import { toBuffer, toQueryObjectGTV } from "../formatter"; import { convertToPrintable, requestWithFailoverStrategy, } from "./restclientutil"; import { encodeValue } from "../gtx/serialization"; import { Method } from "./enums"; import { FailoverStrategy } from "../blockchainClient/enums"; import { createEndpointObjects, getUrlsFromEndpoints, } from "../blockchainClient/utils"; import { isTxRidValid } from "../blockchainClient/validation/txRid"; import { createNodeManager } from "./nodeManager"; export function createRestClient(endpointPool, blockchainRid, maxSockets = 10, pollingInterval = 500, failOverConfig, unreachableDuration = 5000, useStickyNode = false) { validateInput(endpointPool, failOverConfig !== null && failOverConfig !== void 0 ? failOverConfig : {}); return { config: { nodeManager: createNodeManager({ nodeUrls: endpointPool, useStickyNode, }), endpointPool: createEndpointObjects(endpointPool), pool: { maxSockets }, pollingInterval, failoverStrategy: (failOverConfig === null || failOverConfig === void 0 ? void 0 : failOverConfig.strategy) || FailoverStrategy.AbortOnError, attemptsPerEndpoint: (failOverConfig === null || failOverConfig === void 0 ? void 0 : failOverConfig.attemptsPerEndpoint) || 3, attemptInterval: (failOverConfig === null || failOverConfig === void 0 ? void 0 : failOverConfig.attemptInterval) || 500, unreachableDuration: unreachableDuration, }, getTransaction: function (txRID, callback) { return __awaiter(this, void 0, void 0, function* () { if (!isTxRidValid(txRID)) { callback(new InvalidTxRidException(txRID), null); } else { const { error, statusCode, rspBody } = yield requestWithFailoverStrategy(Method.GET, `tx/${blockchainRid}/${txRID.toString("hex")}`, this.config); handleGetResponse(error, statusCode, statusCode === 200 ? toBuffer(rspBody.tx) : rspBody, callback); } }); }, postTransaction: function (serializedTransaction, callback) { return __awaiter(this, void 0, void 0, function* () { if (!Buffer.isBuffer(serializedTransaction)) { throw new SerializedTransactionFormatException(); } const transactionObject = { tx: serializedTransaction.toString("hex"), }; const { error, statusCode, rspBody } = yield requestWithFailoverStrategy(Method.POST, `tx/${blockchainRid}`, this.config, transactionObject); handlePostResponse(error, statusCode, rspBody, callback); }); }, status: function (txRID, callback) { return __awaiter(this, void 0, void 0, function* () { if (!isTxRidValid(txRID)) { callback(new InvalidTxRidException(txRID), null); } else { const { error, statusCode, rspBody } = yield requestWithFailoverStrategy(Method.GET, `tx/${blockchainRid}/${txRID.toString("hex")}/status`, this.config); handleGetResponse(error, statusCode, rspBody, callback); } }); }, query: function (nameOrQueryObject, queryArguments) { return __awaiter(this, void 0, void 0, function* () { // eslint-disable-next-line no-async-promise-executor return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { const callback = (error, result) => { if (error) { reject(error); } else { resolve(result); } }; const { error, statusCode, rspBody } = yield requestWithFailoverStrategy(Method.POST, `query_gtv/${blockchainRid}`, this.config, encodeValue(toQueryObjectGTV(nameOrQueryObject, queryArguments))); handlePostResponse(error, statusCode, rspBody, callback); })); }); }, waitConfirmation(txRID) { return new Promise((resolve, reject) => { this.status(txRID, (error, result) => { if (error) { reject(error); } else { const status = result.status; switch (status) { case ResponseStatus.Confirmed: resolve(null); break; case ResponseStatus.Rejected: reject(new TxRejectedError(result.rejectReason)); break; case ResponseStatus.Unknown: reject(new LostMessageError()); break; case ResponseStatus.Waiting: setTimeout(() => this.waitConfirmation(txRID).then(resolve, reject), this.config.pollingInterval); break; default: logger.error(status); reject(new UnexpectedResponseError()); } } }); }); }, postAndWaitConfirmation(serializedTransaction, txRID, validate) { if (validate === true) { return Promise.reject("Automatic validation is not yet implemented"); } return new Promise((resolve, reject) => { this.postTransaction(serializedTransaction, (error) => { if (error) reject(error); else { setTimeout(() => this.waitConfirmation(txRID).then(resolve, reject), 1011); } }); }); }, getEndpointPool() { return getUrlsFromEndpoints(this.config.endpointPool); }, }; } function validateInput(endpointPool, failOverConfig) { if (!endpointPool.length) { throw new EmptyListOfUrlsException(); } if ((failOverConfig === null || failOverConfig === void 0 ? void 0 : failOverConfig.attemptsPerEndpoint) && failOverConfig.attemptsPerEndpoint < 1) { logger.debug("Attempts can not be 0 or below, setting it to 1"); failOverConfig.attemptsPerEndpoint = 1; } } /** * @param error response error * @param statusCode response status code * @param responseObject the responsebody from the server * @param callback the callback function to propagate the error and response back to the caller */ export function handleGetResponse(error, statusCode, responseObject, callback) { try { const responseObjectPrintable = convertToPrintable(responseObject); logger.debug(`error: ${error}, status code: ${statusCode}, response body: ${responseObjectPrintable}`); if (error) { return callback(error, null); } if (statusCode !== 200) { return callback(new UnexpectedStatusError(statusCode !== null && statusCode !== void 0 ? statusCode : 400, responseObjectPrintable), null); } return callback(null, responseObject); } catch (error) { callback(error, null); logger.error(`restclient.handleGetResponse(): Failed to call the callback function. ${error}`); } } /** * @param error response error * @param statusCode response status code * @param responseObject the responsebody from the server * @param callback the callback function to propagate the error and response back to the caller */ export function handlePostResponse(error, statusCode, responseObject, callback) { const responseObjectPrintable = convertToPrintable(responseObject); logger.debug(`error: ${error}, status code: ${statusCode}, response body: ${responseObjectPrintable}`); try { if (error) { logger.error(`In restclient post(). ${error}`); callback(error, null); } else if (statusCode != 200) { let errorMessage = `Unexpected status code from server. Code: ${statusCode}.`; if (responseObjectPrintable) { errorMessage += ` Message: ${responseObjectPrintable}.`; } logger.error(errorMessage); callback(new UnexpectedStatusError(statusCode !== null && statusCode !== void 0 ? statusCode : 400, responseObjectPrintable), responseObject); } else { logger.info(`Calling responseCallback with responseObject: ${responseObjectPrintable}`); callback(null, responseObject); } } catch (error) { logger.error(`restclient.handlePostResponse(): Failed to call callback function ${error}`); } } //# sourceMappingURL=restclient.js.map