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 +4 -4
- data/lib/kameleoon/configuration/data_file.rb +15 -1
- data/lib/kameleoon/configuration/feature_flag.rb +1 -1
- data/lib/kameleoon/data/manager/assigned_variation.rb +3 -1
- data/lib/kameleoon/hybrid/manager.rb +7 -4
- data/lib/kameleoon/kameleoon_client.rb +186 -42
- data/lib/kameleoon/kameleoon_client_config.rb +1 -1
- data/lib/kameleoon/managers/data/data_manager.rb +4 -4
- data/lib/kameleoon/managers/tracking/tracking_manager.rb +5 -4
- data/lib/kameleoon/network/cookie/cookie_manager.rb +7 -6
- data/lib/kameleoon/network/network_manager.rb +6 -5
- data/lib/kameleoon/network/url_provider.rb +1 -1
- data/lib/kameleoon/types/variation.rb +4 -0
- data/lib/kameleoon/utils.rb +31 -0
- data/lib/kameleoon/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 283250365ae9bf4087ebffeb7a4de0e31cca91f06a865cdd4ad2cae1f88c692c
|
4
|
+
data.tar.gz: 31ab8ddbd1ef7524b41019a0afe442a47ee5b5e9e1d50649ed04aab625d7c3a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
@@ -18,7 +18,9 @@ module Kameleoon
|
|
18
18
|
"assignment_time:#{@assignment_time},rule_type:#{@rule_type}}"
|
19
19
|
end
|
20
20
|
|
21
|
-
def initialize(
|
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
|
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
|
-
|
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',
|
273
|
-
|
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
|
-
|
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',
|
281
|
-
|
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.
|
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.
|
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.
|
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.
|
554
|
-
|
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
|
-
|
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
|
-
|
858
|
-
|
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.
|
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
|
20
|
-
@container.
|
19
|
+
def visitor_code_managed?
|
20
|
+
@container.visitor_code_managed
|
21
21
|
end
|
22
22
|
|
23
23
|
class Container
|
24
|
-
attr_reader :data_file, :
|
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
|
-
@
|
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.
|
84
|
-
|
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.
|
88
|
-
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
|
92
|
-
|
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
|
-
|
95
|
-
|
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.
|
22
|
+
TEST_AUTOMATION_API_DOMAIN = 'api.kameleoon.net'
|
23
23
|
|
24
24
|
attr_reader :site_code, :data_api_domain, :automation_api_domain
|
25
25
|
|
data/lib/kameleoon/utils.rb
CHANGED
@@ -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
|
data/lib/kameleoon/version.rb
CHANGED
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
|
+
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-
|
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
|