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.5 KiB

10 years ago
  1. package core_client
  2. import (
  3. "bytes"
  4. "fmt"
  5. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  6. rpctypes "github.com/tendermint/tendermint/rpc/types"
  7. "github.com/tendermint/tendermint/wire"
  8. "io/ioutil"
  9. "net/http"
  10. "net/url"
  11. //"reflect"
  12. // Uncomment to use go:generate
  13. // _ "github.com/tendermint/go-rpc-gen"
  14. )
  15. // maps camel-case function names to lower case rpc version
  16. var reverseFuncMap = map[string]string{
  17. "Status": "status",
  18. "NetInfo": "net_info",
  19. "BlockchainInfo": "blockchain",
  20. "Genesis": "genesis",
  21. "GetBlock": "get_block",
  22. "GetAccount": "get_account",
  23. "GetStorage": "get_storage",
  24. "Call": "call",
  25. "CallCode": "call_code",
  26. "ListValidators": "list_validators",
  27. "DumpConsensusState": "dump_consensus_state",
  28. "DumpStorage": "dump_storage",
  29. "BroadcastTx": "broadcast_tx",
  30. "ListUnconfirmedTxs": "list_unconfirmed_txs",
  31. "ListAccounts": "list_accounts",
  32. "GetName": "get_name",
  33. "ListNames": "list_names",
  34. "GenPrivAccount": "unsafe/gen_priv_account",
  35. "SignTx": "unsafe/sign_tx",
  36. }
  37. /*
  38. // fill the map from camelcase to lowercase
  39. func fillReverseFuncMap() map[string]string {
  40. fMap := make(map[string]string)
  41. for name, f := range core.Routes {
  42. camelName := runtime.FuncForPC(f.f.Pointer()).Name()
  43. spl := strings.Split(camelName, ".")
  44. if len(spl) > 1 {
  45. camelName = spl[len(spl)-1]
  46. }
  47. fMap[camelName] = name
  48. }
  49. return fMap
  50. }
  51. */
  52. type Response struct {
  53. Status string
  54. Data interface{}
  55. Error string
  56. }
  57. //go:generate go-rpc-gen -interface Client -dir ../core -pkg core -type *ClientHTTP,*ClientJSON -exclude pipe.go -out-pkg core_client
  58. type ClientJSON struct {
  59. addr string
  60. }
  61. type ClientHTTP struct {
  62. addr string
  63. }
  64. func NewClient(addr, typ string) Client {
  65. switch typ {
  66. case "HTTP":
  67. return &ClientHTTP{addr}
  68. case "JSONRPC":
  69. return &ClientJSON{addr}
  70. default:
  71. panic("Unknown client type " + typ + ". Select HTTP or JSONRPC")
  72. }
  73. return nil
  74. }
  75. func argsToJson(args ...interface{}) ([]string, error) {
  76. l := len(args)
  77. jsons := make([]string, l)
  78. n, err := new(int64), new(error)
  79. for i, a := range args {
  80. buf := new(bytes.Buffer)
  81. wire.WriteJSON(a, buf, n, err)
  82. if *err != nil {
  83. return nil, *err
  84. }
  85. jsons[i] = string(buf.Bytes())
  86. }
  87. return jsons, nil
  88. }
  89. func (c *ClientJSON) RequestResponse(s rpctypes.RPCRequest) (b []byte, err error) {
  90. b = wire.JSONBytes(s)
  91. buf := bytes.NewBuffer(b)
  92. resp, err := http.Post(c.addr, "text/json", buf)
  93. if err != nil {
  94. return nil, err
  95. }
  96. defer resp.Body.Close()
  97. return ioutil.ReadAll(resp.Body)
  98. }
  99. /*
  100. What follows is used by `rpc-gen` when `go generate` is called
  101. to populate the rpc client methods
  102. */
  103. // first we define the base interface, which rpc-gen will further populate with generated methods
  104. /*rpc-gen:define-interface Client
  105. type Client interface {
  106. Address() string // returns the remote address
  107. }
  108. */
  109. // encoding functions
  110. func binaryWriter(args ...interface{}) ([]interface{}, error) {
  111. list := []interface{}{}
  112. for _, a := range args {
  113. buf, n, err := new(bytes.Buffer), new(int64), new(error)
  114. wire.WriteJSON(a, buf, n, err)
  115. if *err != nil {
  116. return nil, *err
  117. }
  118. list = append(list, buf.Bytes())
  119. }
  120. return list, nil
  121. }
  122. func argsToURLValues(argNames []string, args ...interface{}) (url.Values, error) {
  123. values := make(url.Values)
  124. if len(argNames) == 0 {
  125. return values, nil
  126. }
  127. if len(argNames) != len(args) {
  128. return nil, fmt.Errorf("argNames and args have different lengths: %d, %d", len(argNames), len(args))
  129. }
  130. slice, err := argsToJson(args...)
  131. if err != nil {
  132. return nil, err
  133. }
  134. for i, name := range argNames {
  135. s := slice[i]
  136. values.Set(name, s) // s[0]
  137. /*for j := 1; j < len(s); j++ {
  138. values.Add(name, s[j])
  139. }*/
  140. }
  141. return values, nil
  142. }
  143. func unmarshalCheckResponse(body []byte) (response *ctypes.Response, err error) {
  144. response = new(ctypes.Response)
  145. wire.ReadJSON(response, body, &err)
  146. if err != nil {
  147. return nil, err
  148. }
  149. if response.Error != "" {
  150. return nil, fmt.Errorf(response.Error)
  151. }
  152. return response, nil
  153. }
  154. // import statements we will need for the templates
  155. /*rpc-gen:imports:
  156. rpctypes github.com/tendermint/tendermint/rpc/types
  157. net/http
  158. io/ioutil
  159. fmt
  160. */
  161. // Template functions to be filled in
  162. /*rpc-gen:template:*ClientJSON func (c *ClientJSON) {{name}}({{args.def}}) ({{response}}) {
  163. request := rpctypes.RPCRequest{
  164. JSONRPC: "2.0",
  165. Method: reverseFuncMap["{{name}}"],
  166. Params: []interface{}{ {{args.ident}} },
  167. ID: "",
  168. }
  169. body, err := c.RequestResponse(request)
  170. if err != nil{
  171. return nil, err
  172. }
  173. response, err := unmarshalCheckResponse(body)
  174. if err != nil{
  175. return nil, err
  176. }
  177. if response.Result == nil {
  178. return nil, nil
  179. }
  180. result, ok := response.Result.({{response.0}})
  181. if !ok{
  182. return nil, fmt.Errorf("response result was wrong type")
  183. }
  184. return result, nil
  185. }*/
  186. /*rpc-gen:template:*ClientHTTP func (c *ClientHTTP) {{name}}({{args.def}}) ({{response}}){
  187. values, err := argsToURLValues({{args.name}}, {{args.ident}})
  188. if err != nil{
  189. return nil, err
  190. }
  191. resp, err := http.PostForm(c.addr+reverseFuncMap["{{name}}"], values)
  192. if err != nil {
  193. return nil, err
  194. }
  195. defer resp.Body.Close()
  196. body, err := ioutil.ReadAll(resp.Body)
  197. if err != nil {
  198. return nil, err
  199. }
  200. response, err := unmarshalCheckResponse(body)
  201. if err != nil{
  202. return nil, err
  203. }
  204. if response.Result == nil {
  205. return nil, nil
  206. }
  207. result, ok := response.Result.({{response.0}})
  208. if !ok{
  209. return nil, fmt.Errorf("response result was wrong type")
  210. }
  211. return result, nil
  212. }*/