cmd/abci-cli: use a single connection per session

Use the single client connection at startup time
for sending over commands instead of shelling out
for every command.
This code fixes the regression from
https://github.com/tendermint/abci/pull/117
which instead used "os/exec".Command with:
    "abci-cli <the_command> [args...]"

The purpose of this code is to restore us
back to the state after cobra replace urlfave/cli.
There is still a bit of work to implement Batch
itself, but that should be simpler as a focused
command.

Fixes #133
This commit is contained in:
Emmanuel Odeke
2017-12-09 19:48:29 -07:00
parent 310beae63c
commit ecc13d5a8e

View File

@ -7,7 +7,6 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"os/exec"
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -348,6 +347,13 @@ func cmdTest(cmd *cobra.Command, args []string) error {
func cmdBatch(cmd *cobra.Command, args []string) error { func cmdBatch(cmd *cobra.Command, args []string) error {
bufReader := bufio.NewReader(os.Stdin) bufReader := bufio.NewReader(os.Stdin)
for { for {
// TODO: (@ebuchman, @zramsay, @odeke-em) Implement the actual batch logic
printResponse(cmd, args, response{
Code: codeBad,
Log: "Unimplemented",
})
return nil
line, more, err := bufReader.ReadLine() line, more, err := bufReader.ReadLine()
if more { if more {
return errors.New("Input line is too long") return errors.New("Input line is too long")
@ -358,19 +364,11 @@ func cmdBatch(cmd *cobra.Command, args []string) error {
} else if err != nil { } else if err != nil {
return err return err
} }
pArgs := persistentArgs(line)
out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() // nolint: gas
if err != nil {
return err
}
fmt.Println(string(out))
} }
return nil return nil
} }
func cmdConsole(cmd *cobra.Command, args []string) error { func cmdConsole(cmd *cobra.Command, args []string) error {
for { for {
fmt.Printf("> ") fmt.Printf("> ")
bufReader := bufio.NewReader(os.Stdin) bufReader := bufio.NewReader(os.Stdin)
@ -382,18 +380,67 @@ func cmdConsole(cmd *cobra.Command, args []string) error {
} }
pArgs := persistentArgs(line) pArgs := persistentArgs(line)
out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() // nolint: gas if err := muxOnCommands(cmd, pArgs); err != nil {
if err != nil {
return err return err
} }
fmt.Println(string(out))
} }
return nil return nil
} }
var (
errBadPersistentArgs = errors.New("expecting persistent args of the form: abci-cli [command] <...>")
errUnimplemented = errors.New("unimplemented")
)
func muxOnCommands(cmd *cobra.Command, pArgs []string) error {
if len(pArgs) < 2 {
return errBadPersistentArgs
}
subCommand, actualArgs := pArgs[1], pArgs[2:]
switch strings.ToLower(subCommand) {
case "batch":
return cmdBatch(cmd, actualArgs)
case "check_tx":
return cmdCheckTx(cmd, actualArgs)
case "commit":
return cmdCommit(cmd, actualArgs)
case "deliver_tx":
return cmdDeliverTx(cmd, actualArgs)
case "echo":
return cmdEcho(cmd, actualArgs)
case "info":
return cmdInfo(cmd, actualArgs)
case "query":
return cmdQuery(cmd, actualArgs)
case "set_option":
return cmdSetOption(cmd, actualArgs)
default:
return cmdUnimplemented(cmd, pArgs)
}
}
func cmdUnimplemented(cmd *cobra.Command, args []string) error {
// TODO: Print out all the sub-commands available
msg := "unimplemented command"
if err := cmd.Help(); err != nil {
msg = err.Error()
}
printResponse(cmd, args, response{
Code: codeBad,
Log: msg,
})
return nil
}
// Have the application echo a message // Have the application echo a message
func cmdEcho(cmd *cobra.Command, args []string) error { func cmdEcho(cmd *cobra.Command, args []string) error {
res, err := client.EchoSync(args[0]) msg := ""
if len(args) > 0 {
msg = args[0]
}
res, err := client.EchoSync(msg)
if err != nil { if err != nil {
return err return err
} }
@ -419,8 +466,18 @@ func cmdInfo(cmd *cobra.Command, args []string) error {
return nil return nil
} }
const codeBad uint32 = 10
// Set an option on the application // Set an option on the application
func cmdSetOption(cmd *cobra.Command, args []string) error { func cmdSetOption(cmd *cobra.Command, args []string) error {
if len(args) < 2 {
printResponse(cmd, args, response{
Code: codeBad,
Log: "want at least arguments of the form: <key> <value>",
})
return nil
}
key, val := args[0], args[1] key, val := args[0], args[1]
res, err := client.SetOptionSync(types.RequestSetOption{key, val}) res, err := client.SetOptionSync(types.RequestSetOption{key, val})
if err != nil { if err != nil {
@ -435,6 +492,13 @@ func cmdSetOption(cmd *cobra.Command, args []string) error {
// Append a new tx to application // Append a new tx to application
func cmdDeliverTx(cmd *cobra.Command, args []string) error { func cmdDeliverTx(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
printResponse(cmd, args, response{
Code: codeBad,
Log: "want the tx",
})
return nil
}
txBytes, err := stringOrHexToBytes(args[0]) txBytes, err := stringOrHexToBytes(args[0])
if err != nil { if err != nil {
return err return err
@ -453,6 +517,13 @@ func cmdDeliverTx(cmd *cobra.Command, args []string) error {
// Validate a tx // Validate a tx
func cmdCheckTx(cmd *cobra.Command, args []string) error { func cmdCheckTx(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
printResponse(cmd, args, response{
Code: codeBad,
Log: "want the tx",
})
return nil
}
txBytes, err := stringOrHexToBytes(args[0]) txBytes, err := stringOrHexToBytes(args[0])
if err != nil { if err != nil {
return err return err
@ -485,6 +556,13 @@ func cmdCommit(cmd *cobra.Command, args []string) error {
// Query application state // Query application state
func cmdQuery(cmd *cobra.Command, args []string) error { func cmdQuery(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
printResponse(cmd, args, response{
Code: codeBad,
Log: "want the query",
})
return nil
}
queryBytes, err := stringOrHexToBytes(args[0]) queryBytes, err := stringOrHexToBytes(args[0])
if err != nil { if err != nil {
return err return err