You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

275 lines
5.7 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. package main
  2. import (
  3. "bufio"
  4. "encoding/hex"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "net"
  9. "os"
  10. "reflect"
  11. "strings"
  12. . "github.com/tendermint/go-common"
  13. "github.com/tendermint/go-wire"
  14. "github.com/tendermint/tmsp/types"
  15. "github.com/codegangsta/cli"
  16. )
  17. // connection is a global variable so it can be reused by the console
  18. var conn net.Conn
  19. func main() {
  20. app := cli.NewApp()
  21. app.Name = "cli"
  22. app.Usage = "cli [command] [args...]"
  23. app.Flags = []cli.Flag{
  24. cli.StringFlag{
  25. Name: "address",
  26. Value: "tcp://127.0.0.1:46658",
  27. Usage: "address of application socket",
  28. },
  29. }
  30. app.Commands = []cli.Command{
  31. {
  32. Name: "batch",
  33. Usage: "Run a batch of tmsp commands against an application",
  34. Action: func(c *cli.Context) {
  35. cmdBatch(app, c)
  36. },
  37. },
  38. {
  39. Name: "console",
  40. Usage: "Start an interactive tmsp console for multiple commands",
  41. Action: func(c *cli.Context) {
  42. cmdConsole(app, c)
  43. },
  44. },
  45. {
  46. Name: "echo",
  47. Usage: "Have the application echo a message",
  48. Action: func(c *cli.Context) {
  49. cmdEcho(c)
  50. },
  51. },
  52. {
  53. Name: "info",
  54. Usage: "Get some info about the application",
  55. Action: func(c *cli.Context) {
  56. cmdInfo(c)
  57. },
  58. },
  59. {
  60. Name: "set_option",
  61. Usage: "Set an option on the application",
  62. Action: func(c *cli.Context) {
  63. cmdSetOption(c)
  64. },
  65. },
  66. {
  67. Name: "append_tx",
  68. Usage: "Append a new tx to application",
  69. Action: func(c *cli.Context) {
  70. cmdAppendTx(c)
  71. },
  72. },
  73. {
  74. Name: "get_hash",
  75. Usage: "Get application Merkle root hash",
  76. Action: func(c *cli.Context) {
  77. cmdGetHash(c)
  78. },
  79. },
  80. {
  81. Name: "commit",
  82. Usage: "Commit the application state",
  83. Action: func(c *cli.Context) {
  84. cmdCommit(c)
  85. },
  86. },
  87. {
  88. Name: "rollback",
  89. Usage: "Roll back the application state to the latest commit",
  90. Action: func(c *cli.Context) {
  91. cmdRollback(c)
  92. },
  93. },
  94. }
  95. app.Before = before
  96. app.Run(os.Args)
  97. }
  98. func before(c *cli.Context) error {
  99. if conn == nil {
  100. var err error
  101. conn, err = Connect(c.GlobalString("address"))
  102. if err != nil {
  103. Exit(err.Error())
  104. }
  105. }
  106. return nil
  107. }
  108. //--------------------------------------------------------------------------------
  109. func cmdBatch(app *cli.App, c *cli.Context) {
  110. bufReader := bufio.NewReader(os.Stdin)
  111. for {
  112. line, more, err := bufReader.ReadLine()
  113. if more {
  114. Exit("input line is too long")
  115. } else if err == io.EOF {
  116. break
  117. } else if len(line) == 0 {
  118. continue
  119. } else if err != nil {
  120. Exit(err.Error())
  121. }
  122. args := []string{"tmsp"}
  123. args = append(args, strings.Split(string(line), " ")...)
  124. app.Run(args)
  125. }
  126. }
  127. func cmdConsole(app *cli.App, c *cli.Context) {
  128. for {
  129. fmt.Printf("> ")
  130. bufReader := bufio.NewReader(os.Stdin)
  131. line, more, err := bufReader.ReadLine()
  132. if more {
  133. Exit("input is too long")
  134. } else if err != nil {
  135. Exit(err.Error())
  136. }
  137. args := []string{"tmsp"}
  138. args = append(args, strings.Split(string(line), " ")...)
  139. app.Run(args)
  140. }
  141. }
  142. // Have the application echo a message
  143. func cmdEcho(c *cli.Context) {
  144. args := c.Args()
  145. if len(args) != 1 {
  146. Exit("echo takes 1 argument")
  147. }
  148. res, err := makeRequest(conn, types.RequestEcho{args[0]})
  149. if err != nil {
  150. Exit(err.Error())
  151. }
  152. fmt.Println(res)
  153. }
  154. // Get some info from the application
  155. func cmdInfo(c *cli.Context) {
  156. res, err := makeRequest(conn, types.RequestInfo{})
  157. if err != nil {
  158. Exit(err.Error())
  159. }
  160. fmt.Println(res)
  161. }
  162. // Set an option on the application
  163. func cmdSetOption(c *cli.Context) {
  164. args := c.Args()
  165. if len(args) != 2 {
  166. Exit("set_option takes 2 arguments (key, value)")
  167. }
  168. _, err := makeRequest(conn, types.RequestSetOption{args[0], args[1]})
  169. if err != nil {
  170. Exit(err.Error())
  171. }
  172. fmt.Printf("%s=%s\n", args[0], args[1])
  173. }
  174. // Append a new tx to application
  175. func cmdAppendTx(c *cli.Context) {
  176. args := c.Args()
  177. if len(args) != 1 {
  178. Exit("append_tx takes 1 argument")
  179. }
  180. txString := args[0]
  181. tx := []byte(txString)
  182. if len(txString) > 2 && strings.HasPrefix(txString, "0x") {
  183. var err error
  184. tx, err = hex.DecodeString(txString[2:])
  185. if err != nil {
  186. Exit(err.Error())
  187. }
  188. }
  189. res, err := makeRequest(conn, types.RequestAppendTx{tx})
  190. if err != nil {
  191. Exit(err.Error())
  192. }
  193. fmt.Println("Response:", res)
  194. }
  195. // Get application Merkle root hash
  196. func cmdGetHash(c *cli.Context) {
  197. res, err := makeRequest(conn, types.RequestGetHash{})
  198. if err != nil {
  199. Exit(err.Error())
  200. }
  201. fmt.Printf("%X\n", res.(types.ResponseGetHash).Hash)
  202. }
  203. // Commit the application state
  204. func cmdCommit(c *cli.Context) {
  205. _, err := makeRequest(conn, types.RequestCommit{})
  206. if err != nil {
  207. Exit(err.Error())
  208. }
  209. fmt.Println("Committed.")
  210. }
  211. // Roll back the application state to the latest commit
  212. func cmdRollback(c *cli.Context) {
  213. _, err := makeRequest(conn, types.RequestRollback{})
  214. if err != nil {
  215. Exit(err.Error())
  216. }
  217. fmt.Println("Rolled back.")
  218. }
  219. //--------------------------------------------------------------------------------
  220. func makeRequest(conn net.Conn, req types.Request) (types.Response, error) {
  221. var n int
  222. var err error
  223. // Write desired request
  224. wire.WriteBinaryLengthPrefixed(struct{ types.Request }{req}, conn, &n, &err)
  225. if err != nil {
  226. return nil, err
  227. }
  228. // Write flush request
  229. wire.WriteBinaryLengthPrefixed(struct{ types.Request }{types.RequestFlush{}}, conn, &n, &err)
  230. if err != nil {
  231. return nil, err
  232. }
  233. // Read desired response
  234. var res types.Response
  235. wire.ReadBinaryPtrLengthPrefixed(&res, conn, 0, &n, &err)
  236. if err != nil {
  237. return nil, err
  238. }
  239. // Read flush response
  240. var resFlush types.Response
  241. wire.ReadBinaryPtrLengthPrefixed(&resFlush, conn, 0, &n, &err)
  242. if err != nil {
  243. return nil, err
  244. }
  245. if _, ok := resFlush.(types.ResponseFlush); !ok {
  246. return nil, errors.New(Fmt("Expected types.ResponseFlush but got %v instead", reflect.TypeOf(resFlush)))
  247. }
  248. return res, nil
  249. }