-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
client.go
164 lines (140 loc) · 6.04 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
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 whatsonchain
import (
"net"
"net/http"
"time"
"github.com/gojektech/heimdall/v6"
"github.com/gojektech/heimdall/v6/httpclient"
)
const (
// version is the current version
version = "v0.13.0"
// defaultUserAgent is the default user agent for all requests
defaultUserAgent string = "go-whatsonchain: " + version
// defaultRateLimit is the default rate limit for API requests
defaultRateLimit int = 3
// apiEndpoint is where we fire requests
apiEndpoint string = "https://api.whatsonchain.com/v1/bsv/"
// socketEndpoint is where we connect to websockets
socketEndpoint string = "wss://socket.whatsonchain.com/"
// apiHeaderKey is the header key for the API key
apiHeaderKey string = "woc-api-key"
)
// HTTPInterface is used for the http client (mocking heimdall)
type HTTPInterface interface {
Do(req *http.Request) (*http.Response, error)
}
// Client is the parent struct that wraps the heimdall client
type Client struct {
apiKey string // optional for requests that require an API Key
httpClient HTTPInterface // carries out the http operations (heimdall client)
lastRequest *LastRequest // is the raw information from the last request
network NetworkType // is the BitcoinSV network to use
rateLimit int // configured rate limit per second
userAgent string // optional for changing user agents
}
// Options holds all the configuration for connection, dialer and transport
type Options struct {
APIKey string `json:"api_key"`
BackOffExponentFactor float64 `json:"back_off_exponent_factor"`
BackOffInitialTimeout time.Duration `json:"back_off_initial_timeout"`
BackOffMaximumJitterInterval time.Duration `json:"back_off_maximum_jitter_interval"`
BackOffMaxTimeout time.Duration `json:"back_off_max_timeout"`
DialerKeepAlive time.Duration `json:"dialer_keep_alive"`
DialerTimeout time.Duration `json:"dialer_timeout"`
RateLimit int `json:"rate_limit"`
RequestRetryCount int `json:"request_retry_count"`
RequestTimeout time.Duration `json:"request_timeout"`
TransportExpectContinueTimeout time.Duration `json:"transport_expect_continue_timeout"`
TransportIdleTimeout time.Duration `json:"transport_idle_timeout"`
TransportMaxIdleConnections int `json:"transport_max_idle_connections"`
TransportTLSHandshakeTimeout time.Duration `json:"transport_tls_handshake_timeout"`
UserAgent string `json:"user_agent"`
}
// LastRequest is used to track what was submitted via the request()
type LastRequest struct {
Method string `json:"method"` // method is the HTTP method used
PostData string `json:"post_data"` // postData is the post data submitted if POST/PUT request
StatusCode int `json:"status_code"` // statusCode is the last code from the request
URL string `json:"url"` // url is the url used for the request
}
// ClientDefaultOptions will return an "Options" struct with the default settings
// Useful for starting with the default and then modifying as needed
func ClientDefaultOptions() (clientOptions *Options) {
return &Options{
BackOffExponentFactor: 2.0,
BackOffInitialTimeout: 2 * time.Millisecond,
BackOffMaximumJitterInterval: 2 * time.Millisecond,
BackOffMaxTimeout: 10 * time.Millisecond,
DialerKeepAlive: 20 * time.Second,
DialerTimeout: 5 * time.Second,
RequestRetryCount: 2,
RequestTimeout: 30 * time.Second,
TransportExpectContinueTimeout: 3 * time.Second,
TransportIdleTimeout: 20 * time.Second,
TransportMaxIdleConnections: 10,
TransportTLSHandshakeTimeout: 5 * time.Second,
UserAgent: defaultUserAgent,
RateLimit: defaultRateLimit,
}
}
// createClient will make a new http client based on the options provided
func createClient(network NetworkType, options *Options, customHTTPClient HTTPInterface) (c *Client) {
// Create a client
c = &Client{
lastRequest: &LastRequest{},
network: network,
}
// Set options (either default or user modified)
if options == nil {
options = ClientDefaultOptions()
}
// Set values on the client from the given options
c.apiKey = options.APIKey
c.rateLimit = options.RateLimit
c.userAgent = options.UserAgent
// Is there a custom HTTP client to use?
if customHTTPClient != nil {
c.httpClient = customHTTPClient
return
}
// dial is the net dialer for clientDefaultTransport
dial := &net.Dialer{KeepAlive: options.DialerKeepAlive, Timeout: options.DialerTimeout}
// clientDefaultTransport is the default transport struct for the HTTP client
clientDefaultTransport := &http.Transport{
DialContext: dial.DialContext,
ExpectContinueTimeout: options.TransportExpectContinueTimeout,
IdleConnTimeout: options.TransportIdleTimeout,
MaxIdleConns: options.TransportMaxIdleConnections,
Proxy: http.ProxyFromEnvironment,
TLSHandshakeTimeout: options.TransportTLSHandshakeTimeout,
}
// Determine the strategy for the http client (no retry enabled)
if options.RequestRetryCount <= 0 {
c.httpClient = httpclient.NewClient(
httpclient.WithHTTPTimeout(options.RequestTimeout),
httpclient.WithHTTPClient(&http.Client{
Transport: clientDefaultTransport,
Timeout: options.RequestTimeout,
}),
)
} else { // Retry enabled
// Create exponential back-off
backOff := heimdall.NewExponentialBackoff(
options.BackOffInitialTimeout,
options.BackOffMaxTimeout,
options.BackOffExponentFactor,
options.BackOffMaximumJitterInterval,
)
c.httpClient = httpclient.NewClient(
httpclient.WithHTTPTimeout(options.RequestTimeout),
httpclient.WithRetrier(heimdall.NewRetrier(backOff)),
httpclient.WithRetryCount(options.RequestRetryCount),
httpclient.WithHTTPClient(&http.Client{
Transport: clientDefaultTransport,
Timeout: options.RequestTimeout,
}),
)
}
return
}