/* This file is part of ethereum.js. ethereum.js is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ethereum.js is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ /** * @file method.js * @author Marek Kotewicz * @date 2015 */ var utils = require('../utils/utils'); var errors = require('./errors'); var Method = function (options) { this.name = options.name; this.call = options.call; this.params = options.params || 0; this.inputFormatter = options.inputFormatter; this.outputFormatter = options.outputFormatter; this.requestManager = null; }; Method.prototype.setRequestManager = function (rm) { this.requestManager = rm; }; /** * Should be used to determine name of the jsonrpc method based on arguments * * @method getCall * @param {Array} arguments * @return {String} name of jsonrpc method */ Method.prototype.getCall = function (args) { return utils.isFunction(this.call) ? this.call(args) : this.call; }; /** * Should be used to extract callback from array of arguments. Modifies input param * * @method extractCallback * @param {Array} arguments * @return {Function|Null} callback, if exists */ Method.prototype.extractCallback = function (args) { if (utils.isFunction(args[args.length - 1])) { return args.pop(); // modify the args array! } }; /** * Should be called to check if the number of arguments is correct * * @method validateArgs * @param {Array} arguments * @throws {Error} if it is not */ Method.prototype.validateArgs = function (args) { if (args.length !== this.params) { throw errors.InvalidNumberOfParams(); } }; /** * Should be called to format input args of method * * @method formatInput * @param {Array} * @return {Array} */ Method.prototype.formatInput = function (args) { if (!this.inputFormatter) { return args; } return this.inputFormatter.map(function (formatter, index) { return formatter ? formatter(args[index]) : args[index]; }); }; /** * Should be called to format output(result) of method * * @method formatOutput * @param {Object} * @return {Object} */ Method.prototype.formatOutput = function (result) { return this.outputFormatter && result ? this.outputFormatter(result) : result; }; /** * Should create payload from given input args * * @method toPayload * @param {Array} args * @return {Object} */ Method.prototype.toPayload = function (args) { var call = this.getCall(args); var callback = this.extractCallback(args); var params = this.formatInput(args); this.validateArgs(params); return { method: call, params: params, callback: callback }; }; Method.prototype.attachToObject = function (obj) { var func = this.buildCall(); // func.call = this.call; // that's ugly. filter.js uses it var name = this.name.split('.'); if (name.length > 1) { obj[name[0]] = obj[name[0]] || {}; obj[name[0]][name[1]] = func; } else { obj[name[0]] = func; } }; Method.prototype.buildCall = function() { var method = this; return function send() { var payload = method.toPayload(Array.prototype.slice.call(arguments)); if (payload.callback) { return method.requestManager.sendAsync(payload, function (err, result) { payload.callback(err, method.formatOutput(result)); }); } return method.formatOutput(method.requestManager.send(payload)); }; }; module.exports = Method;