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.

201 lines
5.8 KiB

  1. /*
  2. package http returns a Client implementation that communicates
  3. with a tendermint node over json rpc and websockets.
  4. This is the main implementation you probably want to use in
  5. production code. There are other implementations when calling
  6. the tendermint node in-process (local), or when you want to mock
  7. out the server for test code (mock).
  8. */
  9. package http
  10. import (
  11. "encoding/json"
  12. "github.com/pkg/errors"
  13. "github.com/tendermint/go-rpc/client"
  14. "github.com/tendermint/tendermint/rpc/client"
  15. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  16. "github.com/tendermint/tendermint/types"
  17. )
  18. // Client is a Client implementation that communicates over
  19. // JSONRPC
  20. type Client struct {
  21. remote string
  22. endpoint string
  23. rpc *rpcclient.ClientJSONRPC
  24. ws *rpcclient.WSClient
  25. }
  26. // New takes a remote endpoint in the form tcp://<host>:<port>
  27. // and the websocket path (which always seems to be "/websocket")
  28. func New(remote, wsEndpoint string) *Client {
  29. return &Client{
  30. rpc: rpcclient.NewClientJSONRPC(remote),
  31. remote: remote,
  32. endpoint: wsEndpoint,
  33. }
  34. }
  35. func (c *Client) _assertIsClient() client.Client {
  36. return c
  37. }
  38. func (c *Client) Status() (*ctypes.ResultStatus, error) {
  39. tmResult := new(ctypes.TMResult)
  40. _, err := c.rpc.Call("status", []interface{}{}, tmResult)
  41. if err != nil {
  42. return nil, errors.Wrap(err, "Status")
  43. }
  44. // note: panics if rpc doesn't match. okay???
  45. return (*tmResult).(*ctypes.ResultStatus), nil
  46. }
  47. func (c *Client) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
  48. tmResult := new(ctypes.TMResult)
  49. _, err := c.rpc.Call("abci_info", []interface{}{}, tmResult)
  50. if err != nil {
  51. return nil, errors.Wrap(err, "ABCIInfo")
  52. }
  53. return (*tmResult).(*ctypes.ResultABCIInfo), nil
  54. }
  55. func (c *Client) ABCIQuery(path string, data []byte, prove bool) (*ctypes.ResultABCIQuery, error) {
  56. tmResult := new(ctypes.TMResult)
  57. _, err := c.rpc.Call("abci_query", []interface{}{path, data, prove}, tmResult)
  58. if err != nil {
  59. return nil, errors.Wrap(err, "ABCIQuery")
  60. }
  61. return (*tmResult).(*ctypes.ResultABCIQuery), nil
  62. }
  63. func (c *Client) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
  64. tmResult := new(ctypes.TMResult)
  65. _, err := c.rpc.Call("broadcast_tx_commit", []interface{}{tx}, tmResult)
  66. if err != nil {
  67. return nil, errors.Wrap(err, "broadcast_tx_commit")
  68. }
  69. return (*tmResult).(*ctypes.ResultBroadcastTxCommit), nil
  70. }
  71. func (c *Client) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  72. return c.broadcastTX("broadcast_tx_async", tx)
  73. }
  74. func (c *Client) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  75. return c.broadcastTX("broadcast_tx_sync", tx)
  76. }
  77. func (c *Client) broadcastTX(route string, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  78. tmResult := new(ctypes.TMResult)
  79. _, err := c.rpc.Call(route, []interface{}{tx}, tmResult)
  80. if err != nil {
  81. return nil, errors.Wrap(err, route)
  82. }
  83. return (*tmResult).(*ctypes.ResultBroadcastTx), nil
  84. }
  85. func (c *Client) NetInfo() (*ctypes.ResultNetInfo, error) {
  86. tmResult := new(ctypes.TMResult)
  87. _, err := c.rpc.Call("net_info", nil, tmResult)
  88. if err != nil {
  89. return nil, errors.Wrap(err, "NetInfo")
  90. }
  91. return (*tmResult).(*ctypes.ResultNetInfo), nil
  92. }
  93. func (c *Client) DialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
  94. tmResult := new(ctypes.TMResult)
  95. // TODO: is this the correct way to marshall seeds?
  96. _, err := c.rpc.Call("dial_seeds", []interface{}{seeds}, tmResult)
  97. if err != nil {
  98. return nil, errors.Wrap(err, "DialSeeds")
  99. }
  100. return (*tmResult).(*ctypes.ResultDialSeeds), nil
  101. }
  102. func (c *Client) BlockchainInfo(minHeight, maxHeight int) (*ctypes.ResultBlockchainInfo, error) {
  103. tmResult := new(ctypes.TMResult)
  104. _, err := c.rpc.Call("blockchain", []interface{}{minHeight, maxHeight}, tmResult)
  105. if err != nil {
  106. return nil, errors.Wrap(err, "BlockchainInfo")
  107. }
  108. return (*tmResult).(*ctypes.ResultBlockchainInfo), nil
  109. }
  110. func (c *Client) Genesis() (*ctypes.ResultGenesis, error) {
  111. tmResult := new(ctypes.TMResult)
  112. _, err := c.rpc.Call("genesis", nil, tmResult)
  113. if err != nil {
  114. return nil, errors.Wrap(err, "Genesis")
  115. }
  116. return (*tmResult).(*ctypes.ResultGenesis), nil
  117. }
  118. func (c *Client) Block(height int) (*ctypes.ResultBlock, error) {
  119. tmResult := new(ctypes.TMResult)
  120. _, err := c.rpc.Call("block", []interface{}{height}, tmResult)
  121. if err != nil {
  122. return nil, errors.Wrap(err, "Block")
  123. }
  124. return (*tmResult).(*ctypes.ResultBlock), nil
  125. }
  126. func (c *Client) Commit(height int) (*ctypes.ResultCommit, error) {
  127. tmResult := new(ctypes.TMResult)
  128. _, err := c.rpc.Call("commit", []interface{}{height}, tmResult)
  129. if err != nil {
  130. return nil, errors.Wrap(err, "Commit")
  131. }
  132. return (*tmResult).(*ctypes.ResultCommit), nil
  133. }
  134. func (c *Client) Validators() (*ctypes.ResultValidators, error) {
  135. tmResult := new(ctypes.TMResult)
  136. _, err := c.rpc.Call("validators", nil, tmResult)
  137. if err != nil {
  138. return nil, errors.Wrap(err, "Validators")
  139. }
  140. return (*tmResult).(*ctypes.ResultValidators), nil
  141. }
  142. /** websocket event stuff here... **/
  143. // StartWebsocket starts up a websocket and a listener goroutine
  144. // if already started, do nothing
  145. func (c *Client) StartWebsocket() error {
  146. var err error
  147. if c.ws == nil {
  148. ws := rpcclient.NewWSClient(c.remote, c.endpoint)
  149. _, err = ws.Start()
  150. if err == nil {
  151. c.ws = ws
  152. }
  153. }
  154. return errors.Wrap(err, "StartWebsocket")
  155. }
  156. // StopWebsocket stops the websocket connection
  157. func (c *Client) StopWebsocket() {
  158. if c.ws != nil {
  159. c.ws.Stop()
  160. c.ws = nil
  161. }
  162. }
  163. // GetEventChannels returns the results and error channel from the websocket
  164. func (c *Client) GetEventChannels() (chan json.RawMessage, chan error) {
  165. if c.ws == nil {
  166. return nil, nil
  167. }
  168. return c.ws.ResultsCh, c.ws.ErrorsCh
  169. }
  170. func (c *Client) Subscribe(event string) error {
  171. return errors.Wrap(c.ws.Subscribe(event), "Subscribe")
  172. }
  173. func (c *Client) Unsubscribe(event string) error {
  174. return errors.Wrap(c.ws.Unsubscribe(event), "Unsubscribe")
  175. }