From aadc5be3ff9e3818e41d83910b9730e5f1af042e Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 15 Aug 2014 00:24:14 +0200 Subject: [PATCH] Implemented new watch * Old watch methods have been removed * Implemented new callback handlers for onWatchCb * added new Filter JS object --- ethereal/assets/ext/ethereum.js | 32 +++++++++++++++-- ethereal/assets/ext/test.html | 30 ++++++++++++++++ ethereal/assets/qml/webapp.qml | 18 +++++++--- ethereal/ext_app.go | 63 +++++++++++---------------------- ethereal/html_container.go | 13 +++++++ ethereal/qml_container.go | 8 ++++- 6 files changed, 114 insertions(+), 50 deletions(-) create mode 100644 ethereal/assets/ext/test.html diff --git a/ethereal/assets/ext/ethereum.js b/ethereal/assets/ext/ethereum.js index 5b8fb54f3..5891fb9f9 100644 --- a/ethereal/assets/ext/ethereum.js +++ b/ethereal/assets/ext/ethereum.js @@ -137,6 +137,7 @@ window.eth = { postData({call: "getSecretToAddress", args: [sec]}, cb); }, + /* watch: function(address, storageAddrOrCb, cb) { var ev; if(cb === undefined) { @@ -166,6 +167,16 @@ window.eth = { postData({call: "disconnect", args: [address, storageAddrOrCb]}); }, + */ + + watch: function(options) { + var filter = new Filter(options); + filter.number = newWatchNum().toString() + + postData({call: "watch", args: [options, filter.number]}) + + return filter; + }, set: function(props) { postData({call: "set", args: props}); @@ -208,11 +219,28 @@ window.eth = { } } }, - - } + window.eth._callbacks = {} window.eth._onCallbacks = {} + +var Filter = function(options) { + this.options = options; +}; + +Filter.prototype.changed = function(callback) { + eth.on("watched:"+this.number, callback) +} + +Filter.prototype.getMessages = function(cb) { + return eth.getMessages(this.options, cb) +} + +var watchNum = 0; +function newWatchNum() { + return watchNum++; +} + function postData(data, cb) { data._seed = Math.floor(Math.random() * 1000000) if(cb) { diff --git a/ethereal/assets/ext/test.html b/ethereal/assets/ext/test.html new file mode 100644 index 000000000..b605e8dbd --- /dev/null +++ b/ethereal/assets/ext/test.html @@ -0,0 +1,30 @@ + + + +Tests + + + + + + + + + + diff --git a/ethereal/assets/qml/webapp.qml b/ethereal/assets/qml/webapp.qml index 48b410787..b0f50c8f9 100644 --- a/ethereal/assets/qml/webapp.qml +++ b/ethereal/assets/qml/webapp.qml @@ -220,11 +220,16 @@ ApplicationWindow { postData(data._seed, key) break + /* case "watch": - require(1) - eth.watch(data.args[0], data.args[1]); + require(1) + eth.watch(data.args[0], data.args[1]); - break + break + */ + case "watch": + require(2) + eth.watch(data.args[0], data.args[1]) case "disconnect": require(1) @@ -247,7 +252,7 @@ ApplicationWindow { break case "debug": - console.log(data.args[0]); + console.log(data.args[0]); break; } } catch(e) { @@ -269,6 +274,11 @@ ApplicationWindow { webview.experimental.postMessage(JSON.stringify({data: data, _event: event})) } + function onWatchedCb(data, id) { + var messages = JSON.parse(data) + postEvent("watched:"+id, messages) + } + function onNewBlockCb(block) { postEvent("block:new", block) } diff --git a/ethereal/ext_app.go b/ethereal/ext_app.go index 4533b2438..627f9e9ca 100644 --- a/ethereal/ext_app.go +++ b/ethereal/ext_app.go @@ -7,7 +7,6 @@ import ( "github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethstate" - "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/go-ethereum/javascript" "github.com/go-qml/qml" ) @@ -23,6 +22,7 @@ type AppContainer interface { ObjectChanged(*ethstate.StateObject) StorageChanged(*ethstate.StorageState) NewWatcher(chan bool) + Messages(ethstate.Messages, string) } type ExtApplication struct { @@ -31,9 +31,12 @@ type ExtApplication struct { blockChan chan ethreact.Event changeChan chan ethreact.Event + messageChan chan ethreact.Event quitChan chan bool watcherQuitChan chan bool + filters map[string]*ethchain.Filter + container AppContainer lib *UiLib registeredEvents []string @@ -45,8 +48,10 @@ func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication { lib.eth, make(chan ethreact.Event, 100), make(chan ethreact.Event, 100), + make(chan ethreact.Event, 100), make(chan bool), make(chan bool), + make(map[string]*ethchain.Filter), container, lib, nil, @@ -73,6 +78,7 @@ func (app *ExtApplication) run() { // Subscribe to events reactor := app.lib.eth.Reactor() reactor.Subscribe("newBlock", app.blockChan) + reactor.Subscribe("messages", app.messageChan) app.container.NewWatcher(app.watcherQuitChan) @@ -118,56 +124,27 @@ out: } else if storageObject, ok := object.Resource.(*ethstate.StorageState); ok { app.container.StorageChanged(storageObject) } + + case msg := <-app.messageChan: + if messages, ok := msg.Resource.(ethstate.Messages); ok { + for id, filter := range app.filters { + msgs := filter.FilterMessages(messages) + if len(msgs) > 0 { + app.container.Messages(msgs, id) + } + } + } } } } -func (app *ExtApplication) Watch(addr, storageAddr string) { - var event string - if len(storageAddr) == 0 { - event = "object:" + string(ethutil.Hex2Bytes(addr)) - app.lib.eth.Reactor().Subscribe(event, app.changeChan) - } else { - event = "storage:" + string(ethutil.Hex2Bytes(addr)) + ":" + string(ethutil.Hex2Bytes(storageAddr)) - app.lib.eth.Reactor().Subscribe(event, app.changeChan) - } - - app.registeredEvents = append(app.registeredEvents, event) +func (self *ExtApplication) Watch(filterOptions map[string]interface{}, identifier string) { + self.filters[identifier] = ethchain.NewFilterFromMap(filterOptions, self.eth) } func (self *ExtApplication) GetMessages(object map[string]interface{}) string { - filter := ethchain.NewFilter(self.eth) - - if object["earliest"] != nil { - earliest := object["earliest"] - if e, ok := earliest.(string); ok { - filter.SetEarliestBlock(ethutil.Hex2Bytes(e)) - } else { - filter.SetEarliestBlock(earliest) - } - } - - if object["latest"] != nil { - latest := object["latest"] - if l, ok := latest.(string); ok { - filter.SetLatestBlock(ethutil.Hex2Bytes(l)) - } else { - filter.SetLatestBlock(latest) - } - } - if object["to"] != nil { - filter.AddTo(ethutil.Hex2Bytes(object["to"].(string))) - } - if object["from"] != nil { - filter.AddFrom(ethutil.Hex2Bytes(object["from"].(string))) - } - if object["max"] != nil { - filter.SetMax(object["max"].(int)) - } - if object["skip"] != nil { - filter.SetSkip(object["skip"].(int)) - } + filter := ethchain.NewFilterFromMap(object, self.eth) messages := filter.Find() var msgs []javascript.JSMessage diff --git a/ethereal/html_container.go b/ethereal/html_container.go index 40a9f5584..7deee487d 100644 --- a/ethereal/html_container.go +++ b/ethereal/html_container.go @@ -1,6 +1,7 @@ package main import ( + "encoding/json" "errors" "io/ioutil" "net/url" @@ -12,6 +13,7 @@ import ( "github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/go-ethereum/javascript" "github.com/go-qml/qml" "github.com/howeyc/fsnotify" ) @@ -131,6 +133,17 @@ func (app *HtmlApplication) StorageChanged(storageObject *ethstate.StorageState) app.webView.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject)) } +func (self *HtmlApplication) Messages(messages ethstate.Messages, id string) { + var msgs []javascript.JSMessage + for _, m := range messages { + msgs = append(msgs, javascript.NewJSMessage(m)) + } + + b, _ := json.Marshal(msgs) + + self.webView.Call("onWatchedCb", string(b), id) +} + func (app *HtmlApplication) Destroy() { app.engine.Destroy() } diff --git a/ethereal/qml_container.go b/ethereal/qml_container.go index 53ff13c2f..45a6c0327 100644 --- a/ethereal/qml_container.go +++ b/ethereal/qml_container.go @@ -1,12 +1,14 @@ package main import ( + "fmt" + "runtime" + "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" "github.com/go-qml/qml" - "runtime" ) type QmlApplication struct { @@ -59,6 +61,10 @@ func (app *QmlApplication) StorageChanged(storageObject *ethstate.StorageState) app.win.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject)) } +func (self *QmlApplication) Messages(msgs ethstate.Messages, id string) { + fmt.Println("IMPLEMENT QML APPLICATION MESSAGES METHOD") +} + // Getters func (app *QmlApplication) Engine() *qml.Engine { return app.engine