filters refactor

This commit is contained in:
Marek Kotewicz 2015-02-05 23:11:16 +01:00
parent 82cc5f63ae
commit c29f4a1361
8 changed files with 247 additions and 170 deletions

193
dist/ethereum.js vendored
View File

@ -295,6 +295,7 @@ var web3 = require('./web3');
var abi = require('./abi');
var utils = require('./utils');
var eventImpl = require('./event');
var filter = require('./filter');
var exportNatspecGlobals = function (vars) {
// it's used byt natspec.js
@ -416,11 +417,11 @@ var addEventsToContract = function (contract, desc, address) {
var signature = abi.eventSignatureFromAscii(e.name);
var event = eventImpl.inputParser(address, signature, e);
var o = event.apply(null, params);
o._onWatchEventResult = function (data) {
var outputFormatter = function (data) {
var parser = eventImpl.outputParser(e);
return parser(data);
};
return web3.eth.watch(o);
return web3.eth.watch(o, undefined, undefined, outputFormatter);
};
// this property should be used by eth.filter to check if object is an event
@ -487,7 +488,7 @@ var contract = function (address, desc) {
module.exports = contract;
},{"./abi":1,"./event":4,"./utils":12,"./web3":13}],4:[function(require,module,exports){
},{"./abi":1,"./event":4,"./filter":5,"./utils":12,"./web3":13}],4:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -650,84 +651,96 @@ module.exports = {
* @date 2014
*/
var web3 = require('./web3'); // jshint ignore:line
/// Should be called to check if filter implementation is valid
/// @returns true if it is, otherwise false
var implementationIsValid = function (i) {
return !!i &&
typeof i.newFilter === 'function' &&
typeof i.getMessages === 'function' &&
typeof i.uninstallFilter === 'function' &&
typeof i.startPolling === 'function' &&
typeof i.stopPolling === 'function';
};
/// should be used when we want to watch something
/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones
/// @param should be string or object
/// @returns options string or object
var getOptions = function (options) {
if (typeof options === 'string') {
return options;
}
options = options || {};
if (options.topics) {
console.warn('"topics" is deprecated, is "topic" instead');
}
// evaluate lazy properties
return {
to: options.to,
topic: options.topic,
earliest: options.earliest,
latest: options.latest,
max: options.max,
skip: options.skip,
address: options.address
};
};
/// Should be used when we want to watch something
/// it's using inner polling mechanism and is notified about changes
/// TODO: change 'options' name cause it may be not the best matching one, since we have events
var Filter = function(options, impl) {
if (typeof options !== "string") {
// topics property is deprecated, warn about it!
if (options.topics) {
console.warn('"topics" is deprecated, use "topic" instead');
}
this._onWatchResult = options._onWatchEventResult;
// evaluate lazy properties
options = {
to: options.to,
topic: options.topic,
earliest: options.earliest,
latest: options.latest,
max: options.max,
skip: options.skip,
address: options.address
};
/// @param options are filter options
/// @param implementation, an abstract polling implementation
/// @param formatter (optional), callback function which formats output before 'real' callback
var filter = function(options, implementation, formatter) {
if (!implementationIsValid(implementation)) {
console.error('filter implemenation is invalid');
return;
}
options = getOptions(options);
var callbacks = [];
var filterId = implementation.newFilter(options);
var onMessages = function (messages) {
messages.forEach(function (message) {
messages = formatter ? formatter(message) : message;
callbacks.forEach(function (callback) {
callback(message);
});
});
};
implementation.startPolling(filterId, onMessages);
var changed = function (callback) {
callbacks.push(callback);
};
var messages = function () {
return implementation.getMessages(filterId);
};
this.impl = impl;
this.callbacks = [];
var uninstall = function (callback) {
implementation.stopPolling(filterId);
implementation.uninstallFilter(filterId);
callbacks = [];
};
this.id = impl.newFilter(options);
web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this));
return {
changed: changed,
arrived: changed,
happened: changed,
messages: messages,
logs: messages,
uninstall: uninstall
};
};
/// alias for changed*
Filter.prototype.arrived = function(callback) {
this.changed(callback);
};
Filter.prototype.happened = function(callback) {
this.changed(callback);
};
module.exports = filter;
/// gets called when there is new eth/shh message
Filter.prototype.changed = function(callback) {
this.callbacks.push(callback);
};
/// trigger calling new message from people
Filter.prototype.trigger = function(messages) {
for (var i = 0; i < this.callbacks.length; i++) {
for (var j = 0; j < messages.length; j++) {
var message = this._onWatchResult ? this._onWatchResult(messages[j]) : messages[j];
this.callbacks[i].call(this, message);
}
}
};
/// should be called to uninstall current filter
Filter.prototype.uninstall = function() {
this.impl.uninstallFilter(this.id);
web3.provider.stopPolling(this.id);
};
/// should be called to manually trigger getting latest messages from the client
Filter.prototype.messages = function() {
return this.impl.getMessages(this.id);
};
/// alias for messages
Filter.prototype.logs = function () {
return this.messages();
};
module.exports = Filter;
},{"./web3":13}],6:[function(require,module,exports){
},{}],6:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1392,6 +1405,7 @@ if ("build" !== 'build') {/*
var BigNumber = require('bignumber.js');
*/}
var filter = require('./filter');
var utils = require('./utils');
/// @returns an array of objects describing web3 api methods
@ -1573,11 +1587,11 @@ var web3 = {
/// @param filter may be a string, object or event
/// @param indexed is optional, this is an object with optional event indexed params
/// @param options is optional, this is an object with optional event options ('max'...)
watch: function (filter, indexed, options) {
if (filter._isEvent) {
return filter(indexed, options);
watch: function (fil, indexed, options, formatter) {
if (fil._isEvent) {
return fil(indexed, options);
}
return new web3.filter(filter, ethWatch);
return filter(fil, ethWatch, formatter);
}
},
@ -1586,10 +1600,9 @@ var web3 = {
/// shh object prototype
shh: {
/// @param filter may be a string, object or event
watch: function (filter, indexed) {
return new web3.filter(filter, shhWatch);
watch: function (fil) {
return filter(fil, shhWatch);
}
},
};
@ -1601,14 +1614,27 @@ setupProperties(web3.eth, ethProperties());
setupMethods(web3.db, dbMethods());
setupMethods(web3.shh, shhMethods());
var startPolling = function (method, id, callback) {
web3.provider.startPolling({
method: method,
params: [id]
}, id, callback);
};
var stopPolling = function (id) {
web3.provider.stopPolling(id);
};
var ethWatch = {
changed: 'eth_changed'
startPolling: startPolling.bind(null, 'eth_changed'),
stopPolling: stopPolling
};
setupMethods(ethWatch, ethWatchMethods());
var shhWatch = {
changed: 'shh_changed'
startPolling: startPolling.bind(null, 'shh_changed'),
stopPolling: stopPolling
};
setupMethods(shhWatch, shhWatchMethods());
@ -1620,11 +1646,10 @@ web3.setProvider = function(provider) {
module.exports = web3;
},{"./utils":12}],"web3":[function(require,module,exports){
},{"./filter":5,"./utils":12}],"web3":[function(require,module,exports){
var web3 = require('./lib/web3');
var ProviderManager = require('./lib/providermanager');
web3.provider = new ProviderManager();
web3.filter = require('./lib/filter');
web3.providers.HttpSyncProvider = require('./lib/httpsync');
web3.providers.QtSyncProvider = require('./lib/qtsync');
web3.eth.contract = require('./lib/contract');
@ -1633,7 +1658,7 @@ web3.abi = require('./lib/abi');
module.exports = web3;
},{"./lib/abi":1,"./lib/contract":3,"./lib/filter":5,"./lib/httpsync":7,"./lib/providermanager":9,"./lib/qtsync":10,"./lib/web3":13}]},{},["web3"])
},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":7,"./lib/providermanager":9,"./lib/qtsync":10,"./lib/web3":13}]},{},["web3"])
//# sourceMappingURL=ethereum.js.map

