From a4a4e9fcf824189d8d06940492a01effe6e6cf92 Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Wed, 17 Jun 2015 16:22:35 +0200 Subject: removed old rpc structure and added new inproc api client --- cmd/geth/js.go | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 3 deletions(-) (limited to 'cmd/geth/js.go') diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 7e6e10ca9..2ae4817b3 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -33,6 +33,10 @@ import ( "github.com/ethereum/go-ethereum/eth" re "github.com/ethereum/go-ethereum/jsre" "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/rpc/api" + "github.com/ethereum/go-ethereum/rpc/codec" + "github.com/ethereum/go-ethereum/rpc/comms" + "github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/xeth" "github.com/peterh/liner" "github.com/robertkrimen/otto" @@ -70,10 +74,70 @@ type jsre struct { ps1 string atexit func() corsDomain string + client comms.EthereumClient prompter } -func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain, ipcpath string, interactive bool, f xeth.Frontend) *jsre { +var ( + loadedModulesMethods map[string][]string +) + +func keywordCompleter(line string) []string { + results := make([]string, 0) + + if strings.Contains(line, ".") { + elements := strings.Split(line, ".") + if len(elements) == 2 { + module := elements[0] + partialMethod := elements[1] + if methods, found := loadedModulesMethods[module]; found { + for _, method := range methods { + if strings.HasPrefix(method, partialMethod) { // e.g. debug.se + results = append(results, module+"."+method) + } + } + } + } + } else { + for module, methods := range loadedModulesMethods { + if line == module { // user typed in full module name, show all methods + for _, method := range methods { + results = append(results, module+"."+method) + } + } else if strings.HasPrefix(module, line) { // partial method name, e.g. admi + results = append(results, module) + } + } + } + return results +} + +func apiWordCompleter(line string, pos int) (head string, completions []string, tail string) { + if len(line) == 0 { + return "", nil, "" + } + + i := 0 + for i = pos - 1; i > 0; i-- { + if line[i] == '.' || (line[i] >= 'a' && line[i] <= 'z') || (line[i] >= 'A' && line[i] <= 'Z') { + continue + } + if i >= 3 && line[i] == '3' && line[i-3] == 'w' && line[i-2] == 'e' && line[i-1] == 'b' { + continue + } + i += 1 + break + } + + begin := line[:i] + keyword := line[i:pos] + end := line[pos:] + + completionWords := keywordCompleter(keyword) + return begin, completionWords, end +} + +func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre { js := &jsre{ethereum: ethereum, ps1: "> "} // set default cors domain used by startRpc from CLI flag js.corsDomain = corsDomain @@ -82,10 +146,16 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain, ipcpath string, intera } js.xeth = xeth.New(ethereum, f) js.wait = js.xeth.UpdateState() + js.client = client + if clt, ok := js.client.(*comms.InProcClient); ok { + clt.Initialize(js.xeth, ethereum) + } + // update state in separare forever blocks js.re = re.New(libPath) - js.apiBindings(ipcpath, f) - js.adminBindings() + if err := js.apiBindings(f); err != nil { + utils.Fatalf("Unable to connect - %v", err) + } if !liner.TerminalSupported() || !interactive { js.prompter = dumbterm{bufio.NewReader(os.Stdin)} @@ -93,6 +163,9 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain, ipcpath string, intera lr := liner.NewLiner() js.withHistory(func(hist *os.File) { lr.ReadHistory(hist) }) lr.SetCtrlCAborts(true) + js.loadAutoCompletion() + lr.SetWordCompleter(apiWordCompleter) + lr.SetTabCompletionStyle(liner.TabPrints) js.prompter = lr js.atexit = func() { js.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) }) @@ -103,8 +176,117 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain, ipcpath string, intera return js } +func (self *jsre) loadAutoCompletion() { + if modules, err := self.suportedApis(); err == nil { + loadedModulesMethods = make(map[string][]string) + for module, _ := range modules { + loadedModulesMethods[module] = api.AutoCompletion[module] + } + } +} + +func (self *jsre) suportedApis() (map[string]string, error) { + req := shared.Request{ + Id: 1, + Jsonrpc: "2.0", + Method: "modules", + } + + err := self.client.Send(&req) + if err != nil { + return nil, err + } + + res, err := self.client.Recv() + if err != nil { + return nil, err + } + + if sucRes, ok := res.(map[string]string); ok { + if err == nil { + return sucRes, nil + } + } + + return nil, fmt.Errorf("Unable to determine supported API's") +} + +func (js *jsre) apiBindings(f xeth.Frontend) error { + apis, err := js.suportedApis() + if err != nil { + return err + } + + apiNames := make([]string, 0, len(apis)) + for a, _ := range apis { + apiNames = append(apiNames, a) + } + + apiImpl, err := api.ParseApiString(strings.Join(apiNames, ","), codec.JSON, js.xeth, js.ethereum) + if err != nil { + utils.Fatalf("Unable to determine supported api's: %v", err) + } + + jeth := rpc.NewJeth(api.Merge(apiImpl...), js.re, js.client) + js.re.Set("jeth", struct{}{}) + t, _ := js.re.Get("jeth") + jethObj := t.Object() + + jethObj.Set("send", jeth.Send) + jethObj.Set("sendAsync", jeth.Send) + + err = js.re.Compile("bignumber.js", re.BigNumber_JS) + if err != nil { + utils.Fatalf("Error loading bignumber.js: %v", err) + } + + err = js.re.Compile("ethereum.js", re.Web3_JS) + if err != nil { + utils.Fatalf("Error loading web3.js: %v", err) + } + + _, err = js.re.Eval("var web3 = require('web3');") + if err != nil { + utils.Fatalf("Error requiring web3: %v", err) + } + + _, err = js.re.Eval("web3.setProvider(jeth)") + if err != nil { + utils.Fatalf("Error setting web3 provider: %v", err) + } + + // load only supported API's in javascript runtime + shortcuts := "var eth = web3.eth; " + for _, apiName := range apiNames { + if apiName == api.Web3ApiName || apiName == api.EthApiName { + continue // manually mapped + } + + if err = js.re.Compile(fmt.Sprintf("%s.js", apiName), api.Javascript(apiName)); err == nil { + shortcuts += fmt.Sprintf("var %s = web3.%s; ", apiName, apiName) + } else { + utils.Fatalf("Error loading %s.js: %v", apiName, err) + } + } + + _, err = js.re.Eval(shortcuts) + + if err != nil { + utils.Fatalf("Error setting namespaces: %v", err) + } + + js.re.Eval(globalRegistrar + "registrar = GlobalRegistrar.at(\"" + globalRegistrarAddr + "\");") + return nil +} + +/* func (js *jsre) apiBindings(ipcpath string, f xeth.Frontend) { xe := xeth.New(js.ethereum, f) + apiNames, err := js.suportedApis(ipcpath) + if err != nil { + return + } + ethApi := rpc.NewEthereumApi(xe) jeth := rpc.NewJeth(ethApi, js.re, ipcpath) @@ -146,6 +328,7 @@ var net = web3.net; js.re.Eval(globalRegistrar + "registrar = GlobalRegistrar.at(\"" + globalRegistrarAddr + "\");") } +*/ var ds, _ = docserver.New("/") -- cgit v1.2.3 From 603192cfa7eb081d9504170677045794cff3b7ab Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Wed, 17 Jun 2015 16:33:34 +0200 Subject: cleanup comments/code --- cmd/geth/js.go | 51 --------------------------------------------------- 1 file changed, 51 deletions(-) (limited to 'cmd/geth/js.go') diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 2ae4817b3..bb5143170 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -279,57 +279,6 @@ func (js *jsre) apiBindings(f xeth.Frontend) error { return nil } -/* -func (js *jsre) apiBindings(ipcpath string, f xeth.Frontend) { - xe := xeth.New(js.ethereum, f) - apiNames, err := js.suportedApis(ipcpath) - if err != nil { - return - } - - ethApi := rpc.NewEthereumApi(xe) - jeth := rpc.NewJeth(ethApi, js.re, ipcpath) - - js.re.Set("jeth", struct{}{}) - t, _ := js.re.Get("jeth") - jethObj := t.Object() - - jethObj.Set("send", jeth.Send) - jethObj.Set("sendAsync", jeth.Send) - - err := js.re.Compile("bignumber.js", re.BigNumber_JS) - if err != nil { - utils.Fatalf("Error loading bignumber.js: %v", err) - } - - err = js.re.Compile("ethereum.js", re.Web3_JS) - if err != nil { - utils.Fatalf("Error loading ethereum.js: %v", err) - } - - _, err = js.re.Eval("var web3 = require('web3');") - if err != nil { - utils.Fatalf("Error requiring web3: %v", err) - } - - _, err = js.re.Eval("web3.setProvider(jeth)") - if err != nil { - utils.Fatalf("Error setting web3 provider: %v", err) - } - _, err = js.re.Eval(` -var eth = web3.eth; -var shh = web3.shh; -var db = web3.db; -var net = web3.net; - `) - if err != nil { - utils.Fatalf("Error setting namespaces: %v", err) - } - - js.re.Eval(globalRegistrar + "registrar = GlobalRegistrar.at(\"" + globalRegistrarAddr + "\");") -} -*/ - var ds, _ = docserver.New("/") func (self *jsre) ConfirmTransaction(tx string) bool { -- cgit v1.2.3 From f20256377731097c9478ede750efffd46d83b494 Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Thu, 18 Jun 2015 18:23:13 +0200 Subject: added attach over ipc command --- cmd/geth/js.go | 89 +++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 25 deletions(-) (limited to 'cmd/geth/js.go') diff --git a/cmd/geth/js.go b/cmd/geth/js.go index bb5143170..38ef59583 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -26,6 +26,8 @@ import ( "path/filepath" "strings" + "sort" + "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/docserver" @@ -36,7 +38,6 @@ import ( "github.com/ethereum/go-ethereum/rpc/api" "github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/comms" - "github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/xeth" "github.com/peterh/liner" "github.com/robertkrimen/otto" @@ -137,6 +138,40 @@ func apiWordCompleter(line string, pos int) (head string, completions []string, return begin, completionWords, end } +func newLightweightJSRE(libPath string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre { + js := &jsre{ps1: "> "} + js.wait = make(chan *big.Int) + js.client = client + + if f == nil { + f = js + } + + // update state in separare forever blocks + js.re = re.New(libPath) + if err := js.apiBindings(f); err != nil { + utils.Fatalf("Unable to initialize console - %v", err) + } + + if !liner.TerminalSupported() || !interactive { + js.prompter = dumbterm{bufio.NewReader(os.Stdin)} + } else { + lr := liner.NewLiner() + //js.withHistory(func(hist *os.File) { lr.ReadHistory(hist) }) + lr.SetCtrlCAborts(true) + js.loadAutoCompletion() + lr.SetWordCompleter(apiWordCompleter) + lr.SetTabCompletionStyle(liner.TabPrints) + js.prompter = lr + js.atexit = func() { + js.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) }) + lr.Close() + close(js.wait) + } + } + return js +} + func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre { js := &jsre{ethereum: ethereum, ps1: "> "} // set default cors domain used by startRpc from CLI flag @@ -177,7 +212,7 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, client comms.Et } func (self *jsre) loadAutoCompletion() { - if modules, err := self.suportedApis(); err == nil { + if modules, err := self.supportedApis(); err == nil { loadedModulesMethods = make(map[string][]string) for module, _ := range modules { loadedModulesMethods[module] = api.AutoCompletion[module] @@ -185,34 +220,33 @@ func (self *jsre) loadAutoCompletion() { } } -func (self *jsre) suportedApis() (map[string]string, error) { - req := shared.Request{ - Id: 1, - Jsonrpc: "2.0", - Method: "modules", - } - - err := self.client.Send(&req) - if err != nil { - return nil, err - } - - res, err := self.client.Recv() - if err != nil { - return nil, err - } - - if sucRes, ok := res.(map[string]string); ok { - if err == nil { - return sucRes, nil +// show summary of current geth instance +func (self *jsre) welcome() { + self.re.Eval(`console.log('instance: ' + web3.version.client);`) + self.re.Eval(`console.log(' datadir: ' + admin.datadir);`) + self.re.Eval(`console.log("coinbase: " + eth.coinbase);`) + self.re.Eval(`var lastBlockTimestamp = 1000 * eth.getBlock(eth.blockNumber).timestamp`) + self.re.Eval(`console.log("at block: " + eth.blockNumber + " (" + new Date(lastBlockTimestamp).toLocaleDateString() + + " " + new Date(lastBlockTimestamp).toLocaleTimeString() + ")");`) + + if modules, err := self.supportedApis(); err == nil { + loadedModules := make([]string, 0) + for api, version := range modules { + loadedModules = append(loadedModules, fmt.Sprintf("%s:%s", api, version)) } + sort.Strings(loadedModules) + + self.re.Eval(fmt.Sprintf("var modules = '%s';", strings.Join(loadedModules, " "))) + self.re.Eval(`console.log(" modules: " + modules);`) } +} - return nil, fmt.Errorf("Unable to determine supported API's") +func (self *jsre) supportedApis() (map[string]string, error) { + return self.client.SupportedModules() } func (js *jsre) apiBindings(f xeth.Frontend) error { - apis, err := js.suportedApis() + apis, err := js.supportedApis() if err != nil { return err } @@ -366,7 +400,12 @@ func (self *jsre) interactive() { } func (self *jsre) withHistory(op func(*os.File)) { - hist, err := os.OpenFile(filepath.Join(self.ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm) + datadir := common.DefaultDataDir() + if self.ethereum != nil { + datadir = self.ethereum.DataDir + } + + hist, err := os.OpenFile(filepath.Join(datadir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm) if err != nil { fmt.Printf("unable to open history file: %v\n", err) return -- cgit v1.2.3 From 29297d3b82eae4d4d23e86cfebec61abf96fffda Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Fri, 19 Jun 2015 13:05:38 +0200 Subject: fixed bug where history file was create in cwd --- cmd/geth/js.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cmd/geth/js.go') diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 38ef59583..6e4e3e0c1 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -157,7 +157,7 @@ func newLightweightJSRE(libPath string, client comms.EthereumClient, interactive js.prompter = dumbterm{bufio.NewReader(os.Stdin)} } else { lr := liner.NewLiner() - //js.withHistory(func(hist *os.File) { lr.ReadHistory(hist) }) + js.withHistory(func(hist *os.File) { lr.ReadHistory(hist) }) lr.SetCtrlCAborts(true) js.loadAutoCompletion() lr.SetWordCompleter(apiWordCompleter) -- cgit v1.2.3 From f87501b1c547a1d9cd882497ffafbab4f9941ef1 Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Fri, 19 Jun 2015 14:04:18 +0200 Subject: added batch support to console and attach actions --- cmd/geth/js.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'cmd/geth/js.go') diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 6e4e3e0c1..761943b63 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -220,6 +220,25 @@ func (self *jsre) loadAutoCompletion() { } } +func (self *jsre) batch(statement string) { + val, err := self.re.Run(statement) + + if err != nil { + fmt.Printf("error: %v", err) + } else if val.IsDefined() && val.IsObject() { + obj, _ := self.re.Get("ret_result") + fmt.Printf("%v", obj) + } else if val.IsDefined() { + fmt.Printf("%v", val) + } + + if self.atexit != nil { + self.atexit() + } + + self.re.Stop(false) +} + // show summary of current geth instance func (self *jsre) welcome() { self.re.Eval(`console.log('instance: ' + web3.version.client);`) -- cgit v1.2.3 From 2e0b56a72b3eafc89938003da29c06496ac9ad4e Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Mon, 22 Jun 2015 12:47:32 +0200 Subject: added RPC start/stop support --- cmd/geth/js.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'cmd/geth/js.go') diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 761943b63..c0c77c02a 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -41,6 +41,7 @@ import ( "github.com/ethereum/go-ethereum/xeth" "github.com/peterh/liner" "github.com/robertkrimen/otto" + "github.com/ethereum/go-ethereum/rpc/shared" ) type prompter interface { @@ -183,7 +184,9 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, client comms.Et js.wait = js.xeth.UpdateState() js.client = client if clt, ok := js.client.(*comms.InProcClient); ok { - clt.Initialize(js.xeth, ethereum) + if offeredApis, err := api.ParseApiString(shared.AllApis, codec.JSON, js.xeth, ethereum); err == nil { + clt.Initialize(api.Merge(offeredApis...)) + } } // update state in separare forever blocks @@ -311,7 +314,7 @@ func (js *jsre) apiBindings(f xeth.Frontend) error { // load only supported API's in javascript runtime shortcuts := "var eth = web3.eth; " for _, apiName := range apiNames { - if apiName == api.Web3ApiName || apiName == api.EthApiName { + if apiName == shared.Web3ApiName || apiName == shared.EthApiName { continue // manually mapped } -- cgit v1.2.3 From 4ee7f6fc88d504f2eac96de4e6e04d72032a933a Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Mon, 22 Jun 2015 13:54:13 +0200 Subject: added missing change for sign test --- cmd/geth/js.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cmd/geth/js.go') diff --git a/cmd/geth/js.go b/cmd/geth/js.go index c0c77c02a..01840ebd9 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -314,7 +314,7 @@ func (js *jsre) apiBindings(f xeth.Frontend) error { // load only supported API's in javascript runtime shortcuts := "var eth = web3.eth; " for _, apiName := range apiNames { - if apiName == shared.Web3ApiName || apiName == shared.EthApiName { + if apiName == shared.Web3ApiName { continue // manually mapped } -- cgit v1.2.3