kameleoon-client-ruby 3.4.0 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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