aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/ethereum/js.go207
-rw-r--r--cmd/ethereum/main.go5
-rw-r--r--cmd/ethereum/repl/console_colors_windows.go97
-rw-r--r--cmd/ethereum/repl/repl.go201
-rw-r--r--cmd/ethereum/repl/repl_darwin.go144
l---------cmd/ethereum/repl/repl_linux.go1
-rw-r--r--cmd/ethereum/repl/repl_windows.go92
7 files changed, 209 insertions, 538 deletions
diff --git a/cmd/ethereum/js.go b/cmd/ethereum/js.go
index f0aeb45f5..e16ee171e 100644
--- a/cmd/ethereum/js.go
+++ b/cmd/ethereum/js.go
@@ -18,13 +18,21 @@
package main
import (
+ "fmt"
"io/ioutil"
"os"
+ "path"
+ "strings"
"github.com/ethereum/go-ethereum/cmd/utils"
+ "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/javascript"
+ "github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/xeth"
+ "github.com/obscuren/otto"
+ "github.com/peterh/liner"
)
func execJsFile(ethereum *eth.Ethereum, filename string) {
@@ -41,3 +49,202 @@ func execJsFile(ethereum *eth.Ethereum, filename string) {
utils.Fatalf("Javascript Error: %v", err)
}
}
+
+type repl struct {
+ re *javascript.JSRE
+ ethereum *eth.Ethereum
+ xeth *xeth.XEth
+ prompt string
+ histfile *os.File
+ lr *liner.State
+ running bool
+}
+
+func newREPL(ethereum *eth.Ethereum) *repl {
+ hist, err := os.OpenFile(path.Join(ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
+ if err != nil {
+ panic(err)
+ }
+ xeth := xeth.New(ethereum)
+ repl := &repl{
+ re: javascript.NewJSRE(xeth),
+ xeth: xeth,
+ ethereum: ethereum,
+ prompt: "> ",
+ histfile: hist,
+ lr: liner.NewLiner(),
+ }
+ repl.initStdFuncs()
+ return repl
+}
+
+func (self *repl) Start() {
+ if !self.running {
+ self.running = true
+ self.lr.ReadHistory(self.histfile)
+ go self.read()
+ }
+}
+
+func (self *repl) Stop() {
+ if self.running {
+ self.running = false
+ self.histfile.Truncate(0)
+ self.lr.WriteHistory(self.histfile)
+ self.histfile.Close()
+ }
+}
+
+func (self *repl) parseInput(code string) {
+ defer func() {
+ if r := recover(); r != nil {
+ fmt.Println("[native] error", r)
+ }
+ }()
+ value, err := self.re.Run(code)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ self.printValue(value)
+}
+
+var indentCount = 0
+var str = ""
+
+func (self *repl) setIndent() {
+ open := strings.Count(str, "{")
+ open += strings.Count(str, "(")
+ closed := strings.Count(str, "}")
+ closed += strings.Count(str, ")")
+ indentCount = open - closed
+ if indentCount <= 0 {
+ self.prompt = "> "
+ } else {
+ self.prompt = strings.Join(make([]string, indentCount*2), "..")
+ self.prompt += " "
+ }
+}
+
+func (self *repl) read() {
+ for {
+ input, err := self.lr.Prompt(self.prompt)
+ if err != nil {
+ return
+ }
+ if input == "" {
+ continue
+ }
+ str += input + "\n"
+ self.setIndent()
+ if indentCount <= 0 {
+ if input == "exit" {
+ self.Stop()
+ return
+ }
+ hist := str[:len(str)-1]
+ self.lr.AppendHistory(hist)
+ self.parseInput(str)
+ str = ""
+ }
+ }
+}
+
+func (self *repl) printValue(v interface{}) {
+ method, _ := self.re.Vm.Get("prettyPrint")
+ v, err := self.re.Vm.ToValue(v)
+ if err == nil {
+ val, err := method.Call(method, v)
+ if err == nil {
+ fmt.Printf("%v", val)
+ }
+ }
+}
+
+func (self *repl) initStdFuncs() {
+ t, _ := self.re.Vm.Get("eth")
+ eth := t.Object()
+ eth.Set("connect", self.connect)
+ eth.Set("stopMining", self.stopMining)
+ eth.Set("startMining", self.startMining)
+ eth.Set("dump", self.dump)
+ eth.Set("export", self.export)
+}
+
+/*
+ * The following methods are natively implemented javascript functions.
+ */
+
+func (self *repl) dump(call otto.FunctionCall) otto.Value {
+ var block *types.Block
+
+ if len(call.ArgumentList) > 0 {
+ if call.Argument(0).IsNumber() {
+ num, _ := call.Argument(0).ToInteger()
+ block = self.ethereum.ChainManager().GetBlockByNumber(uint64(num))
+ } else if call.Argument(0).IsString() {
+ hash, _ := call.Argument(0).ToString()
+ block = self.ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(hash))
+ } else {
+ fmt.Println("invalid argument for dump. Either hex string or number")
+ }
+
+ if block == nil {
+ fmt.Println("block not found")
+
+ return otto.UndefinedValue()
+ }
+
+ } else {
+ block = self.ethereum.ChainManager().CurrentBlock()
+ }
+
+ statedb := state.New(block.Root(), self.ethereum.Db())
+
+ v, _ := self.re.Vm.ToValue(statedb.RawDump())
+
+ return v
+}
+
+func (self *repl) stopMining(call otto.FunctionCall) otto.Value {
+ self.xeth.Miner().Stop()
+ return otto.TrueValue()
+}
+
+func (self *repl) startMining(call otto.FunctionCall) otto.Value {
+ self.xeth.Miner().Start()
+ return otto.TrueValue()
+}
+
+func (self *repl) connect(call otto.FunctionCall) otto.Value {
+ nodeURL, err := call.Argument(0).ToString()
+ if err != nil {
+ return otto.FalseValue()
+ }
+ if err := self.ethereum.SuggestPeer(nodeURL); err != nil {
+ return otto.FalseValue()
+ }
+ return otto.TrueValue()
+}
+
+func (self *repl) export(call otto.FunctionCall) otto.Value {
+ if len(call.ArgumentList) == 0 {
+ fmt.Println("err: require file name")
+ return otto.FalseValue()
+ }
+
+ fn, err := call.Argument(0).ToString()
+ if err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+
+ data := self.ethereum.ChainManager().Export()
+
+ if err := ethutil.WriteFile(fn, data); err != nil {
+ fmt.Println(err)
+ return otto.FalseValue()
+ }
+
+ return otto.TrueValue()
+}
diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go
index a38e012c2..c85caf229 100644
--- a/cmd/ethereum/main.go
+++ b/cmd/ethereum/main.go
@@ -28,7 +28,6 @@ import (
"time"
"github.com/codegangsta/cli"
- "github.com/ethereum/go-ethereum/cmd/ethereum/repl"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
@@ -145,9 +144,9 @@ func runjs(ctx *cli.Context) {
eth := utils.GetEthereum(ClientIdentifier, Version, ctx)
startEth(ctx, eth)
if len(ctx.Args()) == 0 {
- repl := ethrepl.NewJSRepl(eth)
- repl.Start()
+ repl := newREPL(eth)
utils.RegisterInterrupt(func(os.Signal) { repl.Stop() })
+ repl.Start()
eth.WaitForShutdown()
} else if len(ctx.Args()) == 1 {
execJsFile(eth, ctx.Args()[0])
diff --git a/cmd/ethereum/repl/console_colors_windows.go b/cmd/ethereum/repl/console_colors_windows.go
deleted file mode 100644
index 8062746fb..000000000
--- a/cmd/ethereum/repl/console_colors_windows.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-// MA 02110-1301 USA
-
-/* Inspired by https://github.com/xuyu/logging/blob/master/colorful_win.go */
-
-package ethrepl
-
-import (
- "syscall"
- "unsafe"
-)
-
-type color uint16
-
-const (
- green = color(0x0002)
- red = color(0x0004)
- yellow = color(0x000E)
-)
-
-const (
- mask = uint16(yellow | green | red)
-)
-
-var (
- kernel32 = syscall.NewLazyDLL("kernel32.dll")
- procGetStdHandle = kernel32.NewProc("GetStdHandle")
- procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
- procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
- hStdout uintptr
- initScreenInfo *consoleScreenBufferInfo
-)
-
-func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool {
- ret, _, _ := procSetConsoleTextAttribute.Call(hConsoleOutput, uintptr(wAttributes))
- return ret != 0
-}
-
-type coord struct {
- X, Y int16
-}
-
-type smallRect struct {
- Left, Top, Right, Bottom int16
-}
-
-type consoleScreenBufferInfo struct {
- DwSize coord
- DwCursorPosition coord
- WAttributes uint16
- SrWindow smallRect
- DwMaximumWindowSize coord
-}
-
-func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo {
- var csbi consoleScreenBufferInfo
- ret, _, _ := procGetConsoleScreenBufferInfo.Call(hConsoleOutput, uintptr(unsafe.Pointer(&csbi)))
- if ret == 0 {
- return nil
- }
- return &csbi
-}
-
-const (
- stdOutputHandle = uint32(-11 & 0xFFFFFFFF)
-)
-
-func init() {
- hStdout, _, _ = procGetStdHandle.Call(uintptr(stdOutputHandle))
- initScreenInfo = getConsoleScreenBufferInfo(hStdout)
-}
-
-func resetColorful() {
- if initScreenInfo == nil {
- return
- }
- setConsoleTextAttribute(hStdout, initScreenInfo.WAttributes)
-}
-
-func changeColor(c color) {
- attr := uint16(0) & ^mask | uint16(c)
- setConsoleTextAttribute(hStdout, attr)
-}
diff --git a/cmd/ethereum/repl/repl.go b/cmd/ethereum/repl/repl.go
deleted file mode 100644
index 05ea71e79..000000000
--- a/cmd/ethereum/repl/repl.go
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-// MA 02110-1301 USA
-
-package ethrepl
-
-import (
- "bufio"
- "fmt"
- "io"
- "os"
- "path"
-
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/ethutil"
- "github.com/ethereum/go-ethereum/javascript"
- "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/state"
- "github.com/ethereum/go-ethereum/xeth"
- "github.com/obscuren/otto"
-)
-
-var repllogger = logger.NewLogger("REPL")
-
-type Repl interface {
- Start()
- Stop()
-}
-
-type JSRepl struct {
- re *javascript.JSRE
- ethereum *eth.Ethereum
- xeth *xeth.XEth
-
- prompt string
-
- history *os.File
-
- running bool
-}
-
-func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
- hist, err := os.OpenFile(path.Join(ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
- if err != nil {
- panic(err)
- }
-
- xeth := xeth.New(ethereum)
- repl := &JSRepl{re: javascript.NewJSRE(xeth), xeth: xeth, ethereum: ethereum, prompt: "> ", history: hist}
- repl.initStdFuncs()
-
- return repl
-}
-
-func (self *JSRepl) Start() {
- if !self.running {
- self.running = true
- repllogger.Infoln("init JS Console")
-
- reader := bufio.NewReader(self.history)
- for {
- line, err := reader.ReadString('\n')
- if err != nil && err == io.EOF {
- break
- } else if err != nil {
- fmt.Println("error reading history", err)
- break
- }
-
- addHistory(line[:len(line)-1])
- }
- self.read()
- }
-}
-
-func (self *JSRepl) Stop() {
- if self.running {
- self.running = false
- repllogger.Infoln("exit JS Console")
- self.history.Close()
- }
-}
-
-func (self *JSRepl) parseInput(code string) {
- defer func() {
- if r := recover(); r != nil {
- fmt.Println("[native] error", r)
- }
- }()
-
- value, err := self.re.Run(code)
- if err != nil {
- fmt.Println(err)
- return
- }
-
- self.PrintValue(value)
-}
-
-func (self *JSRepl) initStdFuncs() {
- t, _ := self.re.Vm.Get("eth")
- eth := t.Object()
- eth.Set("connect", self.connect)
- eth.Set("stopMining", self.stopMining)
- eth.Set("startMining", self.startMining)
- eth.Set("dump", self.dump)
- eth.Set("export", self.export)
-}
-
-/*
- * The following methods are natively implemented javascript functions
- */
-
-func (self *JSRepl) dump(call otto.FunctionCall) otto.Value {
- var block *types.Block
-
- if len(call.ArgumentList) > 0 {
- if call.Argument(0).IsNumber() {
- num, _ := call.Argument(0).ToInteger()
- block = self.ethereum.ChainManager().GetBlockByNumber(uint64(num))
- } else if call.Argument(0).IsString() {
- hash, _ := call.Argument(0).ToString()
- block = self.ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(hash))
- } else {
- fmt.Println("invalid argument for dump. Either hex string or number")
- }
-
- if block == nil {
- fmt.Println("block not found")
-
- return otto.UndefinedValue()
- }
-
- } else {
- block = self.ethereum.ChainManager().CurrentBlock()
- }
-
- statedb := state.New(block.Root(), self.ethereum.Db())
-
- v, _ := self.re.Vm.ToValue(statedb.RawDump())
-
- return v
-}
-
-func (self *JSRepl) stopMining(call otto.FunctionCall) otto.Value {
- self.xeth.Miner().Stop()
-
- return otto.TrueValue()
-}
-
-func (self *JSRepl) startMining(call otto.FunctionCall) otto.Value {
- self.xeth.Miner().Start()
- return otto.TrueValue()
-}
-
-func (self *JSRepl) connect(call otto.FunctionCall) otto.Value {
- nodeURL, err := call.Argument(0).ToString()
- if err != nil {
- return otto.FalseValue()
- }
- if err := self.ethereum.SuggestPeer(nodeURL); err != nil {
- return otto.FalseValue()
- }
- return otto.TrueValue()
-}
-
-func (self *JSRepl) export(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) == 0 {
- fmt.Println("err: require file name")
- return otto.FalseValue()
- }
-
- fn, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- data := self.ethereum.ChainManager().Export()
-
- if err := ethutil.WriteFile(fn, data); err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- return otto.TrueValue()
-}
diff --git a/cmd/ethereum/repl/repl_darwin.go b/cmd/ethereum/repl/repl_darwin.go
deleted file mode 100644
index 3710150cc..000000000
--- a/cmd/ethereum/repl/repl_darwin.go
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-// MA 02110-1301 USA
-
-package ethrepl
-
-// #cgo darwin CFLAGS: -I/usr/local/opt/readline/include
-// #cgo darwin LDFLAGS: -L/usr/local/opt/readline/lib
-// #cgo LDFLAGS: -lreadline
-// #include <stdio.h>
-// #include <stdlib.h>
-// #include <readline/readline.h>
-// #include <readline/history.h>
-import "C"
-import (
- "fmt"
- "os"
- "os/signal"
- "strings"
- "syscall"
- "unsafe"
-)
-
-func initReadLine() {
- C.rl_catch_sigwinch = 0
- C.rl_catch_signals = 0
- c := make(chan os.Signal, 1)
- signal.Notify(c, syscall.SIGWINCH)
- signal.Notify(c, os.Interrupt)
- go func() {
- for sig := range c {
- switch sig {
- case syscall.SIGWINCH:
- C.rl_resize_terminal()
-
- case os.Interrupt:
- C.rl_cleanup_after_signal()
- default:
-
- }
- }
- }()
-}
-
-func readLine(prompt *string) *string {
- var p *C.char
-
- //readline allows an empty prompt(NULL)
- if prompt != nil {
- p = C.CString(*prompt)
- }
-
- ret := C.readline(p)
-
- if p != nil {
- C.free(unsafe.Pointer(p))
- }
-
- if ret == nil {
- return nil
- } //EOF
-
- s := C.GoString(ret)
- C.free(unsafe.Pointer(ret))
- return &s
-}
-
-func addHistory(s string) {
- p := C.CString(s)
- C.add_history(p)
- C.free(unsafe.Pointer(p))
-}
-
-var indentCount = 0
-var str = ""
-
-func (self *JSRepl) setIndent() {
- open := strings.Count(str, "{")
- open += strings.Count(str, "(")
- closed := strings.Count(str, "}")
- closed += strings.Count(str, ")")
- indentCount = open - closed
- if indentCount <= 0 {
- self.prompt = "> "
- } else {
- self.prompt = strings.Join(make([]string, indentCount*2), "..")
- self.prompt += " "
- }
-}
-
-func (self *JSRepl) read() {
- initReadLine()
-L:
- for {
- switch result := readLine(&self.prompt); true {
- case result == nil:
- break L
-
- case *result != "":
- str += *result + "\n"
-
- self.setIndent()
-
- if indentCount <= 0 {
- if *result == "exit" {
- self.Stop()
- break L
- }
-
- hist := str[:len(str)-1]
- addHistory(hist) //allow user to recall this line
- self.history.WriteString(str)
-
- self.parseInput(str)
-
- str = ""
- }
- }
- }
-}
-
-func (self *JSRepl) PrintValue(v interface{}) {
- method, _ := self.re.Vm.Get("prettyPrint")
- v, err := self.re.Vm.ToValue(v)
- if err == nil {
- val, err := method.Call(method, v)
- if err == nil {
- fmt.Printf("%v", val)
- }
- }
-}
diff --git a/cmd/ethereum/repl/repl_linux.go b/cmd/ethereum/repl/repl_linux.go
deleted file mode 120000
index 276f135d7..000000000
--- a/cmd/ethereum/repl/repl_linux.go
+++ /dev/null
@@ -1 +0,0 @@
-repl_darwin.go \ No newline at end of file
diff --git a/cmd/ethereum/repl/repl_windows.go b/cmd/ethereum/repl/repl_windows.go
deleted file mode 100644
index d2c405ee9..000000000
--- a/cmd/ethereum/repl/repl_windows.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-// MA 02110-1301 USA
-
-package ethrepl
-
-import (
- "bufio"
- "fmt"
- "os"
- "strings"
-)
-
-func (self *JSRepl) read() {
- reader := bufio.NewReader(os.Stdin)
- for {
- fmt.Printf(self.prompt)
- str, _, err := reader.ReadLine()
- if err != nil {
- fmt.Println("Error reading input", err)
- } else {
- if string(str) == "exit" {
- self.Stop()
- break
- } else {
- self.parseInput(string(str))
- }
- }
- }
-}
-
-func addHistory(s string) {
-}
-
-func printColored(outputVal string) {
- for outputVal != "" {
- codePart := ""
- if strings.HasPrefix(outputVal, "\033[32m") {
- codePart = "\033[32m"
- changeColor(2)
- }
- if strings.HasPrefix(outputVal, "\033[1m\033[30m") {
- codePart = "\033[1m\033[30m"
- changeColor(8)
- }
- if strings.HasPrefix(outputVal, "\033[31m") {
- codePart = "\033[31m"
- changeColor(red)
- }
- if strings.HasPrefix(outputVal, "\033[35m") {
- codePart = "\033[35m"
- changeColor(5)
- }
- if strings.HasPrefix(outputVal, "\033[0m") {
- codePart = "\033[0m"
- resetColorful()
- }
- textPart := outputVal[len(codePart):len(outputVal)]
- index := strings.Index(textPart, "\033")
- if index == -1 {
- outputVal = ""
- } else {
- outputVal = textPart[index:len(textPart)]
- textPart = textPart[0:index]
- }
- fmt.Printf("%v", textPart)
- }
-}
-
-func (self *JSRepl) PrintValue(v interface{}) {
- method, _ := self.re.Vm.Get("prettyPrint")
- v, err := self.re.Vm.ToValue(v)
- if err == nil {
- val, err := method.Call(method, v)
- if err == nil {
- printColored(fmt.Sprintf("%v", val))
- }
- }
-}