#!/usr/bin/env node 'use strict'; const Config = require('bcfg'); const {NodeClient} = require('../lib/client'); // NOTE: This is part of generated `hs-client`. // Don't introduce any unnecessary dependencies to this. // This needs to be remain as is for hs-client to be simple. const ports = { main: 12037, testnet: 13037, regtest: 14037, simnet: 15037 }; const HELP = ` Commands: $ block [hash/height]: View block. $ broadcast [tx-hex]: Broadcast transaction. $ coin [hash+index/address]: View coins. $ header [hash/height]: View block header. $ help: Show help message. $ info: Get server info. $ mempool: Get mempool snapshot. $ reset [height/hash]: Reset chain to desired block. $ rpc [command] [args]: Execute RPC command. $ tx [hash/address]: View transactions. For additional information and a complete list of commands visit https://hsd-dev.org/api-docs/ `; class CLI { constructor() { this.config = new Config('hsd', { suffix: 'network', fallback: 'main', alias: { 'n': 'network', 'u': 'url', 'uri': 'url', 'k': 'apikey', 's': 'ssl', 'h': 'httphost', 'p': 'httpport' } }); this.config.load({ argv: true, env: true }); this.config.open('hsd.conf'); this.argv = this.config.argv; this.network = this.config.str('network', 'main'); this.client = new NodeClient({ url: this.config.str('url'), apiKey: this.config.str('api-key'), ssl: this.config.bool('ssl'), host: this.config.str('http-host'), port: this.config.uint('http-port') || ports[this.network] || ports.main, timeout: this.config.uint('timeout'), limit: this.config.uint('limit') }); } log(json) { if (typeof json === 'string') return console.log.apply(console, arguments); return console.log(JSON.stringify(json, null, 2)); } async getInfo() { const info = await this.client.getInfo(); this.log(info); } async getTX() { const hash = this.config.str(0, ''); if (hash.length !== 64) { const txs = await this.client.getTXByAddress(hash); this.log(txs); return; } const tx = await this.client.getTX(hash); if (!tx) { this.log('TX not found.'); return; } this.log(tx); } async getBlock() { let hash = this.config.str(0, ''); if (hash.length !== 64) hash = parseInt(hash, 10); const block = await this.client.getBlock(hash); if (!block) { this.log('Block not found.'); return; } this.log(block); } async getBlockHeader() { let hash = this.config.str(0, ''); if (hash.length !== 64) hash = parseInt(hash, 10); const header = await this.client.getBlockHeader(hash); if (!header) { this.log('Block header not found.'); return; } this.log(header); } async getCoin() { const hash = this.config.str(0, ''); const index = this.config.uint(1); if (hash.length !== 64) { const coins = await this.client.getCoinsByAddress(hash); this.log(coins); return; } const coin = await this.client.getCoin(hash, index); if (!coin) { this.log('Coin not found.'); return; } this.log(coin); } async getMempool() { const txs = await this.client.getMempool(); this.log(txs); } async broadcast() { const raw = this.config.str([0, 'tx']); const tx = await this.client.broadcast(raw); this.log('Broadcasted:'); this.log(tx); } async reset() { let hash = this.config.str(0); if (hash.length !== 64) hash = parseInt(hash, 10); await this.client.reset(hash); this.log('Chain has been reset.'); } async rpc() { const method = this.argv.shift(); if (!method) { this.log('Missing RPC method'); return; } const params = []; for (const arg of this.argv) { let param; try { param = JSON.parse(arg); } catch (e) { param = arg; } params.push(param); } let result; try { result = await this.client.execute(method, params); } catch (e) { if (e.type === 'RPCError') { this.log(e.message); return; } throw e; } this.log(result); } async open() { switch (this.argv.shift()) { case 'block': await this.getBlock(); break; case 'broadcast': await this.broadcast(); break; case 'coin': await this.getCoin(); break; case 'header': await this.getBlockHeader(); break; case 'help': process.stdout.write(HELP + '\n'); break; case 'info': await this.getInfo(); break; case 'mempool': await this.getMempool(); break; case 'reset': await this.reset(); break; case 'rpc': await this.rpc(); break; case 'tx': await this.getTX(); break; default: process.stdout.write('Unrecognized command.\n'); process.stdout.write(HELP + '\n'); break; } } async destroy() { if (this.client && this.client.opened) await this.client.close(); } } (async () => { const cli = new CLI(); await cli.open(); await cli.destroy(); })().catch((err) => { console.error(err.stack); process.exit(1); });