Skip to content

Commit 954b6bf

Browse files
SakshamGuptasoftvar
authored andcommitted
feat(lib): promisify APIs to be able to use async storage service
1 parent f5b1b4c commit 954b6bf

17 files changed

+1256
-364
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.68.0] - 2024-02-15
9+
### Added
10+
- Promise based approach for all APIs to support async user storage operations
11+
812
## [1.64.3] - 2024-01-02
913

1014
### Added

dist/vwo-javascript-sdk.js

Lines changed: 460 additions & 165 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/vwo-javascript-sdk.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/vwo-javascript-sdk.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/vwo-javascript-sdk.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/VWO.js

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,14 @@ class VWO {
5050
this.userStorageService = config.userStorageService;
5151
this.logger = config.logger;
5252
this.returnPromiseFor = config.returnPromiseFor;
53+
this.asyncStorageConfig = config.asyncStorageConfig;
5354
this.optOut = false;
5455

56+
if (this.userStorageService === undefined && config.asyncStorageConfig) {
57+
// replace the userStorageService with the redisObject passed in asyncStorageConfig
58+
this.userStorageService = config.asyncStorageConfig.redisStorage;
59+
config.userStorageService = this.userStorageService;
60+
}
5561
let settingsFileManager = new SettingsFileService(config);
5662

5763
// Validate the config file i.e. check if required fields contain appropriate data
@@ -152,6 +158,37 @@ class VWO {
152158
try {
153159
let self = this;
154160

161+
if (self.asyncStorageConfig && DataTypeUtil.isObject(self.asyncStorageConfig)) {
162+
self.logger.log(
163+
LogLevelEnum.INFO,
164+
LogMessageUtil.build(LogMessageEnum.INFO_MESSAGES.CONFIG_ASYNC_RETURN_PROMISE, {
165+
file,
166+
method: ApiEnum.ACTIVATE
167+
})
168+
);
169+
170+
return new Promise(resolve => {
171+
if (this.optOut) {
172+
this.logger.log(
173+
LogLevelEnum.INFO,
174+
LogMessageUtil.build(LogMessageEnum.INFO_MESSAGES.API_NOT_ENABLED, {
175+
file,
176+
api: ApiEnum.ACTIVATE
177+
})
178+
);
179+
resolve(null);
180+
} else {
181+
return api.activate(self, campaignKey, userId, options).then(function(data) {
182+
if (DataTypeUtil.isObject(data)) {
183+
resolve(data.variationName);
184+
} else {
185+
resolve(data);
186+
}
187+
});
188+
}
189+
});
190+
}
191+
155192
// Check if returnPromiseFor is provided. If yes, return a promise instead of value
156193
// i.e. wait till the network call is not successful
157194
if (self.returnPromiseFor && (self.returnPromiseFor.activate || self.returnPromiseFor.all)) {
@@ -180,7 +217,7 @@ class VWO {
180217
variationName = api.activate(self, campaignKey, userId, options);
181218

182219
// If we get null from the API i.e. no tracking call was sent
183-
// In this case, respponseCallback will not be fired and hence we have to manually resolve the promise
220+
// In this case, responseCallback will not be fired and hence we have to manually resolve the promise
184221
if (!variationName) {
185222
resolve(variationName);
186223
} else if (DataTypeUtil.isObject(variationName)) {
@@ -227,6 +264,37 @@ class VWO {
227264
try {
228265
let self = this;
229266

267+
if (self.asyncStorageConfig && DataTypeUtil.isObject(self.asyncStorageConfig)) {
268+
self.logger.log(
269+
LogLevelEnum.INFO,
270+
LogMessageUtil.build(LogMessageEnum.INFO_MESSAGES.CONFIG_ASYNC_RETURN_PROMISE, {
271+
file,
272+
method: ApiEnum.GET_VARIATION_NAME
273+
})
274+
);
275+
276+
return new Promise(resolve => {
277+
if (this.optOut) {
278+
this.logger.log(
279+
LogLevelEnum.INFO,
280+
LogMessageUtil.build(LogMessageEnum.INFO_MESSAGES.API_NOT_ENABLED, {
281+
file,
282+
api: ApiEnum.GET_VARIATION_NAME
283+
})
284+
);
285+
resolve(null);
286+
} else {
287+
return api.getVariation(self, campaignKey, userId, options).then(function(data) {
288+
if (DataTypeUtil.isObject(data)) {
289+
resolve(data.variationName);
290+
} else {
291+
resolve(data);
292+
}
293+
});
294+
}
295+
});
296+
}
297+
230298
// Check if returnPromiseFor is provided. If yes, return a promise instead of value
231299
if (self.returnPromiseFor && (self.returnPromiseFor.getVariationName || self.returnPromiseFor.all)) {
232300
self.logger.log(
@@ -283,6 +351,34 @@ class VWO {
283351
try {
284352
let self = this;
285353

354+
// In case we use any asyncStorage like redis, promisify track
355+
if (self.asyncStorageConfig && DataTypeUtil.isObject(self.asyncStorageConfig)) {
356+
self.logger.log(
357+
LogLevelEnum.INFO,
358+
LogMessageUtil.build(LogMessageEnum.INFO_MESSAGES.CONFIG_ASYNC_RETURN_PROMISE, {
359+
file,
360+
method: ApiEnum.TRACK
361+
})
362+
);
363+
364+
return new Promise(resolve => {
365+
if (this.optOut) {
366+
this.logger.log(
367+
LogLevelEnum.INFO,
368+
LogMessageUtil.build(LogMessageEnum.INFO_MESSAGES.API_NOT_ENABLED, {
369+
file,
370+
api: ApiEnum.TRACK
371+
})
372+
);
373+
resolve(null);
374+
} else {
375+
return api.track(self, campaignSpecifier, userId, goalIdentifier, options).then(function(trackResponse) {
376+
resolve(trackResponse);
377+
});
378+
}
379+
});
380+
}
381+
286382
// Check if returnPromiseFor is provided. If yes, return a promise instead of value
287383
// i.e. wait till the network call is not successful
288384
if (self.returnPromiseFor && (self.returnPromiseFor.track || self.returnPromiseFor.all)) {
@@ -368,6 +464,37 @@ class VWO {
368464
try {
369465
let self = this;
370466

467+
if (self.asyncStorageConfig && DataTypeUtil.isObject(self.asyncStorageConfig)) {
468+
self.logger.log(
469+
LogLevelEnum.INFO,
470+
LogMessageUtil.build(LogMessageEnum.INFO_MESSAGES.CONFIG_ASYNC_RETURN_PROMISE, {
471+
file,
472+
method: ApiEnum.IS_FEATURE_ENABLED
473+
})
474+
);
475+
476+
return new Promise(resolve => {
477+
if (this.optOut) {
478+
this.logger.log(
479+
LogLevelEnum.INFO,
480+
LogMessageUtil.build(LogMessageEnum.INFO_MESSAGES.API_NOT_ENABLED, {
481+
file,
482+
api: ApiEnum.IS_FEATURE_ENABLED
483+
})
484+
);
485+
resolve(null);
486+
} else {
487+
return api.isFeatureEnabled(self, campaignKey, userId, options).then(function(data) {
488+
if (DataTypeUtil.isObject(data)) {
489+
resolve(data.isFeatureEnabled);
490+
} else {
491+
resolve(data);
492+
}
493+
});
494+
}
495+
});
496+
}
497+
371498
// Check if returnPromiseFor is provided. If yes, return a promise instead of value
372499
// i.e. wait till the network call is not successful
373500
if (self.returnPromiseFor && (self.returnPromiseFor.isFeatureEnabled || self.returnPromiseFor.all)) {
@@ -446,6 +573,37 @@ class VWO {
446573
try {
447574
let self = this;
448575

576+
if (self.asyncStorageConfig && DataTypeUtil.isObject(self.asyncStorageConfig)) {
577+
self.logger.log(
578+
LogLevelEnum.INFO,
579+
LogMessageUtil.build(LogMessageEnum.INFO_MESSAGES.CONFIG_ASYNC_RETURN_PROMISE, {
580+
file,
581+
method: ApiEnum.GET_FEATURE_VARIABLE_VALUE
582+
})
583+
);
584+
585+
return new Promise(resolve => {
586+
if (this.optOut) {
587+
this.logger.log(
588+
LogLevelEnum.INFO,
589+
LogMessageUtil.build(LogMessageEnum.INFO_MESSAGES.API_NOT_ENABLED, {
590+
file,
591+
api: ApiEnum.GET_FEATURE_VARIABLE_VALUE
592+
})
593+
);
594+
resolve(null);
595+
} else {
596+
return api.getFeatureVariableValue(self, campaignKey, variableKey, userId, options).then(function(data) {
597+
if (DataTypeUtil.isObject(data)) {
598+
resolve(data.typeCastedValue);
599+
} else {
600+
resolve(data);
601+
}
602+
});
603+
}
604+
});
605+
}
606+
449607
// Check if returnPromiseFor is provided. If yes, return a promise instead of value
450608
if (self.returnPromiseFor && (self.returnPromiseFor.getFeatureVariableValue || self.returnPromiseFor.all)) {
451609
self.logger.log(

lib/api/activate.js

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ function activate(vwoInstance, campaignKey, userId, options = {}) {
154154
}
155155

156156
// Once the matching RUNNING campaign is found, assign the deterministic variation to the userId provided
157-
const { variationId, variationName, isStoredVariation } = DecisionUtil.getVariation(
157+
const result = DecisionUtil.getVariation(
158158
config,
159159
settingsFile,
160160
campaign,
@@ -165,10 +165,62 @@ function activate(vwoInstance, campaignKey, userId, options = {}) {
165165
userStorageData,
166166
metaData,
167167
true,
168+
false,
168169
undefined,
169170
api
170171
);
171172

173+
if (DataTypeUtil.isPromise(result)) {
174+
return result.then(function(data) {
175+
return _validateAndReturnVariation(
176+
vwoInstance,
177+
campaignKey,
178+
userId,
179+
config,
180+
api,
181+
shouldTrackReturningUser,
182+
settingsFile,
183+
campaign,
184+
visitorUserAgent,
185+
userIpAddress,
186+
responseCallback,
187+
data
188+
);
189+
});
190+
}
191+
192+
return _validateAndReturnVariation(
193+
vwoInstance,
194+
campaignKey,
195+
userId,
196+
config,
197+
api,
198+
shouldTrackReturningUser,
199+
settingsFile,
200+
campaign,
201+
visitorUserAgent,
202+
userIpAddress,
203+
responseCallback,
204+
result
205+
);
206+
}
207+
208+
function _validateAndReturnVariation(
209+
vwoInstance,
210+
campaignKey,
211+
userId,
212+
config,
213+
api,
214+
shouldTrackReturningUser,
215+
settingsFile,
216+
campaign,
217+
visitorUserAgent,
218+
userIpAddress,
219+
responseCallback,
220+
result
221+
) {
222+
var { variationId, variationName, isStoredVariation } = result;
223+
172224
// Check if variation-name has been assigned to the userId. If not, return no variation
173225
if (!ValidateUtil.isValidValue(variationName)) {
174226
vwoInstance.logger.log(
@@ -243,5 +295,4 @@ function activate(vwoInstance, campaignKey, userId, options = {}) {
243295

244296
return variationName;
245297
}
246-
247298
module.exports = activate;

0 commit comments

Comments
 (0)