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.

326 lines
6.6 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
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. "errors"
  5. "fmt"
  6. "io"
  7. "net"
  8. "os"
  9. "strings"
  10. "github.com/codegangsta/cli"
  11. . "github.com/tendermint/go-common"
  12. "github.com/tendermint/go-wire/expr"
  13. "github.com/tendermint/tmsp/types"
  14. )
  15. // connection is a global variable so it can be reused by the console
  16. var conn net.Conn
  17. func main() {
  18. app := cli.NewApp()
  19. app.Name = "tmsp-cli"
  20. app.Usage = "tmsp-cli [command] [args...]"
  21. app.Flags = []cli.Flag{
  22. cli.StringFlag{
  23. Name: "address",
  24. Value: "tcp://127.0.0.1:46658",
  25. Usage: "address of application socket",
  26. },
  27. }
  28. app.Commands = []cli.Command{
  29. {
  30. Name: "batch",
  31. Usage: "Run a batch of tmsp commands against an application",
  32. Action: func(c *cli.Context) {
  33. cmdBatch(app, c)
  34. },
  35. },
  36. {
  37. Name: "console",
  38. Usage: "Start an interactive tmsp console for multiple commands",
  39. Action: func(c *cli.Context) {
  40. cmdConsole(app, c)
  41. },
  42. },
  43. {
  44. Name: "echo",
  45. Usage: "Have the application echo a message",
  46. Action: func(c *cli.Context) {
  47. cmdEcho(c)
  48. },
  49. },
  50. {
  51. Name: "info",
  52. Usage: "Get some info about the application",
  53. Action: func(c *cli.Context) {
  54. cmdInfo(c)
  55. },
  56. },
  57. {
  58. Name: "set_option",
  59. Usage: "Set an option on the application",
  60. Action: func(c *cli.Context) {
  61. cmdSetOption(c)
  62. },
  63. },
  64. {
  65. Name: "append_tx",
  66. Usage: "Append a new tx to application",
  67. Action: func(c *cli.Context) {
  68. cmdAppendTx(c)
  69. },
  70. },
  71. {
  72. Name: "check_tx",
  73. Usage: "Validate a tx",
  74. Action: func(c *cli.Context) {
  75. cmdCheckTx(c)
  76. },
  77. },
  78. {
  79. Name: "commit",
  80. Usage: "Commit the application state and return the Merkle root hash",
  81. Action: func(c *cli.Context) {
  82. cmdCommit(c)
  83. },
  84. },
  85. {
  86. Name: "query",
  87. Usage: "Query application state",
  88. Action: func(c *cli.Context) {
  89. cmdQuery(c)
  90. },
  91. },
  92. }
  93. app.Before = before
  94. app.Run(os.Args)
  95. }
  96. func before(c *cli.Context) error {
  97. if conn == nil {
  98. var err error
  99. conn, err = Connect(c.GlobalString("address"))
  100. if err != nil {
  101. Exit(err.Error())
  102. }
  103. }
  104. return nil
  105. }
  106. //--------------------------------------------------------------------------------
  107. func cmdBatch(app *cli.App, c *cli.Context) {
  108. bufReader := bufio.NewReader(os.Stdin)
  109. for {
  110. line, more, err := bufReader.ReadLine()
  111. if more {
  112. fmt.Println("input line is too long")
  113. return
  114. } else if err == io.EOF {
  115. break
  116. } else if len(line) == 0 {
  117. continue
  118. } else if err != nil {
  119. fmt.Println(err.Error())
  120. return
  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("\n> ")
  130. bufReader := bufio.NewReader(os.Stdin)
  131. line, more, err := bufReader.ReadLine()
  132. if more {
  133. fmt.Println("input is too long")
  134. return
  135. } else if err != nil {
  136. fmt.Println(err.Error())
  137. return
  138. }
  139. args := []string{"tmsp"}
  140. args = append(args, strings.Split(string(line), " ")...)
  141. app.Run(args)
  142. }
  143. }
  144. // Have the application echo a message
  145. func cmdEcho(c *cli.Context) {
  146. args := c.Args()
  147. if len(args) != 1 {
  148. fmt.Println("echo takes 1 argument")
  149. return
  150. }
  151. res, err := makeRequest(conn, types.RequestEcho(args[0]))
  152. if err != nil {
  153. fmt.Println(err.Error())
  154. return
  155. }
  156. printResponse(res, string(res.Data))
  157. }
  158. // Get some info from the application
  159. func cmdInfo(c *cli.Context) {
  160. res, err := makeRequest(conn, types.RequestInfo())
  161. if err != nil {
  162. fmt.Println(err.Error())
  163. return
  164. }
  165. printResponse(res, string(res.Data))
  166. }
  167. // Set an option on the application
  168. func cmdSetOption(c *cli.Context) {
  169. args := c.Args()
  170. if len(args) != 2 {
  171. fmt.Println("set_option takes 2 arguments (key, value)")
  172. return
  173. }
  174. res, err := makeRequest(conn, types.RequestSetOption(args[0], args[1]))
  175. if err != nil {
  176. fmt.Println(err.Error())
  177. return
  178. }
  179. printResponse(res, Fmt("%s=%s", args[0], args[1]))
  180. }
  181. // Append a new tx to application
  182. func cmdAppendTx(c *cli.Context) {
  183. args := c.Args()
  184. if len(args) != 1 {
  185. fmt.Println("append_tx takes 1 argument")
  186. return
  187. }
  188. txExprString := c.Args()[0]
  189. txBytes, err := expr.Compile(txExprString)
  190. if err != nil {
  191. fmt.Println(err.Error())
  192. return
  193. }
  194. res, err := makeRequest(conn, types.RequestAppendTx(txBytes))
  195. if err != nil {
  196. fmt.Println(err.Error())
  197. return
  198. }
  199. printResponse(res, string(res.Data))
  200. }
  201. // Validate a tx
  202. func cmdCheckTx(c *cli.Context) {
  203. args := c.Args()
  204. if len(args) != 1 {
  205. fmt.Println("check_tx takes 1 argument")
  206. return
  207. }
  208. txExprString := c.Args()[0]
  209. txBytes, err := expr.Compile(txExprString)
  210. if err != nil {
  211. fmt.Println(err.Error())
  212. return
  213. }
  214. res, err := makeRequest(conn, types.RequestCheckTx(txBytes))
  215. if err != nil {
  216. fmt.Println(err.Error())
  217. return
  218. }
  219. printResponse(res, string(res.Data))
  220. }
  221. // Get application Merkle root hash
  222. func cmdCommit(c *cli.Context) {
  223. res, err := makeRequest(conn, types.RequestCommit())
  224. if err != nil {
  225. fmt.Println(err.Error())
  226. return
  227. }
  228. printResponse(res, Fmt("%X", res.Data))
  229. }
  230. // Query application state
  231. func cmdQuery(c *cli.Context) {
  232. args := c.Args()
  233. if len(args) != 1 {
  234. fmt.Println("query takes 1 argument")
  235. return
  236. }
  237. queryExprString := args[0]
  238. queryBytes, err := expr.Compile(queryExprString)
  239. if err != nil {
  240. fmt.Println(err.Error())
  241. return
  242. }
  243. res, err := makeRequest(conn, types.RequestQuery(queryBytes))
  244. if err != nil {
  245. fmt.Println(err.Error())
  246. return
  247. }
  248. printResponse(res, string(res.Data))
  249. }
  250. //--------------------------------------------------------------------------------
  251. func printResponse(res *types.Response, s string) {
  252. switch res.Type {
  253. case types.MessageType_AppendTx, types.MessageType_CheckTx, types.MessageType_Query:
  254. fmt.Printf("-> code: %s\n", res.Code.String())
  255. }
  256. if res.Error != "" {
  257. fmt.Printf("-> error: %s\n", res.Error)
  258. }
  259. if s != "" {
  260. fmt.Printf("-> data: {%s}\n", s)
  261. }
  262. if res.Log != "" {
  263. fmt.Printf("-> log: %s\n", res.Log)
  264. }
  265. }
  266. func responseString(res *types.Response) string {
  267. return Fmt("type: %v\tdata: %v\tcode: %v", res.Type, res.Data, res.Code)
  268. }
  269. func makeRequest(conn net.Conn, req *types.Request) (*types.Response, error) {
  270. // Write desired request
  271. err := types.WriteMessage(req, conn)
  272. if err != nil {
  273. return nil, err
  274. }
  275. // Write flush request
  276. err = types.WriteMessage(types.RequestFlush(), conn)
  277. if err != nil {
  278. return nil, err
  279. }
  280. // Read desired response
  281. var res = &types.Response{}
  282. err = types.ReadMessage(conn, res)
  283. if err != nil {
  284. return nil, err
  285. }
  286. // Read flush response
  287. var resFlush = &types.Response{}
  288. err = types.ReadMessage(conn, resFlush)
  289. if err != nil {
  290. return nil, err
  291. }
  292. if resFlush.Type != types.MessageType_Flush {
  293. return nil, errors.New(Fmt("Expected types.MessageType_Flush but got %v instead", resFlush.Type))
  294. }
  295. return res, nil
  296. }