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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kameleoon/configuration/custom_data_info.rb +16 -8
  3. data/lib/kameleoon/configuration/data_file.rb +40 -17
  4. data/lib/kameleoon/configuration/feature_flag.rb +10 -0
  5. data/lib/kameleoon/configuration/rule.rb +4 -0
  6. data/lib/kameleoon/configuration/settings.rb +13 -8
  7. data/lib/kameleoon/configuration/variation_exposition.rb +4 -0
  8. data/lib/kameleoon/data/browser.rb +4 -0
  9. data/lib/kameleoon/data/conversion.rb +4 -0
  10. data/lib/kameleoon/data/cookie.rb +4 -0
  11. data/lib/kameleoon/data/custom_data.rb +11 -3
  12. data/lib/kameleoon/data/data.rb +30 -4
  13. data/lib/kameleoon/data/device.rb +4 -0
  14. data/lib/kameleoon/data/geolocation.rb +5 -0
  15. data/lib/kameleoon/data/kcs_heat.rb +16 -0
  16. data/lib/kameleoon/data/manager/assigned_variation.rb +5 -0
  17. data/lib/kameleoon/data/manager/data_array_storage.rb +7 -0
  18. data/lib/kameleoon/data/manager/data_map_storage.rb +7 -0
  19. data/lib/kameleoon/data/manager/page_view_visit.rb +4 -0
  20. data/lib/kameleoon/data/manager/visitor.rb +198 -67
  21. data/lib/kameleoon/data/manager/visitor_manager.rb +54 -17
  22. data/lib/kameleoon/data/mapping_identifier.rb +33 -0
  23. data/lib/kameleoon/data/operating_system.rb +4 -0
  24. data/lib/kameleoon/data/page_view.rb +6 -1
  25. data/lib/kameleoon/data/unique_identifier.rb +11 -0
  26. data/lib/kameleoon/data/user_agent.rb +4 -0
  27. data/lib/kameleoon/data/visitor_visits.rb +12 -1
  28. data/lib/kameleoon/hybrid/manager.rb +13 -4
  29. data/lib/kameleoon/kameleoon_client.rb +348 -146
  30. data/lib/kameleoon/kameleoon_client_config.rb +64 -17
  31. data/lib/kameleoon/kameleoon_client_factory.rb +15 -2
  32. data/lib/kameleoon/logging/default_logger.rb +20 -0
  33. data/lib/kameleoon/logging/kameleoon_logger.rb +77 -0
  34. data/lib/kameleoon/logging/logger.rb +12 -0
  35. data/lib/kameleoon/managers/data/data_manager.rb +36 -0
  36. data/lib/kameleoon/managers/remote_data/remote_data_manager.rb +33 -18
  37. data/lib/kameleoon/managers/remote_data/remote_visitor_data.rb +42 -16
  38. data/lib/kameleoon/managers/tracking/tracking_builder.rb +149 -0
  39. data/lib/kameleoon/managers/tracking/tracking_manager.rb +97 -0
  40. data/lib/kameleoon/managers/tracking/visitor_tracking_registry.rb +94 -0
  41. data/lib/kameleoon/managers/warehouse/warehouse_manager.rb +22 -5
  42. data/lib/kameleoon/network/access_token_source.rb +46 -14
  43. data/lib/kameleoon/network/cookie/cookie_manager.rb +45 -7
  44. data/lib/kameleoon/network/net_provider.rb +2 -3
  45. data/lib/kameleoon/network/network_manager.rb +16 -21
  46. data/lib/kameleoon/network/request.rb +14 -3
  47. data/lib/kameleoon/network/response.rb +4 -0
  48. data/lib/kameleoon/network/url_provider.rb +11 -10
  49. data/lib/kameleoon/real_time/real_time_configuration_service.rb +10 -11
  50. data/lib/kameleoon/sdk_version.rb +31 -0
  51. data/lib/kameleoon/targeting/condition.rb +6 -2
  52. data/lib/kameleoon/targeting/condition_factory.rb +3 -0
  53. data/lib/kameleoon/targeting/conditions/browser_condition.rb +3 -3
  54. data/lib/kameleoon/targeting/conditions/cookie_condition.rb +10 -10
  55. data/lib/kameleoon/targeting/conditions/geolocation_condition.rb +0 -1
  56. data/lib/kameleoon/targeting/conditions/kcs_heat_range_condition.rb +37 -0
  57. data/lib/kameleoon/targeting/conditions/number_condition.rb +4 -4
  58. data/lib/kameleoon/targeting/conditions/operating_system_condition.rb +1 -2
  59. data/lib/kameleoon/targeting/conditions/sdk_language_condition.rb +2 -1
  60. data/lib/kameleoon/targeting/conditions/segment_condition.rb +3 -3
  61. data/lib/kameleoon/targeting/conditions/string_value_condition.rb +2 -1
  62. data/lib/kameleoon/targeting/conditions/target_feature_flag_condition.rb +7 -11
  63. data/lib/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.rb +1 -2
  64. data/lib/kameleoon/targeting/conditions/visit_number_today_condition.rb +4 -4
  65. data/lib/kameleoon/targeting/conditions/visit_number_total_condition.rb +5 -3
  66. data/lib/kameleoon/targeting/conditions/visitor_new_return_condition.rb +7 -6
  67. data/lib/kameleoon/targeting/models.rb +0 -14
  68. data/lib/kameleoon/targeting/targeting_manager.rb +37 -7
  69. data/lib/kameleoon/targeting/tree_builder.rb +10 -5
  70. data/lib/kameleoon/types/remote_visitor_data_filter.rb +21 -3
  71. data/lib/kameleoon/types/variable.rb +21 -0
  72. data/lib/kameleoon/types/variation.rb +22 -0
  73. data/lib/kameleoon/utils.rb +18 -0
  74. data/lib/kameleoon/version.rb +1 -27
  75. 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, :verbose_mode
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: false
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
- @verbose_mode = verbose_mode || false
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
- log('Configuration refresh interval must have positive value. ' \
35
- "Default refresh interval (#{DEFAULT_REFRESH_INTERVAL_MINUTES} minutes) is applied.")
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
- log('Session duration must have positive value. ' \
44
- "Default session duration (#{DEFAULT_SESSION_DURATION_MINUTES} minutes) is applied.")
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
- log('Default timeout must have positive value. ' \
53
- "Default timeout (#{DEFAULT_TIMEOUT_MILLISECONDS} ms) is applied.")
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
- log('Setting top level domain is strictly recommended, otherwise you may have problems when using subdomains.')
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
- warn "Kameleoon SDK: Configuration file with path #{path} does not exist"
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,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kameleoon
4
+ module Logging
5
+ class Logger
6
+
7
+ def log(level, message)
8
+ raise NotImplementedError, 'Subclasses must implement log(level, message)'
9
+ end
10
+ end
11
+ end
12
+ 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, :log_func
12
+ attr_reader :network_manager, :visitor_manger
12
13
 
