launch_darkly.go 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package features
  2. import (
  3. "errors"
  4. "fmt"
  5. "time"
  6. "github.com/launchdarkly/go-sdk-common/v3/ldcontext"
  7. ld "github.com/launchdarkly/go-server-sdk/v6"
  8. )
  9. // Client is a struct wrapper around the launchdarkly client
  10. type Client struct {
  11. Client LDClient
  12. useDatabase bool
  13. }
  14. // LDClient is an interface that allows us to mock
  15. // the LaunchDarkly client in tests
  16. type LDClient interface {
  17. BoolVariation(key string, context ldcontext.Context, defaultVal bool) (bool, error)
  18. }
  19. // BoolVariation returns the value of a boolean feature flag for a given evaluation context.
  20. //
  21. // Returns defaultVal if there is an error, if the flag doesn't exist, or the feature is turned off and
  22. // has no off variation.
  23. //
  24. // For more information, see the Reference Guide: https://docs.launchdarkly.com/sdk/features/evaluating#go
  25. func (c Client) BoolVariation(field string, context ldcontext.Context, defaultValue bool) (bool, error) {
  26. if c.Client == nil {
  27. return defaultValue, errors.New("failed to participate in launchdarkly test: no client available")
  28. }
  29. return c.Client.BoolVariation(field, context, defaultValue)
  30. }
  31. // UseDatabase returns whether we should force using the database for feature flags
  32. //
  33. // The initial implementation of feature flags stored flags in
  34. // table-specific columns, making it so we need to use a nasty hack to
  35. // fetch the correct value for on-prem deployments. A proper refactor would
  36. // be to introduce a migration that moved these flags to a feature flags
  37. // table that we could implement a proper WrappedClient for, but a shortcut
  38. // is taken here in order to fix this sooner and give us time for a proper
  39. // refactor.
  40. func (c Client) UseDatabase() bool {
  41. return c.useDatabase
  42. }
  43. // GetClient retrieves a Client for interacting with LaunchDarkly
  44. func GetClient(featureFlagClient string, launchDarklySDKKey string) (*Client, error) {
  45. validClients := map[string]bool{
  46. "database": true,
  47. "launch_darkly": true,
  48. }
  49. if !validClients[featureFlagClient] {
  50. return &Client{}, fmt.Errorf("failed to create new feature flag client: invalid feature flag client specified")
  51. }
  52. if featureFlagClient == "database" {
  53. return &Client{
  54. useDatabase: true,
  55. }, nil
  56. }
  57. if launchDarklySDKKey == "" {
  58. return &Client{}, fmt.Errorf("failed to create new feature flag client: missing launch_darkly sdk key")
  59. }
  60. ldClient, err := ld.MakeClient(launchDarklySDKKey, 5*time.Second)
  61. if err != nil {
  62. return &Client{}, fmt.Errorf("failed to create new feature flag client: %w", err)
  63. }
  64. if ldClient == nil {
  65. return &Client{}, errors.New("failed to create new feature flag client: invalid config")
  66. }
  67. if !ldClient.Initialized() {
  68. return &Client{}, errors.New("failed to create new feature flag client: sdk failed to initialize")
  69. }
  70. return &Client{
  71. Client: ldClient,
  72. useDatabase: false,
  73. }, nil
  74. }