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.

167 lines
4.2 KiB

  1. package rpcclient
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "io/ioutil"
  7. "net"
  8. "net/http"
  9. "net/url"
  10. . "github.com/tendermint/go-common"
  11. "github.com/tendermint/go-rpc/types"
  12. "github.com/tendermint/go-wire"
  13. )
  14. // Set the net.Dial manually so we can do http over tcp or unix.
  15. // Get/Post require a dummyDomain but it's over written by the Transport
  16. var dummyDomain = "http://dummyDomain"
  17. func dialer(remote string) func(string, string) (net.Conn, error) {
  18. return func(proto, addr string) (conn net.Conn, err error) {
  19. return net.Dial(rpctypes.SocketType(remote), remote)
  20. }
  21. }
  22. // remote is IP:PORT or /path/to/socket
  23. func socketTransport(remote string) *http.Transport {
  24. return &http.Transport{
  25. Dial: dialer(remote),
  26. }
  27. }
  28. //------------------------------------------------------------------------------------
  29. type Client interface {
  30. }
  31. //------------------------------------------------------------------------------------
  32. // JSON rpc takes params as a slice
  33. type ClientJSONRPC struct {
  34. remote string
  35. client *http.Client
  36. }
  37. func NewClientJSONRPC(remote string) *ClientJSONRPC {
  38. return &ClientJSONRPC{
  39. remote: remote,
  40. client: &http.Client{Transport: socketTransport(remote)},
  41. }
  42. }
  43. func (c *ClientJSONRPC) Call(method string, params []interface{}, result interface{}) (interface{}, error) {
  44. return c.call(method, params, result)
  45. }
  46. func (c *ClientJSONRPC) call(method string, params []interface{}, result interface{}) (interface{}, error) {
  47. // Make request and get responseBytes
  48. request := rpctypes.RPCRequest{
  49. JSONRPC: "2.0",
  50. Method: method,
  51. Params: params,
  52. ID: "",
  53. }
  54. requestBytes := wire.JSONBytes(request)
  55. requestBuf := bytes.NewBuffer(requestBytes)
  56. // log.Info(Fmt("RPC request to %v (%v): %v", c.remote, method, string(requestBytes)))
  57. httpResponse, err := c.client.Post(dummyDomain, "text/json", requestBuf)
  58. if err != nil {
  59. return nil, err
  60. }
  61. defer httpResponse.Body.Close()
  62. responseBytes, err := ioutil.ReadAll(httpResponse.Body)
  63. if err != nil {
  64. return nil, err
  65. }
  66. // log.Info(Fmt("RPC response: %v", string(responseBytes)))
  67. return unmarshalResponseBytes(responseBytes, result)
  68. }
  69. //-------------------------------------------------------------
  70. // URI takes params as a map
  71. type ClientURI struct {
  72. remote string
  73. client *http.Client
  74. }
  75. func NewClientURI(remote string) *ClientURI {
  76. return &ClientURI{
  77. remote: remote,
  78. client: &http.Client{Transport: socketTransport(remote)},
  79. }
  80. }
  81. func (c *ClientURI) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
  82. return c.call(method, params, result)
  83. }
  84. func (c *ClientURI) call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
  85. values, err := argsToURLValues(params)
  86. if err != nil {
  87. return nil, err
  88. }
  89. log.Info(Fmt("URI request to %v (%v): %v", c.remote, method, values))
  90. resp, err := c.client.PostForm(dummyDomain+"/"+method, values)
  91. if err != nil {
  92. return nil, err
  93. }
  94. defer resp.Body.Close()
  95. responseBytes, err := ioutil.ReadAll(resp.Body)
  96. if err != nil {
  97. return nil, err
  98. }
  99. return unmarshalResponseBytes(responseBytes, result)
  100. }
  101. //------------------------------------------------
  102. func unmarshalResponseBytes(responseBytes []byte, result interface{}) (interface{}, error) {
  103. // read response
  104. // if rpc/core/types is imported, the result will unmarshal
  105. // into the correct type
  106. var err error
  107. response := &rpctypes.RPCResponse{}
  108. err = json.Unmarshal(responseBytes, response)
  109. if err != nil {
  110. return nil, err
  111. }
  112. errorStr := response.Error
  113. if errorStr != "" {
  114. return nil, errors.New(errorStr)
  115. }
  116. // unmarshal the RawMessage into the result
  117. result = wire.ReadJSONPtr(result, *response.Result, &err)
  118. return result, err
  119. }
  120. func argsToURLValues(args map[string]interface{}) (url.Values, error) {
  121. values := make(url.Values)
  122. if len(args) == 0 {
  123. return values, nil
  124. }
  125. err := argsToJson(args)
  126. if err != nil {
  127. return nil, err
  128. }
  129. for key, val := range args {
  130. values.Set(key, val.(string))
  131. }
  132. return values, nil
  133. }
  134. func argsToJson(args map[string]interface{}) error {
  135. var n int
  136. var err error
  137. for k, v := range args {
  138. buf := new(bytes.Buffer)
  139. wire.WriteJSON(v, buf, &n, &err)
  140. if err != nil {
  141. return err
  142. }
  143. args[k] = buf.String()
  144. }
  145. return nil
  146. }