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.

236 lines
5.1 KiB

  1. package rpc
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "github.com/tendermint/tendermint2/binary"
  7. "io/ioutil"
  8. "net/http"
  9. "net/url"
  10. "reflect"
  11. )
  12. type Response struct {
  13. Status string
  14. Data interface{}
  15. Error string
  16. }
  17. //go:generate rpc-gen -interface Client -pkg core -type *ClientHTTP,*ClientJSON -exclude pipe.go -out-pkg rpc
  18. type ClientJSON struct {
  19. addr string
  20. }
  21. type ClientHTTP struct {
  22. addr string
  23. }
  24. func NewClient(addr, typ string) Client {
  25. switch typ {
  26. case "HTTP":
  27. return &ClientHTTP{addr}
  28. case "JSONRPC":
  29. return &ClientJSON{addr}
  30. }
  31. return nil
  32. }
  33. func argsToJson(args ...interface{}) ([][]string, error) {
  34. l := len(args)
  35. jsons := make([][]string, l)
  36. n, err := new(int64), new(error)
  37. for i, a := range args {
  38. //if its a slice, we serliaze separately and pack into a slice of strings
  39. // otherwise its a slice of length 1
  40. if v := reflect.ValueOf(a); v.Kind() == reflect.Slice {
  41. ty := v.Type()
  42. rt := ty.Elem()
  43. if rt.Kind() == reflect.Uint8 {
  44. buf := new(bytes.Buffer)
  45. binary.WriteJSON(a, buf, n, err)
  46. if *err != nil {
  47. return nil, *err
  48. }
  49. jsons[i] = []string{string(buf.Bytes())}
  50. } else {
  51. slice := make([]string, v.Len())
  52. for j := 0; j < v.Len(); j++ {
  53. buf := new(bytes.Buffer)
  54. binary.WriteJSON(v.Index(j).Interface(), buf, n, err)
  55. if *err != nil {
  56. return nil, *err
  57. }
  58. slice[j] = string(buf.Bytes())
  59. }
  60. jsons[i] = slice
  61. }
  62. } else {
  63. buf := new(bytes.Buffer)
  64. binary.WriteJSON(a, buf, n, err)
  65. if *err != nil {
  66. return nil, *err
  67. }
  68. jsons[i] = []string{string(buf.Bytes())}
  69. }
  70. }
  71. return jsons, nil
  72. }
  73. func (c *ClientHTTP) RequestResponse(method string, values url.Values) (*Response, error) {
  74. resp, err := http.PostForm(c.addr+method, values)
  75. if err != nil {
  76. return nil, err
  77. }
  78. defer resp.Body.Close()
  79. body, err := ioutil.ReadAll(resp.Body)
  80. if err != nil {
  81. return nil, err
  82. }
  83. response := new(Response)
  84. fmt.Println(string(body))
  85. binary.ReadJSON(response, body, &err)
  86. if err != nil {
  87. return nil, err
  88. }
  89. fmt.Println(response.Data)
  90. return response, nil
  91. }
  92. func (c *ClientJSON) requestResponse(s JSONRPC) ([]byte, error) {
  93. b, err := json.Marshal(s)
  94. if err != nil {
  95. return nil, err
  96. }
  97. buf := bytes.NewBuffer(b)
  98. resp, err := http.Post(c.addr, "text/json", buf)
  99. if err != nil {
  100. return nil, err
  101. }
  102. defer resp.Body.Close()
  103. return ioutil.ReadAll(resp.Body)
  104. }
  105. /*
  106. What follows is used by `rpc-gen` when `go generate` is called
  107. to populate the rpc client methods
  108. */
  109. // first we define the base interface, which rpc-gen will further populate with generated methods
  110. /*rpc-gen:define-interface Client
  111. type Client interface {
  112. Address() string // returns the remote address
  113. }
  114. */
  115. // encoding functions
  116. func binaryWriter(args ...interface{}) ([]interface{}, error) {
  117. list := []interface{}{}
  118. for _, a := range args {
  119. buf, n, err := new(bytes.Buffer), new(int64), new(error)
  120. binary.WriteJSON(a, buf, n, err)
  121. if *err != nil {
  122. return nil, *err
  123. }
  124. list = append(list, buf.Bytes())
  125. }
  126. return list, nil
  127. }
  128. func argsToURLValues(argNames []string, args ...interface{}) (url.Values, error) {
  129. values := make(url.Values)
  130. if len(argNames) == 0 {
  131. return values, nil
  132. }
  133. if len(argNames) != len(args) {
  134. return nil, fmt.Errorf("argNames and args have different lengths: %d, %d", len(argNames), len(args))
  135. }
  136. slice, err := argsToJson(args...)
  137. if err != nil {
  138. return nil, err
  139. }
  140. for i, name := range argNames {
  141. s := slice[i]
  142. values.Set(name, s[0])
  143. for i := 1; i < len(s); i++ {
  144. values.Add(name, s[i])
  145. }
  146. }
  147. return values, nil
  148. }
  149. // import statements we will need for the templates
  150. /*rpc-gen:imports:
  151. github.com/tendermint/tendermint2/binary
  152. net/http
  153. io/ioutil
  154. fmt
  155. */
  156. // Template functions to be filled in
  157. /*rpc-gen:template:*ClientJSON func (c *ClientJSON) {{name}}({{args.def}}) ({{response}}) {
  158. params, err := binaryWriter({{args.ident}})
  159. if err != nil{
  160. return nil, err
  161. }
  162. s := JSONRPC{
  163. JSONRPC: "2.0",
  164. Method: {{lowername}},
  165. Params: params,
  166. Id: 0,
  167. }
  168. body, err := c.requestResponse(s)
  169. if err != nil{
  170. return nil, err
  171. }
  172. var response struct {
  173. Result {{response.0}} `json:"result"`
  174. Error string `json:"error"`
  175. Id string `json:"id"`
  176. JSONRPC string `json:"jsonrpc"`
  177. }
  178. binary.ReadJSON(&response, body, &err)
  179. if err != nil {
  180. return nil, err
  181. }
  182. if response.Error != ""{
  183. return nil, fmt.Errorf(response.Error)
  184. }
  185. return response.Result, nil
  186. }*/
  187. /*rpc-gen:template:*ClientHTTP func (c *ClientHTTP) {{name}}({{args.def}}) ({{response}}){
  188. values, err := argsToURLValues({{args.name}}, {{args.ident}})
  189. if err != nil{
  190. return nil, err
  191. }
  192. resp, err := http.PostForm(c.addr+{{lowername}}, values)
  193. if err != nil {
  194. return nil, err
  195. }
  196. defer resp.Body.Close()
  197. body, err := ioutil.ReadAll(resp.Body)
  198. if err != nil {
  199. return nil, err
  200. }
  201. var response struct {
  202. Result {{response.0}} `json:"result"`
  203. Error string `json:"error"`
  204. Id string `json:"id"`
  205. JSONRPC string `json:"jsonrpc"`
  206. }
  207. binary.ReadJSON(&response, body, &err)
  208. if err != nil {
  209. return nil, err
  210. }
  211. if response.Error != ""{
  212. return nil, fmt.Errorf(response.Error)
  213. }
  214. return response.Result, nil
  215. }*/