From 93308a3e6f7b4879ed40993971e8c0042fd41468 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 30 Nov 2015 20:56:36 -0500 Subject: [PATCH 1/3] interactive tmsp console --- cmd/tmsp/cli.go | 61 ++++++++++++++++++++++++++++++++++-------------- server/server.go | 7 +++++- 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/cmd/tmsp/cli.go b/cmd/tmsp/cli.go index 1eab662e..e4550b8e 100644 --- a/cmd/tmsp/cli.go +++ b/cmd/tmsp/cli.go @@ -1,9 +1,11 @@ package main import ( + "bufio" "fmt" "net" "os" + "strings" . "github.com/tendermint/go-common" "github.com/tendermint/go-wire" @@ -12,6 +14,9 @@ import ( "github.com/codegangsta/cli" ) +// connection is a global variable so it can be reused by the console +var conn net.Conn + func main() { app := cli.NewApp() app.Name = "cli" @@ -24,6 +29,13 @@ func main() { }, } app.Commands = []cli.Command{ + { + Name: "console", + Usage: "Start an interactive tmsp console for multiple commands", + Action: func(c *cli.Context) { + cmdConsole(app, c) + }, + }, { Name: "append_tx", Usage: "Append a new tx to application", @@ -53,19 +65,44 @@ func main() { }, }, } + app.Before = before app.Run(os.Args) } +func before(c *cli.Context) error { + if conn == nil { + var err error + conn, err = Connect(c.GlobalString("address")) + if err != nil { + Exit(err.Error()) + } + } + return nil +} + //-------------------------------------------------------------------------------- +func cmdConsole(app *cli.App, c *cli.Context) { + for { + fmt.Printf("> ") + bufReader := bufio.NewReader(os.Stdin) + line, more, err := bufReader.ReadLine() + if more { + Exit("input is too long") + } else if err != nil { + Exit(err.Error()) + } + + args := []string{"tmsp"} + args = append(args, strings.Split(string(line), " ")...) + app.Run(args) + } +} + // Append a new tx to application func cmdAppendTx(c *cli.Context) { args := c.Args() // Args to AppendTx - conn, err := Connect(c.GlobalString("address")) - if err != nil { - Exit(err.Error()) - } res, err := makeRequest(conn, types.RequestAppendTx{[]byte(args[0])}) if err != nil { Exit(err.Error()) @@ -75,10 +112,6 @@ func cmdAppendTx(c *cli.Context) { // Get application Merkle root hash func cmdGetHash(c *cli.Context) { - conn, err := Connect(c.GlobalString("address")) - if err != nil { - Exit(err.Error()) - } res, err := makeRequest(conn, types.RequestGetHash{}) if err != nil { Exit(err.Error()) @@ -88,11 +121,7 @@ func cmdGetHash(c *cli.Context) { // Commit the application state func cmdCommit(c *cli.Context) { - conn, err := Connect(c.GlobalString("address")) - if err != nil { - Exit(err.Error()) - } - _, err = makeRequest(conn, types.RequestCommit{}) + _, err := makeRequest(conn, types.RequestCommit{}) if err != nil { Exit(err.Error()) } @@ -101,11 +130,7 @@ func cmdCommit(c *cli.Context) { // Roll back the application state to the latest commit func cmdRollback(c *cli.Context) { - conn, err := Connect(c.GlobalString("address")) - if err != nil { - Exit(err.Error()) - } - _, err = makeRequest(conn, types.RequestRollback{}) + _, err := makeRequest(conn, types.RequestRollback{}) if err != nil { Exit(err.Error()) } diff --git a/server/server.go b/server/server.go index 1ed2dec4..e5945c81 100644 --- a/server/server.go +++ b/server/server.go @@ -3,6 +3,7 @@ package server import ( "bufio" "fmt" + "io" "net" "strings" @@ -86,7 +87,11 @@ func handleRequests(appC types.AppContext, closeConn chan error, conn net.Conn, var req types.Request wire.ReadBinaryPtr(&req, bufReader, 0, &n, &err) if err != nil { - closeConn <- fmt.Errorf("Error in handleRequests: %v", err.Error()) + if err == io.EOF { + closeConn <- fmt.Errorf("Connection closed by client") + } else { + closeConn <- fmt.Errorf("Error in handleRequests: %v", err.Error()) + } return } count++ From 86c2484c29ef44555f49d176b7b19790c225ef65 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 30 Nov 2015 23:49:18 -0500 Subject: [PATCH 2/3] cmdInfo, cmdSetOption; append_tx can take hex --- cmd/tmsp/cli.go | 60 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/cmd/tmsp/cli.go b/cmd/tmsp/cli.go index e4550b8e..aa5a5a8b 100644 --- a/cmd/tmsp/cli.go +++ b/cmd/tmsp/cli.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "encoding/hex" "fmt" "net" "os" @@ -36,6 +37,20 @@ func main() { cmdConsole(app, c) }, }, + { + Name: "info", + Usage: "Get some info about the application", + Action: func(c *cli.Context) { + cmdInfo(c) + }, + }, + { + Name: "set_option", + Usage: "Set an option on the application", + Action: func(c *cli.Context) { + cmdSetOption(c) + }, + }, { Name: "append_tx", Usage: "Append a new tx to application", @@ -100,14 +115,49 @@ func cmdConsole(app *cli.App, c *cli.Context) { } } -// Append a new tx to application -func cmdAppendTx(c *cli.Context) { - args := c.Args() // Args to AppendTx - res, err := makeRequest(conn, types.RequestAppendTx{[]byte(args[0])}) +// Get some info from the application +func cmdInfo(c *cli.Context) { + res, err := makeRequest(conn, types.RequestInfo{}) if err != nil { Exit(err.Error()) } - fmt.Println("Sent tx:", args[0], "response:", res) + fmt.Println(res) +} + +// Set an option on the application +func cmdSetOption(c *cli.Context) { + args := c.Args() + if len(args) != 2 { + Exit("set_option takes 2 arguments (key, value)") + } + _, err := makeRequest(conn, types.RequestSetOption{args[0], args[1]}) + if err != nil { + Exit(err.Error()) + } + fmt.Printf("Set option %s = %s\n", args[0], args[1]) +} + +// Append a new tx to application +func cmdAppendTx(c *cli.Context) { + args := c.Args() + if len(args) != 1 { + Exit("append_tx takes 1 argument") + } + txString := args[0] + tx := []byte(txString) + if len(txString) > 2 && strings.HasPrefix(txString, "0x") { + var err error + tx, err = hex.DecodeString(txString[2:]) + if err != nil { + Exit(err.Error()) + } + } + + res, err := makeRequest(conn, types.RequestAppendTx{tx}) + if err != nil { + Exit(err.Error()) + } + fmt.Println("Sent tx:", txString, "response:", res) } // Get application Merkle root hash From 3e721456f5c01556bdc35495e0c537f653d81ca1 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 1 Dec 2015 01:49:54 -0500 Subject: [PATCH 3/3] tmsp batch and some tests --- cmd/counter/main.go | 22 ++++++++++ cmd/tmsp/cli.go | 29 ++++++++++++- example/counter.go | 2 +- test.sh | 100 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 cmd/counter/main.go create mode 100644 test.sh diff --git a/cmd/counter/main.go b/cmd/counter/main.go new file mode 100644 index 00000000..36485996 --- /dev/null +++ b/cmd/counter/main.go @@ -0,0 +1,22 @@ +package main + +import ( + . "github.com/tendermint/go-common" + "github.com/tendermint/tmsp/example" + "github.com/tendermint/tmsp/server" +) + +func main() { + + // Start the listener + _, err := server.StartListener("tcp://127.0.0.1:8080", example.NewCounterApplication()) + if err != nil { + Exit(err.Error()) + } + + // Wait forever + TrapSignal(func() { + // Cleanup + }) + +} diff --git a/cmd/tmsp/cli.go b/cmd/tmsp/cli.go index aa5a5a8b..242ffa60 100644 --- a/cmd/tmsp/cli.go +++ b/cmd/tmsp/cli.go @@ -4,6 +4,7 @@ import ( "bufio" "encoding/hex" "fmt" + "io" "net" "os" "strings" @@ -30,6 +31,13 @@ func main() { }, } app.Commands = []cli.Command{ + { + Name: "batch", + Usage: "Run a batch of tmsp commands against an application", + Action: func(c *cli.Context) { + cmdBatch(app, c) + }, + }, { Name: "console", Usage: "Start an interactive tmsp console for multiple commands", @@ -98,6 +106,23 @@ func before(c *cli.Context) error { //-------------------------------------------------------------------------------- +func cmdBatch(app *cli.App, c *cli.Context) { + bufReader := bufio.NewReader(os.Stdin) + for { + line, more, err := bufReader.ReadLine() + if more { + Exit("input line is too long") + } else if err == io.EOF { + break + } else if err != nil { + Exit(err.Error()) + } + args := []string{"tmsp"} + args = append(args, strings.Split(string(line), " ")...) + app.Run(args) + } +} + func cmdConsole(app *cli.App, c *cli.Context) { for { fmt.Printf("> ") @@ -134,7 +159,7 @@ func cmdSetOption(c *cli.Context) { if err != nil { Exit(err.Error()) } - fmt.Printf("Set option %s = %s\n", args[0], args[1]) + fmt.Printf("%s=%s\n", args[0], args[1]) } // Append a new tx to application @@ -166,7 +191,7 @@ func cmdGetHash(c *cli.Context) { if err != nil { Exit(err.Error()) } - fmt.Println("Got hash:", Fmt("%X", res.(types.ResponseGetHash).Hash)) + fmt.Printf("%X\n", res.(types.ResponseGetHash).Hash) } // Commit the application state diff --git a/example/counter.go b/example/counter.go index 870d5a80..d4b0e477 100644 --- a/example/counter.go +++ b/example/counter.go @@ -69,7 +69,7 @@ func (appC *CounterAppContext) AppendTx(tx []byte) ([]types.Event, types.RetCode func (appC *CounterAppContext) GetHash() ([]byte, types.RetCode) { hash := make([]byte, 32) - binary.PutVarint(hash, int64(appC.hashCount)) + binary.PutVarint(hash, int64(appC.txCount)) appC.hashCount += 1 return hash, 0 } diff --git a/test.sh b/test.sh new file mode 100644 index 00000000..00c1f203 --- /dev/null +++ b/test.sh @@ -0,0 +1,100 @@ +#! /bin/bash + +# Make sure the tmsp cli can connect to the dummy +echo "Dummy test ..." +dummy &> /dev/null & +PID=`echo $!` +sleep 1 +RESULT_HASH=`tmsp get_hash` +if [[ "$RESULT_HASH" != "" ]]; then + echo "Expected nothing but got: $RESULT_HASH" + exit 1 +fi +echo "... Pass!" +echo "" + +# Add a tx, get hash, commit, get hash +# hashes should be non-empty and identical +echo "Dummy batch test ..." +OUTPUT=`(tmsp batch) < /dev/null & +PID=`echo $!` +sleep 1 +OUTPUT=`(tmsp batch) <