Skip to content

Commit 47f3e6c

Browse files
authored
Merge pull request #116 from xanzy/svh/f-http-client
Introduce optional client configuration options
2 parents 42f262b + ca5ab20 commit 47f3e6c

2 files changed

Lines changed: 70 additions & 10 deletions

File tree

cloudstack/cloudstack.go

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ func IsID(id string) bool {
4646
return idRegex.MatchString(id)
4747
}
4848

49+
// ClientOption can be passed to new client functions to set custom options
50+
type ClientOption func(*CloudStackClient)
51+
4952
// OptionFunc can be passed to the courtesy helper functions to set additional parameters
5053
type OptionFunc func(*CloudStackClient, interface{}) error
5154

@@ -142,7 +145,7 @@ type CloudStackClient struct {
142145
}
143146

144147
// Creates a new client for communicating with CloudStack
145-
func newClient(apiurl string, apikey string, secret string, async bool, verifyssl bool) *CloudStackClient {
148+
func newClient(apiurl string, apikey string, secret string, async bool, verifyssl bool, options ...ClientOption) *CloudStackClient {
146149
jar, _ := cookiejar.New(nil)
147150
cs := &CloudStackClient{
148151
client: &http.Client{
@@ -169,6 +172,11 @@ func newClient(apiurl string, apikey string, secret string, async bool, verifyss
169172
options: []OptionFunc{},
170173
timeout: 300,
171174
}
175+
176+
for _, fn := range options {
177+
fn(cs)
178+
}
179+
172180
cs.APIDiscovery = NewAPIDiscoveryService(cs)
173181
cs.Account = NewAccountService(cs)
174182
cs.Address = NewAddressService(cs)
@@ -238,23 +246,24 @@ func newClient(apiurl string, apikey string, secret string, async bool, verifyss
238246
cs.VirtualMachine = NewVirtualMachineService(cs)
239247
cs.Volume = NewVolumeService(cs)
240248
cs.Zone = NewZoneService(cs)
249+
241250
return cs
242251
}
243252

244253
// Default non-async client. So for async calls you need to implement and check the async job result yourself. When using
245254
// HTTPS with a self-signed certificate to connect to your CloudStack API, you would probably want to set 'verifyssl' to
246255
// false so the call ignores the SSL errors/warnings.
247-
func NewClient(apiurl string, apikey string, secret string, verifyssl bool) *CloudStackClient {
248-
cs := newClient(apiurl, apikey, secret, false, verifyssl)
256+
func NewClient(apiurl string, apikey string, secret string, verifyssl bool, options ...ClientOption) *CloudStackClient {
257+
cs := newClient(apiurl, apikey, secret, false, verifyssl, options...)
249258
return cs
250259
}
251260

252261
// For sync API calls this client behaves exactly the same as a standard client call, but for async API calls
253262
// this client will wait until the async job is finished or until the configured AsyncTimeout is reached. When the async
254263
// job finishes successfully it will return actual object received from the API and nil, but when the timout is
255264
// reached it will return the initial object containing the async job ID for the running job and a warning.
256-
func NewAsyncClient(apiurl string, apikey string, secret string, verifyssl bool) *CloudStackClient {
257-
cs := newClient(apiurl, apikey, secret, true, verifyssl)
265+
func NewAsyncClient(apiurl string, apikey string, secret string, verifyssl bool, options ...ClientOption) *CloudStackClient {
266+
cs := newClient(apiurl, apikey, secret, true, verifyssl, options...)
258267
return cs
259268
}
260269

@@ -419,6 +428,15 @@ func getRawValue(b json.RawMessage) (json.RawMessage, error) {
419428
return nil, fmt.Errorf("Unable to extract the raw value from:\n\n%s\n\n", string(b))
420429
}
421430

431+
// WithAsyncTimeout takes a custom timeout to be used by the CloudStackClient
432+
func WithAsyncTimeout(timeout int64) ClientOption {
433+
return func(cs *CloudStackClient) {
434+
if timeout != 0 {
435+
cs.timeout = timeout
436+
}
437+
}
438+
}
439+
422440
// DomainIDSetter is an interface that every type that can set a domain ID must implement
423441
type DomainIDSetter interface {
424442
SetDomainid(string)
@@ -447,6 +465,18 @@ func WithDomain(domain string) OptionFunc {
447465
}
448466
}
449467

468+
// WithHTTPClient takes a custom HTTP client to be used by the CloudStackClient
469+
func WithHTTPClient(client *http.Client) ClientOption {
470+
return func(cs *CloudStackClient) {
471+
if client != nil {
472+
if client.Jar == nil {
473+
client.Jar = cs.client.Jar
474+
}
475+
cs.client = client
476+
}
477+
}
478+
}
479+
450480
// ProjectIDSetter is an interface that every type that can set a project ID must implement
451481
type ProjectIDSetter interface {
452482
SetProjectid(string)

generate/generate.go

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ func (as *allServices) GeneralCode() ([]byte, error) {
241241
pn(" return idRegex.MatchString(id)")
242242
pn("}")
243243
pn("")
244+
pn("// ClientOption can be passed to new client functions to set custom options")
245+
pn("type ClientOption func(*CloudStackClient)")
246+
pn("")
244247
pn("// OptionFunc can be passed to the courtesy helper functions to set additional parameters")
245248
pn("type OptionFunc func(*CloudStackClient, interface{}) error")
246249
pn("")
@@ -271,7 +274,7 @@ func (as *allServices) GeneralCode() ([]byte, error) {
271274
pn("}")
272275
pn("")
273276
pn("// Creates a new client for communicating with CloudStack")
274-
pn("func newClient(apiurl string, apikey string, secret string, async bool, verifyssl bool) *CloudStackClient {")
277+
pn("func newClient(apiurl string, apikey string, secret string, async bool, verifyssl bool, options ...ClientOption) *CloudStackClient {")
275278
pn(" jar, _ := cookiejar.New(nil)")
276279
pn(" cs := &CloudStackClient{")
277280
pn(" client: &http.Client{")
@@ -298,26 +301,32 @@ func (as *allServices) GeneralCode() ([]byte, error) {
298301
pn(" options: []OptionFunc{},")
299302
pn(" timeout: 300,")
300303
pn(" }")
304+
pn("")
305+
pn(" for _, fn := range options {")
306+
pn(" fn(cs)")
307+
pn(" }")
308+
pn("")
301309
for _, s := range as.services {
302310
pn(" cs.%s = New%s(cs)", strings.TrimSuffix(s.name, "Service"), s.name)
303311
}
312+
pn("")
304313
pn(" return cs")
305314
pn("}")
306315
pn("")
307316
pn("// Default non-async client. So for async calls you need to implement and check the async job result yourself. When using")
308317
pn("// HTTPS with a self-signed certificate to connect to your CloudStack API, you would probably want to set 'verifyssl' to")
309318
pn("// false so the call ignores the SSL errors/warnings.")
310-
pn("func NewClient(apiurl string, apikey string, secret string, verifyssl bool) *CloudStackClient {")
311-
pn(" cs := newClient(apiurl, apikey, secret, false, verifyssl)")
319+
pn("func NewClient(apiurl string, apikey string, secret string, verifyssl bool, options ...ClientOption) *CloudStackClient {")
320+
pn(" cs := newClient(apiurl, apikey, secret, false, verifyssl, options...)")
312321
pn(" return cs")
313322
pn("}")
314323
pn("")
315324
pn("// For sync API calls this client behaves exactly the same as a standard client call, but for async API calls")
316325
pn("// this client will wait until the async job is finished or until the configured AsyncTimeout is reached. When the async")
317326
pn("// job finishes successfully it will return actual object received from the API and nil, but when the timout is")
318327
pn("// reached it will return the initial object containing the async job ID for the running job and a warning.")
319-
pn("func NewAsyncClient(apiurl string, apikey string, secret string, verifyssl bool) *CloudStackClient {")
320-
pn(" cs := newClient(apiurl, apikey, secret, true, verifyssl)")
328+
pn("func NewAsyncClient(apiurl string, apikey string, secret string, verifyssl bool, options ...ClientOption) *CloudStackClient {")
329+
pn(" cs := newClient(apiurl, apikey, secret, true, verifyssl, options...)")
321330
pn(" return cs")
322331
pn("}")
323332
pn("")
@@ -482,6 +491,15 @@ func (as *allServices) GeneralCode() ([]byte, error) {
482491
pn(" return nil, fmt.Errorf(\"Unable to extract the raw value from:\\n\\n%%s\\n\\n\", string(b))")
483492
pn("}")
484493
pn("")
494+
pn("// WithAsyncTimeout takes a custom timeout to be used by the CloudStackClient")
495+
pn("func WithAsyncTimeout(timeout int64) ClientOption {")
496+
pn(" return func(cs *CloudStackClient) {")
497+
pn(" if timeout != 0 {")
498+
pn(" cs.timeout = timeout")
499+
pn(" }")
500+
pn(" }")
501+
pn("}")
502+
pn("")
485503
pn("// DomainIDSetter is an interface that every type that can set a domain ID must implement")
486504
pn("type DomainIDSetter interface {")
487505
pn(" SetDomainid(string)")
@@ -510,6 +528,18 @@ func (as *allServices) GeneralCode() ([]byte, error) {
510528
pn(" }")
511529
pn("}")
512530
pn("")
531+
pn("// WithHTTPClient takes a custom HTTP client to be used by the CloudStackClient")
532+
pn("func WithHTTPClient(client *http.Client) ClientOption {")
533+
pn(" return func(cs *CloudStackClient) {")
534+
pn(" if client != nil {")
535+
pn(" if client.Jar == nil {")
536+
pn(" client.Jar = cs.client.Jar")
537+
pn(" }")
538+
pn(" cs.client = client")
539+
pn(" }")
540+
pn(" }")
541+
pn("}")
542+
pn("")
513543
pn("// ProjectIDSetter is an interface that every type that can set a project ID must implement")
514544
pn("type ProjectIDSetter interface {")
515545
pn(" SetProjectid(string)")

0 commit comments

Comments
 (0)