github.com/jonasnick/go-ethereum@v0.7.12-0.20150216215225-22176f05d387/cmd/mist/ui_lib.go (about)

     1  /*
     2  	This file is part of go-ethereum
     3  
     4  	go-ethereum is free software: you can redistribute it and/or modify
     5  	it under the terms of the GNU General Public License as published by
     6  	the Free Software Foundation, either version 3 of the License, or
     7  	(at your option) any later version.
     8  
     9  	go-ethereum is distributed in the hope that it will be useful,
    10  	but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  	GNU General Public License for more details.
    13  
    14  	You should have received a copy of the GNU General Public License
    15  	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
    16  */
    17  /**
    18   * @authors
    19   * 	Jeffrey Wilcke <i@jev.io>
    20   */
    21  package main
    22  
    23  import (
    24  	"fmt"
    25  	"io/ioutil"
    26  	"path"
    27  
    28  	"github.com/jonasnick/go-ethereum/core/types"
    29  	"github.com/jonasnick/go-ethereum/eth"
    30  	"github.com/jonasnick/go-ethereum/ethutil"
    31  	"github.com/jonasnick/go-ethereum/event/filter"
    32  	"github.com/jonasnick/go-ethereum/javascript"
    33  	"github.com/jonasnick/go-ethereum/miner"
    34  	"github.com/jonasnick/go-ethereum/xeth"
    35  	"github.com/obscuren/qml"
    36  )
    37  
    38  type memAddr struct {
    39  	Num   string
    40  	Value string
    41  }
    42  
    43  // UI Library that has some basic functionality exposed
    44  type UiLib struct {
    45  	*xeth.XEth
    46  	engine    *qml.Engine
    47  	eth       *eth.Ethereum
    48  	connected bool
    49  	assetPath string
    50  	// The main application window
    51  	win      *qml.Window
    52  	Db       *Debugger
    53  	DbWindow *DebuggerWindow
    54  
    55  	jsEngine *javascript.JSRE
    56  
    57  	filterCallbacks map[int][]int
    58  	filterManager   *filter.FilterManager
    59  
    60  	miner *miner.Miner
    61  }
    62  
    63  func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
    64  	lib := &UiLib{XEth: xeth.New(eth), engine: engine, eth: eth, assetPath: assetPath, jsEngine: javascript.NewJSRE(eth), filterCallbacks: make(map[int][]int)} //, filters: make(map[int]*xeth.JSFilter)}
    65  	lib.miner = miner.New(eth.KeyManager().Address(), eth)
    66  	lib.filterManager = filter.NewFilterManager(eth.EventMux())
    67  	go lib.filterManager.Start()
    68  
    69  	return lib
    70  }
    71  
    72  func (self *UiLib) Notef(args []interface{}) {
    73  	guilogger.Infoln(args...)
    74  }
    75  
    76  func (self *UiLib) ImportTx(rlpTx string) {
    77  	tx := types.NewTransactionFromBytes(ethutil.Hex2Bytes(rlpTx))
    78  	err := self.eth.TxPool().Add(tx)
    79  	if err != nil {
    80  		guilogger.Infoln("import tx failed ", err)
    81  	}
    82  }
    83  
    84  func (self *UiLib) EvalJavascriptFile(path string) {
    85  	self.jsEngine.LoadExtFile(path[7:])
    86  }
    87  
    88  func (self *UiLib) EvalJavascriptString(str string) string {
    89  	value, err := self.jsEngine.Run(str)
    90  	if err != nil {
    91  		return err.Error()
    92  	}
    93  
    94  	return fmt.Sprintf("%v", value)
    95  }
    96  
    97  func (ui *UiLib) OpenQml(path string) {
    98  	container := NewQmlApplication(path[7:], ui)
    99  	app := NewExtApplication(container, ui)
   100  
   101  	go app.run()
   102  }
   103  
   104  func (ui *UiLib) OpenHtml(path string) {
   105  	container := NewHtmlApplication(path, ui)
   106  	app := NewExtApplication(container, ui)
   107  
   108  	go app.run()
   109  }
   110  
   111  func (ui *UiLib) OpenBrowser() {
   112  	ui.OpenHtml("file://" + ui.AssetPath("ext/home.html"))
   113  }
   114  
   115  func (ui *UiLib) Muted(content string) {
   116  	component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml"))
   117  	if err != nil {
   118  		guilogger.Debugln(err)
   119  
   120  		return
   121  	}
   122  	win := component.CreateWindow(nil)
   123  	go func() {
   124  		path := "file://" + ui.AssetPath("muted/index.html")
   125  		win.Set("url", path)
   126  
   127  		win.Show()
   128  		win.Wait()
   129  	}()
   130  }
   131  
   132  func (ui *UiLib) Connect(button qml.Object) {
   133  	if !ui.connected {
   134  		ui.eth.Start()
   135  		ui.connected = true
   136  		button.Set("enabled", false)
   137  	}
   138  }
   139  
   140  func (ui *UiLib) ConnectToPeer(nodeURL string) {
   141  	if err := ui.eth.SuggestPeer(nodeURL); err != nil {
   142  		guilogger.Infoln("SuggestPeer error: " + err.Error())
   143  	}
   144  }
   145  
   146  func (ui *UiLib) AssetPath(p string) string {
   147  	return path.Join(ui.assetPath, p)
   148  }
   149  
   150  func (self *UiLib) StartDbWithContractAndData(contractHash, data string) {
   151  	dbWindow := NewDebuggerWindow(self)
   152  	object := self.eth.ChainManager().State().GetStateObject(ethutil.Hex2Bytes(contractHash))
   153  	if len(object.Code) > 0 {
   154  		dbWindow.SetCode(ethutil.Bytes2Hex(object.Code))
   155  	}
   156  	dbWindow.SetData(data)
   157  
   158  	dbWindow.Show()
   159  }
   160  
   161  func (self *UiLib) StartDbWithCode(code string) {
   162  	dbWindow := NewDebuggerWindow(self)
   163  	dbWindow.SetCode(code)
   164  	dbWindow.Show()
   165  }
   166  
   167  func (self *UiLib) StartDebugger() {
   168  	dbWindow := NewDebuggerWindow(self)
   169  
   170  	dbWindow.Show()
   171  }
   172  
   173  func (self *UiLib) Transact(params map[string]interface{}) (string, error) {
   174  	object := mapToTxParams(params)
   175  
   176  	return self.XEth.Transact(
   177  		object["to"],
   178  		object["value"],
   179  		object["gas"],
   180  		object["gasPrice"],
   181  		object["data"],
   182  	)
   183  }
   184  
   185  func (self *UiLib) Compile(code string) (string, error) {
   186  	bcode, err := ethutil.Compile(code, false)
   187  	if err != nil {
   188  		return err.Error(), err
   189  	}
   190  
   191  	return ethutil.Bytes2Hex(bcode), err
   192  }
   193  
   194  func (self *UiLib) Call(params map[string]interface{}) (string, error) {
   195  	object := mapToTxParams(params)
   196  
   197  	return self.XEth.Execute(
   198  		object["to"],
   199  		object["value"],
   200  		object["gas"],
   201  		object["gasPrice"],
   202  		object["data"],
   203  	)
   204  }
   205  
   206  func (self *UiLib) AddLocalTransaction(to, data, gas, gasPrice, value string) int {
   207  	return 0
   208  	/*
   209  		return self.miner.AddLocalTx(&miner.LocalTx{
   210  			To:       ethutil.Hex2Bytes(to),
   211  			Data:     ethutil.Hex2Bytes(data),
   212  			Gas:      gas,
   213  			GasPrice: gasPrice,
   214  			Value:    value,
   215  		}) - 1
   216  	*/
   217  }
   218  
   219  func (self *UiLib) RemoveLocalTransaction(id int) {
   220  	//self.miner.RemoveLocalTx(id)
   221  }
   222  
   223  func (self *UiLib) SetGasPrice(price string) {
   224  	self.miner.MinAcceptedGasPrice = ethutil.Big(price)
   225  }
   226  
   227  func (self *UiLib) SetExtra(extra string) {
   228  	self.miner.Extra = extra
   229  }
   230  
   231  func (self *UiLib) ToggleMining() bool {
   232  	if !self.miner.Mining() {
   233  		self.miner.Start()
   234  
   235  		return true
   236  	} else {
   237  		self.miner.Stop()
   238  
   239  		return false
   240  	}
   241  }
   242  
   243  func (self *UiLib) ToHex(data string) string {
   244  	return "0x" + ethutil.Bytes2Hex([]byte(data))
   245  }
   246  
   247  func (self *UiLib) ToAscii(data string) string {
   248  	start := 0
   249  	if len(data) > 1 && data[0:2] == "0x" {
   250  		start = 2
   251  	}
   252  	return string(ethutil.Hex2Bytes(data[start:]))
   253  }
   254  
   255  /// Ethereum filter methods
   256  func (self *UiLib) NewFilter(object map[string]interface{}, view *qml.Common) (id int) {
   257  	/* TODO remove me
   258  	filter := qt.NewFilterFromMap(object, self.eth)
   259  	filter.MessageCallback = func(messages state.Messages) {
   260  		view.Call("messages", xeth.ToMessages(messages), id)
   261  	}
   262  	id = self.filterManager.InstallFilter(filter)
   263  	return id
   264  	*/
   265  	return 0
   266  }
   267  
   268  func (self *UiLib) NewFilterString(typ string, view *qml.Common) (id int) {
   269  	/* TODO remove me
   270  	filter := core.NewFilter(self.eth)
   271  	filter.BlockCallback = func(block *types.Block) {
   272  		view.Call("messages", "{}", id)
   273  	}
   274  	id = self.filterManager.InstallFilter(filter)
   275  	return id
   276  	*/
   277  	return 0
   278  }
   279  
   280  func (self *UiLib) Messages(id int) *ethutil.List {
   281  	/* TODO remove me
   282  	filter := self.filterManager.GetFilter(id)
   283  	if filter != nil {
   284  		messages := xeth.ToMessages(filter.Find())
   285  
   286  		return messages
   287  	}
   288  	*/
   289  
   290  	return ethutil.EmptyList()
   291  }
   292  
   293  func (self *UiLib) ReadFile(p string) string {
   294  	content, err := ioutil.ReadFile(self.AssetPath(path.Join("ext", p)))
   295  	if err != nil {
   296  		guilogger.Infoln("error reading file", p, ":", err)
   297  	}
   298  	return string(content)
   299  }
   300  
   301  func (self *UiLib) UninstallFilter(id int) {
   302  	self.filterManager.UninstallFilter(id)
   303  }
   304  
   305  func mapToTxParams(object map[string]interface{}) map[string]string {
   306  	// Default values
   307  	if object["from"] == nil {
   308  		object["from"] = ""
   309  	}
   310  	if object["to"] == nil {
   311  		object["to"] = ""
   312  	}
   313  	if object["value"] == nil {
   314  		object["value"] = ""
   315  	}
   316  	if object["gas"] == nil {
   317  		object["gas"] = ""
   318  	}
   319  	if object["gasPrice"] == nil {
   320  		object["gasPrice"] = ""
   321  	}
   322  
   323  	var dataStr string
   324  	var data []string
   325  	if list, ok := object["data"].(*qml.List); ok {
   326  		list.Convert(&data)
   327  	} else if str, ok := object["data"].(string); ok {
   328  		data = []string{str}
   329  	}
   330  
   331  	for _, str := range data {
   332  		if ethutil.IsHex(str) {
   333  			str = str[2:]
   334  
   335  			if len(str) != 64 {
   336  				str = ethutil.LeftPadString(str, 64)
   337  			}
   338  		} else {
   339  			str = ethutil.Bytes2Hex(ethutil.LeftPadBytes(ethutil.Big(str).Bytes(), 32))
   340  		}
   341  
   342  		dataStr += str
   343  	}
   344  	object["data"] = dataStr
   345  
   346  	conv := make(map[string]string)
   347  	for key, value := range object {
   348  		if v, ok := value.(string); ok {
   349  			conv[key] = v
   350  		}
   351  	}
   352  
   353  	return conv
   354  }