10
dist/ethereum.js.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,6 @@
var web3 = require('./lib/web3');
var ProviderManager = require('./lib/providermanager');
web3.provider = new ProviderManager();
web3.filter = require('./lib/filter');
web3.providers.HttpSyncProvider = require('./lib/httpsync');
web3.providers.QtSyncProvider = require('./lib/qtsync');
web3.eth.contract = require('./lib/contract');

View File

@ -24,6 +24,7 @@ var web3 = require('./web3');
var abi = require('./abi');
var utils = require('./utils');
var eventImpl = require('./event');
var filter = require('./filter');
var exportNatspecGlobals = function (vars) {
// it's used byt natspec.js
@ -145,11 +146,11 @@ var addEventsToContract = function (contract, desc, address) {
var signature = abi.eventSignatureFromAscii(e.name);
var event = eventImpl.inputParser(address, signature, e);
var o = event.apply(null, params);
o._onWatchEventResult = function (data) {
var outputFormatter = function (data) {
var parser = eventImpl.outputParser(e);
return parser(data);
};
return web3.eth.watch(o);
return web3.eth.watch(o, undefined, undefined, outputFormatter);
};
// this property should be used by eth.filter to check if object is an event

View File

@ -23,79 +23,91 @@
* @date 2014
*/
var web3 = require('./web3'); // jshint ignore:line
/// Should be called to check if filter implementation is valid
/// @returns true if it is, otherwise false
var implementationIsValid = function (i) {
return !!i &&
typeof i.newFilter === 'function' &&
typeof i.getMessages === 'function' &&
typeof i.uninstallFilter === 'function' &&
typeof i.startPolling === 'function' &&
typeof i.stopPolling === 'function';
};
/// should be used when we want to watch something
/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones
/// @param should be string or object
/// @returns options string or object
var getOptions = function (options) {
if (typeof options === 'string') {
return options;
}
options = options || {};
if (options.topics) {
console.warn('"topics" is deprecated, is "topic" instead');
}
// evaluate lazy properties
return {
to: options.to,
topic: options.topic,
earliest: options.earliest,
latest: options.latest,
max: options.max,
skip: options.skip,
address: options.address
};
};
/// Should be used when we want to watch something
/// it's using inner polling mechanism and is notified about changes
/// TODO: change 'options' name cause it may be not the best matching one, since we have events
var Filter = function(options, impl) {
if (typeof options !== "string") {
// topics property is deprecated, warn about it!
if (options.topics) {
console.warn('"topics" is deprecated, use "topic" instead');
}
this._onWatchResult = options._onWatchEventResult;
// evaluate lazy properties
options = {
to: options.to,
topic: options.topic,
earliest: options.earliest,
latest: options.latest,
max: options.max,
skip: options.skip,
address: options.address
};
/// @param options are filter options
/// @param implementation, an abstract polling implementation
/// @param formatter (optional), callback function which formats output before 'real' callback
var filter = function(options, implementation, formatter) {
if (!implementationIsValid(implementation)) {
console.error('filter implemenation is invalid');
return;
}
options = getOptions(options);
var callbacks = [];
var filterId = implementation.newFilter(options);
var onMessages = function (messages) {
messages.forEach(function (message) {
messages = formatter ? formatter(message) : message;
callbacks.forEach(function (callback) {
callback(message);
});
});
};
implementation.startPolling(filterId, onMessages);
var changed = function (callback) {
callbacks.push(callback);
};
var messages = function () {
return implementation.getMessages(filterId);
};
this.impl = impl;
this.callbacks = [];
var uninstall = function (callback) {
implementation.stopPolling(filterId);
implementation.uninstallFilter(filterId);
callbacks = [];
};
this.id = impl.newFilter(options);
web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this));
return {
changed: changed,
arrived: changed,
happened: changed,
messages: messages,
logs: messages,
uninstall: uninstall
};
};
/// alias for changed*
Filter.prototype.arrived = function(callback) {
this.changed(callback);
};
Filter.prototype.happened = function(callback) {
this.changed(callback);
};
module.exports = filter;
/// gets called when there is new eth/shh message
Filter.prototype.changed = function(callback) {
this.callbacks.push(callback);
};
/// trigger calling new message from people
Filter.prototype.trigger = function(messages) {
for (var i = 0; i < this.callbacks.length; i++) {
for (var j = 0; j < messages.length; j++) {
var message = this._onWatchResult ? this._onWatchResult(messages[j]) : messages[j];
this.callbacks[i].call(this, message);
}
}
};
/// should be called to uninstall current filter
Filter.prototype.uninstall = function() {
this.impl.uninstallFilter(this.id);
web3.provider.stopPolling(this.id);
};
/// should be called to manually trigger getting latest messages from the client
Filter.prototype.messages = function() {
return this.impl.getMessages(this.id);
};
/// alias for messages
Filter.prototype.logs = function () {
return this.messages();
};
module.exports = Filter;

View File

@ -27,6 +27,7 @@ if (process.env.NODE_ENV !== 'build') {
var BigNumber = require('bignumber.js');
}
var filter = require('./filter');
var utils = require('./utils');
/// @returns an array of objects describing web3 api methods
@ -208,11 +209,11 @@ var web3 = {
/// @param filter may be a string, object or event
/// @param indexed is optional, this is an object with optional event indexed params
/// @param options is optional, this is an object with optional event options ('max'...)
watch: function (filter, indexed, options) {
if (filter._isEvent) {
return filter(indexed, options);
watch: function (fil, indexed, options, formatter) {
if (fil._isEvent) {
return fil(indexed, options);
}
return new web3.filter(filter, ethWatch);
return filter(fil, ethWatch, formatter);
}
},
@ -221,10 +222,9 @@ var web3 = {
/// shh object prototype
shh: {
/// @param filter may be a string, object or event
watch: function (filter, indexed) {
return new web3.filter(filter, shhWatch);
watch: function (fil) {
return filter(fil, shhWatch);
}
},
};
@ -236,14 +236,27 @@ setupProperties(web3.eth, ethProperties());
setupMethods(web3.db, dbMethods());
setupMethods(web3.shh, shhMethods());
var startPolling = function (method, id, callback) {
web3.provider.startPolling({
method: method,
params: [id]
}, id, callback);
};
var stopPolling = function (id) {
web3.provider.stopPolling(id);
};
var ethWatch = {
changed: 'eth_changed'
startPolling: startPolling.bind(null, 'eth_changed'),
stopPolling: stopPolling
};
setupMethods(ethWatch, ethWatchMethods());
var shhWatch = {
changed: 'shh_changed'
startPolling: startPolling.bind(null, 'shh_changed'),
stopPolling: stopPolling
};
setupMethods(shhWatch, shhWatchMethods());

27
test/filter.methods.js Normal file
View File

@ -0,0 +1,27 @@
var assert = require('assert');
var filter = require('../lib/filter');
var u = require('./test.utils.js');
var empty = function () {};
var implementation = {
newFilter: empty,
getMessages: empty,
uninstallFilter: empty,
startPolling: empty,
stopPolling: empty,
};
describe('web3', function () {
describe('eth', function () {
describe('filter', function () {
var f = filter({}, implementation);
u.methodExists(f, 'arrived');
u.methodExists(f, 'happened');
u.methodExists(f, 'changed');
u.methodExists(f, 'messages');
u.methodExists(f, 'logs');
u.methodExists(f, 'uninstall');
});
});
});