httprpc.js 4.03 KB
Newer Older
Marian Oancea's avatar
Marian Oancea committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
    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 <http://www.gnu.org/licenses/>.
*/
/** @file httprpc.js
 * @authors:
 *   Marek Kotewicz <marek@ethdev.com>
 *   Marian Oancea <marian@ethdev.com>
 * @date 2014
 */

Marek Kotewicz's avatar
Marek Kotewicz committed
24
// TODO: is these line is supposed to be here? 
Marek Kotewicz's avatar
Marek Kotewicz committed
25
if (process.env.NODE_ENV !== 'build') {
Marian Oancea's avatar
Marian Oancea committed
26
    var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
Marek Kotewicz's avatar
Marek Kotewicz committed
27
}
Marian Oancea's avatar
Marian Oancea committed
28

Marek Kotewicz's avatar
Marek Kotewicz committed
29 30 31 32 33 34 35
/**
 * HttpRpcProvider object prototype is implementing 'provider protocol'
 * Should be used when we want to connect to ethereum backend over http && jsonrpc
 * It's compatible with cpp client
 * The contructor allows to specify host uri
 * This provider is using in-browser polling mechanism
 */
Marek Kotewicz's avatar
Marek Kotewicz committed
36 37 38 39
var HttpRpcProvider = function (host) {
    this.handlers = [];
    this.host = host;
};
Marian Oancea's avatar
Marian Oancea committed
40

Marek Kotewicz's avatar
Marek Kotewicz committed
41 42 43
/// Transforms inner message to proper jsonrpc object
/// @param inner message object
/// @returns jsonrpc object
Marek Kotewicz's avatar
Marek Kotewicz committed
44 45 46 47 48 49
function formatJsonRpcObject(object) {
    return {
        jsonrpc: '2.0',
        method: object.call,
        params: object.args,
        id: object._id
Marian Oancea's avatar
Marian Oancea committed
50
    };
Marek Kotewicz's avatar
Marek Kotewicz committed
51
}
Marian Oancea's avatar
Marian Oancea committed
52

Marek Kotewicz's avatar
Marek Kotewicz committed
53 54 55
/// Transforms jsonrpc object to inner message
/// @param incoming jsonrpc message 
/// @returns inner message object
Marek Kotewicz's avatar
Marek Kotewicz committed
56 57
function formatJsonRpcMessage(message) {
    var object = JSON.parse(message);
Marian Oancea's avatar
Marian Oancea committed
58

Marek Kotewicz's avatar
Marek Kotewicz committed
59 60 61 62
    return {
        _id: object.id,
        data: object.result,
        error: object.error
Marian Oancea's avatar
Marian Oancea committed
63
    };
Marek Kotewicz's avatar
Marek Kotewicz committed
64
}
Marian Oancea's avatar
Marian Oancea committed
65

Marek Kotewicz's avatar
Marek Kotewicz committed
66 67 68 69
/// Prototype object method 
/// Asynchronously sends request to server
/// @param payload is inner message object
/// @param cb is callback which is being called when response is comes back
Marek Kotewicz's avatar
Marek Kotewicz committed
70 71 72 73 74 75 76 77 78 79
HttpRpcProvider.prototype.sendRequest = function (payload, cb) {
    var data = formatJsonRpcObject(payload);

    var request = new XMLHttpRequest();
    request.open("POST", this.host, true);
    request.send(JSON.stringify(data));
    request.onreadystatechange = function () {
        if (request.readyState === 4 && cb) {
            cb(request);
        }
Marian Oancea's avatar
Marian Oancea committed
80
    };
Marek Kotewicz's avatar
Marek Kotewicz committed
81
};
Marian Oancea's avatar
Marian Oancea committed
82

Marek Kotewicz's avatar
Marek Kotewicz committed
83 84 85 86 87
/// Prototype object method
/// Should be called when we want to send single api request to server
/// Asynchronous
/// On response it passes message to handlers
/// @param payload is inner message object
Marek Kotewicz's avatar
Marek Kotewicz committed
88 89 90 91 92
HttpRpcProvider.prototype.send = function (payload) {
    var self = this;
    this.sendRequest(payload, function (request) {
        self.handlers.forEach(function (handler) {
            handler.call(self, formatJsonRpcMessage(request.responseText));
Marian Oancea's avatar
Marian Oancea committed
93
        });
Marek Kotewicz's avatar
Marek Kotewicz committed
94 95
    });
};
Marian Oancea's avatar
Marian Oancea committed
96

Marek Kotewicz's avatar
Marek Kotewicz committed
97 98 99 100 101 102 103
/// Prototype object method
/// Should be called only for polling requests
/// Asynchronous
/// On response it passege message to handlers, but only if message's result is true or not empty array
/// Otherwise response is being silently ignored
/// @param payload is inner message object
/// @id is id of poll that we are calling
Marek Kotewicz's avatar
Marek Kotewicz committed
104 105 106 107 108 109
HttpRpcProvider.prototype.poll = function (payload, id) {
    var self = this;
    this.sendRequest(payload, function (request) {
        var parsed = JSON.parse(request.responseText);
        if (parsed.error || (parsed.result instanceof Array ? parsed.result.length === 0 : !parsed.result)) {
            return;
Marian Oancea's avatar
Marian Oancea committed
110
        }
Marek Kotewicz's avatar
Marek Kotewicz committed
111 112 113
        self.handlers.forEach(function (handler) {
            handler.call(self, {_event: payload.call, _id: id, data: parsed.result});
        });
Marian Oancea's avatar
Marian Oancea committed
114
    });
Marek Kotewicz's avatar
Marek Kotewicz committed
115 116
};

Marek Kotewicz's avatar
Marek Kotewicz committed
117 118
/// Prototype object property
/// Should be used to set message handlers for this provider
Marek Kotewicz's avatar
Marek Kotewicz committed
119 120 121 122 123
Object.defineProperty(HttpRpcProvider.prototype, "onmessage", {
    set: function (handler) {
        this.handlers.push(handler);
    }
});
Marian Oancea's avatar
Marian Oancea committed
124 125

module.exports = HttpRpcProvider;
Marek Kotewicz's avatar
Marek Kotewicz committed
126