Skip to content

Commit

Permalink
feat: add built-in support for retryable-http
Browse files Browse the repository at this point in the history
Signed-off-by: Pierre-Henri Symoneaux <[email protected]>
  • Loading branch information
phsym committed Oct 16, 2024
1 parent 49e6fff commit 187140d
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 3 deletions.
99 changes: 97 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,120 @@ package okms

import (
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"net/http"
"net/http/httputil"
"os"
"reflect"
"strings"
"time"

"github.com/google/uuid"
"github.com/hashicorp/go-retryablehttp"
"github.com/ovh/okms-sdk-go/internal"
"github.com/ovh/okms-sdk-go/types"
)

const DefaultHTTPClientTimeout = 30 * time.Second

// RestAPIClient is the main client to the KMS rest api.
type RestAPIClient struct {
inner internal.ClientWithResponsesInterface
customHeaders map[string]string
}

// NewRestAPIClientWithHttp creates and initialize a new HTTP connection to the KMS at url `endpoint`
// using the provided [http.Client].
// LeveledLogger represents loggers that can be used inside the client.
type LeveledLogger retryablehttp.LeveledLogger

// ClientConfig is used to configure Rest clients created using NewRestAPIClient().
type ClientConfig struct {
Timeout *time.Duration
Retry *RetryConfig
Logger LeveledLogger
TlsCfg *tls.Config
Middleware func(http.RoundTripper) http.RoundTripper
}

type RetryConfig struct {
RetryMax int
RetryWaitMin time.Duration
RetryWaitMax time.Duration
}

type debugTransport struct {
next http.RoundTripper
out io.Writer
}

// RoundTrip implements http.RoundTripper.
func (t *debugTransport) RoundTrip(r *http.Request) (*http.Response, error) {
data, _ := httputil.DumpRequestOut(r, true)
fmt.Fprintf(os.Stderr, "REQUEST:\n%s\n", data)
resp, err := t.next.RoundTrip(r)
if err != nil {
return resp, err
}
data, _ = httputil.DumpResponse(resp, true)
fmt.Fprintf(os.Stderr, "RESPONSE:\n%s\n", data)
return resp, nil
}

// DebugTransport creates an http client middleware that will dump all the HTTP resquests and
// responses to the giver io.Writer. It can be passed to ClientConfig.Middleware.
func DebugTransport(out io.Writer) func(http.RoundTripper) http.RoundTripper {
return func(rt http.RoundTripper) http.RoundTripper {
if rt == nil {
rt = http.DefaultTransport
}
if out == nil {
out = os.Stderr
}
return &debugTransport{
next: rt,
out: out,
}
}
}

// NewRestAPIClient creates and initializes a new HTTP connection to the KMS at url `endpoint`
// using the provided client configuration. It allows configuring retries, timeouts and loggers.
func NewRestAPIClient(endpoint string, clientCfg ClientConfig) (*RestAPIClient, error) {
client := retryablehttp.NewClient()
client.HTTPClient.Timeout = DefaultHTTPClientTimeout
client.Logger = nil

client.HTTPClient.Transport.(*http.Transport).TLSClientConfig = clientCfg.TlsCfg
if clientCfg.Logger != nil {
client.Logger = clientCfg.Logger
}

if clientCfg.Timeout != nil {
client.HTTPClient.Timeout = *clientCfg.Timeout
}

if clientCfg.Retry != nil {
client.RetryMax = clientCfg.Retry.RetryMax
if clientCfg.Retry.RetryWaitMin > 0 {
client.RetryWaitMin = clientCfg.Retry.RetryWaitMin
}
if clientCfg.Retry.RetryWaitMax > 0 {
client.RetryWaitMax = clientCfg.Retry.RetryWaitMax
}
}
if clientCfg.Middleware != nil {
client.HTTPClient.Transport = clientCfg.Middleware(client.HTTPClient.Transport)
}

client.ErrorHandler = retryablehttp.PassthroughErrorHandler

return NewRestAPIClientWithHttp(endpoint, client.StandardClient())
}

// NewRestAPIClientWithHttp is a lower level constructor to create and initialize a new HTTP
// connection to the KMS at url `endpoint` using the provided [http.Client].
//
// The client must be configured with an appropriate tls.Config using client TLS certificates for authentication.
func NewRestAPIClientWithHttp(endpoint string, c *http.Client) (*RestAPIClient, error) {
Expand Down
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ go 1.23.0

require (
github.com/google/uuid v1.6.0
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/oapi-codegen/runtime v1.1.1
golang.org/x/crypto v0.28.0
)

require github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
require (
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
)
14 changes: 14 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,21 @@ github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvF
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand All @@ -19,5 +31,7 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 comments on commit 187140d

Please sign in to comment.