@@ -18,6 +18,7 @@ package ffresty
18
18
19
19
import (
20
20
"context"
21
+ "crypto/tls"
21
22
"encoding/base64"
22
23
"fmt"
23
24
"io"
@@ -29,7 +30,6 @@ import (
29
30
"github.com/go-resty/resty/v2"
30
31
"github.com/hyperledger/firefly-common/pkg/config"
31
32
"github.com/hyperledger/firefly-common/pkg/ffapi"
32
- "github.com/hyperledger/firefly-common/pkg/fftls"
33
33
"github.com/hyperledger/firefly-common/pkg/fftypes"
34
34
"github.com/hyperledger/firefly-common/pkg/i18n"
35
35
"github.com/hyperledger/firefly-common/pkg/log"
@@ -44,6 +44,28 @@ type retryCtx struct {
44
44
attempts uint
45
45
}
46
46
47
+ type Config struct {
48
+ URL string `json:"httpURL,omitempty"`
49
+ ProxyURL string `json:"proxyURL,omitempty"`
50
+ HTTPRequestTimeout time.Duration `json:"requestTimeout,omitempty"`
51
+ HTTPIdleConnTimeout time.Duration `json:"idleTimeout,omitempty"`
52
+ HTTPMaxIdleTimeout time.Duration `json:"maxIdleTimeout,omitempty"`
53
+ HTTPConnectionTimeout time.Duration `json:"connectionTimeout,omitempty"`
54
+ HTTPExpectContinueTimeout time.Duration `json:"expectContinueTimeout,omitempty"`
55
+ AuthUsername string `json:"authUsername,omitempty"`
56
+ AuthPassword string `json:"authPassword,omitempty"`
57
+ Retry bool `json:"retry,omitempty"`
58
+ RetryCount int `json:"retryCount,omitempty"`
59
+ RetryInitialDelay time.Duration `json:"retryInitialDelay,omitempty"`
60
+ RetryMaximumDelay time.Duration `json:"retryMaximumDelay,omitempty"`
61
+ HTTPMaxIdleConns int `json:"maxIdleConns,omitempty"`
62
+ HTTPPassthroughHeadersEnabled bool `json:"httpPassthroughHeadersEnabled,omitempty"`
63
+ HTTPHeaders fftypes.JSONObject `json:"headers,omitempty"`
64
+ TLSClientConfig * tls.Config `json:"tlsClientConfig,omitempty"`
65
+ HTTPTLSHandshakeTimeout time.Duration `json:"tlsHandshakeTimeout,omitempty"`
66
+ HTTPCustomClient interface {} `json:"httpCustomClient,omitempty"`
67
+ }
68
+
47
69
// OnAfterResponse when using SetDoNotParseResponse(true) for streaming binary replies,
48
70
// the caller should invoke ffresty.OnAfterResponse on the response manually.
49
71
// The middleware is disabled on this path :-(
@@ -69,54 +91,62 @@ func OnAfterResponse(c *resty.Client, resp *resty.Response) {
69
91
// You can use the normal Resty builder pattern, to set per-instance configuration
70
92
// as required.
71
93
func New (ctx context.Context , staticConfig config.Section ) (client * resty.Client , err error ) {
72
- passthroughHeadersEnabled := staticConfig .GetBool (HTTPPassthroughHeadersEnabled )
94
+ ffrestyConfig , err := GenerateConfig (ctx , staticConfig )
95
+ if err != nil {
96
+ return nil , err
97
+ }
73
98
74
- iHTTPClient := staticConfig .Get (HTTPCustomClient )
75
- if iHTTPClient != nil {
76
- if httpClient , ok := iHTTPClient .(* http.Client ); ok {
99
+ return NewWithConfig (ctx , * ffrestyConfig ), nil
100
+ }
101
+
102
+ // New creates a new Resty client, using static configuration (from the config file)
103
+ // from a given section in the static configuration
104
+ //
105
+ // You can use the normal Resty builder pattern, to set per-instance configuration
106
+ // as required.
107
+ func NewWithConfig (ctx context.Context , ffrestyConfig Config ) (client * resty.Client ) {
108
+ if ffrestyConfig .HTTPCustomClient != nil {
109
+ if httpClient , ok := ffrestyConfig .HTTPCustomClient .(* http.Client ); ok {
77
110
client = resty .NewWithClient (httpClient )
78
111
}
79
112
}
113
+
80
114
if client == nil {
81
115
82
116
httpTransport := & http.Transport {
83
117
Proxy : http .ProxyFromEnvironment ,
84
118
DialContext : (& net.Dialer {
85
- Timeout : staticConfig . GetDuration ( HTTPConnectionTimeout ) ,
86
- KeepAlive : staticConfig . GetDuration ( HTTPConnectionTimeout ) ,
119
+ Timeout : ffrestyConfig . HTTPConnectionTimeout ,
120
+ KeepAlive : ffrestyConfig . HTTPConnectionTimeout ,
87
121
}).DialContext ,
88
122
ForceAttemptHTTP2 : true ,
89
- MaxIdleConns : staticConfig . GetInt ( HTTPMaxIdleConns ) ,
90
- IdleConnTimeout : staticConfig . GetDuration ( HTTPIdleTimeout ) ,
91
- TLSHandshakeTimeout : staticConfig . GetDuration ( HTTPTLSHandshakeTimeout ) ,
92
- ExpectContinueTimeout : staticConfig . GetDuration ( HTTPExpectContinueTimeout ) ,
123
+ MaxIdleConns : ffrestyConfig . HTTPMaxIdleConns ,
124
+ IdleConnTimeout : ffrestyConfig . HTTPIdleConnTimeout ,
125
+ TLSHandshakeTimeout : ffrestyConfig . HTTPTLSHandshakeTimeout ,
126
+ ExpectContinueTimeout : ffrestyConfig . HTTPExpectContinueTimeout ,
93
127
}
94
128
95
- tlsConfig , err := fftls .ConstructTLSConfig (ctx , staticConfig .SubSection ("tls" ), "client" )
96
- if err != nil {
97
- return nil , err
129
+ if ffrestyConfig .TLSClientConfig != nil {
130
+ httpTransport .TLSClientConfig = ffrestyConfig .TLSClientConfig
98
131
}
99
132
100
- httpTransport .TLSClientConfig = tlsConfig
101
-
102
133
httpClient := & http.Client {
103
134
Transport : httpTransport ,
104
135
}
105
136
client = resty .NewWithClient (httpClient )
106
137
}
107
138
108
- url := strings .TrimSuffix (staticConfig . GetString ( HTTPConfigURL ) , "/" )
139
+ url := strings .TrimSuffix (ffrestyConfig . URL , "/" )
109
140
if url != "" {
110
141
client .SetBaseURL (url )
111
142
log .L (ctx ).Debugf ("Created REST client to %s" , url )
112
143
}
113
144
114
- proxy := staticConfig .GetString (HTTPConfigProxyURL )
115
- if proxy != "" {
116
- client .SetProxy (proxy )
145
+ if ffrestyConfig .ProxyURL != "" {
146
+ client .SetProxy (ffrestyConfig .ProxyURL )
117
147
}
118
148
119
- client .SetTimeout (staticConfig . GetDuration ( HTTPConfigRequestTimeout ) )
149
+ client .SetTimeout (ffrestyConfig . HTTPRequestTimeout )
120
150
121
151
client .OnBeforeRequest (func (c * resty.Client , req * resty.Request ) error {
122
152
rCtx := req .Context ()
@@ -135,7 +165,7 @@ func New(ctx context.Context, staticConfig config.Section) (client *resty.Client
135
165
}
136
166
137
167
// If passthroughHeaders: true for this rest client, pass any of the allowed headers on the original req
138
- if passthroughHeadersEnabled {
168
+ if ffrestyConfig . HTTPPassthroughHeadersEnabled {
139
169
ctxHeaders := rCtx .Value (ffapi.CtxHeadersKey {})
140
170
if ctxHeaders != nil {
141
171
passthroughHeaders := ctxHeaders .(http.Header )
@@ -159,22 +189,19 @@ func New(ctx context.Context, staticConfig config.Section) (client *resty.Client
159
189
160
190
client .OnAfterResponse (func (c * resty.Client , r * resty.Response ) error { OnAfterResponse (c , r ); return nil })
161
191
162
- headers := staticConfig .GetObject (HTTPConfigHeaders )
163
- for k , v := range headers {
192
+ for k , v := range ffrestyConfig .HTTPHeaders {
164
193
if vs , ok := v .(string ); ok {
165
194
client .SetHeader (k , vs )
166
195
}
167
196
}
168
- authUsername := staticConfig .GetString ((HTTPConfigAuthUsername ))
169
- authPassword := staticConfig .GetString ((HTTPConfigAuthPassword ))
170
- if authUsername != "" && authPassword != "" {
171
- client .SetHeader ("Authorization" , fmt .Sprintf ("Basic %s" , base64 .StdEncoding .EncodeToString ([]byte (fmt .Sprintf ("%s:%s" , authUsername , authPassword )))))
197
+ if ffrestyConfig .AuthUsername != "" && ffrestyConfig .AuthPassword != "" {
198
+ client .SetHeader ("Authorization" , fmt .Sprintf ("Basic %s" , base64 .StdEncoding .EncodeToString ([]byte (fmt .Sprintf ("%s:%s" , ffrestyConfig .AuthUsername , ffrestyConfig .AuthPassword )))))
172
199
}
173
200
174
- if staticConfig . GetBool ( HTTPConfigRetryEnabled ) {
175
- retryCount := staticConfig . GetInt ( HTTPConfigRetryCount )
176
- minTimeout := staticConfig . GetDuration ( HTTPConfigRetryInitDelay )
177
- maxTimeout := staticConfig . GetDuration ( HTTPConfigRetryMaxDelay )
201
+ if ffrestyConfig . Retry {
202
+ retryCount := ffrestyConfig . RetryCount
203
+ minTimeout := ffrestyConfig . RetryInitialDelay
204
+ maxTimeout := ffrestyConfig . RetryMaximumDelay
178
205
client .
179
206
SetRetryCount (retryCount ).
180
207
SetRetryWaitTime (minTimeout ).
@@ -191,7 +218,7 @@ func New(ctx context.Context, staticConfig config.Section) (client *resty.Client
191
218
})
192
219
}
193
220
194
- return client , nil
221
+ return client
195
222
}
196
223
197
224
func WrapRestErr (ctx context.Context , res * resty.Response , err error , key i18n.ErrorMessageKey ) error {
0 commit comments