postchain-client
Version:
Client library for accessing a Postchain node through REST.
202 lines • 10.3 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());
});
};
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
;