kameleoon-client-ruby 3.1.1 → 3.3.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/custom_data_info.rb +43 -0
- data/lib/kameleoon/configuration/data_file.rb +31 -2
- data/lib/kameleoon/configuration/rule.rb +4 -1
- data/lib/kameleoon/configuration/variation_exposition.rb +1 -1
- data/lib/kameleoon/data/browser.rb +19 -0
- data/lib/kameleoon/data/cookie.rb +14 -0
- data/lib/kameleoon/data/custom_data.rb +2 -0
- data/lib/kameleoon/data/data.rb +2 -0
- data/lib/kameleoon/data/geolocation.rb +45 -0
- data/lib/kameleoon/data/kcs_heat.rb +12 -0
- data/lib/kameleoon/data/manager/assigned_variation.rb +2 -1
- data/lib/kameleoon/data/manager/page_view_visit.rb +16 -2
- data/lib/kameleoon/data/manager/visitor.rb +71 -14
- data/lib/kameleoon/data/manager/visitor_manager.rb +23 -1
- data/lib/kameleoon/data/operating_system.rb +72 -0
- data/lib/kameleoon/data/page_view.rb +2 -2
- data/lib/kameleoon/data/visitor_visits.rb +20 -0
- data/lib/kameleoon/kameleoon_client.rb +122 -94
- data/lib/kameleoon/managers/remote_data/remote_data_manager.rb +55 -0
- data/lib/kameleoon/managers/remote_data/remote_visitor_data.rb +188 -0
- data/lib/kameleoon/managers/warehouse/warehouse_manager.rb +3 -1
- data/lib/kameleoon/network/access_token_source.rb +22 -5
- data/lib/kameleoon/network/network_manager.rb +10 -10
- data/lib/kameleoon/network/response.rb +1 -1
- data/lib/kameleoon/network/url_provider.rb +16 -12
- data/lib/kameleoon/targeting/condition.rb +24 -2
- data/lib/kameleoon/targeting/condition_factory.rb +39 -6
- data/lib/kameleoon/targeting/conditions/cookie_condition.rb +55 -0
- data/lib/kameleoon/targeting/conditions/exclusive_feature_flag_condition.rb +27 -0
- data/lib/kameleoon/targeting/conditions/geolocation_condition.rb +33 -0
- data/lib/kameleoon/targeting/conditions/kcs_heat_range_condition.rb +37 -0
- data/lib/kameleoon/targeting/conditions/number_condition.rb +38 -0
- data/lib/kameleoon/targeting/conditions/operating_system_condition.rb +27 -0
- data/lib/kameleoon/targeting/conditions/page_view_number_condition.rb +28 -0
- data/lib/kameleoon/targeting/conditions/previous_page_condition.rb +35 -0
- data/lib/kameleoon/targeting/conditions/segment_condition.rb +42 -0
- data/lib/kameleoon/targeting/conditions/target_feature_flag_condition.rb +59 -0
- data/lib/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.rb +29 -0
- data/lib/kameleoon/targeting/conditions/visit_number_today_condition.rb +28 -0
- data/lib/kameleoon/targeting/conditions/visit_number_total_condition.rb +23 -0
- data/lib/kameleoon/targeting/conditions/visitor_new_return_condition.rb +34 -0
- data/lib/kameleoon/targeting/targeting_manager.rb +68 -0
- data/lib/kameleoon/types/remote_visitor_data_filter.rb +29 -0
- data/lib/kameleoon/types/variable.rb +17 -0
- data/lib/kameleoon/types/variation.rb +18 -0
- data/lib/kameleoon/utils.rb +1 -0
- data/lib/kameleoon/version.rb +1 -1
- metadata +28 -4
- data/lib/kameleoon/targeting/conditions/exclusive_experiment.rb +0 -18
- data/lib/kameleoon/targeting/conditions/target_experiment.rb +0 -45
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '019ae7a1fe145f50f68beea1eb05bcae993d4061a2b1bdb2fe4324fc4215aa39'
|
4
|
+
data.tar.gz: fe9637047ba81b006c1b19a4c85e82fa5641a4d3f666fe14cb28ee243076b6ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5455718dd4a68c584c280e4004ff1c96e28b35d7bfcd9bd8299c68b9d0f3930bd064e16057ce71bbfc386911f106839f54a6398165e6966cad5ce5a4388ccbe9
|
7
|
+
data.tar.gz: 7a2e231a4625c642a56354615999543c26d7e882d8fc7a2c743f7f4f045d01bc88d5dafd227757fd88f308053610f22f21bfa6cbadd79eafe2b7f2bc3a5e03b7
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kameleoon
|
4
|
+
# Module which contains all internal data of SDK
|
5
|
+
module Configuration
|
6
|
+
|
7
|
+
class CustomDataInfo
|
8
|
+
attr_reader :local_only, :visitor_scope, :mapping_identifier_index
|
9
|
+
SCOPE_VISITOR = 'VISITOR'
|
10
|
+
|
11
|
+
def initialize(hashes, log_func = nil)
|
12
|
+
@local_only = Set[]
|
13
|
+
@visitor_scope = Set[]
|
14
|
+
@log_func = log_func
|
15
|
+
unless hashes.nil?
|
16
|
+
for hash in hashes
|
17
|
+
index = hash['index']
|
18
|
+
@local_only.add(index) if hash['localOnly']
|
19
|
+
@visitor_scope.add(index) if hash['scope'] == SCOPE_VISITOR
|
20
|
+
if hash['isMappingIdentifier']
|
21
|
+
if @mapping_identifier_index != nil
|
22
|
+
@log_func&.call('More than one mapping identifier is set. Undefined behavior may occur on cross-device reconciliation.')
|
23
|
+
end
|
24
|
+
@mapping_identifier_index = index
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def local_only? (index)
|
31
|
+
@local_only.include?(index)
|
32
|
+
end
|
33
|
+
|
34
|
+
def mapping_identifier? (index)
|
35
|
+
index == @mapping_identifier_index
|
36
|
+
end
|
37
|
+
|
38
|
+
def visitor_scope? (index)
|
39
|
+
@visitor_scope.include?(index)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,16 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'kameleoon/configuration/settings'
|
4
|
+
require 'kameleoon/configuration/feature_flag'
|
5
|
+
require 'kameleoon/configuration/custom_data_info'
|
4
6
|
|
5
7
|
module Kameleoon
|
6
8
|
module Configuration
|
7
9
|
class DataFile
|
8
|
-
attr_reader :settings, :feature_flags, :has_any_targeted_delivery_rule
|
10
|
+
attr_reader :settings, :feature_flags, :has_any_targeted_delivery_rule, :feature_flag_by_id, :rule_by_segment_id,
|
11
|
+
:variation_by_id, :custom_data_info
|
9
12
|
|
10
|
-
def initialize(environment)
|
13
|
+
def initialize(environment, log_func = nil)
|
11
14
|
@settings = Settings.new
|
12
15
|
@feature_flags = {}
|
13
16
|
@environment = environment
|
17
|
+
@log_func = log_func
|
18
|
+
collect_indices
|
19
|
+
@custom_data_info = Kameleoon::Configuration::CustomDataInfo.new(nil, @log_func)
|
14
20
|
end
|
15
21
|
|
16
22
|
def init(configuration)
|
@@ -20,6 +26,8 @@ module Kameleoon
|
|
20
26
|
@feature_flags[ff.feature_key] = ff
|
21
27
|
end
|
22
28
|
@has_any_targeted_delivery_rule = any_targeted_delivery_rule?
|
29
|
+
collect_indices
|
30
|
+
@custom_data_info = CustomDataInfo.new(configuration['customData'], @log_func)
|
23
31
|
self
|
24
32
|
end
|
25
33
|
|
@@ -36,6 +44,27 @@ module Kameleoon
|
|
36
44
|
def any_targeted_delivery_rule?
|
37
45
|
@feature_flags.any? { |_, ff| ff.environment_enabled && ff.rules.any?(&:targeted_delivery_type?) }
|
38
46
|
end
|
47
|
+
|
48
|
+
def collect_indices
|
49
|
+
@feature_flag_by_id = {}
|
50
|
+
@rule_by_segment_id = {}
|
51
|
+
@variation_by_id = {}
|
52
|
+
|
53
|
+
@feature_flags.each_value do |feature_flag|
|
54
|
+
@feature_flag_by_id[feature_flag.id] = feature_flag
|
55
|
+
next if feature_flag.rules.nil?
|
56
|
+
|
57
|
+
feature_flag.rules.each do |rule|
|
58
|
+
@rule_by_segment_id[rule.segment_id] = rule
|
59
|
+
rule.variation_by_exposition.each do |variation|
|
60
|
+
@variation_by_id[variation.variation_id] = variation
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
@feature_flag_by_id.freeze
|
65
|
+
@rule_by_segment_id.freeze
|
66
|
+
@variation_by_id.freeze
|
67
|
+
end
|
39
68
|
end
|
40
69
|
end
|
41
70
|
end
|
@@ -29,7 +29,7 @@ module Kameleoon
|
|
29
29
|
|
30
30
|
# Rule is a class for new rules of feature flags
|
31
31
|
class Rule
|
32
|
-
attr_reader :id, :order, :type, :exposition, :experiment_id, :variation_by_exposition, :respool_time
|
32
|
+
attr_reader :id, :order, :type, :exposition, :experiment_id, :variation_by_exposition, :respool_time, :segment_id, :first_variation
|
33
33
|
attr_accessor :targeting_segment
|
34
34
|
|
35
35
|
def self.create_from_array(array)
|
@@ -44,7 +44,10 @@ module Kameleoon
|
|
44
44
|
@experiment_id = hash['experimentId']
|
45
45
|
@respool_time = hash['respoolTime']
|
46
46
|
@variation_by_exposition = VariationByExposition.create_from_array(hash['variationByExposition'])
|
47
|
+
@variation_by_exposition.freeze
|
48
|
+
@first_variation = @variation_by_exposition.first
|
47
49
|
@targeting_segment = Kameleoon::Targeting::Segment.new((hash['segment'])) if hash['segment']
|
50
|
+
@segment_id = @targeting_segment != nil ? targeting_segment.id : -1
|
48
51
|
end
|
49
52
|
|
50
53
|
def get_variation(hash_double)
|
@@ -5,7 +5,7 @@ module Kameleoon
|
|
5
5
|
module Configuration
|
6
6
|
# VariationByExposition represents a variation with exposition rate for rule
|
7
7
|
class VariationByExposition
|
8
|
-
|
8
|
+
attr_reader :variation_key, :variation_id, :exposition
|
9
9
|
|
10
10
|
def self.create_from_array(array)
|
11
11
|
array&.map { |it| VariationByExposition.new(it) }
|
@@ -12,6 +12,25 @@ module Kameleoon
|
|
12
12
|
SAFARI = 3
|
13
13
|
OPERA = 4
|
14
14
|
OTHER = 5
|
15
|
+
|
16
|
+
def self.from_name(name)
|
17
|
+
case name
|
18
|
+
when 'CHROME'
|
19
|
+
BrowserType::CHROME
|
20
|
+
when 'INTERNET_EXPLORER'
|
21
|
+
BrowserType::INTERNET_EXPLORER
|
22
|
+
when 'FIREFOX'
|
23
|
+
BrowserType::FIREFOX
|
24
|
+
when 'SAFARI'
|
25
|
+
BrowserType::SAFARI
|
26
|
+
when 'OPERA'
|
27
|
+
BrowserType::OPERA
|
28
|
+
when 'OTHER'
|
29
|
+
BrowserType::OTHER
|
30
|
+
else
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
15
34
|
end
|
16
35
|
|
17
36
|
# Represents browser data for tracking calls
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kameleoon
|
4
|
+
# Cookie contains information about the cookie stored on the visitor's device
|
5
|
+
class Cookie
|
6
|
+
attr_reader :cookies
|
7
|
+
|
8
|
+
# @param [Hash] cookies
|
9
|
+
def initialize(cookies)
|
10
|
+
@cookies = cookies
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -8,6 +8,7 @@ module Kameleoon
|
|
8
8
|
# Represents any custom data for targeting conditions
|
9
9
|
class CustomData < DuplicationUnsafeData
|
10
10
|
attr_reader :id, :values
|
11
|
+
attr_accessor :is_mapping_identifier
|
11
12
|
|
12
13
|
# @param [Integer] id Id of the custom data
|
13
14
|
# @param [String] value Value of the custom data
|
@@ -50,6 +51,7 @@ module Kameleoon
|
|
50
51
|
overwrite: 'true',
|
51
52
|
nonce: nonce
|
52
53
|
}
|
54
|
+
params[:mappingIdentifier] = is_mapping_identifier if is_mapping_identifier
|
53
55
|
Kameleoon::Network::UriHelper.encode_query(params)
|
54
56
|
end
|
55
57
|
end
|
data/lib/kameleoon/data/data.rb
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kameleoon
|
4
|
+
# Geolocation contains the visitor's geolocation details
|
5
|
+
class Geolocation < DuplicationUnsafeData
|
6
|
+
attr_reader :country, :region, :city, :postal_code, :latitude, :longitude
|
7
|
+
|
8
|
+
# @param [String] country Country of visitor's geolocation. Required
|
9
|
+
# @param [String] region Region of visitor's geolocation. Optional
|
10
|
+
# @param [String] city City of visitor's geolocation. Optional
|
11
|
+
# @param [String] postal_code Postal code of visitor's geolocation. Optional
|
12
|
+
# @param [Float] latitude Latitude of visitor's geolocation. Optional
|
13
|
+
# @param [Float] longitude Longitude of visitor's geolocation. Optional
|
14
|
+
def initialize(country, region = nil, city = nil, postal_code = nil, latitude = Float::NAN, longitude = Float::NAN)
|
15
|
+
super(DataType::GEOLOCATION)
|
16
|
+
@country = country
|
17
|
+
@region = region
|
18
|
+
@city = city
|
19
|
+
@postal_code = postal_code
|
20
|
+
@latitude = latitude
|
21
|
+
@longitude = longitude
|
22
|
+
end
|
23
|
+
|
24
|
+
def obtain_full_post_text_line
|
25
|
+
params = {
|
26
|
+
eventType: 'staticData',
|
27
|
+
nonce: nonce
|
28
|
+
}
|
29
|
+
params[:country] = @country if @country.is_a?(String)
|
30
|
+
params[:region] = @region if @region.is_a?(String)
|
31
|
+
params[:city] = @city if @city.is_a?(String)
|
32
|
+
params[:postalCode] = @postal_code if @postal_code.is_a?(String)
|
33
|
+
params[:latitude] = @latitude if valid_number?(@latitude)
|
34
|
+
params[:longitude] = @longitude if valid_number?(@longitude)
|
35
|
+
Kameleoon::Network::UriHelper.encode_query(params)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def valid_number?(value)
|
41
|
+
value.is_a?(Integer) || (value.is_a?(Float) && !value.nan?)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'kameleoon/data/data'
|
4
4
|
require 'kameleoon/network/uri_helper'
|
5
|
+
require 'kameleoon/configuration/rule'
|
5
6
|
|
6
7
|
module Kameleoon
|
7
8
|
module DataManager
|
@@ -12,7 +13,7 @@ module Kameleoon
|
|
12
13
|
|
13
14
|
attr_reader :experiment_id, :variation_id, :rule_type, :assignment_time
|
14
15
|
|
15
|
-
def initialize(experiment_id, variation_id, rule_type, assignment_time: nil)
|
16
|
+
def initialize(experiment_id, variation_id, rule_type = Kameleoon::Configuration::RuleType::UNKNOWN, assignment_time: nil)
|
16
17
|
super(DataType::ASSIGNED_VARIATION)
|
17
18
|
@experiment_id = experiment_id
|
18
19
|
@variation_id = variation_id
|
@@ -3,17 +3,31 @@
|
|
3
3
|
module Kameleoon
|
4
4
|
module DataManager
|
5
5
|
class PageViewVisit
|
6
|
-
attr_reader :page_view, :count
|
6
|
+
attr_reader :page_view, :count, :last_timestamp
|
7
7
|
|
8
|
-
def initialize(page_view, count = 1)
|
8
|
+
def initialize(page_view, count = 1, timestamp = nil)
|
9
9
|
@page_view = page_view
|
10
10
|
@count = count
|
11
|
+
@last_timestamp = timestamp != nil ? timestamp : Time.new.to_i
|
11
12
|
end
|
12
13
|
|
14
|
+
# Not thread-save method, should be called in synchronized code
|
15
|
+
# We need to return a new PageViewVisit for case if PageView was already sent and it's new visit
|
13
16
|
def overwrite(page_view)
|
14
17
|
@page_view = page_view
|
15
18
|
@count += 1
|
16
19
|
end
|
20
|
+
|
21
|
+
# Not thread-save method, should be called in synchronized code
|
22
|
+
def merge (page_view_visit)
|
23
|
+
@count += page_view_visit.count
|
24
|
+
@last_timestamp = [@last_timestamp, page_view_visit.last_timestamp].max
|
25
|
+
end
|
26
|
+
|
27
|
+
# Not thread-save method, should be called in synchronized code
|
28
|
+
def increase_page_visits
|
29
|
+
@count += 1
|
30
|
+
end
|
17
31
|
end
|
18
32
|
end
|
19
33
|
end
|
@@ -18,8 +18,9 @@ module Kameleoon
|
|
18
18
|
# Visitor is a container of all data assigned to a visitor.
|
19
19
|
# It is thread-safe
|
20
20
|
class Visitor
|
21
|
-
attr_reader :last_activity_time, :user_agent, :device, :browser
|
22
|
-
|
21
|
+
attr_reader :last_activity_time, :user_agent, :device, :browser, :geolocation, :operating_system, :cookie,
|
22
|
+
:kcs_heat, :visitor_visits
|
23
|
+
attr_accessor :legal_consent, :mapping_identifier
|
23
24
|
|
24
25
|
def initialize
|
25
26
|
@mutex = Concurrent::ReadWriteLock.new
|
@@ -34,6 +35,8 @@ module Kameleoon
|
|
34
35
|
def enumerate_sendable_data(&blk)
|
35
36
|
blk.call(@device) unless @device.nil?
|
36
37
|
blk.call(@browser) unless @browser.nil?
|
38
|
+
blk.call(@operating_system) unless @operating_system.nil?
|
39
|
+
blk.call(@geolocation) unless @geolocation.nil?
|
37
40
|
@mutex.with_read_lock do
|
38
41
|
@custom_data_map&.each { |_, cd| blk.call(cd) }
|
39
42
|
@page_view_visits&.each { |_, pvv| blk.call(pvv.page_view) }
|
@@ -47,6 +50,8 @@ module Kameleoon
|
|
47
50
|
@mutex.with_read_lock do
|
48
51
|
count += 1 unless @device.nil?
|
49
52
|
count += 1 unless @browser.nil?
|
53
|
+
count += 1 unless @geolocation.nil?
|
54
|
+
count += 1 unless @operating_system.nil?
|
50
55
|
count += @custom_data_map.size unless @custom_data_map.nil?
|
51
56
|
count += @page_view_visits.size unless @page_view_visits.nil?
|
52
57
|
count += @conversions.size unless @conversions.nil?
|
@@ -71,22 +76,36 @@ module Kameleoon
|
|
71
76
|
DataMapStorage.new(@mutex, @variations)
|
72
77
|
end
|
73
78
|
|
74
|
-
def add_data(log_func, *args)
|
79
|
+
def add_data(log_func, *args, overwrite: true)
|
75
80
|
@mutex.with_write_lock do
|
76
81
|
args.each do |data|
|
77
82
|
case data
|
78
83
|
when Kameleoon::UserAgent
|
79
|
-
|
84
|
+
set_user_agent(data)
|
85
|
+
when Kameleoon::DataManager::AssignedVariation
|
86
|
+
add_variation(data, overwrite)
|
80
87
|
when Kameleoon::Device
|
81
|
-
|
88
|
+
set_device(data, overwrite)
|
82
89
|
when Kameleoon::Browser
|
83
|
-
|
90
|
+
set_browser(data, overwrite)
|
84
91
|
when Kameleoon::CustomData
|
85
|
-
add_custom_data(data)
|
92
|
+
add_custom_data(data, overwrite)
|
86
93
|
when Kameleoon::PageView
|
87
94
|
add_page_view(data)
|
95
|
+
when Kameleoon::DataManager::PageViewVisit
|
96
|
+
add_page_view_visit(data)
|
88
97
|
when Kameleoon::Conversion
|
89
98
|
add_conversion(data)
|
99
|
+
when Kameleoon::Cookie
|
100
|
+
set_cookie(data)
|
101
|
+
when Kameleoon::OperatingSystem
|
102
|
+
set_operating_system(data, overwrite)
|
103
|
+
when Kameleoon::Geolocation
|
104
|
+
set_geolocation(data, overwrite)
|
105
|
+
when Kameleoon::KcsHeat
|
106
|
+
set_kcs_heat(data)
|
107
|
+
when Kameleoon::VisitorVisits
|
108
|
+
set_visitor_visits(data)
|
90
109
|
else
|
91
110
|
log_func&.call("Data has unsupported type '#{data.class}'")
|
92
111
|
end
|
@@ -103,21 +122,28 @@ module Kameleoon
|
|
103
122
|
|
104
123
|
private
|
105
124
|
|
106
|
-
def
|
125
|
+
def set_user_agent(user_agent)
|
107
126
|
@user_agent = user_agent.value
|
108
127
|
end
|
109
128
|
|
110
|
-
def
|
111
|
-
@device = device
|
129
|
+
def set_device(device, overwrite)
|
130
|
+
@device = device if overwrite || @device == nil
|
112
131
|
end
|
113
132
|
|
114
|
-
def
|
115
|
-
@
|
133
|
+
def add_variation(variation, overwrite)
|
134
|
+
@variations = {} if @variations == nil
|
135
|
+
if overwrite || !@variations.include?(variation.experiment_id)
|
136
|
+
@variations[variation.experiment_id] = variation
|
137
|
+
end
|
116
138
|
end
|
117
139
|
|
118
|
-
def
|
140
|
+
def set_browser(browser, overwrite)
|
141
|
+
@browser = browser if overwrite || @browser == nil
|
142
|
+
end
|
143
|
+
|
144
|
+
def add_custom_data(custom_data, overwrite)
|
119
145
|
@custom_data_map = {} if @custom_data_map.nil?
|
120
|
-
@custom_data_map[custom_data.id] = custom_data
|
146
|
+
@custom_data_map[custom_data.id] = custom_data if overwrite || !@custom_data_map.include?(custom_data.id)
|
121
147
|
end
|
122
148
|
|
123
149
|
def add_page_view(page_view)
|
@@ -133,10 +159,41 @@ module Kameleoon
|
|
133
159
|
@page_view_visits[page_view.url] = visit
|
134
160
|
end
|
135
161
|
|
162
|
+
def add_page_view_visit(page_view_visit)
|
163
|
+
@page_view_visits = {} if @page_view_visits.nil?
|
164
|
+
visit = @page_view_visits[page_view_visit.page_view.url]
|
165
|
+
if visit.nil?
|
166
|
+
visit = page_view_visit
|
167
|
+
@page_view_visits[page_view_visit.page_view.url] = visit
|
168
|
+
else
|
169
|
+
visit.merge(page_view_visit)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
136
173
|
def add_conversion(conversion)
|
137
174
|
@conversions = [] if @conversions.nil?
|
138
175
|
@conversions.push(conversion)
|
139
176
|
end
|
177
|
+
|
178
|
+
def set_geolocation(geolocation, overwrite)
|
179
|
+
@geolocation = geolocation if overwrite || @geolocation == nil
|
180
|
+
end
|
181
|
+
|
182
|
+
def set_cookie(cookie)
|
183
|
+
@cookie = cookie
|
184
|
+
end
|
185
|
+
|
186
|
+
def set_operating_system(operating_system, overwrite)
|
187
|
+
@operating_system = operating_system if overwrite || @operating_system == nil
|
188
|
+
end
|
189
|
+
|
190
|
+
def set_kcs_heat(kcs_heat)
|
191
|
+
@kcs_heat = kcs_heat
|
192
|
+
end
|
193
|
+
|
194
|
+
def set_visitor_visits(visitor_visits)
|
195
|
+
@visitor_visits = visitor_visits
|
196
|
+
end
|
140
197
|
end
|
141
198
|
end
|
142
199
|
end
|
@@ -11,10 +11,12 @@ module Kameleoon
|
|
11
11
|
# It is thread-safe except `stop` method
|
12
12
|
class VisitorManager
|
13
13
|
attr_reader :expiration_period
|
14
|
+
attr_accessor :custom_data_info
|
14
15
|
|
15
|
-
def initialize(expiration_period)
|
16
|
+
def initialize(expiration_period, log_func = nil)
|
16
17
|
@expiration_period = expiration_period
|
17
18
|
@visitors = Concurrent::Map.new
|
19
|
+
@log_func = log_func
|
18
20
|
start
|
19
21
|
end
|
20
22
|
|
@@ -49,6 +51,26 @@ module Kameleoon
|
|
49
51
|
@visitors.size
|
50
52
|
end
|
51
53
|
|
54
|
+
def add_data(visitor_code, *args)
|
55
|
+
visitor = get_or_create_visitor(visitor_code)
|
56
|
+
for custom_data in args
|
57
|
+
next unless custom_data.is_a?(Kameleoon::CustomData)
|
58
|
+
# We shouldn't send custom data with local only type
|
59
|
+
custom_data.mark_as_sent if @custom_data_info.local_only?(custom_data.id)
|
60
|
+
# If mappingIdentifier is passed, we should link anonymous visitor with real unique userId.
|
61
|
+
# After authorization, customer must be able to continue work with userId, but hash for variation
|
62
|
+
# should be calculated based on anonymous visitor code, that's why set MappingIdentifier to visitor.
|
63
|
+
if @custom_data_info.mapping_identifier?(custom_data.id) && custom_data.values.size > 0 && custom_data.values[0].size > 0
|
64
|
+
custom_data.is_mapping_identifier = true
|
65
|
+
visitor.mapping_identifier = visitor_code
|
66
|
+
target_visitor_code = custom_data.values[0]
|
67
|
+
@visitors[target_visitor_code] = visitor if visitor_code != target_visitor_code
|
68
|
+
end
|
69
|
+
end
|
70
|
+
visitor.add_data(@log_func, *args)
|
71
|
+
visitor
|
72
|
+
end
|
73
|
+
|
52
74
|
private
|
53
75
|
|
54
76
|
def purge
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kameleoon
|
4
|
+
module OperatingSystemType
|
5
|
+
WINDOWS = 0
|
6
|
+
MAC = 1
|
7
|
+
IOS = 2
|
8
|
+
LINUX = 3
|
9
|
+
ANDROID = 4
|
10
|
+
WINDOWS_PHONE = 5
|
11
|
+
|
12
|
+
def self.from_name(name)
|
13
|
+
case name
|
14
|
+
when 'WINDOWS'
|
15
|
+
WINDOWS
|
16
|
+
when 'MAC'
|
17
|
+
MAC
|
18
|
+
when 'IOS'
|
19
|
+
IOS
|
20
|
+
when 'LINUX'
|
21
|
+
LINUX
|
22
|
+
when 'ANDROID'
|
23
|
+
ANDROID
|
24
|
+
when 'WINDOWS_PHONE'
|
25
|
+
WINDOWS_PHONE
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.name_from_type(operating_system_type)
|
32
|
+
case operating_system_type
|
33
|
+
when OperatingSystemType::WINDOWS
|
34
|
+
'WINDOWS'
|
35
|
+
when OperatingSystemType::MAC
|
36
|
+
'MAC'
|
37
|
+
when OperatingSystemType::IOS
|
38
|
+
'IOS'
|
39
|
+
when OperatingSystemType::LINUX
|
40
|
+
'LINUX'
|
41
|
+
when OperatingSystemType::ANDROID
|
42
|
+
'ANDROID'
|
43
|
+
when OperatingSystemType::WINDOWS_PHONE
|
44
|
+
'WINDOWS_PHONE'
|
45
|
+
else
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# OperatingSystem contains information about the operating system on the visitor's device
|
52
|
+
class OperatingSystem < DuplicationUnsafeData
|
53
|
+
attr_reader :os_type
|
54
|
+
|
55
|
+
# @param [OperatingSystemType] os_type Operating system type, can be: WINDOWS, MAC, IOS, LINUX, ANDROID, WINDOWS_PHONE
|
56
|
+
def initialize(os_type)
|
57
|
+
super(DataType::OPERATING_SYSTEM)
|
58
|
+
@os_type = os_type
|
59
|
+
end
|
60
|
+
|
61
|
+
def obtain_full_post_text_line
|
62
|
+
params = {
|
63
|
+
eventType: 'staticData',
|
64
|
+
os: OperatingSystemType.name_from_type(@os_type),
|
65
|
+
osIndex: @os_type,
|
66
|
+
nonce: nonce
|
67
|
+
}
|
68
|
+
Kameleoon::Network::UriHelper.encode_query(params)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -10,9 +10,9 @@ module Kameleoon
|
|
10
10
|
attr_reader :url, :title, :referrer
|
11
11
|
|
12
12
|
# @param [String] url Url of the page
|
13
|
-
# @param [String] title
|
13
|
+
# @param [String] title Optional field - title of the page
|
14
14
|
# @param [Array] referrers Optional field - Referrer ids
|
15
|
-
def initialize(url, title, referrers = nil)
|
15
|
+
def initialize(url, title = nil, referrers = nil)
|
16
16
|
super(DataType::PAGE_VIEW)
|
17
17
|
@url = url || ''
|
18
18
|
print('Kameleoon SDK: Url for PageView is required parameter, the data will be ignored.') if url == ''
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kameleoon
|
4
|
+
class VisitorVisits
|
5
|
+
attr_reader :previous_visit_timestamps
|
6
|
+
|
7
|
+
def initialize(previous_visit_timestamps = [])
|
8
|
+
@previous_visit_timestamps = previous_visit_timestamps
|
9
|
+
@previous_visit_timestamps.freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.get_previous_visit_timestamps(visitor_visits)
|
13
|
+
visitor_visits.is_a?(VisitorVisits) ? visitor_visits.previous_visit_timestamps : []
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.visitor_visits?(obj)
|
17
|
+
obj.nil? || obj.is_a?(VisitorVisits)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|