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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88beb4ef415731a07ac86d4d3ce19b9e3ea077d79d00e3e35e84f2b669c802eb
4
- data.tar.gz: 2748de038b879ca5c27e237455bcbd6a62178101eae5c9fe1b2c87f64d5b25d7
3
+ metadata.gz: 53bc0be49f50d280aac4478d6879a31dce269ed69596e5ff2d04b51cbcacbcbd
4
+ data.tar.gz: f28c84dc2ace873bf1c5fd748568d06c16583b466240df54fcf9dbd5dffec888
5
5
  SHA512:
6
- metadata.gz: 38889e01c758f1336042deda0c39e2a678860eff7431bb465885bf72e9032f2277f0ef52ed5837593fd49b9b76ca1d74a673eb7774ee970422f9588b3698e0c6
7
- data.tar.gz: 481f64eb7ff87622f12ff3122dcb57618d56add48ebe99524a8557930dd4e2bea85ee7c875024a45134d4948be47fa5da54e8c6e64463dae4f11d732fd00e2dd
6
+ metadata.gz: 63bf38a8c25c69e01cf7cbfdad204379c0dd03621e947c1848a1fdf24b432bd26672a8d3cb9efded0e45582208a73a0c69142911c900e53e477e06b2d06a069e
7
+ data.tar.gz: 0b9d9165ca2ae918a048537097f2de775fe13d35547c341aa45c7edc42206273775f18120c10ca06fc02821c24652bd25e513a05989889664285210b6fd57f02
data/lib/vwo.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2019-2020 Wingify Software Pvt. Ltd.
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
- @settings ||=
122
- settings_file || VWO::Services::SettingsFileManager.new(@account_id, @sdk_key).get_settings_file
123
- @settings
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] :options Options for custom variables required for segmentation
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
- (variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
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
- # Variation found, dispatch it to server
238
- impression = create_impression(
239
- @settings_file,
240
- campaign['id'],
241
- variation['id'],
242
- user_id
243
- )
244
- @event_dispatcher.dispatch(impression)
245
- variation['name']
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
- (variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
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
- # Get the campaign settings
423
- campaign = get_campaign(@settings_file, campaign_key)
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
- # Validate campaign
426
- if campaign.nil? || (campaign['status'] != STATUS_RUNNING)
427
- # log error
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::CAMPAIGN_NOT_RUNNING,
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
- campaign_type = campaign['type']
610
+ # Get campaigns settings
611
+ campaigns = get_campaigns(@settings_file, campaign_key, goal_identifier, goal_type_to_track)
441
612
 
442
- if campaign_type == CampaignTypes::FEATURE_ROLLOUT
443
- @logger.log(
444
- LogLevelEnum::ERROR,
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
- variation = @variation_decider.get_variation(user_id, campaign, ApiMethods::TRACK, campaign_key, custom_variables, variation_targeting_variables)
618
+ result = {}
619
+ campaigns.each do |campaign|
620
+ campaign_type = campaign['type']
458
621
 
459
- if variation
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::TRACK_API_GOAL_NOT_FOUND,
626
+ LogMessageEnum::ErrorMessages::INVALID_API,
466
627
  file: FILE,
467
- goal_identifier: goal_identifier,
628
+ api_name: ApiMethods::TRACK,
468
629
  user_id: user_id,
469
- campaign_key: campaign_key,
470
- api_name: ApiMethods::TRACK
630
+ campaign_key: campaign['key'],
631
+ campaign_type: campaign_type
471
632
  )
472
633
  )
473
- return false
474
- elsif goal['type'] == GoalTypes::REVENUE && !valid_value?(revenue_value)
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::INFO,
754
+ LogLevelEnum::ERROR,
502
755
  format(
503
- LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_IMPRESSION,
756
+ e.message,
504
757
  file: FILE,
505
- campaign_id: impression[:experiment_id],
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
- false
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
- (variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
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
- impression = create_impression(
615
- @settings_file,
616
- campaign['id'],
617
- variation['id'],
618
- user_id
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
- @event_dispatcher.dispatch(impression)
622
- @logger.log(
623
- LogLevelEnum::INFO,
624
- format(
625
- LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_IMPRESSION,
626
- file: FILE,
627
- campaign_id: impression[:experiment_id],
628
- user_id: impression[:uId],
629
- account_id: impression[:account_id],
630
- variation_id: impression[:combination]
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::FEATURE_NOT_ENABLED_FOR_USER,
941
+ LogMessageEnum::InfoMessages::USER_ALREADY_TRACKED,
650
942
  file: FILE,
651
943
  user_id: user_id,
652
- feature_key: campaign_key,
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
- # Retrieve custom variables
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::GET_FEATURE_VARIABLE_VALUE_API_INVALID_PARAMS,
988
+ LogMessageEnum::ErrorMessages::API_CONFIG_CORRUPTED,
703
989
  file: FILE,
704
- api_name: ApiMethods::GET_FEATURE_VARIABLE_VALUE
990
+ api_name: ApiMethods.GET_FEATURE_VARIABLE_VALUE
705
991
  )
706
992
  )
707
993
  return
708
994
  end
709
995
 
710
- unless @is_instance_valid
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::API_CONFIG_CORRUPTED,
1005
+ LogMessageEnum::ErrorMessages::GET_FEATURE_VARIABLE_VALUE_API_INVALID_PARAMS,
715
1006
  file: FILE,
716
- api_name: ApiMethods.GET_FEATURE_VARIABLE_VALUE
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
- impression = get_url_params(@settings_file, tag_key, tag_value, user_id)
887
-
888
- @event_dispatcher.dispatch(impression)
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::INFO,
1211
+ LogLevelEnum::ERROR,
892
1212
  format(
893
- LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_PUSH_API,
1213
+ LogMessageEnum::ErrorMessages::API_NOT_WORKING,
894
1214
  file: FILE,
895
- u: impression['u'],
896
- user_id: impression['uId'],
897
- account_id: impression['account_id'],
898
- tags: impression['tags']
1215
+ api_name: ApiMethods::PUSH,
1216
+ exception: e
899
1217
  )
900
1218
  )
901
- true
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::PUSH,
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