kameleoon-client-ruby 3.2.0 → 3.4.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 +4 -4
- data/lib/kameleoon/configuration/custom_data_info.rb +16 -8
- data/lib/kameleoon/configuration/data_file.rb +40 -17
- data/lib/kameleoon/configuration/feature_flag.rb +10 -0
- data/lib/kameleoon/configuration/rule.rb +4 -0
- data/lib/kameleoon/configuration/settings.rb +13 -8
- data/lib/kameleoon/configuration/variation_exposition.rb +4 -0
- data/lib/kameleoon/data/browser.rb +4 -0
- data/lib/kameleoon/data/conversion.rb +4 -0
- data/lib/kameleoon/data/cookie.rb +4 -0
- data/lib/kameleoon/data/custom_data.rb +11 -3
- data/lib/kameleoon/data/data.rb +30 -4
- data/lib/kameleoon/data/device.rb +4 -0
- data/lib/kameleoon/data/geolocation.rb +5 -0
- data/lib/kameleoon/data/kcs_heat.rb +16 -0
- data/lib/kameleoon/data/manager/assigned_variation.rb +5 -0
- data/lib/kameleoon/data/manager/data_array_storage.rb +7 -0
- data/lib/kameleoon/data/manager/data_map_storage.rb +7 -0
- data/lib/kameleoon/data/manager/page_view_visit.rb +4 -0
- data/lib/kameleoon/data/manager/visitor.rb +198 -67
- data/lib/kameleoon/data/manager/visitor_manager.rb +54 -17
- data/lib/kameleoon/data/mapping_identifier.rb +33 -0
- data/lib/kameleoon/data/operating_system.rb +4 -0
- data/lib/kameleoon/data/page_view.rb +6 -1
- data/lib/kameleoon/data/unique_identifier.rb +11 -0
- data/lib/kameleoon/data/user_agent.rb +4 -0
- data/lib/kameleoon/data/visitor_visits.rb +12 -1
- data/lib/kameleoon/hybrid/manager.rb +13 -4
- data/lib/kameleoon/kameleoon_client.rb +348 -146
- data/lib/kameleoon/kameleoon_client_config.rb +64 -17
- data/lib/kameleoon/kameleoon_client_factory.rb +15 -2
- data/lib/kameleoon/logging/default_logger.rb +20 -0
- data/lib/kameleoon/logging/kameleoon_logger.rb +77 -0
- data/lib/kameleoon/logging/logger.rb +12 -0
- data/lib/kameleoon/managers/data/data_manager.rb +36 -0
- data/lib/kameleoon/managers/remote_data/remote_data_manager.rb +33 -18
- data/lib/kameleoon/managers/remote_data/remote_visitor_data.rb +42 -16
- data/lib/kameleoon/managers/tracking/tracking_builder.rb +149 -0
- data/lib/kameleoon/managers/tracking/tracking_manager.rb +97 -0
- data/lib/kameleoon/managers/tracking/visitor_tracking_registry.rb +94 -0
- data/lib/kameleoon/managers/warehouse/warehouse_manager.rb +22 -5
- data/lib/kameleoon/network/access_token_source.rb +46 -14
- data/lib/kameleoon/network/cookie/cookie_manager.rb +45 -7
- data/lib/kameleoon/network/net_provider.rb +2 -3
- data/lib/kameleoon/network/network_manager.rb +16 -21
- data/lib/kameleoon/network/request.rb +14 -3
- data/lib/kameleoon/network/response.rb +4 -0
- data/lib/kameleoon/network/url_provider.rb +11 -10
- data/lib/kameleoon/real_time/real_time_configuration_service.rb +10 -11
- data/lib/kameleoon/sdk_version.rb +31 -0
- data/lib/kameleoon/targeting/condition.rb +6 -2
- data/lib/kameleoon/targeting/condition_factory.rb +3 -0
- data/lib/kameleoon/targeting/conditions/browser_condition.rb +3 -3
- data/lib/kameleoon/targeting/conditions/cookie_condition.rb +10 -10
- data/lib/kameleoon/targeting/conditions/geolocation_condition.rb +0 -1
- data/lib/kameleoon/targeting/conditions/kcs_heat_range_condition.rb +37 -0
- data/lib/kameleoon/targeting/conditions/number_condition.rb +4 -4
- data/lib/kameleoon/targeting/conditions/operating_system_condition.rb +1 -2
- data/lib/kameleoon/targeting/conditions/sdk_language_condition.rb +2 -1
- data/lib/kameleoon/targeting/conditions/segment_condition.rb +3 -3
- data/lib/kameleoon/targeting/conditions/string_value_condition.rb +2 -1
- data/lib/kameleoon/targeting/conditions/target_feature_flag_condition.rb +7 -11
- data/lib/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.rb +1 -2
- data/lib/kameleoon/targeting/conditions/visit_number_today_condition.rb +4 -4
- data/lib/kameleoon/targeting/conditions/visit_number_total_condition.rb +5 -3
- data/lib/kameleoon/targeting/conditions/visitor_new_return_condition.rb +7 -6
- data/lib/kameleoon/targeting/models.rb +0 -14
- data/lib/kameleoon/targeting/targeting_manager.rb +37 -7
- data/lib/kameleoon/targeting/tree_builder.rb +10 -5
- data/lib/kameleoon/types/remote_visitor_data_filter.rb +21 -3
- data/lib/kameleoon/types/variable.rb +21 -0
- data/lib/kameleoon/types/variation.rb +22 -0
- data/lib/kameleoon/utils.rb +18 -0
- data/lib/kameleoon/version.rb +1 -27
- metadata +16 -2
|
@@ -1,29 +1,56 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'kameleoon/logging/kameleoon_logger'
|
|
4
|
+
|
|
3
5
|
module Kameleoon
|
|
4
6
|
# KameleoonClient configuration which can be used instead of an external configuration file
|
|
5
7
|
class KameleoonClientConfig
|
|
6
8
|
DEFAULT_REFRESH_INTERVAL_MINUTES = 60
|
|
7
9
|
DEFAULT_SESSION_DURATION_MINUTES = 30
|
|
8
10
|
DEFAULT_TIMEOUT_MILLISECONDS = 10_000
|
|
11
|
+
DEFAULT_TRACKING_INTERVAL_MILLISECONDS = 1000
|
|
12
|
+
MIN_TRACKING_INTERVAL_MILLISECONDS = 300
|
|
13
|
+
MAX_TRACKING_INTERVAL_MILLISECONDS = 1000
|
|
9
14
|
|
|
10
15
|
attr_reader :client_id, :client_secret, :refresh_interval_second, :session_duration_second,
|
|
11
|
-
:default_timeout_millisecond, :environment, :top_level_domain,
|
|
16
|
+
:default_timeout_millisecond, :tracking_interval_second, :environment, :top_level_domain,
|
|
17
|
+
:verbose_mode
|
|
18
|
+
|
|
19
|
+
def to_s
|
|
20
|
+
'KameleoonClientConfig{' \
|
|
21
|
+
"client_id:'#{Utils::Strval.secret(@client_id)}'," \
|
|
22
|
+
"client_secret:'#{Utils::Strval.secret(@client_secret)}'," \
|
|
23
|
+
"refresh_interval_second:#{@refresh_interval_second}," \
|
|
24
|
+
"session_duration_second:#{@session_duration_second}," \
|
|
25
|
+
"environment:'#{@environment}'," \
|
|
26
|
+
"default_timeout_millisecond:#{@default_timeout_millisecond}," \
|
|
27
|
+
"top_level_domain:'#{@top_level_domain}'," \
|
|
28
|
+
"verbose_mode:#{verbose_mode}" \
|
|
29
|
+
'}'
|
|
30
|
+
end
|
|
12
31
|
|
|
32
|
+
# verbose_mode is DEPRECATED. Please use `KameleoonLogger.log_level` instead.
|
|
13
33
|
def initialize(
|
|
14
34
|
client_id,
|
|
15
35
|
client_secret,
|
|
16
36
|
refresh_interval_minute: DEFAULT_REFRESH_INTERVAL_MINUTES,
|
|
17
37
|
session_duration_minute: DEFAULT_SESSION_DURATION_MINUTES,
|
|
18
38
|
default_timeout_millisecond: DEFAULT_TIMEOUT_MILLISECONDS,
|
|
39
|
+
tracking_interval_millisecond: DEFAULT_TRACKING_INTERVAL_MILLISECONDS,
|
|
19
40
|
environment: nil,
|
|
20
41
|
top_level_domain: nil,
|
|
21
|
-
verbose_mode:
|
|
42
|
+
verbose_mode: nil
|
|
22
43
|
)
|
|
23
44
|
raise Exception::ConfigCredentialsInvalid, 'Client ID is not specified' if client_id&.empty? != false
|
|
24
45
|
raise Exception::ConfigCredentialsInvalid, 'Client secret is not specified' if client_secret&.empty? != false
|
|
25
46
|
|
|
26
|
-
|
|
47
|
+
unless verbose_mode.nil?
|
|
48
|
+
Logging::KameleoonLogger.warning(
|
|
49
|
+
'[DEPRECATION] `verbose_mode` is deprecated. Please use `KameleoonLogger.log_level` instead.'
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
@verbose_mode = verbose_mode
|
|
27
54
|
|
|
28
55
|
@client_id = client_id
|
|
29
56
|
@client_secret = client_secret
|
|
@@ -31,8 +58,10 @@ module Kameleoon
|
|
|
31
58
|
if refresh_interval_minute.nil?
|
|
32
59
|
refresh_interval_minute = DEFAULT_REFRESH_INTERVAL_MINUTES
|
|
33
60
|
elsif refresh_interval_minute <= 0
|
|
34
|
-
|
|
35
|
-
|
|
61
|
+
Logging::KameleoonLogger.warning(lambda {
|
|
62
|
+
'Configuration refresh interval must have positive value. ' \
|
|
63
|
+
"Default refresh interval (#{DEFAULT_REFRESH_INTERVAL_MINUTES} minutes) was applied."
|
|
64
|
+
})
|
|
36
65
|
refresh_interval_minute = DEFAULT_REFRESH_INTERVAL_MINUTES
|
|
37
66
|
end
|
|
38
67
|
@refresh_interval_second = refresh_interval_minute * 60
|
|
@@ -40,8 +69,10 @@ module Kameleoon
|
|
|
40
69
|
if session_duration_minute.nil?
|
|
41
70
|
session_duration_minute = DEFAULT_SESSION_DURATION_MINUTES
|
|
42
71
|
elsif session_duration_minute <= 0
|
|
43
|
-
|
|
44
|
-
|
|
72
|
+
Logging::KameleoonLogger.warning(lambda {
|
|
73
|
+
'Session duration must have positive value. ' \
|
|
74
|
+
"Default session duration (#{DEFAULT_SESSION_DURATION_MINUTES} minutes) was applied."
|
|
75
|
+
})
|
|
45
76
|
session_duration_minute = DEFAULT_SESSION_DURATION_MINUTES
|
|
46
77
|
end
|
|
47
78
|
@session_duration_second = session_duration_minute * 60
|
|
@@ -49,17 +80,38 @@ module Kameleoon
|
|
|
49
80
|
if default_timeout_millisecond.nil?
|
|
50
81
|
@default_timeout_millisecond = DEFAULT_TIMEOUT_MILLISECONDS
|
|
51
82
|
elsif default_timeout_millisecond <= 0
|
|
52
|
-
|
|
53
|
-
|
|
83
|
+
Logging::KameleoonLogger.warning(lambda {
|
|
84
|
+
'Default timeout must have positive value. ' \
|
|
85
|
+
"Default timeout (#{DEFAULT_TIMEOUT_MILLISECONDS} ms) was applied."
|
|
86
|
+
})
|
|
54
87
|
@default_timeout_millisecond = DEFAULT_TIMEOUT_MILLISECONDS
|
|
55
88
|
else
|
|
56
89
|
@default_timeout_millisecond = default_timeout_millisecond
|
|
57
90
|
end
|
|
58
91
|
|
|
92
|
+
if tracking_interval_millisecond.nil?
|
|
93
|
+
tracking_interval_millisecond = DEFAULT_TRACKING_INTERVAL_MILLISECONDS
|
|
94
|
+
elsif tracking_interval_millisecond < MIN_TRACKING_INTERVAL_MILLISECONDS
|
|
95
|
+
Logging::KameleoonLogger.warning(lambda {
|
|
96
|
+
'Tracking interval must not be shorter than ' \
|
|
97
|
+
"#{MIN_TRACKING_INTERVAL_MILLISECONDS} ms. Minimum possible interval was applied."
|
|
98
|
+
})
|
|
99
|
+
tracking_interval_millisecond = MIN_TRACKING_INTERVAL_MILLISECONDS
|
|
100
|
+
elsif tracking_interval_millisecond > MAX_TRACKING_INTERVAL_MILLISECONDS
|
|
101
|
+
Logging::KameleoonLogger.warning(lambda {
|
|
102
|
+
'Tracking interval must not be longer than ' \
|
|
103
|
+
"#{MAX_TRACKING_INTERVAL_MILLISECONDS} ms. Maximum possible interval was applied."
|
|
104
|
+
})
|
|
105
|
+
tracking_interval_millisecond = MAX_TRACKING_INTERVAL_MILLISECONDS
|
|
106
|
+
end
|
|
107
|
+
@tracking_interval_second = tracking_interval_millisecond / 1000.0
|
|
108
|
+
|
|
59
109
|
@environment = environment
|
|
60
110
|
|
|
61
111
|
if top_level_domain.nil?
|
|
62
|
-
|
|
112
|
+
Logging::KameleoonLogger.warning(
|
|
113
|
+
'Setting top level domain is strictly recommended, otherwise you may have problems when using subdomains.'
|
|
114
|
+
)
|
|
63
115
|
end
|
|
64
116
|
@top_level_domain = top_level_domain
|
|
65
117
|
end
|
|
@@ -67,7 +119,7 @@ module Kameleoon
|
|
|
67
119
|
def self.read_from_yaml(path)
|
|
68
120
|
yaml = YAML.load_file(path) if File.exist?(path)
|
|
69
121
|
if yaml.nil?
|
|
70
|
-
|
|
122
|
+
Logging::KameleoonLogger.warning(-> { "Configuration file with path '#{path}' does not exist" })
|
|
71
123
|
yaml = {}
|
|
72
124
|
end
|
|
73
125
|
KameleoonClientConfig.new(
|
|
@@ -76,16 +128,11 @@ module Kameleoon
|
|
|
76
128
|
refresh_interval_minute: yaml['refresh_interval_minute'],
|
|
77
129
|
session_duration_minute: yaml['session_duration_minute'],
|
|
78
130
|
default_timeout_millisecond: yaml['default_timeout_millisecond'],
|
|
131
|
+
tracking_interval_millisecond: yaml['tracking_interval_millisecond'],
|
|
79
132
|
environment: yaml['environment'],
|
|
80
133
|
top_level_domain: yaml['top_level_domain'],
|
|
81
134
|
verbose_mode: yaml['verbose_mode']
|
|
82
135
|
)
|
|
83
136
|
end
|
|
84
|
-
|
|
85
|
-
private
|
|
86
|
-
|
|
87
|
-
def log(text)
|
|
88
|
-
print "Kameleoon SDK Log: #{text}\n" if @verbose_mode
|
|
89
|
-
end
|
|
90
137
|
end
|
|
91
138
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'concurrent'
|
|
4
|
+
require 'kameleoon/logging/kameleoon_logger'
|
|
4
5
|
require 'kameleoon/kameleoon_client'
|
|
5
6
|
require 'kameleoon/kameleoon_client_config'
|
|
6
7
|
|
|
@@ -12,25 +13,37 @@ module Kameleoon
|
|
|
12
13
|
@clients = Concurrent::Map.new
|
|
13
14
|
|
|
14
15
|
def self.create(site_code, config: nil, config_path: CONFIG_PATH)
|
|
16
|
+
Logging::KameleoonLogger.info(
|
|
17
|
+
"CALL: KameleoonClientFactory.create(site_code: '%s', config: %s, config_path: '%s')",
|
|
18
|
+
site_code, config, config_path
|
|
19
|
+
)
|
|
15
20
|
unless config.is_a?(KameleoonClientConfig)
|
|
16
21
|
config_path = CONFIG_PATH unless config_path.is_a?(String)
|
|
17
22
|
config = KameleoonClientConfig.read_from_yaml(config_path)
|
|
18
23
|
end
|
|
19
24
|
key = get_client_key(site_code, config.environment)
|
|
20
|
-
@clients.compute_if_absent(key) do
|
|
25
|
+
client = @clients.compute_if_absent(key) do
|
|
21
26
|
client = KameleoonClient.new(site_code, config)
|
|
22
|
-
client.send(:log, "Client created with site code: #{site_code}")
|
|
23
27
|
client.send(:fetch_configuration_initially)
|
|
24
28
|
client
|
|
25
29
|
end
|
|
30
|
+
Logging::KameleoonLogger.info(
|
|
31
|
+
"RETURN: KameleoonClientFactory.create(site_code: '%s', config: %s, config_path: '%s') -> (client)",
|
|
32
|
+
site_code, config, config_path
|
|
33
|
+
)
|
|
34
|
+
client
|
|
26
35
|
end
|
|
27
36
|
|
|
28
37
|
def self.forget(site_code, environment = nil)
|
|
38
|
+
Logging::KameleoonLogger.info("CALL: KameleoonClientFactory.forget(site_code: '%s', environment: '%s')",
|
|
39
|
+
site_code, environment)
|
|
29
40
|
key = get_client_key(site_code, environment)
|
|
30
41
|
@clients.compute_if_present(key) do |client|
|
|
31
42
|
client.send(:dispose)
|
|
32
43
|
nil
|
|
33
44
|
end
|
|
45
|
+
Logging::KameleoonLogger.info("RETURN: KameleoonClientFactory.forget(site_code: '%s', environment: '%s')",
|
|
46
|
+
site_code, environment)
|
|
34
47
|
end
|
|
35
48
|
|
|
36
49
|
private_class_method
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'kameleoon/logging/logger'
|
|
4
|
+
|
|
5
|
+
module Kameleoon
|
|
6
|
+
module Logging
|
|
7
|
+
# A default implementation of a logger that prints log messages to the console.
|
|
8
|
+
# This logger implements the Logger interface.
|
|
9
|
+
class DefaultLogger < Logger
|
|
10
|
+
|
|
11
|
+
# Logs a message at the specified log level.
|
|
12
|
+
#
|
|
13
|
+
# @param level [LogLevel] the log level
|
|
14
|
+
# @param message [String] the log message
|
|
15
|
+
def log(level, message)
|
|
16
|
+
puts message
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'kameleoon/logging/default_logger'
|
|
4
|
+
|
|
5
|
+
module Kameleoon
|
|
6
|
+
module Logging
|
|
7
|
+
module LogLevel
|
|
8
|
+
NONE = 0
|
|
9
|
+
ERROR = 1
|
|
10
|
+
WARNING = 2
|
|
11
|
+
INFO = 3
|
|
12
|
+
DEBUG = 4
|
|
13
|
+
|
|
14
|
+
def self.name_from_level(log_level)
|
|
15
|
+
case log_level
|
|
16
|
+
when LogLevel::NONE
|
|
17
|
+
'NONE'
|
|
18
|
+
when LogLevel::ERROR
|
|
19
|
+
'ERROR'
|
|
20
|
+
when LogLevel::WARNING
|
|
21
|
+
'WARNING'
|
|
22
|
+
when LogLevel::INFO
|
|
23
|
+
'INFO'
|
|
24
|
+
when LogLevel::DEBUG
|
|
25
|
+
'DEBUG'
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module KameleoonLogger
|
|
31
|
+
extend self
|
|
32
|
+
|
|
33
|
+
@logger = DefaultLogger.new
|
|
34
|
+
@log_level = LogLevel::WARNING
|
|
35
|
+
|
|
36
|
+
attr_accessor :logger, :log_level
|
|
37
|
+
|
|
38
|
+
def log(level, data, *args)
|
|
39
|
+
return unless check_level(level)
|
|
40
|
+
|
|
41
|
+
if data.class.method_defined?(:call)
|
|
42
|
+
message = data.call
|
|
43
|
+
else
|
|
44
|
+
message = args.empty? ? data : data % args
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
write_message(level, message)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def info(data, *args)
|
|
51
|
+
log(LogLevel::INFO, data, *args)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def error(data, *args)
|
|
55
|
+
log(LogLevel::ERROR, data, *args)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def warning(data, *args)
|
|
59
|
+
log(LogLevel::WARNING, data, *args)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def debug(data, *args)
|
|
63
|
+
log(LogLevel::DEBUG, data, *args)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def check_level(level)
|
|
69
|
+
level <= @log_level && level != LogLevel::NONE
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def write_message(level, message)
|
|
73
|
+
@logger.log(level, "Kameleoon [#{LogLevel.name_from_level(level)}]: #{message}")
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kameleoon
|
|
4
|
+
module Managers
|
|
5
|
+
module Data
|
|
6
|
+
class DataManager
|
|
7
|
+
def initialize(data_file)
|
|
8
|
+
self.data_file = data_file
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def data_file
|
|
12
|
+
@container.data_file
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def data_file=(value)
|
|
16
|
+
@container = Container.new(value)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def consent_required?
|
|
20
|
+
@container.is_consent_required
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class Container
|
|
24
|
+
attr_reader :data_file, :is_consent_required
|
|
25
|
+
|
|
26
|
+
def initialize(data_file)
|
|
27
|
+
@data_file = data_file
|
|
28
|
+
# Regarding GDPR policy we should set visitorCode if legal consent isn't required or we have at
|
|
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
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -1,57 +1,72 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'kameleoon/logging/kameleoon_logger'
|
|
3
4
|
require 'kameleoon/managers/remote_data/remote_visitor_data'
|
|
4
5
|
require 'kameleoon/types/remote_visitor_data_filter'
|
|
6
|
+
require 'kameleoon/utils'
|
|
5
7
|
|
|
6
8
|
module Kameleoon
|
|
7
9
|
module Managers
|
|
8
10
|
module RemoteData
|
|
9
|
-
|
|
10
11
|
class RemoteDataManager
|
|
11
|
-
attr_reader :network_manager, :visitor_manger
|
|
12
|
+
attr_reader :network_manager, :visitor_manger
|
|
12
13
|
|
|
13
|
-
def initialize(network_manager, visitor_manger
|
|
14
|
+
def initialize(data_manager, network_manager, visitor_manger)
|
|
15
|
+
Logging::KameleoonLogger.debug('CALL: RemoteDataManager.new(data_manager, networkManager, visitorManager)')
|
|
16
|
+
@data_manager = data_manager
|
|
14
17
|
@network_manager = network_manager
|
|
15
18
|
@visitor_manger = visitor_manger
|
|
16
|
-
|
|
19
|
+
Logging::KameleoonLogger.debug('RETURN: RemoteDataManager.new(data_manager, networkManager, visitorManager)')
|
|
17
20
|
end
|
|
18
21
|
|
|
19
22
|
def get_data(key, timeout)
|
|
23
|
+
Logging::KameleoonLogger.debug("CALL: RemoteDataManager.get_data(key: '%s', timeout: %s)", key, timeout)
|
|
20
24
|
response = @network_manager.get_remote_data(key, timeout)
|
|
21
|
-
JSON.parse(response) if response
|
|
25
|
+
data = JSON.parse(response) if response
|
|
26
|
+
Logging::KameleoonLogger.debug(
|
|
27
|
+
"RETURN: RemoteDataManager.get_data(key: '%s', timeout: %s) -> (remote_data: %s)",
|
|
28
|
+
key, timeout, data
|
|
29
|
+
)
|
|
30
|
+
data
|
|
22
31
|
rescue StandardError => e
|
|
23
|
-
|
|
32
|
+
Logging::KameleoonLogger.error("Parsing of remote data of '#{key}' failed: #{e}")
|
|
24
33
|
raise
|
|
25
34
|
end
|
|
26
35
|
|
|
27
|
-
def get_visitor_data(visitor_code, add_data, filter = nil,
|
|
36
|
+
def get_visitor_data(visitor_code, add_data, filter = nil, timeout = nil)
|
|
37
|
+
Logging::KameleoonLogger.debug(
|
|
38
|
+
"CALL: RemoteDataManager.get_visitor_data(visitor_code: '%s', add_data: %s, filter: %s, timeout: %s)",
|
|
39
|
+
visitor_code, add_data, filter, timeout
|
|
40
|
+
)
|
|
28
41
|
Utils::VisitorCode.validate(visitor_code)
|
|
29
|
-
filter =
|
|
42
|
+
filter = Types::RemoteVisitorDataFilter.new unless filter.is_a?(Types::RemoteVisitorDataFilter)
|
|
43
|
+
is_unique_identifier = @visitor_manger.get_visitor(visitor_code)&.is_unique_identifier || false
|
|
30
44
|
response = @network_manager.get_remote_visitor_data(visitor_code, filter, is_unique_identifier, timeout)
|
|
31
45
|
(data_to_add, data_to_return) = parse_custom_data_array(visitor_code, response)
|
|
32
46
|
if add_data && !data_to_add.empty?
|
|
47
|
+
# Cannot use `VisitorManager.add_data` because it could use remote visitor data for mapping.
|
|
33
48
|
visitor = @visitor_manger.get_or_create_visitor(visitor_code)
|
|
34
|
-
visitor.add_data(
|
|
49
|
+
visitor.add_data(*data_to_add, overwrite: false)
|
|
35
50
|
end
|
|
51
|
+
Logging::KameleoonLogger.debug(
|
|
52
|
+
"RETURN: RemoteDataManager.get_visitor_data(visitor_code: '%s', add_data: %s, filter: %s," \
|
|
53
|
+
' timeout: %s) -> (visitor_data: %s)',
|
|
54
|
+
visitor_code, add_data, filter, timeout, data_to_return
|
|
55
|
+
)
|
|
36
56
|
data_to_return
|
|
37
57
|
end
|
|
38
58
|
|
|
39
|
-
|
|
40
59
|
##
|
|
41
60
|
# helper method used by `get_remote_visitor_data`
|
|
42
61
|
def parse_custom_data_array(visitor_code, response)
|
|
43
|
-
remote_visitor_data =
|
|
44
|
-
remote_visitor_data.mark_data_as_sent(@
|
|
62
|
+
remote_visitor_data = RemoteVisitorData.new(JSON.parse(response))
|
|
63
|
+
remote_visitor_data.mark_data_as_sent(@data_manager.data_file.custom_data_info)
|
|
45
64
|
[remote_visitor_data.collect_data_to_add, remote_visitor_data.collect_data_to_return]
|
|
46
65
|
rescue StandardError => e
|
|
47
|
-
|
|
66
|
+
Logging::KameleoonLogger.error("Parsing of remote visitor data of '#{visitor_code}' failed: #{e}")
|
|
48
67
|
raise
|
|
49
68
|
end
|
|
50
|
-
|
|
51
|
-
def log(text)
|
|
52
|
-
@log_func&.call(text)
|
|
53
|
-
end
|
|
54
69
|
end
|
|
55
70
|
end
|
|
56
71
|
end
|
|
57
|
-
end
|
|
72
|
+
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
require 'kameleoon/data/manager/page_view_visit'
|
|
4
4
|
require 'kameleoon/data/manager/assigned_variation'
|
|
5
5
|
require 'kameleoon/data/visitor_visits'
|
|
@@ -8,13 +8,15 @@ require 'kameleoon/data/device'
|
|
|
8
8
|
require 'kameleoon/data/conversion'
|
|
9
9
|
require 'kameleoon/data/custom_data'
|
|
10
10
|
require 'kameleoon/data/geolocation'
|
|
11
|
+
require 'kameleoon/data/kcs_heat'
|
|
11
12
|
require 'kameleoon/data/page_view'
|
|
12
13
|
|
|
13
14
|
module Kameleoon
|
|
14
15
|
module Managers
|
|
15
16
|
module RemoteData
|
|
16
17
|
class RemoteVisitorData
|
|
17
|
-
attr_reader :custom_data_dict, :page_view_visits, :conversions, :experiments, :device, :browser,
|
|
18
|
+
attr_reader :custom_data_dict, :page_view_visits, :conversions, :experiments, :device, :browser,
|
|
19
|
+
:operating_system, :geolocation, :previous_visitor_visits, :kcs_heat
|
|
18
20
|
|
|
19
21
|
def initialize(hash)
|
|
20
22
|
current_visit = hash['currentVisit']
|
|
@@ -30,12 +32,14 @@ module Kameleoon
|
|
|
30
32
|
end
|
|
31
33
|
@previous_visitor_visits = VisitorVisits.new(times_started)
|
|
32
34
|
end
|
|
35
|
+
@kcs_heat = parse_kcs_heat(hash['kcs'])
|
|
33
36
|
end
|
|
34
37
|
|
|
35
38
|
def collect_data_to_add
|
|
36
39
|
data_to_add = []
|
|
37
40
|
data_to_add.concat(@custom_data_dict.values) unless @custom_data_dict.nil?
|
|
38
41
|
data_to_add.push(@previous_visitor_visits) unless @previous_visitor_visits.nil?
|
|
42
|
+
data_to_add.push(@kcs_heat) unless @kcs_heat.nil?
|
|
39
43
|
data_to_add.concat(@page_view_visits.values) unless @page_view_visits.nil?
|
|
40
44
|
data_to_add.concat(@experiments.values) unless @experiments.nil?
|
|
41
45
|
data_to_add.concat(conversions_single_objects)
|
|
@@ -95,7 +99,7 @@ module Kameleoon
|
|
|
95
99
|
page_view_visit = @page_view_visits[href]
|
|
96
100
|
if page_view_visit.nil?
|
|
97
101
|
page_view = PageView.new(href, page_event['data']['title'])
|
|
98
|
-
@page_view_visits[href] =
|
|
102
|
+
@page_view_visits[href] = DataManager::PageViewVisit.new(page_view, 1, page_event['time'])
|
|
99
103
|
else
|
|
100
104
|
page_view_visit.increase_page_visits
|
|
101
105
|
end
|
|
@@ -108,7 +112,10 @@ module Kameleoon
|
|
|
108
112
|
id = experiment_event['data']['id']
|
|
109
113
|
variation = @experiments[id]
|
|
110
114
|
if variation.nil?
|
|
111
|
-
variation =
|
|
115
|
+
variation = DataManager::AssignedVariation.new(
|
|
116
|
+
id, experiment_event['data']['variationId'],
|
|
117
|
+
Configuration::RuleType::UNKNOWN, assignment_time: experiment_event['time']
|
|
118
|
+
)
|
|
112
119
|
@experiments[id] = variation
|
|
113
120
|
end
|
|
114
121
|
end
|
|
@@ -130,33 +137,52 @@ module Kameleoon
|
|
|
130
137
|
|
|
131
138
|
def parse_static_data(static_data_event)
|
|
132
139
|
return if @device != nil && @browser != nil && @operating_system != nil
|
|
140
|
+
|
|
133
141
|
data = static_data_event['data']
|
|
134
|
-
if @device
|
|
142
|
+
if @device.nil?
|
|
135
143
|
device_type = data['deviceType']
|
|
136
|
-
@device = Device.new(device_type)
|
|
144
|
+
@device = Device.new(device_type) unless device_type.nil?
|
|
137
145
|
end
|
|
138
|
-
if @browser
|
|
139
|
-
browser_type =
|
|
140
|
-
@browser = Browser.new(browser_type, data['browserVersion'])
|
|
146
|
+
if @browser.nil?
|
|
147
|
+
browser_type = BrowserType.from_name(data['browser'])
|
|
148
|
+
@browser = Browser.new(browser_type, data['browserVersion']) unless browser_type.nil?
|
|
141
149
|
end
|
|
142
|
-
if @operating_system
|
|
143
|
-
operating_system_type =
|
|
144
|
-
@operating_system = OperatingSystem.new(operating_system_type)
|
|
150
|
+
if @operating_system.nil?
|
|
151
|
+
operating_system_type = OperatingSystemType.from_name(data['os'])
|
|
152
|
+
@operating_system = OperatingSystem.new(operating_system_type) unless operating_system_type.nil?
|
|
145
153
|
end
|
|
146
154
|
end
|
|
147
155
|
|
|
148
156
|
def conversions_single_objects
|
|
149
157
|
objects = []
|
|
150
|
-
unless @conversions.nil?
|
|
151
|
-
objects += @conversions
|
|
152
|
-
end
|
|
158
|
+
objects += @conversions unless @conversions.nil?
|
|
153
159
|
objects.push(@device) unless @device.nil?
|
|
154
160
|
objects.push(@browser) unless @browser.nil?
|
|
155
161
|
objects.push(@operating_system) unless @operating_system.nil?
|
|
156
162
|
objects.push(@geolocation) unless @geolocation.nil?
|
|
157
163
|
objects
|
|
158
164
|
end
|
|
165
|
+
|
|
166
|
+
def parse_kcs_heat(kcs)
|
|
167
|
+
return nil if kcs.nil?
|
|
168
|
+
|
|
169
|
+
value_map = {}
|
|
170
|
+
kcs.each do |str_key_moment_id, goal_scores|
|
|
171
|
+
next unless str_key_moment_id.is_a?(String) && goal_scores.is_a?(Hash)
|
|
172
|
+
|
|
173
|
+
goal_score_map = {}
|
|
174
|
+
goal_scores.each do |str_goal_id, score|
|
|
175
|
+
next unless str_goal_id.is_a?(String) && (score.is_a?(Float) || score.is_a?(Integer))
|
|
176
|
+
|
|
177
|
+
goal_id = str_goal_id.to_i
|
|
178
|
+
goal_score_map[goal_id] = score
|
|
179
|
+
end
|
|
180
|
+
key_moment_id = str_key_moment_id.to_i
|
|
181
|
+
value_map[key_moment_id] = goal_score_map
|
|
182
|
+
end
|
|
183
|
+
KcsHeat.new(value_map)
|
|
184
|
+
end
|
|
159
185
|
end
|
|
160
186
|
end
|
|
161
187
|
end
|
|
162
|
-
end
|
|
188
|
+
end
|