1717package lib
1818
1919import (
20+ "bytes"
2021 "encoding/json"
2122 "errors"
22- "fmt"
23- "net/http"
24- "sync"
25- "time"
26-
2723 "github.com/IBM/appconfiguration-go-sdk/lib/internal/constants"
2824 "github.com/IBM/appconfiguration-go-sdk/lib/internal/messages"
2925 "github.com/IBM/appconfiguration-go-sdk/lib/internal/models"
3026 "github.com/IBM/appconfiguration-go-sdk/lib/internal/utils"
31- "github.com/IBM/go-sdk-core/v5/core"
32-
3327 "github.com/IBM/appconfiguration-go-sdk/lib/internal/utils/log"
28+ "github.com/IBM/go-sdk-core/v5/core"
3429 "github.com/gorilla/websocket"
30+ "net/http"
31+ "path"
32+ "sync"
33+ "time"
3534)
3635
3736type configurationUpdateListenerFunc func ()
@@ -48,8 +47,10 @@ type ConfigurationHandler struct {
4847 appConfig * AppConfiguration
4948 cache * models.Cache
5049 configurationUpdateListener configurationUpdateListenerFunc
51- configurationFile string
50+ persistentCacheDirectory string
51+ bootstrapFile string
5252 liveConfigUpdateEnabled bool
53+ persistentData []byte
5354 retryCount int
5455 retryInterval int64
5556 socketConnection * websocket.Conn
@@ -75,14 +76,15 @@ func (ch *ConfigurationHandler) Init(region, guid, apikey string) {
7576}
7677
7778// SetContext : Set Context
78- func (ch * ConfigurationHandler ) SetContext (collectionID , environmentID , configurationFile string , liveConfigUpdateEnabled bool ) {
79+ func (ch * ConfigurationHandler ) SetContext (collectionID , environmentID string , options ContextOptions ) {
7980 ch .collectionID = collectionID
8081 ch .environmentID = environmentID
8182 ch .urlBuilder = utils .GetInstance ()
8283 ch .urlBuilder .Init (ch .collectionID , ch .environmentID , ch .region , ch .guid , ch .apikey , OverrideServerHost )
8384 utils .GetMeteringInstance ().Init (ch .guid , environmentID , collectionID )
84- ch .configurationFile = configurationFile
85- ch .liveConfigUpdateEnabled = liveConfigUpdateEnabled
85+ ch .persistentCacheDirectory = options .PersistentCacheDirectory
86+ ch .bootstrapFile = options .BootstrapFile
87+ ch .liveConfigUpdateEnabled = options .LiveConfigUpdateEnabled
8688 ch .isInitialized = true
8789 ch .retryCount = 3
8890 ch .retryInterval = 600
@@ -91,14 +93,31 @@ func (ch *ConfigurationHandler) loadData() {
9193 if ! ch .isInitialized {
9294 log .Error (messages .ConfigurationHandlerInitError )
9395 }
94- log .Debug (messages .LoadingData )
95- log .Debug (messages .CheckConfigurationFileProvided )
96- if len (ch .configurationFile ) > 0 {
97- log .Debug (messages .ConfigurationFileProvided )
98- ch .getFileData (ch .configurationFile )
96+ if len (ch .persistentCacheDirectory ) > 0 {
97+ ch .persistentData = utils .ReadFiles (path .Join (ch .persistentCacheDirectory , constants .ConfigurationFile ))
98+ if ! bytes .Equal (ch .persistentData , []byte (`{}` )) {
99+ // no updating the listener here. Only updating cache is enough
100+ ch .saveInCache (ch .persistentData )
101+ }
102+ }
103+ if len (ch .bootstrapFile ) > 0 {
104+ log .Debug (messages .BootstrapFileProvided )
105+ if len (ch .persistentCacheDirectory ) > 0 {
106+ if bytes .Equal (ch .persistentData , []byte (`{}` )) {
107+ bootstrapFileData := utils .ReadFiles (ch .bootstrapFile )
108+ go utils .StoreFiles (string (bootstrapFileData ), ch .persistentCacheDirectory )
109+ ch .updateCacheAndListener (bootstrapFileData )
110+ } else {
111+ // update the only listener here. Because, cache is already updated above (line 100)
112+ if ch .configurationUpdateListener != nil {
113+ ch .configurationUpdateListener ()
114+ }
115+ }
116+ } else {
117+ bootstrapFileData := utils .ReadFiles (ch .bootstrapFile )
118+ ch .updateCacheAndListener (bootstrapFileData )
119+ }
99120 }
100- log .Debug (messages .LiveUpdateCheck )
101- log .Debug (fmt .Sprint (ch .liveConfigUpdateEnabled ))
102121 if ch .liveConfigUpdateEnabled {
103122 ch .FetchConfigurationData ()
104123 }
@@ -112,11 +131,11 @@ func (ch *ConfigurationHandler) FetchConfigurationData() {
112131 go ch .startWebSocket ()
113132 }
114133}
115- func (ch * ConfigurationHandler ) saveInCache (data string ) {
134+ func (ch * ConfigurationHandler ) saveInCache (data [] byte ) {
116135 ch .mu .Lock ()
117136 defer ch .mu .Unlock ()
118137 configResponse := models.ConfigResponse {}
119- err := json .Unmarshal ([] byte ( data ) , & configResponse )
138+ err := json .Unmarshal (data , & configResponse )
120139 if err != nil {
121140 log .Error (messages .UnmarshalJSONErr , err )
122141 return
@@ -140,6 +159,12 @@ func (ch *ConfigurationHandler) saveInCache(data string) {
140159 models .SetCache (featureMap , propertyMap , segmentMap )
141160 ch .cache = models .GetCacheInstance ()
142161}
162+ func (ch * ConfigurationHandler ) updateCacheAndListener (data []byte ) {
163+ ch .saveInCache (data )
164+ if ch .configurationUpdateListener != nil {
165+ ch .configurationUpdateListener ()
166+ }
167+ }
143168func (ch * ConfigurationHandler ) fetchFromAPI () {
144169 if ch .isInitialized {
145170 ch .retryCount --
@@ -159,14 +184,24 @@ func (ch *ConfigurationHandler) fetchFromAPI() {
159184 if response != nil && response .StatusCode >= 200 && response .StatusCode <= 299 {
160185 if ch .liveConfigUpdateEnabled {
161186 jsonData , _ := json .Marshal (response .Result )
162- ch . saveInCache ( string ( jsonData ))
163- if ch .configurationUpdateListener != nil {
164- ch . configurationUpdateListener ( )
187+ // asynchronously write the response to persistent volume, if enabled
188+ if len ( ch .persistentCacheDirectory ) > 0 {
189+ go utils . StoreFiles ( string ( jsonData ), ch . persistentCacheDirectory )
165190 }
191+ // load the configurations in the response to cache maps
192+ ch .updateCacheAndListener (jsonData )
166193 }
167194 } else {
168195 if ch .retryCount > 0 {
169- log .Error (messages .ConfigAPIError )
196+ if response != nil {
197+ if response .Result != nil {
198+ log .Error (response .Result )
199+ } else {
200+ log .Error (string (response .RawResult ))
201+ }
202+ } else {
203+ log .Error (messages .ConfigAPIError )
204+ }
170205 ch .fetchFromAPI ()
171206 } else {
172207 ch .retryCount = 3
@@ -219,18 +254,6 @@ func (ch *ConfigurationHandler) startWebSocket() {
219254 }
220255 }
221256 }()
222-
223- }
224-
225- func (ch * ConfigurationHandler ) getFeatureActions (featureID string ) (models.Feature , error ) {
226- if ch .cache != nil && len (ch .cache .FeatureMap ) > 0 {
227- if val , ok := ch .cache .FeatureMap [featureID ]; ok {
228- return val , nil
229- }
230- log .Error (messages .InvalidFeatureID , featureID )
231- return models.Feature {}, errors .New (messages .ErrorInvalidFeatureID + featureID )
232- }
233- return models.Feature {}, errors .New (messages .ErrorInvalidFeatureID + featureID )
234257}
235258func (ch * ConfigurationHandler ) getFeatures () (map [string ]models.Feature , error ) {
236259 if ch .cache == nil {
@@ -243,21 +266,10 @@ func (ch *ConfigurationHandler) getFeature(featureID string) (models.Feature, er
243266 if val , ok := ch .cache .FeatureMap [featureID ]; ok {
244267 return val , nil
245268 }
246- return ch .getFeatureActions (featureID )
247269 }
248- return ch .getFeatureActions (featureID )
249-
250- }
270+ log .Error (messages .InvalidFeatureID , featureID )
271+ return models.Feature {}, errors .New (messages .ErrorInvalidFeatureID + featureID )
251272
252- func (ch * ConfigurationHandler ) getPropertyActions (propertyID string ) (models.Property , error ) {
253- if ch .cache != nil && len (ch .cache .PropertyMap ) > 0 {
254- if val , ok := ch .cache .PropertyMap [propertyID ]; ok {
255- return val , nil
256- }
257- log .Error (messages .InvalidPropertyID , propertyID )
258- return models.Property {}, errors .New (messages .ErrorInvalidPropertyID + propertyID )
259- }
260- return models.Property {}, errors .New (messages .ErrorInvalidPropertyID + propertyID )
261273}
262274func (ch * ConfigurationHandler ) getProperties () (map [string ]models.Property , error ) {
263275 if ch .cache == nil {
@@ -270,9 +282,9 @@ func (ch *ConfigurationHandler) getProperty(propertyID string) (models.Property,
270282 if val , ok := ch .cache .PropertyMap [propertyID ]; ok {
271283 return val , nil
272284 }
273- return ch .getPropertyActions (propertyID )
274285 }
275- return ch .getPropertyActions (propertyID )
286+ log .Error (messages .InvalidPropertyID , propertyID )
287+ return models.Property {}, errors .New (messages .ErrorInvalidPropertyID + propertyID )
276288}
277289
278290func (ch * ConfigurationHandler ) registerConfigurationUpdateListener (chl configurationUpdateListenerFunc ) {
@@ -287,23 +299,3 @@ func (ch *ConfigurationHandler) registerConfigurationUpdateListener(chl configur
287299 log .Error (messages .CollectionIDError )
288300 }
289301}
290-
291- func (ch * ConfigurationHandler ) getFileData (filePath string ) {
292- data := utils .ReadFiles (filePath )
293- configResp := models.ConfigResponse {}
294- err := json .Unmarshal (data , & configResp )
295- if err != nil {
296- log .Error (messages .UnmarshalJSONErr , err )
297- return
298- }
299- log .Debug (fmt .Sprint (configResp ))
300- out , err := json .Marshal (configResp )
301- if err != nil {
302- log .Error (messages .MarshalJSONErr , err )
303- return
304- }
305- ch .saveInCache (string (out ))
306- if ch .configurationUpdateListener != nil {
307- ch .configurationUpdateListener ()
308- }
309- }
0 commit comments