Source: rest.js

// 在package.json中的browser属性中设置{lib/rest.js : lib/browser/rest.js}以使用相应环境下的实现
import _ from "lodash";
import restSendTX from "./restSendTX";
import restGet from "./restGet";

class RestAPI {
    /**
     * Creates an instance of RestAPI.
     * <br />
     * 与RepChain网络节点交互的Restful API客户端.
     * 
     * @param {!string} address RepChain节点Restful API服务地址
     * @returns {RestAPI} RestAPI对象实例
     */
    constructor(address) {
        if (!_.isString(address)) throw new TypeError("The address param should be a string");
        this._address = address;
    }

    /**
     * 区块链的概要信息
     * 
     * @typedef {Object} ChainInfo 
     * @property {number} height - 最新区块高度
     * @property {string} currentBlockHash - 最新区块哈希值(base64编码字符串)
     * @property {string} previousBlockHash - 最新区块的父区块哈希值(base64编码字符串)
     * @property {string} currentStateHash - 世界状态哈希值(base64编码字符串)
     * @property {number} totalTransactions - 交易总量
     * @memberof RestAPI
     */
    /**
     * 获取区块链的当前概要信息
     *
     * @returns {Promise<ChainInfo>} Json格式信息[ChainInfo]{@link RestAPI.ChainInfo}
     * @memberof RestAPI
     */
    chainInfo() {
        const url = `${this._address}/chaininfo`;
        return restGet(url).then((chainInfo) => {
            const r = chainInfo;
            r.height = parseInt(r.height, 10);
            r.totalTransactions = parseInt(r.totalTransactions, 10);
            return r;
        });
    }

    /**
     * 获取区块链最新区块高度
     * @returns {Promise<number>} 区块高度
     * @memberof RestAPI
     */
    chainHeight() {
        return this.chainInfo().then(chainInfo => chainInfo.height);
    }

    /**
     * 获取最新区块哈希值
     *
     * @returns {Promise<string>} 区块哈希值(base64编码字符串)
     * @memberof RestAPI
     */
    chainCurrentBlockHash() {
        return this.chainInfo().then(chainInfo => chainInfo.currentBlockHash);
    }

    /**
     * 获取最新区块的父区块哈希值
     *
     * @returns {Promise<string>} 最新区块的父区块哈希值(base64编码字符串)
     * @memberof RestAPI
     */
    chainPreviousBlockHash() {
        return this.chainInfo().then(chainInfo => chainInfo.previousBlockHash);
    }

    /**
     * 获取当前的世界状态哈希值
     *
     * @returns {Promise<string>} 世界状态哈希值(base64编码字符串)
     * @memberof RestAPI
     */
    chainCurrentStateHash() {
        return this.chainInfo().then(chainInfo => chainInfo.currentStateHash);
    }

    /**
     * 获取区块链中的交易总数量
     *
     * @returns {Promise<number>} 交易总量
     * @memberof RestAPI
     */
    chainTotalTransactions() {
        return this.chainInfo().then(chainInfo => chainInfo.totalTransactions);
    }

    /**
     * 获取区块数据
     * 
     * @param {number | string | Buffer} id 区块唯一标识,可为区块高度(number)或区块哈希值(base64编码字符串或二进制数据)
     * @param {string} [blockFormat="JSON"] 期望返回的区块数据的格式,可为JSON或STREAM
     * @returns {Promise<Object> | Promise<Buffer>} 区块数据
     * @memberof RestAPI
     */
    block(id, blockFormat = "JSON") {
        let blockID = id;
        if (!_.isInteger(blockID) && !_.isString(blockID) && !Buffer.isBuffer(blockID)) {
            throw new TypeError("The id param should be an integer/string/Buffer");
        }
        const blockEnumFormats = ["JSON", "STREAM"];
        if (_.indexOf(blockEnumFormats, blockFormat) === -1) {
            throw new RangeError(`The blockFormat param should be one of ${blockEnumFormats}`);
        }

        let url = `${this._address}/block`;
        if (blockFormat === "STREAM") {
            url = `${url}/stream`;
        }
        if (_.isString(blockID) || Buffer.isBuffer(blockID)) {
            url = `${url}/hash`;
            if (Buffer.isBuffer(blockID)) blockID = blockID.toString("base64");
        }
        url = `${url}/${blockID}`;

        return restGet(url);
    }

    /**
     * 获取交易数据
     *
     * @param {string} id 交易唯一标识,即txid
     * @param {string} [txFormat="JSON"] 期望返回的交易数据的格式
     * @param {string} [withBlockHeight=false] 返回交易数据中是否包含区块高度,当txFormat="JSON"时才有效
     * @returns {Promise<Object> | Promise<Buffer>}
     */
    transaction(id, txFormat = "JSON", withBlockHeight = false) {
        if (!_.isString(id)) {
            throw new TypeError("The id param should be a string");
        }
        const txEnumFormats = ["JSON", "STREAM"];
        if (_.indexOf(txEnumFormats, txFormat) === -1) {
            throw new RangeError(`The txFormat param should be one of ${txEnumFormats}`);
        }
        let url = `${this._address}/transaction`;
        if (txFormat === "STREAM") {
            url = `${url}/stream`;
        } else if (withBlockHeight) {
            url = `${url}/tranInfoAndHeight`;
        }
        url = `${url}/${id}`;

        return restGet(url);
    }

    /**
     * 发送签名交易
     * 
     * @param {Buffer | String} tx 待发送的已签名交易数据,支持使用Buffer类型数据或其hex编码的String数据
     * @returns {Promise<{txid: string}> | Promise<{err: string}>} 接收交易后RepChain节点的返回信息
     */
    sendTransaction(tx) {
        return restSendTX(tx, this._address);
    }
}

export default RestAPI;