|
|
@ -26,7 +26,9 @@ import ( |
|
|
|
"bytes" |
|
|
|
"bytes" |
|
|
|
"encoding/json" |
|
|
|
"encoding/json" |
|
|
|
"fmt" |
|
|
|
"fmt" |
|
|
|
|
|
|
|
"io/ioutil" |
|
|
|
"math/big" |
|
|
|
"math/big" |
|
|
|
|
|
|
|
"os" |
|
|
|
"path" |
|
|
|
"path" |
|
|
|
"runtime" |
|
|
|
"runtime" |
|
|
|
"strconv" |
|
|
|
"strconv" |
|
|
@ -48,15 +50,22 @@ import ( |
|
|
|
|
|
|
|
|
|
|
|
var guilogger = logger.NewLogger("GUI") |
|
|
|
var guilogger = logger.NewLogger("GUI") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type ServEv byte |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
|
|
|
setup ServEv = iota |
|
|
|
|
|
|
|
update |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
type Gui struct { |
|
|
|
type Gui struct { |
|
|
|
// The main application window
|
|
|
|
// The main application window
|
|
|
|
win *qml.Window |
|
|
|
win *qml.Window |
|
|
|
// QML Engine
|
|
|
|
// QML Engine
|
|
|
|
engine *qml.Engine |
|
|
|
engine *qml.Engine |
|
|
|
component *qml.Common |
|
|
|
component *qml.Common |
|
|
|
qmlDone bool |
|
|
|
|
|
|
|
// The ethereum interface
|
|
|
|
// The ethereum interface
|
|
|
|
eth *eth.Ethereum |
|
|
|
eth *eth.Ethereum |
|
|
|
|
|
|
|
serviceEvents chan ServEv |
|
|
|
|
|
|
|
|
|
|
|
// The public Ethereum library
|
|
|
|
// The public Ethereum library
|
|
|
|
uiLib *UiLib |
|
|
|
uiLib *UiLib |
|
|
@ -86,7 +95,17 @@ func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, clientIden |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
xeth := xeth.NewJSXEth(ethereum) |
|
|
|
xeth := xeth.NewJSXEth(ethereum) |
|
|
|
gui := &Gui{eth: ethereum, txDb: db, xeth: xeth, logLevel: logger.LogLevel(logLevel), Session: session, open: false, clientIdentity: clientIdentity, config: config, plugins: make(map[string]plugin)} |
|
|
|
gui := &Gui{eth: ethereum, |
|
|
|
|
|
|
|
txDb: db, |
|
|
|
|
|
|
|
xeth: xeth, |
|
|
|
|
|
|
|
logLevel: logger.LogLevel(logLevel), |
|
|
|
|
|
|
|
Session: session, |
|
|
|
|
|
|
|
open: false, |
|
|
|
|
|
|
|
clientIdentity: clientIdentity, |
|
|
|
|
|
|
|
config: config, |
|
|
|
|
|
|
|
plugins: make(map[string]plugin), |
|
|
|
|
|
|
|
serviceEvents: make(chan ServEv, 1), |
|
|
|
|
|
|
|
} |
|
|
|
data, _ := ethutil.ReadAllFile(path.Join(ethutil.Config.ExecPath, "plugins.json")) |
|
|
|
data, _ := ethutil.ReadAllFile(path.Join(ethutil.Config.ExecPath, "plugins.json")) |
|
|
|
json.Unmarshal([]byte(data), &gui.plugins) |
|
|
|
json.Unmarshal([]byte(data), &gui.plugins) |
|
|
|
|
|
|
|
|
|
|
@ -98,6 +117,8 @@ func (gui *Gui) Start(assetPath string) { |
|
|
|
|
|
|
|
|
|
|
|
guilogger.Infoln("Starting GUI") |
|
|
|
guilogger.Infoln("Starting GUI") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
go gui.service() |
|
|
|
|
|
|
|
|
|
|
|
// Register ethereum functions
|
|
|
|
// Register ethereum functions
|
|
|
|
qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{ |
|
|
|
qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{ |
|
|
|
Init: func(p *xeth.JSBlock, obj qml.Object) { p.Number = 0; p.Hash = "" }, |
|
|
|
Init: func(p *xeth.JSBlock, obj qml.Object) { p.Number = 0; p.Hash = "" }, |
|
|
@ -154,18 +175,11 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) { |
|
|
|
return nil, err |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
gui.win = gui.createWindow(component) |
|
|
|
gui.createWindow(component) |
|
|
|
|
|
|
|
|
|
|
|
gui.update() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return gui.win, nil |
|
|
|
return gui.win, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// The done handler will be called by QML when all views have been loaded
|
|
|
|
|
|
|
|
func (gui *Gui) Done() { |
|
|
|
|
|
|
|
gui.qmlDone = true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (gui *Gui) ImportKey(filePath string) { |
|
|
|
func (gui *Gui) ImportKey(filePath string) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -179,10 +193,8 @@ func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (gui *Gui) createWindow(comp qml.Object) *qml.Window { |
|
|
|
func (gui *Gui) createWindow(comp qml.Object) *qml.Window { |
|
|
|
win := comp.CreateWindow(nil) |
|
|
|
gui.win = comp.CreateWindow(nil) |
|
|
|
|
|
|
|
gui.uiLib.win = gui.win |
|
|
|
gui.win = win |
|
|
|
|
|
|
|
gui.uiLib.win = win |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return gui.win |
|
|
|
return gui.win |
|
|
|
} |
|
|
|
} |
|
|
@ -335,11 +347,48 @@ func (self *Gui) getObjectByName(objectName string) qml.Object { |
|
|
|
return self.win.Root().ObjectByName(objectName) |
|
|
|
return self.win.Root().ObjectByName(objectName) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Simple go routine function that updates the list of peers in the GUI
|
|
|
|
func loadJavascriptAssets(gui *Gui) (jsfiles string) { |
|
|
|
func (gui *Gui) update() { |
|
|
|
for _, fn := range []string{"ext/q.js", "ext/eth.js/main.js", "ext/eth.js/qt.js", "ext/setup.js"} { |
|
|
|
// We have to wait for qml to be done loading all the windows.
|
|
|
|
f, err := os.Open(gui.uiLib.AssetPath(fn)) |
|
|
|
for !gui.qmlDone { |
|
|
|
if err != nil { |
|
|
|
time.Sleep(300 * time.Millisecond) |
|
|
|
fmt.Println(err) |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
content, err := ioutil.ReadAll(f) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
fmt.Println(err) |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
jsfiles += string(content) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (gui *Gui) SendCommand(cmd ServEv) { |
|
|
|
|
|
|
|
gui.serviceEvents <- cmd |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (gui *Gui) service() { |
|
|
|
|
|
|
|
for ev := range gui.serviceEvents { |
|
|
|
|
|
|
|
switch ev { |
|
|
|
|
|
|
|
case setup: |
|
|
|
|
|
|
|
go gui.setup() |
|
|
|
|
|
|
|
case update: |
|
|
|
|
|
|
|
go gui.update() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (gui *Gui) setup() { |
|
|
|
|
|
|
|
for gui.win == nil { |
|
|
|
|
|
|
|
time.Sleep(time.Millisecond * 200) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for _, plugin := range gui.plugins { |
|
|
|
|
|
|
|
guilogger.Infoln("Loading plugin ", plugin.Name) |
|
|
|
|
|
|
|
gui.win.Root().Call("addPlugin", plugin.Path, "") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
go func() { |
|
|
|
go func() { |
|
|
@ -349,14 +398,21 @@ func (gui *Gui) update() { |
|
|
|
gui.setPeerInfo() |
|
|
|
gui.setPeerInfo() |
|
|
|
}() |
|
|
|
}() |
|
|
|
|
|
|
|
|
|
|
|
gui.whisper.SetView(gui.win.Root().ObjectByName("whisperView")) |
|
|
|
// Inject javascript files each time navigation is requested.
|
|
|
|
|
|
|
|
// Unfortunately webview.experimental.userScripts injects _after_
|
|
|
|
|
|
|
|
// the page has loaded which kind of renders it useless...
|
|
|
|
|
|
|
|
jsfiles := loadJavascriptAssets(gui) |
|
|
|
|
|
|
|
gui.getObjectByName("webView").On("navigationRequested", func() { |
|
|
|
|
|
|
|
gui.getObjectByName("webView").Call("injectJs", jsfiles) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
for _, plugin := range gui.plugins { |
|
|
|
gui.whisper.SetView(gui.getObjectByName("whisperView")) |
|
|
|
guilogger.Infoln("Loading plugin ", plugin.Name) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gui.win.Root().Call("addPlugin", plugin.Path, "") |
|
|
|
gui.SendCommand(update) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Simple go routine function that updates the list of peers in the GUI
|
|
|
|
|
|
|
|
func (gui *Gui) update() { |
|
|
|
peerUpdateTicker := time.NewTicker(5 * time.Second) |
|
|
|
peerUpdateTicker := time.NewTicker(5 * time.Second) |
|
|
|
generalUpdateTicker := time.NewTicker(500 * time.Millisecond) |
|
|
|
generalUpdateTicker := time.NewTicker(500 * time.Millisecond) |
|
|
|
statsUpdateTicker := time.NewTicker(5 * time.Second) |
|
|
|
statsUpdateTicker := time.NewTicker(5 * time.Second) |
|
|
@ -375,7 +431,6 @@ func (gui *Gui) update() { |
|
|
|
core.TxPostEvent{}, |
|
|
|
core.TxPostEvent{}, |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
go func() { |
|
|
|
|
|
|
|
defer events.Unsubscribe() |
|
|
|
defer events.Unsubscribe() |
|
|
|
for { |
|
|
|
for { |
|
|
|
select { |
|
|
|
select { |
|
|
@ -445,7 +500,6 @@ func (gui *Gui) update() { |
|
|
|
gui.setStatsPane() |
|
|
|
gui.setStatsPane() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}() |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (gui *Gui) setStatsPane() { |
|
|
|
func (gui *Gui) setStatsPane() { |
|
|
|