13
- def initialize(network_manager, visitor_manger, log_func = nil)
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
- @log_func = log_func
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
- log("Parsing of visitor data of '#{key}' failed: #{e}")
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, is_unique_identifier = false, timeout = 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 = Kameleoon::Types::RemoteVisitorDataFilter.new unless filter.is_a?(Kameleoon::Types::RemoteVisitorDataFilter)
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(@log_func, *data_to_add, overwrite: false)
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 = Kameleoon::Managers::RemoteData::RemoteVisitorData.new(JSON.parse(response))
44
- remote_visitor_data.mark_data_as_sent(@visitor_manger.custom_data_info)
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
- log("Parsing of visitor data of '#{visitor_code}' failed: #{e}")
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, :operating_system, :geolocation, :previous_visitor_visits
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] = Kameleoon::DataManager::PageViewVisit.new(page_view, 1, page_event['time'])
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 = Kameleoon::DataManager::AssignedVariation.new(id, experiment_event['data']['variationId'], Kameleoon::Configuration::RuleType::UNKNOWN, assignment_time: experiment_event['time'])
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 == nil
142
+ if @device.nil?
135
143
  device_type = data['deviceType']
136
- @device = Device.new(device_type) if device_type != nil
144
+ @device = Device.new(device_type) unless device_type.nil?
137
145
  end
138
- if @browser == nil
139
- browser_type = Kameleoon::BrowserType.from_name(data['browser'])
140
- @browser = Browser.new(browser_type, data['browserVersion']) if browser_type != nil
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 == nil
143
- operating_system_type = Kameleoon::OperatingSystemType.from_name(data['os'])
144
- @operating_system = OperatingSystem.new(operating_system_type) if operating_system_type != nil
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