Skip to content

Commit 8fb9933

Browse files
committed
Move CMAB functionality from pkg/decision to pkg/cmab and update event factory for CMAB impression events
1 parent 656583c commit 8fb9933

File tree

8 files changed

+625
-22
lines changed

8 files changed

+625
-22
lines changed

pkg/decision/cmab_client.go renamed to pkg/cmab/client.go

+114-11
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
* limitations under the License. *
1515
***************************************************************************/
1616

17-
// Package decision provides CMAB client implementation
18-
package decision
17+
// Package cmab provides CMAB client implementation
18+
package cmab
1919

2020
import (
2121
"bytes"
@@ -27,6 +27,9 @@ import (
2727
"net/http"
2828
"time"
2929

30+
"github.com/optimizely/go-sdk/v2/pkg/config"
31+
"github.com/optimizely/go-sdk/v2/pkg/entities"
32+
"github.com/optimizely/go-sdk/v2/pkg/event"
3033
"github.com/optimizely/go-sdk/v2/pkg/logging"
3134
)
3235

@@ -88,16 +91,20 @@ type RetryConfig struct {
8891

8992
// DefaultCmabClient implements the CmabClient interface
9093
type DefaultCmabClient struct {
91-
httpClient *http.Client
92-
retryConfig *RetryConfig
93-
logger logging.OptimizelyLogProducer
94+
httpClient *http.Client
95+
retryConfig *RetryConfig
96+
logger logging.OptimizelyLogProducer
97+
eventProcessor event.Processor
98+
projectConfig config.ProjectConfig
9499
}
95100

96101
// CmabClientOptions defines options for creating a CMAB client
97102
type CmabClientOptions struct {
98-
HTTPClient *http.Client
99-
RetryConfig *RetryConfig
100-
Logger logging.OptimizelyLogProducer
103+
HTTPClient *http.Client
104+
RetryConfig *RetryConfig
105+
Logger logging.OptimizelyLogProducer
106+
EventProcessor event.Processor
107+
ProjectConfig config.ProjectConfig
101108
}
102109

103110
// NewDefaultCmabClient creates a new instance of DefaultCmabClient
@@ -119,9 +126,11 @@ func NewDefaultCmabClient(options CmabClientOptions) *DefaultCmabClient {
119126
}
120127

121128
return &DefaultCmabClient{
122-
httpClient: httpClient,
123-
retryConfig: retryConfig,
124-
logger: logger,
129+
httpClient: httpClient,
130+
retryConfig: retryConfig,
131+
logger: logger,
132+
eventProcessor: options.EventProcessor,
133+
projectConfig: options.ProjectConfig,
125134
}
126135
}
127136

@@ -266,3 +275,97 @@ func (c *DefaultCmabClient) doFetch(ctx context.Context, url string, bodyBytes [
266275
func (c *DefaultCmabClient) validateResponse(response CMABResponse) bool {
267276
return len(response.Predictions) > 0 && response.Predictions[0].VariationID != ""
268277
}
278+
279+
// EventProcessor is an interface for processing events
280+
type EventProcessor interface {
281+
Process(userEvent interface{}) bool
282+
}
283+
284+
// LogImpression logs a CMAB impression event
285+
func (c *DefaultCmabClient) LogImpression(
286+
ctx context.Context,
287+
eventProcessor EventProcessor,
288+
projectConfig config.ProjectConfig,
289+
ruleID string,
290+
userID string,
291+
variationKey string,
292+
variationID string,
293+
attributes map[string]interface{},
294+
cmabUUID string,
295+
) error {
296+
// If no context is provided, create a background context
297+
if ctx == nil {
298+
ctx = context.Background()
299+
}
300+
301+
// Instead of directly creating an event, we'll delegate this to the client
302+
// that has access to the event package
303+
return fmt.Errorf("CMAB impression logging not implemented")
304+
}
305+
306+
// TrackCMABDecision tracks a CMAB decision event
307+
func (c *DefaultCmabClient) TrackCMABDecision(
308+
ruleID string,
309+
userID string,
310+
variationID string,
311+
variationKey string,
312+
attributes map[string]interface{},
313+
cmabUUID string,
314+
) {
315+
if c.eventProcessor == nil || c.projectConfig == nil {
316+
c.logger.Debug("Event processor or project config not available, not tracking impression")
317+
return
318+
}
319+
320+
// Get experiment from project config
321+
experiment, err := c.projectConfig.GetExperimentByID(ruleID)
322+
if err != nil {
323+
c.logger.Error("Error getting experiment", err)
324+
return
325+
}
326+
327+
// Create variation object
328+
variation := entities.Variation{
329+
ID: variationID,
330+
Key: variationKey,
331+
}
332+
333+
// Create user context
334+
userContext := entities.UserContext{
335+
ID: userID,
336+
Attributes: attributes,
337+
}
338+
339+
// Look for associated feature flag (if any)
340+
flagKey := ""
341+
featureList := c.projectConfig.GetFeatureList()
342+
for _, feature := range featureList {
343+
for _, featureExperiment := range feature.FeatureExperiments {
344+
if featureExperiment.ID == ruleID {
345+
flagKey = feature.Key
346+
break
347+
}
348+
}
349+
if flagKey != "" {
350+
break
351+
}
352+
}
353+
354+
// Create user event with CMAB impression
355+
userEvent, shouldDispatch := event.CreateCMABImpressionUserEvent(
356+
c.projectConfig,
357+
experiment,
358+
&variation,
359+
userContext,
360+
flagKey,
361+
experiment.Key, // ruleKey
362+
"experiment", // ruleType
363+
true,
364+
cmabUUID,
365+
)
366+
367+
// Process the event if it should be dispatched
368+
if shouldDispatch {
369+
c.eventProcessor.ProcessEvent(userEvent)
370+
}
371+
}

pkg/decision/cmab_client_test.go renamed to pkg/cmab/client_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
* limitations under the License. *
1515
***************************************************************************/
1616

17-
// Package decision //
18-
package decision
17+
// Package cmab //
18+
package cmab
1919

2020
import (
2121
"context"

pkg/decision/cmab_service.go renamed to pkg/cmab/service.go

+17-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
* limitations under the License. *
1515
***************************************************************************/
1616

17-
// Package decision provides CMAB decision service implementation
18-
package decision
17+
// Package cmab provides CMAB decision service implementation
18+
package cmab
1919

2020
import (
2121
"encoding/json"
@@ -186,6 +186,21 @@ func (s *DefaultCmabService) fetchDecisionWithRetry(
186186
variationID, err := s.cmabClient.FetchDecision(ruleID, userID, attributes, cmabUUID)
187187
if err == nil {
188188
reasons = append(reasons, fmt.Sprintf("Successfully fetched CMAB decision on attempt %d/%d", attempt+1, maxRetries))
189+
190+
// Get variation key from variation ID
191+
// This might require additional logic depending on your implementation
192+
variationKey := variationID // Simplified - you may need to look up the key
193+
194+
// Track the decision event
195+
s.cmabClient.TrackCMABDecision(
196+
ruleID,
197+
userID,
198+
variationID,
199+
variationKey,
200+
attributes,
201+
cmabUUID,
202+
)
203+
189204
return CmabDecision{
190205
VariationID: variationID,
191206
CmabUUID: cmabUUID,

0 commit comments

Comments
 (0)