forked from quobyte/api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rpc_client.go
129 lines (113 loc) · 2.92 KB
/
rpc_client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package quobyte
import (
"bytes"
"encoding/json"
"errors"
"io"
"io/ioutil"
"log"
"math/rand"
"net/http"
"reflect"
"strconv"
)
const (
emptyResponse string = "Empty result and no error occured"
)
type request struct {
ID string `json:"id"`
Version string `json:"jsonrpc"`
Method string `json:"method"`
Params interface{} `json:"params"`
}
type response struct {
ID string `json:"id"`
Version string `json:"jsonrpc"`
Result *json.RawMessage `json:"result"`
Error *json.RawMessage `json:"error"`
}
type rpcError struct {
Code int64 `json:"code"`
Message string `json:"message"`
}
func (err *rpcError) decodeErrorCode() string {
switch err.Code {
case -32600:
return "ERROR_CODE_INVALID_REQUEST"
case -32603:
return "ERROR_CODE_JSON_ENCODING_FAILED"
case -32601:
return "ERROR_CODE_METHOD_NOT_FOUND"
case -32700:
return "ERROR_CODE_PARSE_ERROR"
}
return ""
}
func encodeRequest(method string, params interface{}) ([]byte, error) {
return json.Marshal(&request{
// Generate random ID and convert it to a string
ID: strconv.FormatInt(rand.Int63(), 10),
Version: "2.0",
Method: method,
Params: params,
})
}
func decodeResponse(ioReader io.Reader, reply interface{}) error {
var resp response
if err := json.NewDecoder(ioReader).Decode(&resp); err != nil {
return err
}
if resp.Error != nil {
var rpcErr rpcError
if err := json.Unmarshal(*resp.Error, &rpcErr); err != nil {
return err
}
if rpcErr.Message != "" {
return errors.New(rpcErr.Message)
}
respError := rpcErr.decodeErrorCode()
if respError != "" {
return errors.New(respError)
}
}
if resp.Result != nil && reply != nil {
return json.Unmarshal(*resp.Result, reply)
}
return errors.New(emptyResponse)
}
func (client QuobyteClient) sendRequest(method string, request interface{}, response interface{}) error {
etype := reflect.ValueOf(request).Elem()
field := etype.FieldByName("RetryPolicy")
if field.IsValid() {
field.SetString(client.GetAPIRetryPolicy())
}
message, err := encodeRequest(method, request)
if err != nil {
return err
}
req, err := http.NewRequest("POST", client.url, bytes.NewBuffer(message))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth(client.username, client.password)
resp, err := client.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode > 299 {
log.Printf("Warning: HTTP status code for request is %s\n",
strconv.Itoa(resp.StatusCode))
if resp.StatusCode == 401 {
return errors.New("Unable to authenticate with Quobyte API service")
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return (err)
}
log.Printf("Warning: Dumping full reply body:\n%s\n", string(body))
return errors.New("JsonRPC failed, see plugin logfile for details")
}
return decodeResponse(resp.Body, &response)
}