nano-wallet-js-test-1
Version:
SDK for developers to create and interact with Nanocurrency wallet easily
143 lines (142 loc) • 5.4 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const Constants_1 = require("../Constants");
const logger_1 = __importDefault(require("../logger"));
const LOG_REQUEST_RESPONSE = false;
class NanoRPC {
rpcUrls;
workerUrls;
timeout;
logger;
constructor({ rpcUrls, workerUrls, timeout = Constants_1.DEFAULT_TIMEOUT, debug = false, }) {
this.rpcUrls = rpcUrls instanceof Array ? rpcUrls : [rpcUrls];
if (this.rpcUrls.length < 0) {
throw new Error('No RPC addresses provided');
}
this.rpcUrls.forEach(addr => {
try {
new URL(addr);
}
catch (err) {
throw new Error(`Invalid RPC address: ${addr}`);
}
});
this.workerUrls = workerUrls instanceof Array ? workerUrls : [workerUrls];
if (this.workerUrls.length < 0) {
throw new Error('No workers addresses provided');
}
this.workerUrls.forEach(addr => {
try {
new URL(addr);
}
catch (err) {
throw new Error(`Invalid workers address: ${addr}`);
}
});
this.timeout = timeout;
this.logger = new logger_1.default('NANO_RPC', debug);
}
async postRPC(data, urls = this.rpcUrls, retry = 0) {
const url = urls[retry];
const startedAt = Date.now();
try {
const response = await (0, utils_1.fetchWithTimeout)(url, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
},
timeout: this.timeout,
});
const took = Date.now() - startedAt;
if (!response?.ok) {
this.logger.error(`url: ${url} | action: ${data.action} | status: ${response.status} (${response.statusText}) | took: ${took}ms`, LOG_REQUEST_RESPONSE
? `\n\t- Request: ${JSON.stringify(data)}\n\t- Response: ${JSON.stringify(await response.text())}`
: '');
throw new Error('bad status in response');
}
let body;
// clone, so we can consume the body if response.json() fails
const responseClone = response.clone();
try {
body = await response.json();
}
catch (err) {
this.logger.error(`url: ${url} | action: ${data.action} | status: bad json in response | took: ${took}ms`, LOG_REQUEST_RESPONSE
? `\n\t- Request: ${JSON.stringify(data)}\n\t- Response: ${await responseClone.clone().text()}`
: '');
throw new Error('bad json in response');
}
if (typeof body === 'object' && 'error' in body) {
throw new Error(body.error);
}
this.logger.info(`url: ${url} | action: ${data.action} | status: ${response.status} | took: ${took}ms`, LOG_REQUEST_RESPONSE
? `\n\t- Request: ${JSON.stringify(data)}\n\t- Response: ${JSON.stringify(body)}`
: '');
return body;
}
catch (error) {
const isRetryableError = error instanceof DOMException &&
(error.name === 'AbortError' ||
error.message === 'bad status in response' ||
error.message === 'bad json in response');
const canRetry = isRetryableError && retry < urls.length - 1;
if (error instanceof DOMException && error.name === 'AbortError') {
const took = Date.now() - startedAt;
this.logger.error(`url: ${url} | action: ${data.action} | status: ${error.message} | took: ${took}ms | will retry: ${canRetry}`, LOG_REQUEST_RESPONSE ? `\n\t- Request: ${JSON.stringify(data)}` : '');
}
if (canRetry) {
return await this.postRPC(data, urls, retry + 1);
}
throw error;
}
}
async process(block) {
const data = {
action: 'process',
json_block: 'true',
block,
};
return this.postRPC(data);
}
async workGenerate(hash, difficulty) {
const data = {
action: 'work_generate',
hash,
difficulty,
};
return this.postRPC(data, this.workerUrls);
}
async accountInfo(account) {
const data = {
action: 'account_info',
account,
representative: true,
weight: true,
receivable: true,
};
return this.postRPC(data);
}
async accountBalance(account) {
const data = {
action: 'account_balance',
account,
receivable: true,
};
return this.postRPC(data);
}
async receivable(account, { count = 100, threshold = '1' }) {
const data = {
action: 'receivable',
account,
count,
threshold,
};
return this.postRPC(data);
}
}
exports.default = NanoRPC;