-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.go
134 lines (111 loc) · 3.18 KB
/
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
130
131
132
133
134
/**
* Copyright (c) 2018, TransChain.
*
* This source code is licensed under the Apache 2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
package api
import (
"net"
"time"
"github.com/valyala/fasthttp"
"github.com/katena-chain/sdk-go/entity/api"
"github.com/katena-chain/sdk-go/entity/common"
)
// Client interface defines the methods a concrete client must implement.
type Client interface {
Get(route string, headers map[string]string, queryValues map[string]string) (*api.RawResponse, error)
Post(route string, body []byte, headers map[string]string, queryValues map[string]string) (*api.RawResponse, error)
AddHeader(key string, value string)
RemoveHeader(key string)
}
// FastHttpClient is a fasthttp.FastHttpClient wrapper to dialog with a JSON API.
type FastHttpClient struct {
fastHttpClient *fasthttp.Client
apiUrl string
headers map[string]string
}
// FastHttpClient constructor.
func NewFastHttpClient(apiUrl string) *FastHttpClient {
return &FastHttpClient{
fastHttpClient: &fasthttp.Client{
Dial: func(addr string) (net.Conn, error) {
return fasthttp.DialTimeout(addr, 15*time.Second)
},
MaxIdemponentCallAttempts: 1,
},
apiUrl: apiUrl,
headers: make(map[string]string),
}
}
// AddHeader adds a persistent header that will be sent in every future doRequest calls.
func (c FastHttpClient) AddHeader(key string, value string) {
c.headers[key] = value
}
// RemoveHeader removes a persistent header.
func (c FastHttpClient) RemoveHeader(key string) {
delete(c.headers, key)
}
// Get wraps the doRequest method to do a GET HTTP request.
func (c FastHttpClient) Get(
route string,
headers map[string]string,
queryValues map[string]string,
) (*api.RawResponse, error) {
return c.doRequest("GET", route, nil, headers, queryValues)
}
// Post wraps the doRequest method to do a POST HTTP request.
func (c FastHttpClient) Post(
route string,
body []byte,
headers map[string]string,
queryValues map[string]string,
) (*api.RawResponse, error) {
return c.doRequest("POST", route, body, headers, queryValues)
}
// doRequest uses the fasthttp.FastHttpClient to call a distant api and returns a response.
func (c FastHttpClient) doRequest(
method string,
route string,
body []byte,
headers map[string]string,
queryValues map[string]string,
) (*api.RawResponse, error) {
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
req.SetConnectionClose()
defer func() {
if req != nil {
fasthttp.ReleaseRequest(req)
}
if resp != nil {
fasthttp.ReleaseResponse(resp)
}
}()
fullUri, err := common.BuildUri(c.apiUrl, []string{route}, queryValues)
if err != nil {
return nil, err
}
req.SetRequestURI(fullUri.String())
if body != nil {
req.SetBody(body)
}
req.Header.SetMethod(method)
for key, value := range c.headers {
req.Header.Set(key, value)
}
for key, value := range headers {
req.Header.Set(key, value)
}
err = c.fastHttpClient.Do(req, resp)
if err != nil {
return nil, err
}
originalBody := resp.Body()
copiedBody := make([]byte, len(originalBody))
copy(copiedBody, originalBody)
return &api.RawResponse{
StatusCode: resp.StatusCode(),
Body: copiedBody,
}, nil
}