kameleoon-client-ruby 3.4.0 → 3.5.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: 2fb2eefaf6fa7008e5e475044e2f3c20baa088332657f0e19e17c73abffdfa3b
4
- data.tar.gz: ef078e7a9d1ac4fd2fef3a74edf4ee5328043b6989c59eafc29559f79ab535d4
3
+ metadata.gz: 283250365ae9bf4087ebffeb7a4de0e31cca91f06a865cdd4ad2cae1f88c692c
4
+ data.tar.gz: 31ab8ddbd1ef7524b41019a0afe442a47ee5b5e9e1d50649ed04aab625d7c3a3
5
5
  SHA512:
6
- metadata.gz: 8df54dcee89dc21a3565948e96b330b655d780ca7cbd4955385b12c5ad64ccdbc8318b17043acb02eddcd2d8dd45191eaeb001d6957e250573e8b9cc606ffbf0
7
- data.tar.gz: 3fe4dfe732310de088f45dcc2002c2504b03e45e2e101bb7199b46783cac46aed80a7e35fc0cc6995ddcb7ba0202629d367922e58d8a8e90b974679f91363086
6
+ metadata.gz: 23f61dd193ad1bb7477ee44e0e2eb5c16bec625748b9ebdde37a9a6b9e71a4610a98c218a4e76addb66a5a55ecf2bcae1764f2aac8d9f9f8ebb6bbc3be86e318
7
+ data.tar.gz: d27d91e39fb5bc968ba414016642de07baef8ef7888f1d93969ae5fb67f07b903ba60b981de9387fa5c6eb20e99bd647d965fea0123841348f67a8aa66840f99
@@ -9,7 +9,7 @@ module Kameleoon
9
9
  module Configuration
10
10
  class DataFile
11
11
  attr_reader :settings, :feature_flags, :has_any_targeted_delivery_rule, :feature_flag_by_id, :rule_by_segment_id,
12
- :variation_by_id, :custom_data_info
12
+ :variation_by_id, :custom_data_info, :experiment_ids_with_js_css_variable
13
13
 
14
14
  def to_s
15
15
  'DataFile{' \
@@ -39,6 +39,10 @@ module Kameleoon
39
39
  ff
40
40
  end
41
41
 
42
+ def experiment_js_css_variable?(experiment_id)
43
+ @experiment_ids_with_js_css_variable.include?(experiment_id)
44
+ end
45
+
42
46
  private
43
47
 
44
48
  def init_default
@@ -71,21 +75,31 @@ module Kameleoon
71
75
  @feature_flag_by_id = {}
72
76
  @rule_by_segment_id = {}
73
77
  @variation_by_id = {}
78
+ @experiment_ids_with_js_css_variable = Set.new
74
79
 
75
80
  @feature_flags.each_value do |feature_flag|
76
81
  @feature_flag_by_id[feature_flag.id] = feature_flag
77
82
  next if feature_flag.rules.nil?
78
83
 
84
+ has_feature_flag_variable_js_css = feature_flag_variable_js_css?(feature_flag)
79
85
  feature_flag.rules.each do |rule|
80
86
  @rule_by_segment_id[rule.segment_id] = rule
81
87
  rule.variation_by_exposition.each do |variation|
82
88
  @variation_by_id[variation.variation_id] = variation
83
89
  end
90
+ @experiment_ids_with_js_css_variable.add(rule.experiment_id) if has_feature_flag_variable_js_css
84
91
  end
85
92
  end
86
93
  @feature_flag_by_id.freeze
87
94
  @rule_by_segment_id.freeze
88
95
  @variation_by_id.freeze
96
+ @experiment_ids_with_js_css_variable.freeze
97
+ end
98
+
99
+ def feature_flag_variable_js_css?(feature_flag)
100
+ feature_flag.variations.first&.variables&.any? do |variable|
101
+ %w[JS CSS].include?(variable.type)
102
+ end
89
103
  end
90
104
  end
91
105
  end
@@ -33,7 +33,7 @@ module Kameleoon
33
33
  @rules = Rule.create_from_array(hash['rules'])
34
34
  end
35
35
 
36
- def get_variation_key(key)
36
+ def get_variation_by_key(key)
37
37
  variations.select { |v| v.key == key }.first
38
38
  end
39
39
  end
@@ -18,7 +18,9 @@ module Kameleoon
18
18
  "assignment_time:#{@assignment_time},rule_type:#{@rule_type}}"
19
19
  end
20
20
 
21
- def initialize(experiment_id, variation_id, rule_type = Kameleoon::Configuration::RuleType::UNKNOWN, assignment_time: nil)
21
+ def initialize(
22
+ experiment_id, variation_id, rule_type = Kameleoon::Configuration::RuleType::UNKNOWN, assignment_time: nil
23
+ )
22
24
  super(DataType::ASSIGNED_VARIATION)
23
25
  @experiment_id = experiment_id
24
26
  @variation_id = variation_id
