-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgreq.go
More file actions
164 lines (135 loc) · 4.14 KB
/
greq.go
File metadata and controls
164 lines (135 loc) · 4.14 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Package greq is a simple http client request builder, support batch requests.
package greq
import (
"encoding/json"
"encoding/xml"
"io"
"net"
"net/http"
"time"
)
// DefaultDoer for request.
var DefaultDoer = http.DefaultClient
// BodyProvider provides Body content for http.Request attachment.
//
// Concrete implementations live in internal/bodyprovider; users may also
// implement this interface themselves and pass it via Builder.BodyProvider.
type BodyProvider interface {
// ContentType returns the Content-Type of the body.
ContentType() string
// Body returns the io.Reader body.
Body() (io.Reader, error)
}
// HandleFunc for the Middleware
type HandleFunc func(r *http.Request) (*Response, error)
// AfterSendFn callback func
type AfterSendFn func(resp *Response, err error)
// RetryChecker function type for checking if a request should be retried
type RetryChecker func(resp *Response, err error, attempt int) bool
// DefaultRetryChecker is the default retry condition checker
// It retries on:
// - Network errors (err != nil)
// - 5xx server errors
// - 429 Too Many Requests
func DefaultRetryChecker(resp *Response, err error, attempt int) bool {
// Retry on network errors
if err != nil {
return true
}
// Retry on server errors (5xx)
if resp.StatusCode >= 500 && resp.StatusCode < 600 {
return true
}
// Retry on rate limiting (429)
if resp.StatusCode == 429 {
return true
}
return false
}
// RequestCreator interface
type RequestCreator interface {
NewRequest(method, target string, body io.Reader) *http.Request
}
// RequestCreatorFunc func
type RequestCreatorFunc func(method, target string, body io.Reader) *http.Request
// Must return response, if error will panic
func Must(w *Response, err error) *Response {
if err != nil {
panic(err)
}
return w
}
// NewTransport create new http transport
func NewTransport(onCreate func(ht *http.Transport)) *http.Transport {
transport := &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 500,
MaxConnsPerHost: 200,
MaxIdleConnsPerHost: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
if onCreate != nil {
onCreate(transport)
}
return transport
}
//
// region Middleware
// ------------------------------
// Middleware interface for cli request.
type Middleware interface {
Handle(r *http.Request, next HandleFunc) (*Response, error)
}
// MiddleFunc implements the Middleware interface
type MiddleFunc func(r *http.Request, next HandleFunc) (*Response, error)
// Handle request
func (mf MiddleFunc) Handle(r *http.Request, next HandleFunc) (*Response, error) {
return mf(r, next)
}
// wrap middlewares, and will wrap http.Response to Response
func (h *Client) wrapMiddlewares() {
// set core handler
h.handler = func(r *http.Request) (*Response, error) {
rawResp, err := h.doer.Do(r)
if err != nil {
return nil, err
}
return NewResponse(rawResp, h.RespDecoder), nil
}
for _, m := range h.middles {
h.wrapMiddleware(m)
}
}
func (h *Client) wrapMiddleware(m Middleware) {
next := h.handler
// wrap handler
h.handler = func(r *http.Request) (*Response, error) {
return m.Handle(r, next)
}
}
//
// region Response decoders
// ------------------------------
// RespDecoder decodes http responses into struct values.
type RespDecoder interface {
// Decode decodes the response into the value pointed to by ptr.
Decode(resp *http.Response, ptr any) error
}
// jsonDecoder decodes http response JSON into a JSON-tagged struct value.
type jsonDecoder struct{}
// Decode decodes the Response Body into the value pointed to by ptr.
// Caller must provide a non-nil v and close the resp.Body.
func (d jsonDecoder) Decode(resp *http.Response, ptr any) error {
return json.NewDecoder(resp.Body).Decode(ptr)
}
// XmlDecoder decodes http response body into a XML-tagged struct value.
type XmlDecoder struct{}
// Decode decodes the Response body into the value pointed to by ptr.
func (d XmlDecoder) Decode(resp *http.Response, ptr any) error {
return xml.NewDecoder(resp.Body).Decode(ptr)
}