rpc_client.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package quobyte
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "io"
  7. "log"
  8. "math/rand"
  9. "net/http"
  10. "reflect"
  11. "strconv"
  12. )
  13. const (
  14. emptyResponse string = "Empty result and no error occured"
  15. )
  16. type request struct {
  17. ID string `json:"id"`
  18. Version string `json:"jsonrpc"`
  19. Method string `json:"method"`
  20. Params interface{} `json:"params"`
  21. }
  22. type response struct {
  23. ID string `json:"id"`
  24. Version string `json:"jsonrpc"`
  25. Result *json.RawMessage `json:"result"`
  26. Error *json.RawMessage `json:"error"`
  27. }
  28. type rpcError struct {
  29. Code int64 `json:"code"`
  30. Message string `json:"message"`
  31. }
  32. func (err *rpcError) decodeErrorCode() string {
  33. switch err.Code {
  34. case -32600:
  35. return "ERROR_CODE_INVALID_REQUEST"
  36. case -32603:
  37. return "ERROR_CODE_JSON_ENCODING_FAILED"
  38. case -32601:
  39. return "ERROR_CODE_METHOD_NOT_FOUND"
  40. case -32700:
  41. return "ERROR_CODE_PARSE_ERROR"
  42. }
  43. return ""
  44. }
  45. func encodeRequest(method string, params interface{}) ([]byte, error) {
  46. return json.Marshal(&request{
  47. // Generate random ID and convert it to a string
  48. ID: strconv.FormatInt(rand.Int63(), 10),
  49. Version: "2.0",
  50. Method: method,
  51. Params: params,
  52. })
  53. }
  54. func decodeResponse(ioReader io.Reader, reply interface{}) error {
  55. var resp response
  56. if err := json.NewDecoder(ioReader).Decode(&resp); err != nil {
  57. return err
  58. }
  59. if resp.Error != nil {
  60. var rpcErr rpcError
  61. if err := json.Unmarshal(*resp.Error, &rpcErr); err != nil {
  62. return err
  63. }
  64. if rpcErr.Message != "" {
  65. return errors.New(rpcErr.Message)
  66. }
  67. respError := rpcErr.decodeErrorCode()
  68. if respError != "" {
  69. return errors.New(respError)
  70. }
  71. }
  72. if resp.Result != nil && reply != nil {
  73. return json.Unmarshal(*resp.Result, reply)
  74. }
  75. return errors.New(emptyResponse)
  76. }
  77. func (client QuobyteClient) sendRequest(method string, request interface{}, response interface{}) error {
  78. etype := reflect.ValueOf(request).Elem()
  79. field := etype.FieldByName("RetryPolicy")
  80. if field.IsValid() {
  81. field.SetString(client.GetAPIRetryPolicy())
  82. }
  83. message, err := encodeRequest(method, request)
  84. if err != nil {
  85. return err
  86. }
  87. req, err := http.NewRequest("POST", client.url, bytes.NewBuffer(message))
  88. if err != nil {
  89. return err
  90. }
  91. req.Header.Set("Content-Type", "application/json")
  92. req.SetBasicAuth(client.username, client.password)
  93. resp, err := client.client.Do(req)
  94. if err != nil {
  95. return err
  96. }
  97. defer resp.Body.Close()
  98. if resp.StatusCode < 200 || resp.StatusCode > 299 {
  99. log.Printf("Warning: HTTP status code for request is %s\n", strconv.Itoa(resp.StatusCode))
  100. }
  101. return decodeResponse(resp.Body, &response)
  102. }