@@ -5,8 +5,8 @@ require 'kameleoon/logging/kameleoon_logger'
5
5
  module Kameleoon
6
6
  module Hybrid
7
7
  TC_INIT = 'window.kameleoonQueue=window.kameleoonQueue||[];'
8
- TC_ASSIGN_VARIATION_FORMAT = "window.kameleoonQueue.push(['Experiments.assignVariation',%d,%d]);"
9
- TC_TRIGGER_FORMAT = "window.kameleoonQueue.push(['Experiments.trigger',%d,true]);"
8
+ TC_ASSIGN_VARIATION_FORMAT = "window.kameleoonQueue.push(['Experiments.assignVariation',%d,%d,true]);"
9
+ TC_TRIGGER_FORMAT = "window.kameleoonQueue.push(['Experiments.trigger',%d,%s]);"
10
10
  TC_ASSIGN_VARIATION_TRIGGER_FORMAT = TC_ASSIGN_VARIATION_FORMAT + TC_TRIGGER_FORMAT
11
11
 
12
12
  # Will be useful for Ruby 3.0
@@ -19,10 +19,11 @@ module Kameleoon
19
19
 
20
20
  # Implementation of Cache with auto cleaning feature
21
21
  class ManagerImpl < Manager
22
- def initialize(expiration_time)
22
+ def initialize(expiration_time, data_manager)
23
23
  super()
24
24
  Logging::KameleoonLogger.debug('CALL: HybridManager.new(expiration_time: %s)', expiration_time)
25
25
  @expiration_time = expiration_time
26
+ @data_manager = data_manager
26
27
  Logging::KameleoonLogger.debug('RETURN: HybridManager.new(expiration_time: %s)', expiration_time)
27
28
  end
28
29
 
@@ -34,7 +35,9 @@ module Kameleoon
34
35
  expired_time = (Time.now - @expiration_time).to_i
35
36
  visitor_variations.enumerate do |v|
36
37
  if v.assignment_time > expired_time
37
- v_code = format(TC_ASSIGN_VARIATION_TRIGGER_FORMAT, v.experiment_id, v.variation_id, v.experiment_id)
38
+ tracking_only = !@data_manager.data_file.experiment_js_css_variable?(v.experiment_id)
39
+ v_code = format(TC_ASSIGN_VARIATION_TRIGGER_FORMAT, v.experiment_id, v.variation_id, v.experiment_id,
40
+ tracking_only)
38
41
  tracking_code.push(v_code)
39
42
  end
40
43
  end
@@ -24,6 +24,8 @@ require 'kameleoon/real_time/real_time_configuration_service'
24
24
  require 'kameleoon/storage/cache_factory'
25
25
  require 'kameleoon/targeting/models'
26
26
  require 'kameleoon/targeting/targeting_manager'
27
+ require 'kameleoon/types/variable'
28
+ require 'kameleoon/types/variation'
27
29
  require 'rufus/scheduler'
28
30
  require 'yaml'
29
31
  require 'json'
@@ -59,7 +61,7 @@ module Kameleoon
59
61
  @visitor_manager = Kameleoon::DataManager::VisitorManager.new(
60
62
  @data_manager, config.session_duration_second, @scheduler
61
63
  )
