Skip to content

Commit

Permalink
Merge pull request #117 from harness/FFM-8618
Browse files Browse the repository at this point in the history
FFM-8618 Add SetFlags & SetSegments methods
  • Loading branch information
jcox250 committed Jul 10, 2023
2 parents 5fd7b2a + 12adb2a commit da4e63a
Show file tree
Hide file tree
Showing 7 changed files with 465 additions and 2 deletions.
4 changes: 3 additions & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func (c *CfClient) streamConnect(ctx context.Context) {
}
}
conn := stream.NewSSEClient(c.sdkKey, c.token, sseClient, c.repository, c.api, c.config.Logger, streamErr,
c.config.eventStreamListener)
c.config.eventStreamListener, c.config.proxyMode)

// Connect kicks off a goroutine that attempts to establish a stream connection
// while this is happening we set streamConnected to true - if any errors happen
Expand Down Expand Up @@ -377,6 +377,7 @@ func (c *CfClient) retrieveFlags(ctx context.Context) error {
return nil
}

c.repository.SetFlags(true, c.environmentID, *flags.JSON200...)
for _, flag := range *flags.JSON200 {
c.repository.SetFlag(flag, true)
}
Expand All @@ -401,6 +402,7 @@ func (c *CfClient) retrieveSegments(ctx context.Context) error {
return nil
}

c.repository.SetSegments(true, c.environmentID, *segments.JSON200...)
for _, segment := range *segments.JSON200 {
c.repository.SetSegment(segment, true)
}
Expand Down
2 changes: 2 additions & 0 deletions client/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type config struct {
target evaluation.Target
eventStreamListener stream.EventStreamListener
enableAnalytics bool
proxyMode bool
}

func newDefaultConfig(log logger.Logger) *config {
Expand All @@ -50,5 +51,6 @@ func newDefaultConfig(log logger.Logger) *config {
enableStream: true,
enableStore: true,
enableAnalytics: true,
proxyMode: false,
}
}
7 changes: 7 additions & 0 deletions client/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,10 @@ func WithEventStreamListener(e stream.EventStreamListener) ConfigOption {
config.eventStreamListener = e
}
}

// WithProxyMode should be used when the SDK is being used inside the ff proxy to control the cache and handle sse events
func WithProxyMode(b bool) ConfigOption {
return func(config *config) {
config.proxyMode = b
}
}
10 changes: 10 additions & 0 deletions dto/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,24 @@ type Key struct {
}

const (
// KeyFeatures ...
KeyFeatures = "flags"

// KeyFeature identifies flag messages from ff server or stream
KeyFeature = "flag"

// KeySegment identifies segment messages from ff server or stream
KeySegment = "target-segment"

// KeySegment identifies segment messages from ff server or stream
KeySegments = "target-segments"

// SsePatchEvent identifies a patch event from the SSE stream
SsePatchEvent = "patch"

// SseDeleteEvent identifies a delete event from the SSE stream
SseDeleteEvent = "delete"

// SseCreateEvent identifies a create event from the SSE stream
SseCreateEvent = "create"
)
78 changes: 78 additions & 0 deletions pkg/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ type Repository interface {
GetFlags() ([]rest.FeatureConfig, error)

SetFlag(featureConfig rest.FeatureConfig, initialLoad bool)
SetFlags(initialLoad bool, envID string, featureConfig ...rest.FeatureConfig)
SetSegment(segment rest.Segment, initialLoad bool)
SetSegments(initialLoad bool, envID string, segment ...rest.Segment)

DeleteFlag(identifier string)
DeleteSegment(identifier string)
Expand All @@ -26,8 +28,10 @@ type Repository interface {
// Callback provides events when repository data being modified
type Callback interface {
OnFlagStored(identifier string)
OnFlagsStored(envID string)
OnFlagDeleted(identifier string)
OnSegmentStored(identifier string)
OnSegmentsStored(envID string)
OnSegmentDeleted(identifier string)
}

Expand Down Expand Up @@ -134,6 +138,30 @@ func (r FFRepository) SetFlag(featureConfig rest.FeatureConfig, initialLoad bool
}
}

// SetFlags places all the flags in the repository
func (r FFRepository) SetFlags(initialLoad bool, envID string, featureConfigs ...rest.FeatureConfig) {
if !initialLoad {
if r.areFlagsOutdated(featureConfigs...) {
return
}
}

key := formatFlagsKey(envID)

if r.storage != nil {
if err := r.storage.Set(key, featureConfigs); err != nil {
log.Errorf("error while storing flags for env=%s into repository", envID)
}
r.cache.Remove(key)
} else {
r.cache.Set(key, featureConfigs)
}

if r.callback != nil {
r.callback.OnFlagsStored(envID)
}
}

// SetSegment places a segment in the repository with the new value
func (r FFRepository) SetSegment(segment rest.Segment, initialLoad bool) {
if !initialLoad {
Expand All @@ -156,6 +184,30 @@ func (r FFRepository) SetSegment(segment rest.Segment, initialLoad bool) {
}
}

// SetSegments places all the segments in the repository
func (r FFRepository) SetSegments(initialLoad bool, envID string, segments ...rest.Segment) {
if !initialLoad {
if r.areSegmentsOutdated(segments...) {
return
}
}

key := formatSegmentsKey(envID)

if r.storage != nil {
if err := r.storage.Set(key, segments); err != nil {
log.Errorf("error while storing flags for env=%s into repository", envID)
}
r.cache.Remove(key)
} else {
r.cache.Set(key, segments)
}

if r.callback != nil {
r.callback.OnFlagsStored(envID)
}
}

// DeleteFlag removes a flag from the repository
func (r FFRepository) DeleteFlag(identifier string) {
flagKey := formatFlagKey(identifier)
Expand Down Expand Up @@ -197,6 +249,15 @@ func (r FFRepository) isFlagOutdated(featureConfig rest.FeatureConfig) bool {
return *oldFlag.Version >= *featureConfig.Version
}

func (r FFRepository) areFlagsOutdated(flags ...rest.FeatureConfig) bool {
for _, flag := range flags {
if r.isFlagOutdated(flag) {
return true
}
}
return false
}

func (r FFRepository) isSegmentOutdated(segment rest.Segment) bool {
oldSegment, err := r.getSegmentAndCache(segment.Identifier, false)
if err != nil || oldSegment.Version == nil {
Expand All @@ -206,6 +267,15 @@ func (r FFRepository) isSegmentOutdated(segment rest.Segment) bool {
return *oldSegment.Version >= *segment.Version
}

func (r FFRepository) areSegmentsOutdated(segments ...rest.Segment) bool {
for _, segment := range segments {
if r.isSegmentOutdated(segment) {
return true
}
}
return false
}

// Close all resources
func (r FFRepository) Close() {

Expand All @@ -215,6 +285,14 @@ func formatFlagKey(identifier string) string {
return "flag/" + identifier
}

func formatFlagsKey(envID string) string {
return "flags/" + envID
}

func formatSegmentKey(identifier string) string {
return "target-segment/" + identifier
}

func formatSegmentsKey(envID string) string {
return "target-segments/" + envID
}
Loading

0 comments on commit da4e63a

Please sign in to comment.