vwo-sdk 1.6.0 → 1.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/vwo.rb +571 -195
- data/lib/vwo/constants.rb +26 -3
- data/lib/vwo/core/bucketer.rb +1 -1
- data/lib/vwo/core/variation_decider.rb +155 -40
- data/lib/vwo/enums.rb +30 -5
- data/lib/vwo/logger.rb +1 -1
- data/lib/vwo/schemas/settings_file.rb +1 -1
- data/lib/vwo/services/batch_events_dispatcher.rb +110 -0
- data/lib/vwo/services/batch_events_queue.rb +175 -0
- data/lib/vwo/services/event_dispatcher.rb +1 -13
- data/lib/vwo/services/hooks_manager.rb +36 -0
- data/lib/vwo/services/operand_evaluator.rb +1 -1
- data/lib/vwo/services/segment_evaluator.rb +1 -1
- data/lib/vwo/services/settings_file_manager.rb +8 -4
- data/lib/vwo/services/settings_file_processor.rb +6 -1
- data/lib/vwo/services/usage_stats.rb +29 -0
- data/lib/vwo/user_storage.rb +1 -1
- data/lib/vwo/utils/campaign.rb +108 -1
- data/lib/vwo/utils/custom_dimensions.rb +26 -3
- data/lib/vwo/utils/feature.rb +1 -1
- data/lib/vwo/utils/function.rb +1 -1
- data/lib/vwo/utils/impression.rb +58 -7
- data/lib/vwo/utils/request.rb +15 -1
- data/lib/vwo/utils/segment.rb +1 -1
- data/lib/vwo/utils/uuid.rb +1 -1
- data/lib/vwo/utils/validations.rb +85 -1
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53bc0be49f50d280aac4478d6879a31dce269ed69596e5ff2d04b51cbcacbcbd
|
4
|
+
data.tar.gz: f28c84dc2ace873bf1c5fd748568d06c16583b466240df54fcf9dbd5dffec888
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63bf38a8c25c69e01cf7cbfdad204379c0dd03621e947c1848a1fdf24b432bd26672a8d3cb9efded0e45582208a73a0c69142911c900e53e477e06b2d06a069e
|
7
|
+
data.tar.gz: 0b9d9165ca2ae918a048537097f2de775fe13d35547c341aa45c7edc42206273775f18120c10ca06fc02821c24652bd25e513a05989889664285210b6fd57f02
|
data/lib/vwo.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2019-
|
1
|
+
# Copyright 2019-2021 Wingify Software Pvt. Ltd.
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -25,11 +25,14 @@ require_relative 'vwo/utils/feature'
|
|
25
25
|
require_relative 'vwo/utils/custom_dimensions'
|
26
26
|
require_relative 'vwo/constants'
|
27
27
|
require_relative 'vwo/core/variation_decider'
|
28
|
+
require_relative 'vwo/services/batch_events_dispatcher'
|
29
|
+
require_relative 'vwo/services/batch_events_queue'
|
30
|
+
require_relative 'vwo/services/usage_stats'
|
28
31
|
|
29
32
|
# VWO main file
|
30
33
|
class VWO
|
31
|
-
attr_accessor :is_instance_valid, :logger
|
32
|
-
|
34
|
+
attr_accessor :is_instance_valid, :logger, :settings_file_manager, :variation_decider
|
35
|
+
attr_reader :usage_stats
|
33
36
|
include Enums
|
34
37
|
include Utils::Validations
|
35
38
|
include Utils::Feature
|
@@ -65,7 +68,15 @@ class VWO
|
|
65
68
|
@is_development_mode = is_development_mode
|
66
69
|
@logger = VWO::Logger.get_instance(logger)
|
67
70
|
@logger.instance.level = options[:log_level] if (0..5).include?(options[:log_level])
|
71
|
+
usage_stats = {}
|
72
|
+
|
73
|
+
usage_stats[:cl] = 1 if logger
|
74
|
+
usage_stats[:ll] = 1 if options[:log_level]
|
75
|
+
usage_stats[:ss] = 1 if @user_storage
|
76
|
+
usage_stats[:ig] = 1 if options.key?(:integrations)
|
77
|
+
usage_stats[:eb] = 1 if options.key?(:batch_events)
|
68
78
|
|
79
|
+
@settings_file_manager = VWO::Services::SettingsFileManager.new(@account_id, @sdk_key)
|
69
80
|
unless valid_settings_file?(get_settings(settings_file))
|
70
81
|
@logger.log(
|
71
82
|
LogLevelEnum::ERROR,
|
@@ -74,6 +85,45 @@ class VWO
|
|
74
85
|
@is_instance_valid = false
|
75
86
|
return
|
76
87
|
end
|
88
|
+
|
89
|
+
if options.key?(:should_track_returning_user)
|
90
|
+
if [true, false].include? options[:should_track_returning_user]
|
91
|
+
@should_track_returning_user = options[:should_track_returning_user]
|
92
|
+
usage_stats[:tr] = 1 if @should_track_returning_user
|
93
|
+
else
|
94
|
+
@logger.log(
|
95
|
+
LogLevelEnum::ERROR,
|
96
|
+
format(
|
97
|
+
LogMessageEnum::ErrorMessages::INVALID_TRACK_RETURNING_USER_VALUE,
|
98
|
+
file: FILE
|
99
|
+
)
|
100
|
+
)
|
101
|
+
@is_instance_valid = false
|
102
|
+
return
|
103
|
+
end
|
104
|
+
else
|
105
|
+
@should_track_returning_user = false
|
106
|
+
end
|
107
|
+
|
108
|
+
if options.key?(:goal_type_to_track)
|
109
|
+
if GOAL_TYPES.key? options[:goal_type_to_track]
|
110
|
+
@goal_type_to_track = options[:goal_type_to_track]
|
111
|
+
usage_stats[:gt] = 1
|
112
|
+
else
|
113
|
+
@logger.log(
|
114
|
+
LogLevelEnum::ERROR,
|
115
|
+
format(
|
116
|
+
LogMessageEnum::ErrorMessages::INVALID_GOAL_TYPE,
|
117
|
+
file: FILE
|
118
|
+
)
|
119
|
+
)
|
120
|
+
@is_instance_valid = false
|
121
|
+
return
|
122
|
+
end
|
123
|
+
else
|
124
|
+
@goal_type_to_track = 'ALL'
|
125
|
+
end
|
126
|
+
|
77
127
|
@is_instance_valid = true
|
78
128
|
@config = VWO::Services::SettingsFileProcessor.new(get_settings)
|
79
129
|
|
@@ -89,8 +139,54 @@ class VWO
|
|
89
139
|
@config.process_settings_file
|
90
140
|
@settings_file = @config.get_settings_file
|
91
141
|
|
142
|
+
@usage_stats = VWO::Services::UsageStats.new(usage_stats, @is_development_mode)
|
143
|
+
|
144
|
+
if options.key?(:batch_events)
|
145
|
+
if options[:batch_events].is_a?(Hash)
|
146
|
+
unless is_valid_batch_event_settings(options[:batch_events])
|
147
|
+
@is_instance_valid = false
|
148
|
+
return
|
149
|
+
end
|
150
|
+
@batch_event_dispatcher = VWO::Services::BatchEventsDispatcher.new
|
151
|
+
def dispatcher (events, callback)
|
152
|
+
@batch_event_dispatcher.dispatch(
|
153
|
+
{
|
154
|
+
ev: events
|
155
|
+
},
|
156
|
+
callback,
|
157
|
+
{
|
158
|
+
a: @account_id,
|
159
|
+
sd: SDK_NAME,
|
160
|
+
sv: SDK_VERSION,
|
161
|
+
env: @sdk_key
|
162
|
+
}.merge(@usage_stats.usage_stats)
|
163
|
+
)
|
164
|
+
end
|
165
|
+
@batch_events_queue = VWO::Services::BatchEventsQueue.new(
|
166
|
+
options[:batch_events].merge(
|
167
|
+
{
|
168
|
+
account_id: @account_id,
|
169
|
+
dispatcher: method(:dispatcher)
|
170
|
+
}
|
171
|
+
)
|
172
|
+
)
|
173
|
+
@batch_events_queue.flush(manual: true)
|
174
|
+
@batch_events = options[:batch_events]
|
175
|
+
else
|
176
|
+
@logger.log(
|
177
|
+
LogLevelEnum::ERROR,
|
178
|
+
format(
|
179
|
+
LogMessageEnum::ErrorMessages::EVENT_BATCHING_NOT_OBJECT,
|
180
|
+
file: FILE
|
181
|
+
)
|
182
|
+
)
|
183
|
+
@is_instance_valid = false
|
184
|
+
return
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
92
188
|
# Assign VariationDecider to VWO
|
93
|
-
@variation_decider = VWO::Core::VariationDecider.new(@settings_file, user_storage)
|
189
|
+
@variation_decider = VWO::Core::VariationDecider.new(@settings_file, user_storage, options)
|
94
190
|
|
95
191
|
if is_development_mode
|
96
192
|
@logger.log(
|
@@ -118,9 +214,55 @@ class VWO
|
|
118
214
|
|
119
215
|
# VWO get_settings method to get settings for a particular account_id
|
120
216
|
def get_settings(settings_file = nil)
|
121
|
-
@
|
122
|
-
settings_file ||
|
123
|
-
@
|
217
|
+
@settings_file ||=
|
218
|
+
settings_file || @settings_file_manager.get_settings_file
|
219
|
+
@settings_file
|
220
|
+
end
|
221
|
+
|
222
|
+
# This API method: fetch the latest settings file and update it
|
223
|
+
|
224
|
+
# VWO get_settings method to get settings for a particular account_id
|
225
|
+
def get_and_update_settings_file
|
226
|
+
|
227
|
+
unless @is_instance_valid
|
228
|
+
@logger.log(
|
229
|
+
LogLevelEnum::ERROR,
|
230
|
+
format(
|
231
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
232
|
+
file: FILE,
|
233
|
+
api_name: ApiMethods.GET_AND_UPDATE_SETTINGS_FILE
|
234
|
+
)
|
235
|
+
)
|
236
|
+
return
|
237
|
+
end
|
238
|
+
|
239
|
+
latest_settings = @settings_file_manager.get_settings_file(true)
|
240
|
+
latest_settings = JSON.parse(latest_settings)
|
241
|
+
if latest_settings == @settings_file
|
242
|
+
@logger.log(
|
243
|
+
LogLevelEnum::INFO,
|
244
|
+
format(
|
245
|
+
LogMessageEnum::InfoMessages::SETTINGS_NOT_UPDATED,
|
246
|
+
api_name: ApiMethods::GET_AND_UPDATE_SETTINGS_FILE,
|
247
|
+
file: FILE
|
248
|
+
)
|
249
|
+
)
|
250
|
+
end
|
251
|
+
|
252
|
+
@config.update_settings_file(latest_settings)
|
253
|
+
@settings_file = @config.get_settings_file
|
254
|
+
@settings_file
|
255
|
+
rescue StandardError => e
|
256
|
+
@logger.log(
|
257
|
+
LogLevelEnum::ERROR,
|
258
|
+
format(
|
259
|
+
LogMessageEnum::ErrorMessages::API_NOT_WORKING,
|
260
|
+
file: FILE,
|
261
|
+
api_name: ApiMethods::GET_AND_UPDATE_SETTINGS_FILE,
|
262
|
+
exception: e
|
263
|
+
)
|
264
|
+
)
|
265
|
+
nil
|
124
266
|
end
|
125
267
|
|
126
268
|
# This API method: Gets the variation assigned for the user
|
@@ -136,18 +278,31 @@ class VWO
|
|
136
278
|
#
|
137
279
|
# @param[String] :campaign_key Unique campaign key
|
138
280
|
# @param[String] :user_id ID assigned to a user
|
139
|
-
# @param[Hash]
|
281
|
+
# @param[Hash] :options Options for custom variables required for segmentation
|
140
282
|
# @return[String|None] If variation is assigned then variation-name
|
141
283
|
# otherwise null in case of user not becoming part
|
142
284
|
|
143
285
|
def activate(campaign_key, user_id, options = {})
|
286
|
+
unless @is_instance_valid
|
287
|
+
@logger.log(
|
288
|
+
LogLevelEnum::ERROR,
|
289
|
+
format(
|
290
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
291
|
+
file: FILE,
|
292
|
+
api_name: ApiMethods::ACTIVATE
|
293
|
+
)
|
294
|
+
)
|
295
|
+
return
|
296
|
+
end
|
297
|
+
|
144
298
|
# Retrieve custom variables
|
145
299
|
custom_variables = options['custom_variables'] || options[:custom_variables]
|
146
300
|
variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
|
147
301
|
|
302
|
+
should_track_returning_user = get_should_track_returning_user(options)
|
148
303
|
# Validate input parameters
|
149
304
|
unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
|
150
|
-
|
305
|
+
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables)) && [true, false].include?(should_track_returning_user)
|
151
306
|
@logger.log(
|
152
307
|
LogLevelEnum::ERROR,
|
153
308
|
format(
|
@@ -159,18 +314,6 @@ class VWO
|
|
159
314
|
return
|
160
315
|
end
|
161
316
|
|
162
|
-
unless @is_instance_valid
|
163
|
-
@logger.log(
|
164
|
-
LogLevelEnum::ERROR,
|
165
|
-
format(
|
166
|
-
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
167
|
-
file: FILE,
|
168
|
-
api_name: ApiMethods::ACTIVATE
|
169
|
-
)
|
170
|
-
)
|
171
|
-
return
|
172
|
-
end
|
173
|
-
|
174
317
|
# Get the campaign settings
|
175
318
|
campaign = get_campaign(@settings_file, campaign_key)
|
176
319
|
|
@@ -234,15 +377,56 @@ class VWO
|
|
234
377
|
return
|
235
378
|
end
|
236
379
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
380
|
+
if is_eligible_to_send_impression(should_track_returning_user)
|
381
|
+
if defined?(@batch_events)
|
382
|
+
impression = create_bulk_event_impression(
|
383
|
+
@settings_file,
|
384
|
+
campaign['id'],
|
385
|
+
variation['id'],
|
386
|
+
user_id
|
387
|
+
)
|
388
|
+
@batch_events_queue.enqueue(impression)
|
389
|
+
else
|
390
|
+
# Variation found, dispatch it to server
|
391
|
+
impression = create_impression(
|
392
|
+
@settings_file,
|
393
|
+
campaign['id'],
|
394
|
+
variation['id'],
|
395
|
+
user_id,
|
396
|
+
@sdk_key,
|
397
|
+
nil, # goal_id
|
398
|
+
nil, # revenue
|
399
|
+
usage_stats: @usage_stats.usage_stats
|
400
|
+
)
|
401
|
+
if @event_dispatcher.dispatch(impression)
|
402
|
+
@logger.log(
|
403
|
+
LogLevelEnum::INFO,
|
404
|
+
format(
|
405
|
+
LogMessageEnum::InfoMessages::IMPRESSION_SUCCESS,
|
406
|
+
file: FILE,
|
407
|
+
sdk_key: @sdk_key,
|
408
|
+
account_id: @account_id,
|
409
|
+
campaign_id: campaign['id'],
|
410
|
+
variation_id: variation['id'],
|
411
|
+
end_point: EVENTS::TRACK_USER
|
412
|
+
)
|
413
|
+
)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
variation['name']
|
417
|
+
else
|
418
|
+
@logger.log(
|
419
|
+
LogLevelEnum::INFO,
|
420
|
+
format(
|
421
|
+
LogMessageEnum::InfoMessages::USER_ALREADY_TRACKED,
|
422
|
+
file: FILE,
|
423
|
+
user_id: user_id,
|
424
|
+
campaign_key: campaign_key,
|
425
|
+
api_name: ApiMethods::ACTIVATE
|
426
|
+
)
|
427
|
+
)
|
428
|
+
nil
|
429
|
+
end
|
246
430
|
rescue StandardError => e
|
247
431
|
@logger.log(
|
248
432
|
LogLevelEnum::ERROR,
|
@@ -274,13 +458,24 @@ class VWO
|
|
274
458
|
# Otherwise null in case of user not becoming part
|
275
459
|
#
|
276
460
|
def get_variation_name(campaign_key, user_id, options = {})
|
461
|
+
unless @is_instance_valid
|
462
|
+
@logger.log(
|
463
|
+
LogLevelEnum::ERROR,
|
464
|
+
format(
|
465
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
466
|
+
file: FILE,
|
467
|
+
api_name: ApiMethods::GET_VARIATION_NAME
|
468
|
+
)
|
469
|
+
)
|
470
|
+
return
|
471
|
+
end
|
277
472
|
# Retrieve custom variables
|
278
473
|
custom_variables = options['custom_variables'] || options[:custom_variables]
|
279
474
|
variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
|
280
475
|
|
281
476
|
# Validate input parameters
|
282
477
|
unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
|
283
|
-
|
478
|
+
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
|
284
479
|
@logger.log(
|
285
480
|
LogLevelEnum::ERROR,
|
286
481
|
format(
|
@@ -291,17 +486,6 @@ class VWO
|
|
291
486
|
)
|
292
487
|
return
|
293
488
|
end
|
294
|
-
unless @is_instance_valid
|
295
|
-
@logger.log(
|
296
|
-
LogLevelEnum::ERROR,
|
297
|
-
format(
|
298
|
-
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
299
|
-
file: FILE,
|
300
|
-
api_name: ApiMethods::GET_VARIATION_NAME
|
301
|
-
)
|
302
|
-
)
|
303
|
-
return
|
304
|
-
end
|
305
489
|
|
306
490
|
# Get the campaign settings
|
307
491
|
campaign = get_campaign(@settings_file, campaign_key)
|
@@ -383,30 +567,6 @@ class VWO
|
|
383
567
|
# @param[Numeric|String] :revenue_value It is the revenue generated on triggering the goal
|
384
568
|
#
|
385
569
|
def track(campaign_key, user_id, goal_identifier, *args)
|
386
|
-
if args[0].is_a?(Hash)
|
387
|
-
revenue_value = args[0]['revenue_value'] || args[0][:revenue_value]
|
388
|
-
custom_variables = args[0]['custom_variables'] || args[0][:custom_variables]
|
389
|
-
variation_targeting_variables = args[0]['variation_targeting_variables'] || args[0][:variation_targeting_variables]
|
390
|
-
elsif args.is_a?(Array)
|
391
|
-
revenue_value = args[0]
|
392
|
-
custom_variables = nil
|
393
|
-
end
|
394
|
-
|
395
|
-
# Check for valid args
|
396
|
-
unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
|
397
|
-
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
|
398
|
-
# log invalid params
|
399
|
-
@logger.log(
|
400
|
-
LogLevelEnum::ERROR,
|
401
|
-
format(
|
402
|
-
LogMessageEnum::ErrorMessages::TRACK_API_INVALID_PARAMS,
|
403
|
-
file: FILE,
|
404
|
-
api_name: ApiMethods.TRACK
|
405
|
-
)
|
406
|
-
)
|
407
|
-
return false
|
408
|
-
end
|
409
|
-
|
410
570
|
unless @is_instance_valid
|
411
571
|
@logger.log(
|
412
572
|
LogLevelEnum::ERROR,
|
@@ -419,98 +579,192 @@ class VWO
|
|
419
579
|
return false
|
420
580
|
end
|
421
581
|
|
422
|
-
|
423
|
-
|
582
|
+
if args[0].is_a?(Hash)
|
583
|
+
revenue_value = args[0]['revenue_value'] || args[0][:revenue_value]
|
584
|
+
custom_variables = args[0]['custom_variables'] || args[0][:custom_variables]
|
585
|
+
variation_targeting_variables = args[0]['variation_targeting_variables'] || args[0][:variation_targeting_variables]
|
586
|
+
should_track_returning_user = get_should_track_returning_user(args[0])
|
587
|
+
goal_type_to_track = get_goal_type_to_track(args[0])
|
588
|
+
elsif args.is_a?(Array)
|
589
|
+
revenue_value = args[0]
|
590
|
+
custom_variables = nil
|
591
|
+
should_track_returning_user = @should_track_returning_user
|
592
|
+
goal_type_to_track = @goal_type_to_track
|
593
|
+
end
|
424
594
|
|
425
|
-
#
|
426
|
-
|
427
|
-
|
595
|
+
# Check for valid args
|
596
|
+
unless (valid_string?(campaign_key) || campaign_key.is_a?(Array) || campaign_key.nil?) && valid_string?(user_id) && valid_string?(goal_identifier) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
|
597
|
+
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables)) && [true, false].include?(should_track_returning_user) && (GOAL_TYPES.key? (goal_type_to_track))
|
598
|
+
# log invalid params
|
428
599
|
@logger.log(
|
429
600
|
LogLevelEnum::ERROR,
|
430
601
|
format(
|
431
|
-
LogMessageEnum::ErrorMessages::
|
602
|
+
LogMessageEnum::ErrorMessages::TRACK_API_INVALID_PARAMS,
|
432
603
|
file: FILE,
|
433
|
-
campaign_key: campaign_key,
|
434
604
|
api_name: ApiMethods::TRACK
|
435
605
|
)
|
436
606
|
)
|
437
607
|
return false
|
438
608
|
end
|
439
609
|
|
440
|
-
|
610
|
+
# Get campaigns settings
|
611
|
+
campaigns = get_campaigns(@settings_file, campaign_key, goal_identifier, goal_type_to_track)
|
441
612
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
format(
|
446
|
-
LogMessageEnum::ErrorMessages::INVALID_API,
|
447
|
-
file: FILE,
|
448
|
-
api_name: ApiMethods::TRACK,
|
449
|
-
user_id: user_id,
|
450
|
-
campaign_key: campaign_key,
|
451
|
-
campaign_type: campaign_type
|
452
|
-
)
|
453
|
-
)
|
454
|
-
return false
|
613
|
+
# Validate campaign
|
614
|
+
if campaigns.nil?
|
615
|
+
return nil
|
455
616
|
end
|
456
617
|
|
457
|
-
|
618
|
+
result = {}
|
619
|
+
campaigns.each do |campaign|
|
620
|
+
campaign_type = campaign['type']
|
458
621
|
|
459
|
-
|
460
|
-
goal = get_campaign_goal(campaign, goal_identifier)
|
461
|
-
if goal.nil?
|
622
|
+
if campaign_type == CampaignTypes::FEATURE_ROLLOUT
|
462
623
|
@logger.log(
|
463
624
|
LogLevelEnum::ERROR,
|
464
625
|
format(
|
465
|
-
LogMessageEnum::ErrorMessages::
|
626
|
+
LogMessageEnum::ErrorMessages::INVALID_API,
|
466
627
|
file: FILE,
|
467
|
-
|
628
|
+
api_name: ApiMethods::TRACK,
|
468
629
|
user_id: user_id,
|
469
|
-
campaign_key:
|
470
|
-
|
630
|
+
campaign_key: campaign['key'],
|
631
|
+
campaign_type: campaign_type
|
471
632
|
)
|
472
633
|
)
|
473
|
-
|
474
|
-
|
475
|
-
@logger.log(
|
476
|
-
LogLevelEnum::ERROR,
|
477
|
-
format(
|
478
|
-
LogMessageEnum::ErrorMessages::TRACK_API_REVENUE_NOT_PASSED_FOR_REVENUE_GOAL,
|
479
|
-
file: FILE,
|
480
|
-
user_id: user_id,
|
481
|
-
goal_identifier: goal_identifier,
|
482
|
-
campaign_key: campaign_key,
|
483
|
-
api_name: ApiMethods::TRACK
|
484
|
-
)
|
485
|
-
)
|
486
|
-
return false
|
487
|
-
elsif goal['type'] == GoalTypes::CUSTOM
|
488
|
-
revenue_value = nil
|
634
|
+
result[campaign['key']] = false
|
635
|
+
next
|
489
636
|
end
|
490
|
-
impression = create_impression(
|
491
|
-
@settings_file,
|
492
|
-
campaign['id'],
|
493
|
-
variation['id'],
|
494
|
-
user_id,
|
495
|
-
goal['id'],
|
496
|
-
revenue_value
|
497
|
-
)
|
498
|
-
@event_dispatcher.dispatch(impression)
|
499
637
|
|
638
|
+
variation = @variation_decider.get_variation(user_id, campaign, ApiMethods::TRACK, campaign['key'], custom_variables, variation_targeting_variables, goal_identifier)
|
639
|
+
|
640
|
+
if variation
|
641
|
+
goal = get_campaign_goal(campaign, goal_identifier)
|
642
|
+
if goal.nil? || !goal["id"]
|
643
|
+
@logger.log(
|
644
|
+
LogLevelEnum::ERROR,
|
645
|
+
format(
|
646
|
+
LogMessageEnum::ErrorMessages::TRACK_API_GOAL_NOT_FOUND,
|
647
|
+
file: FILE,
|
648
|
+
goal_identifier: goal_identifier,
|
649
|
+
user_id: user_id,
|
650
|
+
campaign_key: campaign['key'],
|
651
|
+
api_name: ApiMethods::TRACK
|
652
|
+
)
|
653
|
+
)
|
654
|
+
result[campaign['key']] = false
|
655
|
+
next
|
656
|
+
elsif goal['type'] == GoalTypes::REVENUE && !valid_value?(revenue_value)
|
657
|
+
@logger.log(
|
658
|
+
LogLevelEnum::ERROR,
|
659
|
+
format(
|
660
|
+
LogMessageEnum::ErrorMessages::TRACK_API_REVENUE_NOT_PASSED_FOR_REVENUE_GOAL,
|
661
|
+
file: FILE,
|
662
|
+
user_id: user_id,
|
663
|
+
goal_identifier: goal_identifier,
|
664
|
+
campaign_key: campaign['key'],
|
665
|
+
api_name: ApiMethods::TRACK
|
666
|
+
)
|
667
|
+
)
|
668
|
+
result[campaign['key']] = false
|
669
|
+
next
|
670
|
+
elsif goal['type'] == GoalTypes::CUSTOM
|
671
|
+
revenue_value = nil
|
672
|
+
end
|
673
|
+
|
674
|
+
if variation['goal_identifier']
|
675
|
+
identifiers = variation['goal_identifier'].split(VWO_DELIMITER)
|
676
|
+
else
|
677
|
+
variation['goal_identifier'] = ''
|
678
|
+
identifiers = []
|
679
|
+
end
|
680
|
+
|
681
|
+
if !identifiers.include? goal_identifier
|
682
|
+
updated_goal_identifier = variation['goal_identifier']
|
683
|
+
updated_goal_identifier += VWO_DELIMITER + goal_identifier
|
684
|
+
@variation_decider.save_user_storage(user_id, campaign['key'], variation['name'], updated_goal_identifier) if variation['name']
|
685
|
+
# set variation at user storage
|
686
|
+
elsif !should_track_returning_user
|
687
|
+
@logger.log(
|
688
|
+
LogLevelEnum::INFO,
|
689
|
+
format(
|
690
|
+
LogMessageEnum::InfoMessages::GOAL_ALREADY_TRACKED,
|
691
|
+
file: FILE,
|
692
|
+
user_id: user_id,
|
693
|
+
campaign_key: campaign['key'],
|
694
|
+
goal_identifier: goal_identifier,
|
695
|
+
api_name: ApiMethods::TRACK
|
696
|
+
)
|
697
|
+
)
|
698
|
+
result[campaign['key']] = false
|
699
|
+
next
|
700
|
+
end
|
701
|
+
|
702
|
+
if defined?(@batch_events)
|
703
|
+
impression = create_bulk_event_impression(
|
704
|
+
@settings_file,
|
705
|
+
campaign['id'],
|
706
|
+
variation['id'],
|
707
|
+
user_id,
|
708
|
+
goal['id'],
|
709
|
+
revenue_value
|
710
|
+
)
|
711
|
+
@batch_events_queue.enqueue(impression)
|
712
|
+
else
|
713
|
+
impression = create_impression(
|
714
|
+
@settings_file,
|
715
|
+
campaign['id'],
|
716
|
+
variation['id'],
|
717
|
+
user_id,
|
718
|
+
@sdk_key,
|
719
|
+
goal['id'],
|
720
|
+
revenue_value
|
721
|
+
)
|
722
|
+
if @event_dispatcher.dispatch(impression)
|
723
|
+
@logger.log(
|
724
|
+
LogLevelEnum::INFO,
|
725
|
+
format(
|
726
|
+
LogMessageEnum::InfoMessages::IMPRESSION_SUCCESS,
|
727
|
+
file: FILE,
|
728
|
+
sdk_key: @sdk_key,
|
729
|
+
account_id: @account_id,
|
730
|
+
campaign_id: campaign['id'],
|
731
|
+
variation_id: variation['id'],
|
732
|
+
end_point: EVENTS::TRACK_GOAL
|
733
|
+
)
|
734
|
+
)
|
735
|
+
@logger.log(
|
736
|
+
LogLevelEnum::INFO,
|
737
|
+
format(
|
738
|
+
LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_IMPRESSION,
|
739
|
+
file: FILE,
|
740
|
+
sdk_key: @sdk_key,
|
741
|
+
campaign_id: impression[:experiment_id],
|
742
|
+
account_id: impression[:account_id],
|
743
|
+
variation_id: impression[:combination]
|
744
|
+
)
|
745
|
+
)
|
746
|
+
end
|
747
|
+
end
|
748
|
+
result[campaign['key']] = true
|
749
|
+
next
|
750
|
+
end
|
751
|
+
result[campaign['key']] = false
|
752
|
+
rescue StandardError => e
|
500
753
|
@logger.log(
|
501
|
-
LogLevelEnum::
|
754
|
+
LogLevelEnum::ERROR,
|
502
755
|
format(
|
503
|
-
|
756
|
+
e.message,
|
504
757
|
file: FILE,
|
505
|
-
|
506
|
-
user_id: impression[:uId],
|
507
|
-
account_id: impression[:account_id],
|
508
|
-
variation_id: impression[:combination]
|
758
|
+
exception: e
|
509
759
|
)
|
510
760
|
)
|
511
|
-
return true
|
512
761
|
end
|
513
|
-
|
762
|
+
|
763
|
+
if result.length() == 0
|
764
|
+
return nil
|
765
|
+
end
|
766
|
+
|
767
|
+
result
|
514
768
|
rescue StandardError => e
|
515
769
|
@logger.log(
|
516
770
|
LogLevelEnum::ERROR,
|
@@ -538,13 +792,34 @@ class VWO
|
|
538
792
|
# @return[Boolean] true if user becomes part of feature test/rollout, otherwise false.
|
539
793
|
|
540
794
|
def feature_enabled?(campaign_key, user_id, options = {})
|
795
|
+
unless @is_instance_valid
|
796
|
+
@logger.log(
|
797
|
+
LogLevelEnum::ERROR,
|
798
|
+
format(
|
799
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
800
|
+
file: FILE,
|
801
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED
|
802
|
+
)
|
803
|
+
)
|
804
|
+
return false
|
805
|
+
end
|
806
|
+
|
541
807
|
# Retrieve custom variables
|
542
808
|
custom_variables = options['custom_variables'] || options[:custom_variables]
|
543
809
|
variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
|
544
|
-
|
810
|
+
should_track_returning_user = get_should_track_returning_user(options)
|
811
|
+
@logger.log(
|
812
|
+
LogLevelEnum::INFO,
|
813
|
+
format(
|
814
|
+
LogMessageEnum::InfoMessages::API_CALLED,
|
815
|
+
file: FILE,
|
816
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED,
|
817
|
+
user_id: user_id
|
818
|
+
)
|
819
|
+
)
|
545
820
|
# Validate input parameters
|
546
821
|
unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
|
547
|
-
|
822
|
+
(variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables)) && [true, false].include?(should_track_returning_user)
|
548
823
|
@logger.log(
|
549
824
|
LogLevelEnum::ERROR,
|
550
825
|
format(
|
@@ -555,17 +830,6 @@ class VWO
|
|
555
830
|
)
|
556
831
|
return false
|
557
832
|
end
|
558
|
-
unless @is_instance_valid
|
559
|
-
@logger.log(
|
560
|
-
LogLevelEnum::ERROR,
|
561
|
-
format(
|
562
|
-
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
563
|
-
file: FILE,
|
564
|
-
api_name: ApiMethods::IS_FEATURE_ENABLED
|
565
|
-
)
|
566
|
-
)
|
567
|
-
return false
|
568
|
-
end
|
569
833
|
|
570
834
|
# Get the campaign settings
|
571
835
|
campaign = get_campaign(@settings_file, campaign_key)
|
@@ -611,50 +875,77 @@ class VWO
|
|
611
875
|
|
612
876
|
# if campaign type is feature_test Send track call to server
|
613
877
|
if campaign_type == CampaignTypes::FEATURE_TEST
|
614
|
-
|
615
|
-
@
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
878
|
+
if is_eligible_to_send_impression(should_track_returning_user)
|
879
|
+
if defined?(@batch_events)
|
880
|
+
impression = create_bulk_event_impression(
|
881
|
+
@settings_file,
|
882
|
+
campaign['id'],
|
883
|
+
variation['id'],
|
884
|
+
user_id
|
885
|
+
)
|
886
|
+
@batch_events_queue.enqueue(impression)
|
887
|
+
else
|
888
|
+
impression = create_impression(
|
889
|
+
@settings_file,
|
890
|
+
campaign['id'],
|
891
|
+
variation['id'],
|
892
|
+
user_id,
|
893
|
+
@sdk_key,
|
894
|
+
goal_id: nil,
|
895
|
+
revenue: nil,
|
896
|
+
usage_stats: @usage_stats.usage_stats
|
897
|
+
)
|
620
898
|
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
)
|
633
|
-
result = variation['isFeatureEnabled']
|
634
|
-
if result
|
635
|
-
@logger.log(
|
636
|
-
LogLevelEnum::INFO,
|
637
|
-
format(
|
638
|
-
LogMessageEnum::InfoMessages::FEATURE_ENABLED_FOR_USER,
|
639
|
-
file: FILE,
|
640
|
-
user_id: user_id,
|
641
|
-
feature_key: campaign_key,
|
642
|
-
api_name: ApiMethods::IS_FEATURE_ENABLED
|
899
|
+
@event_dispatcher.dispatch(impression)
|
900
|
+
@logger.log(
|
901
|
+
LogLevelEnum::INFO,
|
902
|
+
format(
|
903
|
+
LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_IMPRESSION,
|
904
|
+
file: FILE,
|
905
|
+
campaign_id: impression[:experiment_id],
|
906
|
+
sdk_key: @sdk_key,
|
907
|
+
account_id: impression[:account_id],
|
908
|
+
variation_id: impression[:combination]
|
909
|
+
)
|
643
910
|
)
|
644
|
-
|
911
|
+
end
|
912
|
+
result = variation['isFeatureEnabled']
|
913
|
+
if result
|
914
|
+
@logger.log(
|
915
|
+
LogLevelEnum::INFO,
|
916
|
+
format(
|
917
|
+
LogMessageEnum::InfoMessages::FEATURE_ENABLED_FOR_USER,
|
918
|
+
file: FILE,
|
919
|
+
user_id: user_id,
|
920
|
+
feature_key: campaign_key,
|
921
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED
|
922
|
+
)
|
923
|
+
)
|
924
|
+
else
|
925
|
+
@logger.log(
|
926
|
+
LogLevelEnum::INFO,
|
927
|
+
format(
|
928
|
+
LogMessageEnum::InfoMessages::FEATURE_NOT_ENABLED_FOR_USER,
|
929
|
+
file: FILE,
|
930
|
+
user_id: user_id,
|
931
|
+
feature_key: campaign_key,
|
932
|
+
api_name: ApiMethods::IS_FEATURE_ENABLED
|
933
|
+
)
|
934
|
+
)
|
935
|
+
end
|
936
|
+
return result
|
645
937
|
else
|
646
938
|
@logger.log(
|
647
939
|
LogLevelEnum::INFO,
|
648
940
|
format(
|
649
|
-
LogMessageEnum::InfoMessages::
|
941
|
+
LogMessageEnum::InfoMessages::USER_ALREADY_TRACKED,
|
650
942
|
file: FILE,
|
651
943
|
user_id: user_id,
|
652
|
-
|
944
|
+
campaign_key: campaign_key,
|
653
945
|
api_name: ApiMethods::IS_FEATURE_ENABLED
|
654
946
|
)
|
655
947
|
)
|
656
948
|
end
|
657
|
-
return result
|
658
949
|
end
|
659
950
|
true
|
660
951
|
rescue StandardError => e
|
@@ -690,30 +981,30 @@ class VWO
|
|
690
981
|
#
|
691
982
|
|
692
983
|
def get_feature_variable_value(campaign_key, variable_key, user_id, options = {})
|
693
|
-
|
694
|
-
custom_variables = options['custom_variables'] || options[:custom_variables]
|
695
|
-
variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
|
696
|
-
|
697
|
-
unless valid_string?(campaign_key) && valid_string?(variable_key) && valid_string?(user_id) &&
|
698
|
-
(custom_variables.nil? || valid_hash?(custom_variables)) && (variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
|
984
|
+
unless @is_instance_valid
|
699
985
|
@logger.log(
|
700
986
|
LogLevelEnum::ERROR,
|
701
987
|
format(
|
702
|
-
LogMessageEnum::ErrorMessages::
|
988
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
703
989
|
file: FILE,
|
704
|
-
api_name: ApiMethods
|
990
|
+
api_name: ApiMethods.GET_FEATURE_VARIABLE_VALUE
|
705
991
|
)
|
706
992
|
)
|
707
993
|
return
|
708
994
|
end
|
709
995
|
|
710
|
-
|
996
|
+
# Retrieve custom variables
|
997
|
+
custom_variables = options['custom_variables'] || options[:custom_variables]
|
998
|
+
variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
|
999
|
+
|
1000
|
+
unless valid_string?(campaign_key) && valid_string?(variable_key) && valid_string?(user_id) &&
|
1001
|
+
(custom_variables.nil? || valid_hash?(custom_variables)) && (variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
|
711
1002
|
@logger.log(
|
712
1003
|
LogLevelEnum::ERROR,
|
713
1004
|
format(
|
714
|
-
LogMessageEnum::ErrorMessages::
|
1005
|
+
LogMessageEnum::ErrorMessages::GET_FEATURE_VARIABLE_VALUE_API_INVALID_PARAMS,
|
715
1006
|
file: FILE,
|
716
|
-
api_name: ApiMethods
|
1007
|
+
api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
|
717
1008
|
)
|
718
1009
|
)
|
719
1010
|
return
|
@@ -843,6 +1134,18 @@ class VWO
|
|
843
1134
|
# @return true if call is made successfully, else false
|
844
1135
|
|
845
1136
|
def push(tag_key, tag_value, user_id)
|
1137
|
+
unless @is_instance_valid
|
1138
|
+
@logger.log(
|
1139
|
+
LogLevelEnum::ERROR,
|
1140
|
+
format(
|
1141
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
1142
|
+
file: FILE,
|
1143
|
+
api_name: ApiMethods.PUSH
|
1144
|
+
)
|
1145
|
+
)
|
1146
|
+
return
|
1147
|
+
end
|
1148
|
+
|
846
1149
|
unless valid_string?(tag_key) && valid_string?(tag_value) && valid_string?(user_id)
|
847
1150
|
@logger.log(
|
848
1151
|
LogLevelEnum::ERROR,
|
@@ -883,32 +1186,105 @@ class VWO
|
|
883
1186
|
return false
|
884
1187
|
end
|
885
1188
|
|
886
|
-
|
887
|
-
|
888
|
-
|
1189
|
+
if defined?(@batch_events)
|
1190
|
+
impression = get_batch_event_url_params(@settings_file, tag_key, tag_value, user_id)
|
1191
|
+
@batch_events_queue.enqueue(impression)
|
1192
|
+
else
|
1193
|
+
impression = get_url_params(@settings_file, tag_key, tag_value, user_id, @sdk_key)
|
1194
|
+
@event_dispatcher.dispatch(impression)
|
889
1195
|
|
1196
|
+
@logger.log(
|
1197
|
+
LogLevelEnum::INFO,
|
1198
|
+
format(
|
1199
|
+
LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_PUSH_API,
|
1200
|
+
file: FILE,
|
1201
|
+
sdk_key: @sdk_key,
|
1202
|
+
u: impression['u'],
|
1203
|
+
account_id: impression['account_id'],
|
1204
|
+
tags: impression['tags']
|
1205
|
+
)
|
1206
|
+
)
|
1207
|
+
end
|
1208
|
+
true
|
1209
|
+
rescue StandardError => e
|
890
1210
|
@logger.log(
|
891
|
-
LogLevelEnum::
|
1211
|
+
LogLevelEnum::ERROR,
|
892
1212
|
format(
|
893
|
-
LogMessageEnum::
|
1213
|
+
LogMessageEnum::ErrorMessages::API_NOT_WORKING,
|
894
1214
|
file: FILE,
|
895
|
-
|
896
|
-
|
897
|
-
account_id: impression['account_id'],
|
898
|
-
tags: impression['tags']
|
1215
|
+
api_name: ApiMethods::PUSH,
|
1216
|
+
exception: e
|
899
1217
|
)
|
900
1218
|
)
|
901
|
-
|
1219
|
+
false
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
def get_should_track_returning_user(options)
|
1223
|
+
if !options.key?(:should_track_returning_user)
|
1224
|
+
options[:should_track_returning_user] = @should_track_returning_user
|
1225
|
+
elsif ![true, false].include?(options[:should_track_returning_user])
|
1226
|
+
@logger.log(
|
1227
|
+
LogLevelEnum::ERROR,
|
1228
|
+
format(
|
1229
|
+
LogMessageEnum::ErrorMessages::INVALID_TRACK_RETURNING_USER_VALUE,
|
1230
|
+
file: FILE
|
1231
|
+
)
|
1232
|
+
)
|
1233
|
+
end
|
1234
|
+
options[:should_track_returning_user]
|
1235
|
+
end
|
1236
|
+
|
1237
|
+
def is_eligible_to_send_impression(should_track_returning_user = false)
|
1238
|
+
!@user_storage || !@variation_decider.has_stored_variation || should_track_returning_user
|
1239
|
+
end
|
1240
|
+
|
1241
|
+
def flush_events
|
1242
|
+
unless @is_instance_valid
|
1243
|
+
@logger.log(
|
1244
|
+
LogLevelEnum::ERROR,
|
1245
|
+
format(
|
1246
|
+
LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
|
1247
|
+
file: FILE,
|
1248
|
+
api_name: ApiMethods::FLUSH_EVENTS
|
1249
|
+
)
|
1250
|
+
)
|
1251
|
+
return
|
1252
|
+
end
|
1253
|
+
result = @batch_events_queue.flush(manual: true)
|
1254
|
+
@batch_events_queue.kill_thread
|
1255
|
+
result
|
902
1256
|
rescue StandardError => e
|
903
1257
|
@logger.log(
|
904
1258
|
LogLevelEnum::ERROR,
|
905
1259
|
format(
|
906
1260
|
LogMessageEnum::ErrorMessages::API_NOT_WORKING,
|
907
1261
|
file: FILE,
|
908
|
-
api_name: ApiMethods::
|
1262
|
+
api_name: ApiMethods::FLUSH_EVENTS,
|
909
1263
|
exception: e
|
910
1264
|
)
|
911
1265
|
)
|
912
1266
|
false
|
913
1267
|
end
|
1268
|
+
|
1269
|
+
def get_goal_type_to_track(options)
|
1270
|
+
goal_type_to_track = nil
|
1271
|
+
if !options.key?(:goal_type_to_track)
|
1272
|
+
if @goal_type_to_track
|
1273
|
+
goal_type_to_track = @goal_type_to_track
|
1274
|
+
else
|
1275
|
+
goal_type_to_track = GOAL_TYPES['ALL']
|
1276
|
+
end
|
1277
|
+
elsif GOAL_TYPES.key? options[:goal_type_to_track]
|
1278
|
+
goal_type_to_track = options[:goal_type_to_track]
|
1279
|
+
else
|
1280
|
+
@logger.log(
|
1281
|
+
LogLevelEnum::ERROR,
|
1282
|
+
format(
|
1283
|
+
LogMessageEnum::ErrorMessages::INVALID_GOAL_TYPE,
|
1284
|
+
file: FILE
|
1285
|
+
)
|
1286
|
+
)
|
1287
|
+
end
|
1288
|
+
goal_type_to_track
|
1289
|
+
end
|
914
1290
|
end
|