Skip to content

Commit 29bb8ae

Browse files
added requester to the dispatcher, and providing with highly customizable client
1 parent 0e9359e commit 29bb8ae

File tree

8 files changed

+116
-47
lines changed

8 files changed

+116
-47
lines changed

examples/main.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ package main
55

66
import (
77
"fmt"
8+
"time"
9+
810
"github.com/optimizely/go-sdk/optimizely/client"
911
"github.com/optimizely/go-sdk/optimizely/entities"
12+
"github.com/optimizely/go-sdk/optimizely/event"
1013
"github.com/optimizely/go-sdk/optimizely/logging"
14+
"github.com/optimizely/go-sdk/optimizely/notification"
1115
)
1216

1317
func main() {
@@ -55,4 +59,15 @@ func main() {
5559
enabled, _ = app.IsFeatureEnabled("mutext_feat", user)
5660
fmt.Printf("Is feature enabled? %v\n", enabled)
5761
app.Close() // user can close dispatcher
62+
63+
/************* Setting Polling Interval ********************/
64+
65+
notificationCenter := notification.NewNotificationCenter()
66+
67+
app = optimizelyFactory.GetClient(
68+
client.ConfigManager("4SLpaJA1r1pgE6T2CoMs9q", time.Second, nil),
69+
client.DecisionService(notificationCenter),
70+
client.EventProcessor(event.DefaultBatchSize, event.DefaultEventQueueSize, event.DefaultEventFlushInterval),
71+
)
72+
app.Close()
5873
}

optimizely/client/factory.go

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,14 @@ package client
1919

2020
import (
2121
"errors"
22-
"github.com/optimizely/go-sdk/optimizely/utils"
23-
24-
"github.com/optimizely/go-sdk/optimizely/event"
25-
26-
"github.com/optimizely/go-sdk/optimizely/notification"
22+
"time"
2723

2824
"github.com/optimizely/go-sdk/optimizely"
2925
"github.com/optimizely/go-sdk/optimizely/config"
3026
"github.com/optimizely/go-sdk/optimizely/decision"
27+
"github.com/optimizely/go-sdk/optimizely/event"
28+
"github.com/optimizely/go-sdk/optimizely/notification"
29+
"github.com/optimizely/go-sdk/optimizely/utils"
3130
)
3231

3332
// Options are used to create an instance of the OptimizelyClient with custom configuration
@@ -43,6 +42,47 @@ type OptimizelyFactory struct {
4342
Datafile []byte
4443
}
4544

45+
// OptionFunc is a type to a proper func
46+
type OptionFunc func(*OptimizelyClient, utils.ExecutionCtx)
47+
48+
// GetClient gets client and sets some parameters
49+
func (f OptimizelyFactory) GetClient(clientOptions ...OptionFunc) *OptimizelyClient {
50+
executionCtx := utils.NewCancelableExecutionCtx()
51+
appClient := &OptimizelyClient{
52+
isValid: false,
53+
executionCtx: executionCtx,
54+
}
55+
for _, opt := range clientOptions {
56+
opt(appClient, executionCtx)
57+
}
58+
return appClient
59+
}
60+
61+
// ConfigManager sets config manager on a client
62+
func ConfigManager(sdkKey string, pollingInterval time.Duration, dataFile []byte) OptionFunc {
63+
return func(f *OptimizelyClient, executionCtx utils.ExecutionCtx) {
64+
options := config.PollingProjectConfigManagerOptions{
65+
Datafile: dataFile,
66+
PollingInterval: pollingInterval,
67+
}
68+
f.configManager = config.NewPollingProjectConfigManagerWithOptions(f.executionCtx, sdkKey, options)
69+
}
70+
}
71+
72+
// DecisionService sets decision service on a client
73+
func DecisionService(notificationCenter notification.Center) OptionFunc {
74+
return func(f *OptimizelyClient, executionCtx utils.ExecutionCtx) {
75+
f.decisionService = decision.NewCompositeService(notificationCenter)
76+
}
77+
}
78+
79+
// EventProcessor sets event processor on a client
80+
func EventProcessor(batchSize, queueSize int, flushInterval time.Duration) OptionFunc {
81+
return func(f *OptimizelyClient, executionCtx utils.ExecutionCtx) {
82+
f.eventProcessor = event.NewEventProcessor(executionCtx, batchSize, queueSize, flushInterval)
83+
}
84+
}
85+
4686
// StaticClient returns a client initialized with a static project config
4787
func (f OptimizelyFactory) StaticClient() (*OptimizelyClient, error) {
4888
var configManager optimizely.ProjectConfigManager

optimizely/config/polling_manager.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ var cmLogger = logging.GetLogger("PollingConfigManager")
3939
type PollingProjectConfigManagerOptions struct {
4040
Datafile []byte
4141
PollingInterval time.Duration
42-
Requester Requester
42+
Requester utils.Requester
4343
}
4444

4545
// PollingProjectConfigManager maintains a dynamic copy of the project config
4646
type PollingProjectConfigManager struct {
47-
requester Requester
47+
requester utils.Requester
4848
pollingInterval time.Duration
4949
projectConfig optimizely.ProjectConfig
5050
configLock sync.RWMutex
@@ -99,12 +99,12 @@ func (cm *PollingProjectConfigManager) activate(initialPayload []byte, init bool
9999
// NewPollingProjectConfigManagerWithOptions returns new instance of PollingProjectConfigManager with the given options
100100
func NewPollingProjectConfigManagerWithOptions(exeCtx utils.ExecutionCtx, sdkKey string, options PollingProjectConfigManagerOptions) *PollingProjectConfigManager {
101101

102-
var requester Requester
102+
var requester utils.Requester
103103
if options.Requester != nil {
104104
requester = options.Requester
105105
} else {
106106
url := fmt.Sprintf(DatafileURLTemplate, sdkKey)
107-
requester = NewHTTPRequester(url)
107+
requester = utils.NewHTTPRequester(url)
108108
}
109109

110110
pollingInterval := options.PollingInterval

optimizely/config/polling_manager_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,21 @@
1717
package config
1818

1919
import (
20-
"github.com/optimizely/go-sdk/optimizely/utils"
2120
"testing"
2221

23-
"github.com/stretchr/testify/assert"
24-
2522
"github.com/optimizely/go-sdk/optimizely/config/datafileprojectconfig"
23+
"github.com/optimizely/go-sdk/optimizely/utils"
24+
25+
"github.com/stretchr/testify/assert"
2626
"github.com/stretchr/testify/mock"
2727
)
2828

2929
type MockRequester struct {
30-
Requester
30+
utils.Requester
3131
mock.Mock
3232
}
3333

34-
func (m *MockRequester) Get(headers ...Header) (response []byte, code int, err error) {
34+
func (m *MockRequester) Get(headers ...utils.Header) (response []byte, code int, err error) {
3535
args := m.Called(headers)
3636
return args.Get(0).([]byte), args.Int(1), args.Error(2)
3737
}
@@ -40,7 +40,7 @@ func TestNewPollingProjectConfigManagerWithOptions(t *testing.T) {
4040
mockDatafile := []byte("{ revision: \"42\" }")
4141
projectConfig, _ := datafileprojectconfig.NewDatafileProjectConfig(mockDatafile)
4242
mockRequester := new(MockRequester)
43-
mockRequester.On("Get", []Header(nil)).Return(mockDatafile, 200, nil)
43+
mockRequester.On("Get", []utils.Header(nil)).Return(mockDatafile, 200, nil)
4444

4545
// Test we fetch using requester
4646
sdkKey := "test_sdk_key"
@@ -60,7 +60,7 @@ func TestNewPollingProjectConfigManagerWithOptions(t *testing.T) {
6060
func TestNewPollingProjectConfigManagerWithNull(t *testing.T) {
6161
mockDatafile := []byte("NOT-VALID")
6262
mockRequester := new(MockRequester)
63-
mockRequester.On("Get", []Header(nil)).Return(mockDatafile, 200, nil)
63+
mockRequester.On("Get", []utils.Header(nil)).Return(mockDatafile, 200, nil)
6464

6565
// Test we fetch using requester
6666
sdkKey := "test_sdk_key"

optimizely/event/dispatcher.go

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,15 @@
1818
package event
1919

2020
import (
21-
"bytes"
2221
"context"
23-
"encoding/json"
2422
"fmt"
25-
"net/http"
2623
"sync"
2724
"time"
2825

2926
"github.com/optimizely/go-sdk/optimizely/logging"
27+
"github.com/optimizely/go-sdk/optimizely/utils"
3028
)
3129

32-
const jsonContentType = "application/json"
3330
const maxRetries = 3
3431
const defaultQueueSize = 1000
3532
const sleepTime = 5 * time.Second
@@ -48,19 +45,20 @@ type HTTPEventDispatcher struct {
4845
// DispatchEvent dispatches event with callback
4946
func (*HTTPEventDispatcher) DispatchEvent(event LogEvent) (bool, error) {
5047

51-
jsonValue, _ := json.Marshal(event.Event)
52-
resp, err := http.Post(event.EndPoint, jsonContentType, bytes.NewBuffer(jsonValue))
48+
requester := utils.NewHTTPRequester(event.EndPoint)
49+
_, code, err := requester.Post(event.Event)
50+
5351
// also check response codes
5452
// resp.StatusCode == 400 is an error
5553
var success bool
5654
if err != nil {
5755
dispatcherLogger.Error("http.Post failed:", err)
5856
success = false
5957
} else {
60-
if resp.StatusCode == 204 {
58+
if code == 204 {
6159
success = true
6260
} else {
63-
dispatcherLogger.Error(fmt.Sprintf("http.Post invalid response %d", resp.StatusCode), nil)
61+
dispatcherLogger.Error(fmt.Sprintf("http.Post invalid response %d", code), nil)
6462
success = false
6563
}
6664
}
@@ -80,15 +78,15 @@ func (ed *QueueEventDispatcher) DispatchEvent(event LogEvent) (bool, error) {
8078
go func() {
8179
ed.flushEvents()
8280
}()
83-
return true,nil
81+
return true, nil
8482
}
8583

8684
// flush the events
8785
func (ed *QueueEventDispatcher) flushEvents() {
8886

8987
ed.eventFlushLock.Lock()
9088

91-
defer func(){
89+
defer func() {
9290
ed.eventFlushLock.Unlock()
9391
}()
9492

@@ -136,7 +134,7 @@ func (ed *QueueEventDispatcher) flushEvents() {
136134

137135
// NewQueueEventDispatcher creates a dispatcher that queues in memory and then sends via go routine.
138136
func NewQueueEventDispatcher(ctx context.Context) Dispatcher {
139-
dispatcher := &QueueEventDispatcher{eventQueue: NewInMemoryQueue(defaultQueueSize), dispatcher:&HTTPEventDispatcher{}}
137+
dispatcher := &QueueEventDispatcher{eventQueue: NewInMemoryQueue(defaultQueueSize), dispatcher: &HTTPEventDispatcher{}}
140138

141139
go func() {
142140
<-ctx.Done()

optimizely/event/processor_test.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,14 @@
1818
package event
1919

2020
import (
21-
"context"
22-
"github.com/optimizely/go-sdk/optimizely/utils"
23-
"sync"
2421
"testing"
2522
"time"
2623

24+
"github.com/optimizely/go-sdk/optimizely/utils"
25+
2726
"github.com/stretchr/testify/assert"
2827
)
2928

30-
func close(wg *sync.WaitGroup, cancelFn context.CancelFunc) {
31-
cancelFn()
32-
wg.Wait()
33-
}
3429
func TestDefaultEventProcessor_ProcessImpression(t *testing.T) {
3530
exeCtx := utils.NewCancelableExecutionCtx()
3631
processor := NewEventProcessor(exeCtx, 10, 100, 100)

optimizely/config/requester.go renamed to optimizely/utils/requester.go

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,35 @@
1414
* limitations under the License. *
1515
***************************************************************************/
1616

17-
// Package config //
18-
package config
17+
// Package utils //
18+
package utils
1919

2020
import (
21+
"bytes"
2122
"errors"
2223
"fmt"
24+
"io"
2325
"io/ioutil"
24-
"log"
2526
"net/http"
2627
"time"
2728

2829
"github.com/optimizely/go-sdk/optimizely/logging"
2930

30-
"github.com/json-iterator/go"
31+
jsoniter "github.com/json-iterator/go"
3132
)
3233

3334
const defaultTTL = 5 * time.Second
3435

3536
var requesterLogger = logging.GetLogger("Requester")
37+
var json = jsoniter.ConfigCompatibleWithStandardLibrary
3638

3739
// Requester is used to make outbound requests with
3840
type Requester interface {
3941
Get(...Header) (response []byte, code int, err error)
4042
GetObj(result interface{}, headers ...Header) error
43+
44+
Post(body interface{}, headers ...Header) (response []byte, code int, err error)
45+
PostObj(body interface{}, result interface{}, headers ...Header) error
4146
}
4247

4348
// Header element to be sent
@@ -92,24 +97,41 @@ func NewHTTPRequester(url string, params ...func(*HTTPRequester)) *HTTPRequester
9297
return &res
9398
}
9499

95-
// Get executes HTTP GET with uri and optional extra headers, returns body in []bytes
100+
// Get executes HTTP GET with url and optional extra headers, returns body in []bytes
96101
// url created as url+sdkKey.json
97102
func (r HTTPRequester) Get(headers ...Header) (response []byte, code int, err error) {
98-
return r.Do("GET", headers)
103+
return r.Do("GET", nil, headers)
99104
}
100105

101-
// GetObj executes HTTP GET with uri and optional extra headers, returns filled object
106+
// GetObj executes HTTP GET with url and optional extra headers, returns filled object
102107
func (r HTTPRequester) GetObj(result interface{}, headers ...Header) error {
103-
b, _, err := r.Do("GET", headers)
108+
b, _, err := r.Do("GET", nil, headers)
109+
if err != nil {
110+
return err
111+
}
112+
return json.Unmarshal(b, result)
113+
}
114+
115+
// Post executes HTTP POST with url, body and optional extra headers
116+
func (r HTTPRequester) Post(body interface{}, headers ...Header) (response []byte, code int, err error) {
117+
b, err := json.Marshal(body)
118+
if err != nil {
119+
return nil, 400, err
120+
}
121+
return r.Do("POST", bytes.NewBuffer(b), headers)
122+
}
123+
124+
// PostObj executes HTTP POST with uri, body and optional extra headers. Returns filled object
125+
func (r HTTPRequester) PostObj(body, result interface{}, headers ...Header) error {
126+
b, _, err := r.Post(body, headers...)
104127
if err != nil {
105128
return err
106129
}
107-
var json = jsoniter.ConfigCompatibleWithStandardLibrary
108130
return json.Unmarshal(b, result)
109131
}
110132

111133
// Do executes request and returns response body for requested uri (sdkKey.json).
112-
func (r HTTPRequester) Do(method string, headers []Header) (response []byte, code int, err error) {
134+
func (r HTTPRequester) Do(method string, body io.Reader, headers []Header) (response []byte, code int, err error) {
113135

114136
single := func(request *http.Request) (response []byte, code int, e error) {
115137
resp, doErr := r.client.Do(request)
@@ -137,8 +159,7 @@ func (r HTTPRequester) Do(method string, headers []Header) (response []byte, cod
137159
}
138160

139161
requesterLogger.Debug(fmt.Sprintf("request %s", r.url))
140-
req, err := http.NewRequest(method, r.url, nil)
141-
log.Print(req)
162+
req, err := http.NewRequest(method, r.url, body)
142163
if err != nil {
143164
requesterLogger.Error(fmt.Sprintf("failed to make request %s", r.url), err)
144165
return nil, 0, err

optimizely/config/requester_test.go renamed to optimizely/utils/requester_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License. *
1515
***************************************************************************/
1616

17-
package config
17+
package utils
1818

1919
import (
2020
"errors"

0 commit comments

Comments
 (0)