-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(configcat-provider): Add ConfigCat provider (#242)
Signed-off-by: Rob Crowe <nobby.crowe@gmail.com>
- Loading branch information
Showing
8 changed files
with
3,286 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# ConfigCat OpenFeature provider for Go | ||
|
||
OpenFeature Go provider implementation for [ConfigCat](https://configcat.com) that uses the official [ConfigCat Go SDK](https://github.com/configcat/go-sdk). | ||
|
||
## Installation | ||
|
||
```shell | ||
# ConfigCat SDK | ||
go get github.com/configcat/go-sdk/v7 | ||
|
||
# OpenFeature SDK | ||
go get github.com/open-feature/go-sdk/pkg/openfeature | ||
go get github.com/open-feature/go-sdk-contrib/providers/configcat | ||
``` | ||
|
||
## Usage | ||
|
||
Here's a basic example: | ||
|
||
```go | ||
import ( | ||
"context" | ||
"fmt" | ||
|
||
sdk "github.com/configcat/go-sdk/v7" | ||
configcat "github.com/open-feature/go-sdk-contrib/providers/configcat/pkg" | ||
"github.com/open-feature/go-sdk/pkg/openfeature" | ||
) | ||
|
||
func main() { | ||
provider := configcat.NewProvider(sdk.NewClient("...")) | ||
openfeature.SetProvider(provider) | ||
|
||
client := openfeature.NewClient("app") | ||
|
||
val, err := client.BooleanValue(context.Background(), "flag_name", false, openfeature.NewEvaluationContext("123", map[string]any{ | ||
configcat.EmailKey: "test@example.com", | ||
})) | ||
fmt.Printf("val: %+v - error: %v\n", val, err) | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module github.com/open-feature/go-sdk-contrib/providers/configcat | ||
|
||
go 1.13 | ||
|
||
require ( | ||
github.com/configcat/go-sdk/v7 v7.10.1 | ||
github.com/open-feature/go-sdk v1.4.0 | ||
github.com/stretchr/testify v1.8.4 | ||
) | ||
|
||
require ( | ||
github.com/sirupsen/logrus v1.9.3 // indirect | ||
golang.org/x/sys v0.9.0 // indirect | ||
) |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package clienttest | ||
|
||
import ( | ||
"sync" | ||
|
||
sdk "github.com/configcat/go-sdk/v7" | ||
) | ||
|
||
// NewClient creates enough of the ConfigCat client to record flag interactions. | ||
func NewClient() *Client { | ||
return &Client{} | ||
} | ||
|
||
type Client struct { | ||
mu sync.Mutex | ||
requests []Request | ||
|
||
boolEvaluation func(req Request) sdk.BoolEvaluationDetails | ||
stringEvaluation func(req Request) sdk.StringEvaluationDetails | ||
floatEvaluation func(req Request) sdk.FloatEvaluationDetails | ||
intEvaluation func(req Request) sdk.IntEvaluationDetails | ||
} | ||
|
||
type Request struct { | ||
Key string | ||
DefaultValue interface{} | ||
User sdk.User | ||
} | ||
|
||
func (r *Request) UserData() sdk.UserData { | ||
userData, ok := r.User.(*sdk.UserData) | ||
if !ok { | ||
panic("user is not of type sdk.UserData") | ||
} | ||
return *userData | ||
} | ||
|
||
func (c *Client) Reset() { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
c.requests = nil | ||
c.boolEvaluation = nil | ||
c.stringEvaluation = nil | ||
c.floatEvaluation = nil | ||
c.intEvaluation = nil | ||
} | ||
|
||
func (c *Client) GetRequests() []Request { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
requests := make([]Request, len(c.requests)) | ||
copy(requests, c.requests) | ||
return requests | ||
} | ||
|
||
func (c *Client) WithBoolEvaluation(eval func(req Request) sdk.BoolEvaluationDetails) { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
c.boolEvaluation = eval | ||
} | ||
|
||
func (c *Client) WithStringEvaluation(eval func(req Request) sdk.StringEvaluationDetails) { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
c.stringEvaluation = eval | ||
} | ||
|
||
func (c *Client) WithFloatEvaluation(eval func(req Request) sdk.FloatEvaluationDetails) { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
c.floatEvaluation = eval | ||
} | ||
|
||
func (c *Client) WithIntEvaluation(eval func(req Request) sdk.IntEvaluationDetails) { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
c.intEvaluation = eval | ||
} | ||
|
||
func (c *Client) GetBoolValueDetails(key string, defaultValue bool, user sdk.User) sdk.BoolEvaluationDetails { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
|
||
req := Request{ | ||
Key: key, | ||
DefaultValue: defaultValue, | ||
User: user, | ||
} | ||
c.requests = append(c.requests, req) | ||
|
||
if c.boolEvaluation == nil { | ||
return sdk.BoolEvaluationDetails{ | ||
Data: evalNotFound(key, user), | ||
Value: defaultValue, | ||
} | ||
} | ||
|
||
return c.boolEvaluation(req) | ||
} | ||
|
||
func (c *Client) GetStringValueDetails(key string, defaultValue string, user sdk.User) sdk.StringEvaluationDetails { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
|
||
req := Request{ | ||
Key: key, | ||
DefaultValue: defaultValue, | ||
User: user, | ||
} | ||
c.requests = append(c.requests, req) | ||
|
||
if c.stringEvaluation == nil { | ||
return sdk.StringEvaluationDetails{ | ||
Data: evalNotFound(key, user), | ||
Value: defaultValue, | ||
} | ||
} | ||
|
||
return c.stringEvaluation(req) | ||
} | ||
|
||
func (c *Client) GetFloatValueDetails(key string, defaultValue float64, user sdk.User) sdk.FloatEvaluationDetails { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
|
||
req := Request{ | ||
Key: key, | ||
DefaultValue: defaultValue, | ||
User: user, | ||
} | ||
c.requests = append(c.requests, req) | ||
|
||
if c.floatEvaluation == nil { | ||
return sdk.FloatEvaluationDetails{ | ||
Data: evalNotFound(key, user), | ||
Value: defaultValue, | ||
} | ||
} | ||
|
||
return c.floatEvaluation(req) | ||
} | ||
|
||
func (c *Client) GetIntValueDetails(key string, defaultValue int, user sdk.User) sdk.IntEvaluationDetails { | ||
c.mu.Lock() | ||
defer c.mu.Unlock() | ||
|
||
req := Request{ | ||
Key: key, | ||
DefaultValue: defaultValue, | ||
User: user, | ||
} | ||
c.requests = append(c.requests, req) | ||
|
||
if c.intEvaluation == nil { | ||
return sdk.IntEvaluationDetails{ | ||
Data: evalNotFound(key, user), | ||
Value: defaultValue, | ||
} | ||
} | ||
|
||
return c.intEvaluation(req) | ||
} | ||
|
||
func evalNotFound(key string, user sdk.User) sdk.EvaluationDetailsData { | ||
return sdk.EvaluationDetailsData{ | ||
Key: key, | ||
User: user, | ||
IsDefaultValue: true, | ||
Error: sdk.ErrKeyNotFound{Key: key}, | ||
} | ||
} |
Oops, something went wrong.