Skip to content

Commit

Permalink
add isSyncing and better way of matching batch requests
Browse files Browse the repository at this point in the history
  • Loading branch information
frozeman committed Sep 9, 2015
1 parent f18b532 commit 4159295
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 19 deletions.
5 changes: 5 additions & 0 deletions lib/web3.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var db = require('./web3/methods/db');
var shh = require('./web3/methods/shh');
var watches = require('./web3/methods/watches');
var Filter = require('./web3/filter');
var IsSyncing = require('./web3/syncing');
var utils = require('./utils/utils');
var formatters = require('./web3/formatters');
var RequestManager = require('./web3/requestmanager');
Expand Down Expand Up @@ -85,6 +86,10 @@ web3.version = {};
web3.version.api = version.version;
web3.eth = {};

web3.eth.isSyncing = function (callback) {
return new IsSyncing(callback);
};

/*jshint maxparams:4 */
web3.eth.filter = function (fil, callback) {
return new Filter(fil, watches.eth(), formatters.outputLogFormatter, callback);
Expand Down
12 changes: 7 additions & 5 deletions lib/web3/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,14 @@ var pollFilter = function(self) {
});
}

messages.forEach(function (message) {
message = self.formatter ? self.formatter(message) : message;
self.callbacks.forEach(function (callback) {
callback(null, message);
if(utils.isArray(messages)) {
messages.forEach(function (message) {
message = self.formatter ? self.formatter(message) : message;
self.callbacks.forEach(function (callback) {
callback(null, message);
});
});
});
}
};

RequestManager.getInstance().startPolling({
Expand Down
13 changes: 12 additions & 1 deletion lib/web3/formatters.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,16 @@ var inputAddressFormatter = function (address) {
throw 'invalid address';
};


var outputSyncingFormatter = function(result) {

result.startingBlock = utils.toDecimal(result.startingBlock);
result.currentBlock = utils.toDecimal(result.currentBlock);
result.highestBlock = utils.toDecimal(result.highestBlock);

return result;
};

module.exports = {
inputDefaultBlockNumberFormatter: inputDefaultBlockNumberFormatter,
inputBlockNumberFormatter: inputBlockNumberFormatter,
Expand All @@ -282,6 +292,7 @@ module.exports = {
outputTransactionReceiptFormatter: outputTransactionReceiptFormatter,
outputBlockFormatter: outputBlockFormatter,
outputLogFormatter: outputLogFormatter,
outputPostFormatter: outputPostFormatter
outputPostFormatter: outputPostFormatter,
outputSyncingFormatter: outputSyncingFormatter
};

4 changes: 4 additions & 0 deletions lib/web3/methods/eth.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,10 @@ var properties = [
getter: 'eth_hashrate',
outputFormatter: utils.toDecimal
}),
new Property({
name: 'syncing',
getter: 'eth_syncing'
}),
new Property({
name: 'gasPrice',
getter: 'eth_gasPrice',
Expand Down
23 changes: 15 additions & 8 deletions lib/web3/requestmanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,20 +209,29 @@ RequestManager.prototype.poll = function () {
}

var pollsData = [];
var pollsKeys = [];
var pollsIds = [];
for (var key in this.polls) {
pollsData.push(this.polls[key].data);
pollsKeys.push(key);
pollsIds.push(key);
}

if (pollsData.length === 0) {
return;
}

var payload = Jsonrpc.getInstance().toBatchPayload(pollsData);

// map the request id to they poll id
var pollsIdMap = {};
payload.forEach(function(load, index){
pollsIdMap[load.id] = pollsIds[index];
});


var self = this;
this.provider.sendAsync(payload, function (error, results) {


// TODO: console log?
if (error) {
return;
Expand All @@ -231,12 +240,12 @@ RequestManager.prototype.poll = function () {
if (!utils.isArray(results)) {
throw errors.InvalidResponse(results);
}

results.map(function (result, index) {
var key = pollsKeys[index];
var id = pollsIdMap[result.id];

// make sure the filter is still installed after arrival of the request
if (self.polls[key]) {
result.callback = self.polls[key].callback;
if (self.polls[id]) {
result.callback = self.polls[id].callback;
return result;
} else
return false;
Expand All @@ -248,8 +257,6 @@ RequestManager.prototype.poll = function () {
result.callback(errors.InvalidResponse(result));
}
return valid;
}).filter(function (result) {
return utils.isArray(result.result) && result.result.length > 0;
}).forEach(function (result) {
result.callback(null, result.result);
});
Expand Down
101 changes: 101 additions & 0 deletions lib/web3/syncing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
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 syncing.js
* @authors:
* Fabian Vogelsteller <fabian@ethdev.com>
* @date 2015
*/

var RequestManager = require('./requestmanager');
var Method = require('./method');
var formatters = require('./formatters');
var utils = require('../utils/utils');



/**
Adds the callback and sets up the methods, to iterate over the results.
@method pollSyncing
@param {Object} self
*/
var pollSyncing = function(self) {
var lastSyncState = false;

var onMessage = function (error, sync) {
if (error) {
return self.callbacks.forEach(function (callback) {
callback(error);
});
}

if(utils.isObject(sync))
sync = self.implementation.outputFormatter(sync);

self.callbacks.forEach(function (callback) {
if(lastSyncState !== sync) {

// call the callback with true first so the app can stop anything, before receiving the sync data
if(!lastSyncState && utils.isObject(sync))
callback(null, true);

// call on the next CPU cycle, so the actions of the sync stop can be processes first
setTimeout(function() {
callback(null, sync);
}, 1);

lastSyncState = sync;
}
});
};

RequestManager.getInstance().startPolling({
method: self.implementation.call,
params: [],
}, self.pollId, onMessage, self.stopWatching.bind(self));

};

var IsSyncing = function (callback) {
this.pollId = 'syncPoll_'+ Math.floor(Math.random() * 1000);
this.callbacks = [];
this.implementation = new Method({
name: 'isSyncing',
call: 'eth_syncing',
params: 0,
outputFormatter: formatters.outputSyncingFormatter
});

this.addCallback(callback);
pollSyncing(this);

return this;
};

IsSyncing.prototype.addCallback = function (callback) {
if(callback)
this.callbacks.push(callback);
return this;
};

IsSyncing.prototype.stopWatching = function () {
RequestManager.getInstance().stopPolling(this.pollId);
this.callbacks = [];
};

module.exports = IsSyncing;

3 changes: 3 additions & 0 deletions test/contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ describe('contract', function () {
assert.equal(result.args.t2, 8);
res++;
if (res === 2) {
event.stopWatching();
done();
}
});
Expand Down Expand Up @@ -191,6 +192,7 @@ describe('contract', function () {
assert.equal(result.args.t2, 8);
res++;
if (res === 2) {
event.stopWatching();
done();
}
});
Expand Down Expand Up @@ -257,6 +259,7 @@ describe('contract', function () {
assert.equal(result.args.t2, 8);
res++;
if (res === 2) {
event.stopWatching();
done();
}
});
Expand Down
25 changes: 20 additions & 5 deletions test/helpers/FakeHttpProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ var chai = require('chai');
var assert = require('assert');
var utils = require('../../lib/utils/utils');

countId = 1;

var getResponseStub = function () {
return {
jsonrpc: '2.0',
id: 1,
id: countId++,
result: 0
};
};

var getErrorStub = function () {
return {
jsonrpc: '2.0',
id: 1,
countId: countId++,
error: {
code: 1234,
message: ''
Expand All @@ -37,7 +39,8 @@ FakeHttpProvider.prototype.send = function (payload) {
// imitate plain json object
this.validation(JSON.parse(JSON.stringify(payload)));
}
return this.getResponse();

return this.getResponse(payload);
};

FakeHttpProvider.prototype.sendAsync = function (payload, callback) {
Expand All @@ -47,7 +50,8 @@ FakeHttpProvider.prototype.sendAsync = function (payload, callback) {
// imitate plain json object
this.validation(JSON.parse(JSON.stringify(payload)), callback);
}
callback(this.error, this.getResponse());

callback(this.error, this.getResponse(payload));
};

FakeHttpProvider.prototype.injectResponse = function (response) {
Expand All @@ -72,7 +76,18 @@ FakeHttpProvider.prototype.injectBatchResults = function (results, error) {
});
};

FakeHttpProvider.prototype.getResponse = function () {
FakeHttpProvider.prototype.getResponse = function (payload) {

if(this.response) {
if(utils.isArray(this.response)) {
this.response = this.response.map(function(response, index) {
response.id = payload[index] ? payload[index].id : countId++;
return response;
});
} else
this.response.id = payload.id;
}

return this.response;
};

Expand Down
2 changes: 2 additions & 0 deletions test/polling.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ var testPolling = function (tests) {
} else {
assert.equal(result, test.secondResult[0]);
}
filter.stopWatching();
done();

});
Expand Down Expand Up @@ -102,6 +103,7 @@ var testPolling = function (tests) {
} else {
assert.equal(result, test.secondResult[0]);
}
filter.stopWatching();
done();

});
Expand Down
4 changes: 4 additions & 0 deletions test/web3.eth.hashRate.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ describe('web3.eth', function () {

// then
assert.strictEqual(test.formattedResult, result);

// clear the validation
provider.injectValidation(function () {});
web3.reset();
});
});
});
Expand Down
Loading

0 comments on commit 4159295

Please sign in to comment.