62
- @hybrid_manager = Hybrid::ManagerImpl.new(HYBRID_EXPIRATION_TIME)
64
+ @hybrid_manager = Hybrid::ManagerImpl.new(HYBRID_EXPIRATION_TIME, @data_manager)
63
65
  @network_manager = Network::NetworkManager.new(
64
66
  config.environment,
65
67
  config.default_timeout_millisecond,
@@ -263,22 +265,31 @@ module Kameleoon
263
265
  # @param [String] feature_key Key of the feature flag you want to expose to a user. This field is mandatory.
264
266
  # @param [Bool] is_unique_identifier(DEPRECATED) Parameter that specifies whether the visitorCode is a unique
265
267
  # identifier. This field is optional.
268
+ # @param [Bool] track Optional flag indicating whether tracking of the feature evaluation is enabled
269
+ # (`true`) or disabled (`false`); the default value is `true`.
270
+ #
271
+ # @return [Bool] If the user has not been associated with your feature flag before, the SDK returns
272
+ # a random boolean value (`true` if the user should have this feature or `false` if not).
266
273
  #
267
274
  # @raise [Kameleoon::Exception::FeatureNotFound] Feature Flag isn't found in this configuration
268
275
  # @raise [Kameleoon::Exception::VisitorCodeInvalid] If the visitor code is empty or longer than 255 chars
269
276
  #
270
- def feature_active?(visitor_code, feature_key, is_unique_identifier: nil)
277
+ def feature_active?(visitor_code, feature_key, is_unique_identifier: nil, track: true)
271
278
  Logging::KameleoonLogger.info(
272
- "CALL: KameleoonClient.feature_active?(visitor_code: '%s', feature_key: '%s', is_unique_identifier: %s)",
273
- visitor_code, feature_key, is_unique_identifier
279
+ "CALL: KameleoonClient.feature_active?(visitor_code: '%s', feature_key: '%s', " \
280
+ 'is_unique_identifier: %s, track: %s)',
281
+ visitor_code, feature_key, is_unique_identifier, track
274
282
  )
275
283
  Utils::VisitorCode.validate(visitor_code)
276
284
  set_unique_identifier(visitor_code, is_unique_identifier) unless is_unique_identifier.nil?
277
- _, variation_key = _get_feature_variation_key(visitor_code, feature_key)
285
+ feature_flag = @data_manager.data_file.get_feature_flag(feature_key)
286
+ variation_key, = get_variation_info(visitor_code, feature_flag, track)
278
287
  feature_active = variation_key != Kameleoon::Configuration::VariationType::VARIATION_OFF
288
+ @tracking_manager.add_visitor_code(visitor_code) if track
279
289
  Logging::KameleoonLogger.info(
280
- "RETURN: KameleoonClient.feature_active?(visitor_code: '%s', feature_key: '%s', is_unique_identifier: %s) " \
281
- '-> (feature_active: false)', visitor_code, feature_key, is_unique_identifier
290
+ "RETURN: KameleoonClient.feature_active?(visitor_code: '%s', feature_key: '%s', " \
291
+ 'is_unique_identifier: %s, track: %s) -> (feature_active: %s)',
292
+ visitor_code, feature_key, is_unique_identifier, track, feature_active
282
293
  )
283
294
  feature_active
284
295
  rescue Exception::FeatureEnvironmentDisabled
@@ -286,6 +297,82 @@ module Kameleoon
286
297
  false
287
298
  end
288
299
 
300
+ ##
301
+ # Retrieves the variation assigned to the given visitor for a specific feature flag.
302
+ #
303
+ # @param [String] visitor_code The unique identifier of the visitor.
304
+ # @param [String] feature_key The unique identifier of the feature flag.
305
+ # @param [Bool] track Optional flag indicating whether tracking of the feature evaluation is enabled
306
+ # (`true`) or disabled (`false`); the default value is `true`.
307
+ #
308
+ # @return [Kameleoon::Types::Variation] The variation assigned to the visitor if the visitor is associated with some
309
+ # rule of the feature flag, otherwise the method returns the default variation of the feature flag.
310
+ #
311
+ # @raise [Kameleoon::Exception::VisitorCodeInvalid] If the visitor code is empty or longer than 255 chars.
312
+ # @raise [Kameleoon::Exception::FeatureNotFound] Feature Flag isn't found in this configuration.
313
+ # @raise [Kameleoon::Exception::FeatureEnvironmentDisabled] If the requested feature flag is disabled for
314
+ # the current environment.
315
+ def get_variation(visitor_code, feature_key, track: true)
316
+ Logging::KameleoonLogger.info(
317
+ "CALL: KameleoonClient.get_variation(visitor_code: '%s', feature_key: '%s', track: %s)",
318
+ visitor_code, feature_key, track
319
+ )
320
+ Utils::VisitorCode.validate(visitor_code)
321
+ feature_flag = @data_manager.data_file.get_feature_flag(feature_key)
322
+ variation_key, var_by_exp, rule = get_variation_info(visitor_code, feature_flag, track)
323
+ variation = feature_flag.get_variation_by_key(variation_key)
324
+ external_variation = make_external_variation(variation, var_by_exp&.variation_id, rule&.experiment_id)
325
+ @tracking_manager.add_visitor_code(visitor_code) if track
326
+ Logging::KameleoonLogger.info(
327
+ "RETURN: KameleoonClient.get_variation(visitor_code: '%s', feature_key: '%s', track: %s)" \
328
+ ' -> (variation: %s)',
329
+ visitor_code, feature_key, track, external_variation
330
+ )
331
+ external_variation
332
+ end
333
+
334
+ ##
335
+ # Forms a dictionary of variations assigned to a given visitor across all feature flags.
336
+ # This method iterates over all available feature flags and returns the assigned variation for each flag
337
+ # associated with the specified visitor.
338
+ #
339
+ # @param [String] visitor_code The unique identifier of the visitor.
340
+ # @param [Bool] only_active Optional flag indicating whether to return only variations for active feature
341
+ # flags (`true`) or for any feature flags (`false`); the default value is `false`.
342
+ # @param [Bool] track Optional flag indicating whether tracking of the feature evaluation is enabled
343
+ # (`true`) or disabled (`false`); the default value is `true`.
344
+ #
345
+ # @return [Hash] A hash consisting of feature flag keys as keys (`String`) and their corresponding
346
+ # variations (or the default variation of that feature flag) as values (`Kameleoon::Types::Variation`).
347
+ #
348
+ # @raise [Kameleoon::Exception::VisitorCodeInvalid] If the visitor code is empty or longer than 255 chars.
349
+ def get_variations(visitor_code, only_active: false, track: true)
350
+ Logging::KameleoonLogger.info(
351
+ "CALL: KameleoonClient.get_variations(visitor_code: '%s', only_active: %s, track: %s)",
352
+ visitor_code, only_active, track
353
+ )
354
+ Utils::VisitorCode.validate(visitor_code)
355
+ variations = {}
356
+ @data_manager.data_file.feature_flags.each_value do |feature_flag|
357
+ next unless feature_flag.environment_enabled
358
+
359
+ variation_key, var_by_exp, rule = get_variation_info(visitor_code, feature_flag, track)
360
+ next if only_active && (variation_key == Configuration::VariationType::VARIATION_OFF)
361
+
362
+ variation = feature_flag.get_variation_by_key(variation_key)
363
+ variations[feature_flag.feature_key] =
364
+ make_external_variation(variation, var_by_exp&.variation_id, rule&.experiment_id)
365
+ end
366
+ variations.freeze
367
+ @tracking_manager.add_visitor_code(visitor_code) if track
368
+ Logging::KameleoonLogger.info(
369
+ "RETURN: KameleoonClient.get_variations(visitor_code: '%s', only_active: %s, track: %s)" \
370
+ ' -> (variations: %s)',
371
+ visitor_code, only_active, track, variations
372
+ )
373
+ variations
374
+ end
375
+
289
376
  ##
290
377
  # get_feature_variation_key returns a variation key for visitor code
291
378
  #
@@ -305,7 +392,12 @@ module Kameleoon
305
392
  # @raise [Kameleoon::Exception::FeatureEnvironmentDisabled] If the requested feature flag is disabled for
306
393
  # the current environment
307
394
  #
395
+ # DEPRECATED. Please use `get_variation(visitor_code, feature_key, track: true)` instead.
308
396
  def get_feature_variation_key(visitor_code, feature_key, is_unique_identifier: nil)
397
+ Logging::KameleoonLogger.info(
398
+ '[DEPRECATION] `get_feature_variation_key` is deprecated. ' \
399
+ 'Please use `get_variation(visitor_code, feature_key, track: true)` instead.'
400
+ )
309
401
  Logging::KameleoonLogger.info(
310
402
  "CALL: KameleoonClient.get_feature_variation_key(visitor_code: '%s', feature_key: '%s', " \
311
403
  'is_unique_identifier: %s)',
@@ -339,7 +431,12 @@ module Kameleoon
339
431
  # @raise [Kameleoon::Exception::FeatureEnvironmentDisabled] If the requested feature flag is disabled for
340
432
  # the current environment
341
433
  #
434
+ # DEPRECATED. Please use `get_variation(visitor_code, feature_key, track: true)` instead.
342
435
  def get_feature_variable(visitor_code, feature_key, variable_name, is_unique_identifier: nil)
436
+ Logging::KameleoonLogger.info(
437
+ '[DEPRECATION] `get_feature_variable` is deprecated. ' \
438
+ 'Please use `get_variation(visitor_code, feature_key, track: true)` instead.'
439
+ )
343
440
  Logging::KameleoonLogger.info(
344
441
  "CALL: KameleoonClient.get_feature_variable(visitor_code: '%s', feature_key: '%s', variable_name: '%s', " \
345
442
  'is_unique_identifier: %s)', visitor_code, feature_key, variable_name, is_unique_identifier
@@ -347,7 +444,7 @@ module Kameleoon
347
444
  Utils::VisitorCode.validate(visitor_code)
348
445
  set_unique_identifier(visitor_code, is_unique_identifier) unless is_unique_identifier.nil?
349
446
  feature_flag, variation_key = _get_feature_variation_key(visitor_code, feature_key)
350
- variation = feature_flag.get_variation_key(variation_key)
447
+ variation = feature_flag.get_variation_by_key(variation_key)
351
448
  variable = variation&.get_variable_by_key(variable_name)
352
449
  if variable.nil?
353
450
  raise Exception::FeatureVariableNotFound.new(variable_name),
@@ -376,13 +473,18 @@ module Kameleoon
376
473
  # @raise [Kameleoon::Exception::FeatureVariationNotFound]
377
474
  # @raise [Kameleoon::Exception::FeatureEnvironmentDisabled]
378
475
  #
476
+ # DEPRECATED. Please use `get_variation(visitor_code, feature_key, track: false)` instead.
379
477
  def get_feature_variation_variables(feature_key, variation_key)
478
+ Logging::KameleoonLogger.info(
479
+ '[DEPRECATION] `get_feature_variation_variables` is deprecated. ' \
480
+ 'Please use `get_variation(visitor_code, feature_key, track: false)` instead.'
481
+ )
380
482
  Logging::KameleoonLogger.info(
381
483
  "CALL: KameleoonClient.get_feature_variation_variables(feature_key: '%s', variation_key: '%s')",
382
484
  feature_key, variation_key
383
485
  )
384
486
  feature_flag = @data_manager.data_file.get_feature_flag(feature_key)
385
- variation = feature_flag.get_variation_key(variation_key)
487
+ variation = feature_flag.get_variation_by_key(variation_key)
386
488
  if variation.nil?
387
489
  raise Exception::FeatureVariationNotFound.new(variation_key),
388
490
  "Variation key #{variation_key} not found"
@@ -508,7 +610,7 @@ module Kameleoon
508
610
  #
509
611
  # DEPRECATED. Please use `get_active_features` instead.
510
612
  def get_active_feature_list_for_visitor(visitor_code)
511
- Logging::KameleoonLogger.warning('[DEPRECATION] `get_active_feature_list_for_visitor` is deprecated.' \
613
+ Logging::KameleoonLogger.info('[DEPRECATION] `get_active_feature_list_for_visitor` is deprecated.' \
512
614
  ' Please use `get_active_features` instead.')
513
615
  Logging::KameleoonLogger.info("CALL: KameleoonClient.get_active_feature_list_for_visitor(visitor_code: '%s')",
514
616
  visitor_code)
@@ -537,7 +639,13 @@ module Kameleoon
537
639
  # @raise [Kameleoon::Exception::VisitorCodeInvalid] If the visitor code is empty or longer than 255 chars or is nil
538
640
  #
539
641
  # @return [Hash] Hash of active features for a visitor
642
+ #
643
+ # DEPRECATED. Please use `get_variations(visitor_code, only_active: true, track: false)` instead.
540
644
  def get_active_features(visitor_code)
645
+ Logging::KameleoonLogger.info(
646
+ '[DEPRECATION] `get_active_features` is deprecated. ' \
647
+ 'Please use `get_variations(visitor_code, only_active: true, track: false)` instead.'
648
+ )
541
649
  Logging::KameleoonLogger.info("CALL: KameleoonClient.get_active_features(visitor_code: '%s')", visitor_code)
542
650
  Utils::VisitorCode.validate(visitor_code)
543
651
  map_active_features = {}
@@ -550,24 +658,9 @@ module Kameleoon
550
658
 
551
659
  next if variation_key == Configuration::VariationType::VARIATION_OFF
552
660
 
553
- variation = feature_flag.get_variation_key(variation_key)
554
- variables = {}
555
-
556
- variation&.variables&.each do |variable|
557
- variables[variable.key] = Kameleoon::Types::Variable.new(
558
- variable.key,
559
- variable.type,
560
- _parse_feature_variable(variable)
561
- )
562
- end
563
-
564
- variables.freeze
565
- map_active_features[feature_flag.feature_key] = Kameleoon::Types::Variation.new(
566
- variation_key,
567
- var_by_exp ? var_by_exp.variation_id : nil,
568
- rule ? rule.experiment_id : nil,
569
- variables
570
- )
661
+ variation = feature_flag.get_variation_by_key(variation_key)
662
+ map_active_features[feature_flag.feature_key] =
663
+ make_external_variation(variation, var_by_exp&.variation_id, rule&.experiment_id)
571
664
  end
572
665
 
573
666
  map_active_features.freeze
@@ -754,6 +847,22 @@ module Kameleoon
754
847
  @targeting_manager.check_targeting(visitor_code, campaign_id, exp_ff_rule)
755
848
  end
756
849
 
850
+ def get_variation_info(visitor_code, feature_flag, track)
851
+ Logging::KameleoonLogger.debug(
852
+ "CALL: KameleoonClient.get_variation_info(visitor_code: '%s', feature_flag: %s, track: %s)",
853
+ visitor_code, feature_flag, track
854
+ )
855
+ var_by_exp, rule = _calculate_variation_key_for_feature(visitor_code, feature_flag)
856
+ variation_key = _get_variation_key(var_by_exp, rule, feature_flag)
857
+ save_variation(visitor_code, rule, var_by_exp, track: track)
858
+ Logging::KameleoonLogger.debug(
859
+ "RETURN: KameleoonClient.get_variation_info(visitor_code: '%s', feature_flag: %s, track: %s)" \
860
+ ' -> (variation_key: %s, variation_by_exposition: %s, rule: %s)',
861
+ visitor_code, feature_flag, track, variation_key, var_by_exp, rule
862
+ )
863
+ [variation_key, var_by_exp, rule]
864
+ end
865
+
757
866
  ##
758
867
  # helper method for getting variation key for feature flag
759
868
  def _get_feature_variation_key(visitor_code, feature_key)
@@ -764,16 +873,7 @@ module Kameleoon
764
873
  feature_flag = @data_manager.data_file.get_feature_flag(feature_key)
765
874
  variation, rule = _calculate_variation_key_for_feature(visitor_code, feature_flag)
766
875
  variation_key = _get_variation_key(variation, rule, feature_flag)
767
- visitor = nil
768
- unless rule.nil?
769
- experiment_id = rule.experiment_id
770
- variation_id = variation.variation_id unless variation.nil?
771
- visitor = @visitor_manager.get_or_create_visitor(visitor_code)
772
- unless experiment_id.nil? || variation_id.nil?
773
- as_variation = Kameleoon::DataManager::AssignedVariation.new(experiment_id, variation_id, rule.type)
774
- visitor.assign_variation(as_variation)
775
- end
776
- end
876
+ save_variation(visitor_code, rule, variation)
777
877
  @tracking_manager.add_visitor_code(visitor_code)
778
878
  Logging::KameleoonLogger.debug(
779
879
  "RETURN: KameleoonClient._get_feature_variation_key(visitor_code: '%s', feature_key: '%s')" \
@@ -783,6 +883,25 @@ module Kameleoon
783
883
  [feature_flag, variation_key]
784
884
  end
785
885
 
886
+ def save_variation(visitor_code, rule, var_by_exp, track: true)
887
+ experiment_id = rule&.experiment_id
888
+ variation_id = var_by_exp&.variation_id
889
+ return if experiment_id.nil? || variation_id.nil?
890
+
891
+ Logging::KameleoonLogger.debug(
892
+ "CALL: KameleoonClient.save_variation(visitor_code: '%s', rule: %s, var_by_exp: %s, track: %s)",
893
+ visitor_code, rule, var_by_exp, track
894
+ )
895
+ visitor = @visitor_manager.get_or_create_visitor(visitor_code)
896
+ as_variation = Kameleoon::DataManager::AssignedVariation.new(experiment_id, variation_id, rule.type)
897
+ as_variation.mark_as_sent unless track
898
+ visitor.assign_variation(as_variation)
899
+ Logging::KameleoonLogger.debug(
900
+ "RETURN: KameleoonClient.save_variation(visitor_code: '%s', rule: %s, var_by_exp: %s, track: %s)",
901
+ visitor_code, rule, var_by_exp, track
902
+ )
903
+ end
904
+
786
905
  ##
787
906
  # helper method for calculate variation key for feature flag
788
907
  def _calculate_variation_key_for_feature(visitor_code, feature_flag)
@@ -845,22 +964,47 @@ module Kameleoon
845
964
  feature_flag.default_variation_key
846
965
  end
847
966
 
967
+ def make_external_variation(internal_variation, variation_id, experiment_id)
968
+ Logging::KameleoonLogger.debug(
969
+ 'CALL: KameleoonClient.make_external_variation(internal_variation: %s, variation_id: %s, experiment_id: %s)',
970
+ internal_variation, variation_id, experiment_id
971
+ )
972
+ variables = {}
973
+ internal_variation&.variables&.each do |variable|
974
+ variables[variable.key] = Types::Variable.new(
975
+ variable.key,
976
+ variable.type,
977
+ _parse_feature_variable(variable)
978
+ )
979
+ end
980
+ variables.freeze
981
+ variation = Types::Variation.new(internal_variation&.key, variation_id, experiment_id, variables)
982
+ Logging::KameleoonLogger.debug(
983
+ 'RETURN: KameleoonClient.make_external_variation(internal_variation: %s, variation_id: %s, experiment_id: %s)' \
984
+ ' -> (variation: %s)',
985
+ internal_variation, variation_id, experiment_id, variation
986
+ )
987
+ variation
988
+ end
989
+
848
990
  ##
849
991
  # helper method for fetching values from a Variable
850
992
  def _parse_feature_variable(variable)
851
993
  case variable.type
852
- when 'BOOLEAN', 'STRING', 'NUMBER'
994
+ when 'BOOLEAN', 'STRING', 'NUMBER', 'JS', 'CSS'
853
995
  variable.value
854
996
  when 'JSON'
855
997
  JSON.parse(variable.value)
856
998
  else
857
- raise TypeError.new('Unknown type for feature variable'),
858
- 'Unknown type for feature variable'
999
+ Logging::KameleoonLogger.error("Unknown type '#{variable.type}' for feature variable")
1000
+ variable.value
859
1001
  end
860
1002
  end
861
1003
 
862
1004
  def set_unique_identifier(visitor_code, is_unique_identifier)
863
- Logging::KameleoonLogger.warning("The 'isUniqueIdentifier' parameter is deprecated. Please, add 'UniqueIdentifier' to a visitor instead.")
1005
+ Logging::KameleoonLogger.info(
1006
+ "The 'isUniqueIdentifier' parameter is deprecated. Please, add 'UniqueIdentifier' to a visitor instead."
1007
+ )
864
1008
  @visitor_manager.add_data(visitor_code, UniqueIdentifier.new(is_unique_identifier))
865
1009
  end
866
1010
  end
@@ -113,7 +113,7 @@ module Kameleoon
113
113
  'Setting top level domain is strictly recommended, otherwise you may have problems when using subdomains.'
114
114
  )
115
115
  end
116
- @top_level_domain = top_level_domain
116
+ @top_level_domain = Utils::Domain.validate_top_level_domain(top_level_domain)
117
117
  end
118
118
 
119
119
  def self.read_from_yaml(path)
@@ -16,18 +16,18 @@ module Kameleoon
16
16
  @container = Container.new(value)
17
17
  end
18
18
 
19
- def consent_required?
20
- @container.is_consent_required
19
+ def visitor_code_managed?
20
+ @container.visitor_code_managed
21
21
  end
22
22
 
23
23
  class Container
24
- attr_reader :data_file, :is_consent_required
24
+ attr_reader :data_file, :visitor_code_managed
25
25
 
26
26
  def initialize(data_file)
27
27
  @data_file = data_file
28
28
  # Regarding GDPR policy we should set visitorCode if legal consent isn't required or we have at
29
29
  # least one Targeted Delivery rule in datafile
30
- @is_consent_required = data_file.settings.is_consent_required && !data_file.has_any_targeted_delivery_rule
30
+ @visitor_code_managed = data_file.settings.is_consent_required && !data_file.has_any_targeted_delivery_rule
31
31
  end
32
32
  end
33
33
  end
@@ -80,12 +80,13 @@ module Kameleoon
80
80
  Thread.new do
81
81
  result = @network_manager.send_tracking_data(lines)
82
82
  if result != false
83
- Logging::KameleoonLogger.debug('Successful request for tracking visitors: %s, data: %s',
84
- visitor_codes, visitor_data)
83
+ Logging::KameleoonLogger.info('Successful request for tracking visitors: %s, data: %s',
84
+ visitor_codes, visitor_data)
85
85
  visitor_data.each { |d| d.mark_as_sent if d.is_a?(Kameleoon::Data) }
86
86
  else
87
- Logging::KameleoonLogger.debug('Failed request for tracking visitors: %s, data: %s',
88
- visitor_codes, visitor_data)
87
+ Logging::KameleoonLogger.error('Tracking request failed')
88
+ Logging::KameleoonLogger.info('Failed request for tracking visitors: %s, data: %s',
89
+ visitor_codes, visitor_data)
89
90
  visitor_data.each { |d| d.mark_as_unsent if d.is_a?(Kameleoon::Data) }
90
91
  @tracking_visitors.add_all(visitor_codes)
91
92
  end
@@ -31,7 +31,7 @@ module Kameleoon
31
31
  Utils::VisitorCode.validate(visitor_code)
32
32
  Logging::KameleoonLogger.debug("Read visitor code '%s' from cookies %s", visitor_code, cookies)
33
33
  # Remove adding cookies when we will be sure that it doesn't break anything
34
- add(visitor_code, cookies) unless @data_manager.consent_required?
34
+ add(visitor_code, cookies) unless @data_manager.visitor_code_managed?
35
35
  Logging::KameleoonLogger.debug(
36
36
  "RETURN: CookieManager.get_or_add(cookies: %s, default_visitor_code: '%s') -> (visitor_code: '%s')",
37
37
  cookies, default_visitor_code, visitor_code
@@ -42,7 +42,7 @@ module Kameleoon
42
42
  if default_visitor_code.nil?
43
43
  visitor_code = Utils::VisitorCode.generate
44
44
  Logging::KameleoonLogger.debug("Generated new visitor code '%s'", visitor_code)
45
- add(visitor_code, cookies) unless @data_manager.consent_required?
45
+ add(visitor_code, cookies) unless @data_manager.visitor_code_managed?
46
46
  Logging::KameleoonLogger.debug(
47
47
  "RETURN: CookieManager.get_or_add(cookies: %s, default_visitor_code: '%s') -> (visitor_code: '%s')",
48
48
  cookies, default_visitor_code, visitor_code
@@ -56,7 +56,8 @@ module Kameleoon
56
56
  add(visitor_code, cookies)
57
57
  Logging::KameleoonLogger.debug(
58
58
  "RETURN: CookieManager.get_or_add(cookies: %s, default_visitor_code: '%s') -> (visitor_code: '%s')",
59
- cookies, default_visitor_code, visitor_code)
59
+ cookies, default_visitor_code, visitor_code
60
+ )
60
61
  visitor_code
61
62
  end
62
63
 
@@ -72,7 +73,7 @@ module Kameleoon
72
73
  remove(cookies)
73
74
  end
74
75
  Logging::KameleoonLogger.debug("RETURN: CookieManager.update(visitor_code: '%s', consent: %s, cookies: %s)",
75
- visitor_code, consent, cookies)
76
+ visitor_code, consent, cookies)
76
77
  end
77
78
 
78
79
  private
@@ -88,13 +89,13 @@ module Kameleoon
88
89
  }
89
90
  cookies[VISITOR_CODE_COOKIE] = cookie
90
91
  Logging::KameleoonLogger.debug("RETURN: CookieManager.add(visitor_code: '%s', cookies: %s)",
91
- visitor_code, cookies)
92
+ visitor_code, cookies)
92
93
  cookies
93
94
  end
94
95
 
95
96
  def remove(cookies)
96
97
  Logging::KameleoonLogger.debug('CALL: CookieManager.remove(cookies: %s)', cookies)
97
- cookies[VISITOR_CODE_COOKIE] = nil if @data_manager.consent_required?
98
+ cookies[VISITOR_CODE_COOKIE] = nil if @data_manager.visitor_code_managed?
98
99
  Logging::KameleoonLogger.debug('RETURN: CookieManager.remove(cookies: %s)', cookies)
99
100
  cookies
100
101
  end
@@ -88,11 +88,13 @@ module Kameleoon
88
88
  if response.success?
89
89
  success = true
90
90
  elsif !response.error.nil?
91
- Logging::KameleoonLogger.warning("%s call '%s' failed: Error occurred during request: %s",
92
- request.method, request.url, response.error)
91
+ log_level = attempt < retry_limit ? Logging::LogLevel::WARNING : Logging::LogLevel::ERROR
92
+ Logging::KameleoonLogger.log(log_level, "%s call '%s' failed: Error occurred during request: %s",
93
+ request.method, request.url, response.error)
93
94
  else
94
- Logging::KameleoonLogger.warning("%s call '%s' failed: Received unexpected status code '%s'",
95
- request.method, request.url, response.code)
95
+ log_level = attempt < retry_limit ? Logging::LogLevel::WARNING : Logging::LogLevel::ERROR
96
+ Logging::KameleoonLogger.log(log_level, "%s call '%s' failed: Received unexpected status code '%s'",
97
+ request.method, request.url, response.code)
96
98
  if response.code == 401 && request.access_token
97
99
  Logging::KameleoonLogger.warning("Unexpected rejection of access token '#{request.access_token}'")
98
100
  @access_token_source.discard_token(request.access_token)
@@ -108,7 +110,6 @@ module Kameleoon
108
110
  attempt += 1
109
111
  end
110
112
  Logging::KameleoonLogger.debug('Fetched response %s for request %s', response, request)
111
- Logging::KameleoonLogger.error("Failed %s request '%s'", request.method, request.url) unless success
112
113
  success ? response.body : false
113
114
  end
114
115
 
@@ -19,7 +19,7 @@ module Kameleoon
19
19
  DEFAULT_DATA_API_DOMAIN = 'data.kameleoon.io'
20
20
  TEST_DATA_API_DOMAIN = 'data.kameleoon.net'
21
21
  DEFAULT_AUTOMATION_API_DOMAIN = 'api.kameleoon.com'
22
- TEST_AUTOMATION_API_DOMAIN = 'api.master.preview.kameleoon.net'
22
+ TEST_AUTOMATION_API_DOMAIN = 'api.kameleoon.net'
23
23
 
24
24
  attr_reader :site_code, :data_api_domain, :automation_api_domain
25
25
 
@@ -17,6 +17,10 @@ module Kameleoon
17
17
  @experiment_id = experiment_id
18
18
  @variables = variables
19
19
  end
20
+
21
+ def active?
22
+ variation_key != Configuration::VariationType::VARIATION_OFF
23
+ end
20
24
  end
21
25
  end
22
26
  end
@@ -4,6 +4,7 @@ require 'fiber'
4
4
  require 'bigdecimal'
5
5
  require 'kameleoon/utils'
6
6
  require 'kameleoon/exceptions'
7
+ require 'kameleoon/logging/kameleoon_logger'
7
8
 
8
9
  module Kameleoon
9
10
  # Utils is a helper module for project
@@ -68,5 +69,35 @@ module Kameleoon
68
69
  secret[0, length - hidden_length] + hid_ch * hidden_length
69
70
  end
70
71
  end
72
+
73
+ module Domain
74
+ HTTP = 'http://'
75
+ HTTPS = 'https://'
76
+ REGEX_DOMAIN = /^(\.?(([a-zA-Z\d][a-zA-Z\d-]*[a-zA-Z\d])|[a-zA-Z\d]))
77
+ (\.(([a-zA-Z\d][a-zA-Z\d-]*[a-zA-Z\d])|[a-zA-Z\d])){1,126}$/x.freeze
78
+
79
+ def self.validate_top_level_domain(top_level_domain)
80
+ return nil if top_level_domain.nil? || top_level_domain.empty?
81
+
82
+ top_level_domain = top_level_domain.downcase
83
+
84
+ [HTTP, HTTPS].each do |protocol|
85
+ next unless top_level_domain.start_with?(protocol)
86
+
87
+ top_level_domain = top_level_domain[protocol.length..]
88
+ Logging::KameleoonLogger.warning(
89
+ "The top-level domain contains '%s'. Domain after protocol trimming: '%s'", protocol, top_level_domain
90
+ )
91
+ break
92
+ end
93
+
94
+ unless REGEX_DOMAIN.match?(top_level_domain)
95
+ Logging::KameleoonLogger.error("The top-level domain '%s' is invalid.", top_level_domain)
96
+ return nil
97
+ end
98
+
99
+ top_level_domain
100
+ end
101
+ end
71
102
  end
72
103
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kameleoon
4
- SDK_VERSION = '3.4.0'
4
+ SDK_VERSION = '3.5.0'
5
5
  SDK_NAME = 'RUBY'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kameleoon-client-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.0
4
+ version: 3.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kameleoon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-15 00:00:00.000000000 Z
11
+ date: 2024-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: em-http-request