Skip to content

Commit 008823f

Browse files
authored
(#114) Added client options (auth,retry and circuitbreaker)
1 parent 8fc2362 commit 008823f

9 files changed

+820
-381
lines changed

clients/auth.go

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package clients
2+
3+
import "oss.nandlabs.io/golly/textutils"
4+
5+
const (
6+
AuthTypeBasic AuthType = "Basic"
7+
AuthTypeBearer AuthType = "Token"
8+
)
9+
10+
// Authenticatable represents an interface that requires the implementation
11+
// of the Apply method. The Apply method takes an Authenticator as a parameter
12+
// and applies it to the implementing type.
13+
type Authenticatable interface {
14+
Apply(AuthProvider)
15+
}
16+
17+
type AuthType string
18+
19+
// AuthProvider defines an interface for authentication mechanisms.
20+
// It provides methods to retrieve the type of authentication, user credentials,
21+
// token, and to refresh the authentication token.
22+
//
23+
// Methods:
24+
// - Type() AuthType: Returns the type of authentication.
25+
// - User() string: Returns the username.
26+
// - Pass() string: Returns the password.
27+
// - Token() string: Returns the authentication token.
28+
// - Refresh() error: Refreshes the authentication token and returns an error if the operation fails.
29+
type AuthProvider interface {
30+
Type() AuthType
31+
User() string
32+
Pass() string
33+
Token() string
34+
}
35+
36+
// BasicAuth represents basic authentication credentials with a username and password.
37+
type BasicAuth struct {
38+
user string
39+
pass string
40+
}
41+
42+
// Type returns the authentication type for BasicAuth, which is AuthTypeBasic.
43+
// This is used to determine the type of authentication to be used.
44+
// Returns:
45+
//
46+
// AuthType: The authentication type. (AuthTypeBasic)
47+
func (b *BasicAuth) Type() AuthType {
48+
return AuthTypeBasic
49+
}
50+
51+
// User returns the username associated with the BasicAuth instance.
52+
// Returns:
53+
//
54+
// string: The username.
55+
func (b *BasicAuth) User() string {
56+
return b.user
57+
}
58+
59+
// Pass returns the password associated with the BasicAuth instance.
60+
// Returns:
61+
//
62+
// string: The password.
63+
func (b *BasicAuth) Pass() string {
64+
return b.pass
65+
}
66+
67+
// Token returns an empty string as the token.
68+
// This method is part of the BasicAuth struct.
69+
// Returns:
70+
//
71+
// string: An empty string.
72+
func (b *BasicAuth) Token() string {
73+
return textutils.EmptyStr
74+
}
75+
76+
// Refresh refreshes the authentication credentials.
77+
// It currently does not perform any operations and always returns nil.
78+
//
79+
// Returns:
80+
//
81+
// error: Always returns nil.
82+
func (b *BasicAuth) Refresh() error {
83+
return nil
84+
}
85+
86+
// NewBasicAuth creates a new BasicAuth instance with the provided username and password.
87+
// Parameters:
88+
//
89+
// user (string): The username.
90+
// pass (string): The password.
91+
//
92+
// Returns:
93+
//
94+
// *BasicAuth: The BasicAuth instance.
95+
func NewBasicAuth(user, pass string) AuthProvider {
96+
return &BasicAuth{
97+
user: user,
98+
pass: pass,
99+
}
100+
}
101+
102+
// TokenBearerAuth represents bearer token authentication credentials.
103+
type TokenBearerAuth struct {
104+
token string
105+
}
106+
107+
// Type returns the authentication type for BearerAuth, which is AuthTypeBearer.
108+
// This is used to determine the type of authentication to be used.
109+
// Returns:
110+
//
111+
// AuthType: The authentication type. (AuthTypeBearer)
112+
func (b *TokenBearerAuth) Type() AuthType {
113+
return AuthTypeBearer
114+
}
115+
116+
// User returns an empty string as the username.
117+
// This method is part of the BearerAuth struct.
118+
// Returns:
119+
//
120+
// string: An empty string.
121+
func (b *TokenBearerAuth) User() string {
122+
return textutils.EmptyStr
123+
}
124+
125+
// Pass returns an empty string as the password.
126+
// This method is part of the BearerAuth struct.
127+
// Returns:
128+
//
129+
// string: An empty string.
130+
func (b *TokenBearerAuth) Pass() string {
131+
return textutils.EmptyStr
132+
}
133+
134+
// Token returns the token associated with the BearerAuth instance.
135+
// Returns:
136+
//
137+
// string: The token.
138+
func (b *TokenBearerAuth) Token() string {
139+
return b.token
140+
}
141+
142+
// Refresh refreshes the authentication token.
143+
// It currently does not perform any operations and always returns nil.
144+
//
145+
// Returns:
146+
//
147+
// error: Always returns nil.
148+
func (b *TokenBearerAuth) Refresh() error {
149+
return nil
150+
}
151+
152+
// NewBearerAuth creates a new BearerAuth instance with the provided token.
153+
// Parameters:
154+
//
155+
// token (string): The token.
156+
//
157+
// Returns:
158+
//
159+
// *BearerAuth: The BearerAuth instance.
160+
func NewBearerAuth(token string) AuthProvider {
161+
return &TokenBearerAuth{
162+
token: token,
163+
}
164+
}

clients/circuitbreaker.go

+8-12
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ const (
1717
defaultFailureThreshold = 3
1818
)
1919

20-
// CBOpenErr is the error returned when the circuit breaker is open and unable to process requests.
21-
var CBOpenErr = errors.New("the Circuit breaker is open and unable to process request")
20+
// ErrCBOpen is the error returned when the circuit breaker is open and unable to process requests.
21+
var ErrCBOpen = errors.New("the Circuit breaker is open and unable to process request")
2222

2323
// BreakerInfo holds the configuration parameters for the CircuitBreaker.
2424
type BreakerInfo struct {
@@ -37,9 +37,9 @@ type CircuitBreaker struct {
3737
halfOpenCounter uint32 // Counter for requests in the half-open state
3838
}
3939

40-
// NewCB creates a new CircuitBreaker instance with the provided BreakerInfo.
40+
// NewCircuitBreaker creates a new CircuitBreaker instance with the provided BreakerInfo.
4141
// If no BreakerInfo is provided, default values will be used.
42-
func NewCB(info *BreakerInfo) (cb *CircuitBreaker) {
42+
func NewCircuitBreaker(info *BreakerInfo) (cb *CircuitBreaker) {
4343
// Set default values if not provided
4444
if info == nil {
4545
info = &BreakerInfo{}
@@ -73,12 +73,12 @@ func NewCB(info *BreakerInfo) (cb *CircuitBreaker) {
7373
func (cb *CircuitBreaker) CanExecute() (err error) {
7474
state := cb.getState()
7575
if state == circuitOpen {
76-
err = CBOpenErr
76+
err = ErrCBOpen
7777
} else if state == circuitHalfOpen {
7878
val := atomic.AddUint32(&cb.halfOpenCounter, 1)
7979
if val > cb.MaxHalfOpen {
8080
cb.updateState(circuitHalfOpen, circuitOpen)
81-
err = CBOpenErr
81+
err = ErrCBOpen
8282
}
8383
}
8484
return
@@ -127,12 +127,8 @@ func (cb *CircuitBreaker) updateState(oldState, newState uint32) {
127127
if newState == circuitOpen {
128128
// Start Timer for HalfOpen
129129
go func() {
130-
select {
131-
case <-time.After(time.Second * time.Duration(cb.Timeout)):
132-
{
133-
cb.updateState(circuitOpen, circuitHalfOpen)
134-
}
135-
}
130+
time.Sleep(time.Second * time.Duration(cb.Timeout))
131+
cb.updateState(circuitOpen, circuitHalfOpen)
136132
}()
137133
}
138134
}

clients/client.go

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package clients
2+
3+
type Client[RQ any, RS any] interface {
4+
SetOptions(options *ClientOptions)
5+
Execute(req RQ) (RS, error)
6+
}

clients/options.go

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package clients
2+
3+
import (
4+
"math"
5+
"time"
6+
7+
"oss.nandlabs.io/golly/config"
8+
)
9+
10+
var EmptyClientOptions = &ClientOptions{
11+
Attributes: config.NewMapAttributes(),
12+
CircuitBreaker: nil,
13+
Auth: nil,
14+
RetryPolicy: nil,
15+
}
16+
17+
type RetryPolicy struct {
18+
MaxRetries int
19+
BackoffInterval time.Duration
20+
MaxBackoff time.Duration
21+
Exponential bool
22+
}
23+
24+
func (r *RetryPolicy) WaitTime(retryCount int) time.Duration {
25+
backoff := r.BackoffInterval
26+
if r.Exponential {
27+
backoff = time.Duration(int64(math.Pow(2, float64(retryCount)))*backoff.Milliseconds()) * time.Millisecond
28+
backoff = min(backoff, r.MaxBackoff)
29+
}
30+
return backoff
31+
}
32+
33+
type ClientOptions struct {
34+
// Attributes
35+
Attributes config.Attributes
36+
// RetryPolicy holds the retry configuration for the client
37+
RetryPolicy *RetryPolicy
38+
// CircuitBreaker holds the circuit breaker configuration for the client
39+
CircuitBreaker *CircuitBreaker
40+
// Auth holds the authentication configuration for the client
41+
Auth AuthProvider
42+
}
43+
44+
type OptionsBuilder struct {
45+
options ClientOptions
46+
}
47+
48+
func NewOptionsBuilder() *OptionsBuilder {
49+
return &OptionsBuilder{
50+
options: ClientOptions{
51+
Attributes: config.NewMapAttributes(),
52+
CircuitBreaker: nil,
53+
Auth: nil,
54+
RetryPolicy: nil,
55+
},
56+
}
57+
}
58+
59+
// WithAtributes sets the attributes for the client.
60+
// Parameters:
61+
// - attributes: The attributes to set.
62+
//
63+
// Returns:
64+
//
65+
// *OptionsBuilder: The options builder.
66+
func (b *OptionsBuilder) WithAttributes(attributes config.Attributes) *OptionsBuilder {
67+
b.options.Attributes = attributes
68+
return b
69+
}
70+
71+
// WithAuth sets the authenticator for the client.
72+
// Parameters:
73+
// - authenticator: The authenticator to set.
74+
//
75+
// Returns:
76+
//
77+
// *OptionsBuilder: The options builder.
78+
func (b *OptionsBuilder) WithAuth(authenticator AuthProvider) *OptionsBuilder {
79+
b.options.Auth = authenticator
80+
return b
81+
}
82+
83+
// WithRetryPolicy sets the retry policy for the client.
84+
// Parameters:
85+
// - retryPolicy: The retry policy to set.
86+
//
87+
// Returns:
88+
// *OptionsBuilder: The options builder.
89+
90+
func (b *OptionsBuilder) WithRetryPolicy(retryPolicy *RetryPolicy) *OptionsBuilder {
91+
b.options.RetryPolicy = retryPolicy
92+
return b
93+
}
94+
95+
// WithCircuitBreaker sets the circuit breaker for the client.
96+
// Parameters:
97+
// - circuitBreaker: The circuit breaker to set.
98+
//
99+
// Returns:
100+
// *OptionsBuilder: The options builder.
101+
102+
func (b *OptionsBuilder) WithCircuitBreaker(circuitBreaker *CircuitBreaker) *OptionsBuilder {
103+
b.options.CircuitBreaker = circuitBreaker
104+
return b
105+
}
106+
107+
// AddRetryPolicy adds a retry policy to the client.
108+
// Parameters:
109+
// - maxRetries: The maximum number of retries allowed.
110+
// - backoffIntervalMs: The wait time between retries in milliseconds. If set to <=0, the client will retry immediately.
111+
112+
func (b *OptionsBuilder) RetryPolicy(maxRetries int, backoffIntervalMs int, exponential bool, maxBackoffInMs int) *OptionsBuilder {
113+
b.options.RetryPolicy = &RetryPolicy{
114+
MaxRetries: maxRetries,
115+
BackoffInterval: time.Duration(backoffIntervalMs) * time.Millisecond,
116+
Exponential: exponential,
117+
MaxBackoff: time.Duration(backoffIntervalMs) * time.Millisecond,
118+
}
119+
return b
120+
}
121+
122+
// AddCircuitBreaker adds a circuit breaker to the client.
123+
// Parameters:
124+
// - failureThreshold: The number of consecutive failures required to open the circuit.
125+
// - successThreshold: The number of consecutive successes required to close the circuit.
126+
// - maxHalfOpen: The maximum number of requests allowed in the half-open state.
127+
// - timeout: The timeout duration for the circuit to transition from open to half-open state.
128+
func (b *OptionsBuilder) CircuitBreaker(failureThreshold uint64, successThreshold uint64, maxHalfOpen uint32, timeout uint32) *OptionsBuilder {
129+
breakerInfo := &BreakerInfo{
130+
FailureThreshold: failureThreshold,
131+
SuccessThreshold: successThreshold,
132+
MaxHalfOpen: maxHalfOpen,
133+
Timeout: timeout,
134+
}
135+
b.options.CircuitBreaker = NewCircuitBreaker(breakerInfo)
136+
return b
137+
}
138+
139+
// AddBasicAuth adds basic authentication to the client.
140+
// This method will override any existing authentication configuration.
141+
// Parameters:
142+
// - user: The username.
143+
// - pass: The password.
144+
func (b *OptionsBuilder) BasicAuth(user, pass string) *OptionsBuilder {
145+
b.options.Auth = &BasicAuth{
146+
user: user,
147+
pass: pass,
148+
}
149+
return b
150+
}
151+
152+
// AddTokenAuth adds token authentication to the client.
153+
// This method will override any existing authentication configuration.
154+
// Parameters:
155+
// - token: The token.
156+
func (b *OptionsBuilder) TokenBearerAuth(token string) *OptionsBuilder {
157+
b.options.Auth = &TokenBearerAuth{
158+
token: token,
159+
}
160+
return b
161+
}
162+
163+
// Build creates a new ClientOptions with the provided configuration.
164+
// Returns:
165+
//
166+
// *ClientOptions: The client.
167+
func (b *OptionsBuilder) Build() *ClientOptions {
168+
return &b.options
169+
}

0 commit comments

Comments
 (0)