11/****************************************************************************
2- * Copyright 2019, Optimizely, Inc. and contributors *
2+ * Copyright 2019-2020 , Optimizely, Inc. and contributors *
33 * *
44 * Licensed under the Apache License, Version 2.0 (the "License"); *
55 * you may not use this file except in compliance with the License. *
@@ -42,9 +42,12 @@ const ModifiedSince = "If-Modified-Since"
4242// LastModified header key for response
4343const LastModified = "Last-Modified"
4444
45- // DatafileURLTemplate is used to construct the endpoint for retrieving the datafile from the CDN
45+ // DatafileURLTemplate is used to construct the endpoint for retrieving regular datafile from the CDN
4646const DatafileURLTemplate = "https://cdn.optimizely.com/datafiles/%s.json"
4747
48+ // AuthDatafileURLTemplate is used to construct the endpoint for retrieving authenticated datafile from the CDN
49+ const AuthDatafileURLTemplate = "https://config.optimizely.com/datafiles/auth/%s.json"
50+
4851// Err403Forbidden is 403Forbidden specific error
4952var Err403Forbidden = errors .New ("unable to fetch fresh datafile (consider rechecking SDK key), status code: 403 Forbidden" )
5053
@@ -58,7 +61,8 @@ type PollingProjectConfigManager struct {
5861 pollingInterval time.Duration
5962 requester utils.Requester
6063 sdkKey string
61- logger logging.OptimizelyLogProducer
64+ logger logging.OptimizelyLogProducer
65+ datafileAccessToken string
6266
6367 configLock sync.RWMutex
6468 err error
@@ -97,6 +101,13 @@ func WithInitialDatafile(datafile []byte) OptionFunc {
97101 }
98102}
99103
104+ // WithDatafileAccessToken is an optional function, sets a passed datafile access token
105+ func WithDatafileAccessToken (datafileAccessToken string ) OptionFunc {
106+ return func (p * PollingProjectConfigManager ) {
107+ p .datafileAccessToken = datafileAccessToken
108+ }
109+ }
110+
100111// SyncConfig downloads datafile and updates projectConfig
101112func (cm * PollingProjectConfigManager ) SyncConfig () {
102113 var e error
@@ -169,6 +180,10 @@ func (cm *PollingProjectConfigManager) SyncConfig() {
169180
170181// Start starts the polling
171182func (cm * PollingProjectConfigManager ) Start (ctx context.Context ) {
183+ if cm .pollingInterval <= 0 {
184+ cm .logger .Info ("Polling Config Manager Disabled" )
185+ return
186+ }
172187 cm .logger .Debug ("Polling Config Manager Initiated" )
173188 t := time .NewTicker (cm .pollingInterval )
174189 for {
@@ -182,48 +197,59 @@ func (cm *PollingProjectConfigManager) Start(ctx context.Context) {
182197 }
183198}
184199
185- // NewPollingProjectConfigManager returns an instance of the polling config manager with the customized configuration
186- func NewPollingProjectConfigManager (sdkKey string , pollingMangerOptions ... OptionFunc ) * PollingProjectConfigManager {
200+ func (cm * PollingProjectConfigManager ) setAuthHeaderIfDatafileAccessTokenPresent () {
201+ if cm .datafileAccessToken != "" {
202+ headers := []utils.Header {{Name : "Content-Type" , Value : "application/json" }, {Name : "Accept" , Value : "application/json" }}
203+ headers = append (headers , utils.Header {Name : "Authorization" , Value : "Bearer " + cm .datafileAccessToken })
204+ cm .requester = utils .NewHTTPRequester (logging .GetLogger (cm .sdkKey , "HTTPRequester" ), utils .Headers (headers ... ))
205+ }
206+ }
187207
208+ func newConfigManager (sdkKey string , logger logging.OptimizelyLogProducer , configOptions ... OptionFunc ) * PollingProjectConfigManager {
188209 pollingProjectConfigManager := PollingProjectConfigManager {
189- notificationCenter : registry .GetNotificationCenter (sdkKey ),
190- pollingInterval : DefaultPollingInterval ,
191- requester : utils .NewHTTPRequester (logging .GetLogger (sdkKey , "HTTPRequester" )),
192- datafileURLTemplate : DatafileURLTemplate ,
193- sdkKey : sdkKey ,
194- logger : logging .GetLogger (sdkKey , "PollingProjectConfigManager" ),
210+ notificationCenter : registry .GetNotificationCenter (sdkKey ),
211+ pollingInterval : DefaultPollingInterval ,
212+ requester : utils .NewHTTPRequester (logging .GetLogger (sdkKey , "HTTPRequester" )),
213+ sdkKey : sdkKey ,
214+ logger : logger ,
195215 }
196216
197- for _ , opt := range pollingMangerOptions {
217+ for _ , opt := range configOptions {
198218 opt (& pollingProjectConfigManager )
199219 }
200220
221+ if pollingProjectConfigManager .datafileURLTemplate == "" {
222+ if pollingProjectConfigManager .datafileAccessToken != "" {
223+ pollingProjectConfigManager .datafileURLTemplate = AuthDatafileURLTemplate
224+ } else {
225+ pollingProjectConfigManager .datafileURLTemplate = DatafileURLTemplate
226+ }
227+ }
228+ pollingProjectConfigManager .setAuthHeaderIfDatafileAccessTokenPresent ()
229+ return & pollingProjectConfigManager
230+ }
231+
232+ // NewPollingProjectConfigManager returns an instance of the polling config manager with the customized configuration
233+ func NewPollingProjectConfigManager (sdkKey string , pollingMangerOptions ... OptionFunc ) * PollingProjectConfigManager {
234+
235+ pollingProjectConfigManager := newConfigManager (sdkKey , logging .GetLogger (sdkKey , "PollingProjectConfigManager" ), pollingMangerOptions ... )
236+
201237 if len (pollingProjectConfigManager .initDatafile ) > 0 {
202238 pollingProjectConfigManager .setInitialDatafile (pollingProjectConfigManager .initDatafile )
203239 } else {
204240 pollingProjectConfigManager .SyncConfig () // initial poll
205241 }
206- return & pollingProjectConfigManager
242+ return pollingProjectConfigManager
207243}
208244
209245// NewAsyncPollingProjectConfigManager returns an instance of the async polling config manager with the customized configuration
210246func NewAsyncPollingProjectConfigManager (sdkKey string , pollingMangerOptions ... OptionFunc ) * PollingProjectConfigManager {
211247
212- pollingProjectConfigManager := PollingProjectConfigManager {
213- notificationCenter : registry .GetNotificationCenter (sdkKey ),
214- pollingInterval : DefaultPollingInterval ,
215- requester : utils .NewHTTPRequester (logging .GetLogger (sdkKey , "HTTPRequester" )),
216- datafileURLTemplate : DatafileURLTemplate ,
217- sdkKey : sdkKey ,
218- logger : logging .GetLogger (sdkKey , "PollingProjectConfigManager" ),
219- }
220-
221- for _ , opt := range pollingMangerOptions {
222- opt (& pollingProjectConfigManager )
248+ pollingProjectConfigManager := newConfigManager (sdkKey , logging .GetLogger (sdkKey , "PollingProjectConfigManager" ), pollingMangerOptions ... )
249+ if len (pollingProjectConfigManager .initDatafile ) > 0 {
250+ pollingProjectConfigManager .setInitialDatafile (pollingProjectConfigManager .initDatafile )
223251 }
224-
225- pollingProjectConfigManager .setInitialDatafile (pollingProjectConfigManager .initDatafile )
226- return & pollingProjectConfigManager
252+ return pollingProjectConfigManager
227253}
228254
229255// GetConfig returns the project config
0 commit comments