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.

162 lines
4.1 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. // JSON rpc takes params as a slice
  30. type ClientJSONRPC struct {
  31. remote string
  32. client *http.Client
  33. }
  34. func NewClientJSONRPC(remote string) *ClientJSONRPC {
  35. return &ClientJSONRPC{
  36. remote: remote,
  37. client: &http.Client{Transport: socketTransport(remote)},
  38. }
  39. }
  40. func (c *ClientJSONRPC) Call(method string, params []interface{}, result interface{}) (interface{}, error) {
  41. return c.call(method, params, result)
  42. }
  43. func (c *ClientJSONRPC) call(method string, params []interface{}, result interface{}) (interface{}, error) {
  44. // Make request and get responseBytes
  45. request := rpctypes.RPCRequest{
  46. JSONRPC: "2.0",
  47. Method: method,
  48. Params: params,
  49. ID: "",
  50. }
  51. requestBytes := wire.JSONBytes(request)
  52. requestBuf := bytes.NewBuffer(requestBytes)
  53. log.Info(Fmt("RPC request to %v (%v): %v", c.remote, method, string(requestBytes)))
  54. httpResponse, err := c.client.Post(dummyDomain, "text/json", requestBuf)
  55. if err != nil {
  56. return nil, err
  57. }
  58. defer httpResponse.Body.Close()
  59. responseBytes, err := ioutil.ReadAll(httpResponse.Body)
  60. if err != nil {
  61. return nil, err
  62. }
  63. // log.Info(Fmt("RPC response: %v", string(responseBytes)))
  64. return unmarshalResponseBytes(responseBytes, result)
  65. }
  66. //-------------------------------------------------------------
  67. // URI takes params as a map
  68. type ClientURI struct {
  69. remote string
  70. client *http.Client
  71. }
  72. func NewClientURI(remote string) *ClientURI {
  73. return &ClientURI{
  74. remote: remote,
  75. client: &http.Client{Transport: socketTransport(remote)},
  76. }
  77. }
  78. func (c *ClientURI) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
  79. return c.call(method, params, result)
  80. }
  81. func (c *ClientURI) call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
  82. values, err := argsToURLValues(params)
  83. if err != nil {
  84. return nil, err
  85. }
  86. log.Info(Fmt("URI request to %v (%v): %v", c.remote, method, values))
  87. resp, err := c.client.PostForm(dummyDomain+"/"+method, values)
  88. if err != nil {
  89. return nil, err
  90. }
  91. defer resp.Body.Close()
  92. responseBytes, err := ioutil.ReadAll(resp.Body)
  93. if err != nil {
  94. return nil, err
  95. }
  96. return unmarshalResponseBytes(responseBytes, result)
  97. }
  98. //------------------------------------------------
  99. func unmarshalResponseBytes(responseBytes []byte, result interface{}) (interface{}, error) {
  100. // read response
  101. // if rpc/core/types is imported, the result will unmarshal
  102. // into the correct type
  103. var err error
  104. response := &rpctypes.RPCResponse{}
  105. err = json.Unmarshal(responseBytes, response)
  106. if err != nil {
  107. return nil, err
  108. }
  109. errorStr := response.Error
  110. if errorStr != "" {
  111. return nil, errors.New(errorStr)
  112. }
  113. // unmarshal the RawMessage into the result
  114. result = wire.ReadJSONPtr(result, *response.Result, &err)
  115. return result, err
  116. }
  117. func argsToURLValues(args map[string]interface{}) (url.Values, error) {
  118. values := make(url.Values)
  119. if len(args) == 0 {
  120. return values, nil
  121. }
  122. err := argsToJson(args)
  123. if err != nil {
  124. return nil, err
  125. }
  126. for key, val := range args {
  127. values.Set(key, val.(string))
  128. }
  129. return values, nil
  130. }
  131. func argsToJson(args map[string]interface{}) error {
  132. var n int
  133. var err error
  134. for k, v := range args {
  135. buf := new(bytes.Buffer)
  136. wire.WriteJSON(v, buf, &n, &err)
  137. if err != nil {
  138. return err
  139. }
  140. args[k] = buf.String()
  141. }
  142. return nil
  143. }