kameleoon-client-ruby 1.1.2 → 2.0.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/client.rb +456 -390
- data/lib/kameleoon/configuration/experiment.rb +42 -0
- data/lib/kameleoon/configuration/feature_flag.rb +41 -0
- data/lib/kameleoon/configuration/feature_flag_v2.rb +30 -0
- data/lib/kameleoon/configuration/rule.rb +45 -0
- data/lib/kameleoon/configuration/variable.rb +23 -0
- data/lib/kameleoon/configuration/variation.rb +31 -0
- data/lib/kameleoon/configuration/variation_exposition.rb +23 -0
- data/lib/kameleoon/cookie.rb +11 -4
- data/lib/kameleoon/data.rb +36 -22
- data/lib/kameleoon/exceptions.rb +46 -23
- data/lib/kameleoon/factory.rb +21 -18
- data/lib/kameleoon/request.rb +14 -13
- data/lib/kameleoon/storage/variation_storage.rb +42 -0
- data/lib/kameleoon/storage/visitor_variation.rb +20 -0
- data/lib/kameleoon/targeting/condition.rb +15 -3
- data/lib/kameleoon/targeting/condition_factory.rb +9 -2
- data/lib/kameleoon/targeting/conditions/custom_datum.rb +20 -36
- data/lib/kameleoon/targeting/conditions/exclusive_experiment.rb +29 -0
- data/lib/kameleoon/targeting/conditions/target_experiment.rb +44 -0
- data/lib/kameleoon/targeting/models.rb +36 -36
- data/lib/kameleoon/utils.rb +4 -1
- data/lib/kameleoon/version.rb +4 -2
- metadata +13 -3
- data/lib/kameleoon/query_graphql.rb +0 -76
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/targeting/models'
|
4
|
+
|
5
|
+
module Kameleoon
|
6
|
+
# Module which contains all internal data of SDK
|
7
|
+
module Configuration
|
8
|
+
# Class for manage all experiments and old feature flags
|
9
|
+
class Experiment
|
10
|
+
attr_accessor :id, :status, :site_enabled, :deviations, :respool_time, :variations, :targeting_segment
|
11
|
+
|
12
|
+
def self.create_from_array(array)
|
13
|
+
array&.map { |it| Experiment.new(it) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(experiment_hash)
|
17
|
+
@id = experiment_hash['id']
|
18
|
+
@status = experiment_hash['status']
|
19
|
+
@site_enabled = experiment_hash['siteEnabled']
|
20
|
+
unless experiment_hash['deviations'].nil?
|
21
|
+
@deviations =
|
22
|
+
Hash[*experiment_hash['deviations'].map do |it|
|
23
|
+
[it['variationId'] == 'origin' ? '0' : it['variationId'], it['value']]
|
24
|
+
end.flatten]
|
25
|
+
end
|
26
|
+
unless experiment_hash['respoolTime'].nil?
|
27
|
+
@respool_time =
|
28
|
+
Hash[*experiment_hash['respoolTime'].map do |it|
|
29
|
+
[it['variationId'] == 'origin' ? '0' : it['variationId'], it['value']]
|
30
|
+
end.flatten]
|
31
|
+
end
|
32
|
+
unless experiment_hash['variations'].nil?
|
33
|
+
@variations =
|
34
|
+
experiment_hash['variations'].map do |it|
|
35
|
+
{ 'id' => it['id'].to_i, 'customJson' => it['customJson'] }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
@targeting_segment = Kameleoon::Targeting::Segment.new((experiment_hash['segment'])) if experiment_hash['segment']
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'experiment'
|
4
|
+
|
5
|
+
module Kameleoon
|
6
|
+
# Module which contains all internal data of SDK
|
7
|
+
module Configuration
|
8
|
+
# Class for manage all experiments and old feature flags
|
9
|
+
class FeatureFlag < Experiment
|
10
|
+
STATUS_ACTIVE = 'ACTIVE'
|
11
|
+
FEATURE_STATUS_DEACTIVATED = 'DEACTIVATED'
|
12
|
+
attr_accessor :identification_key, :feature_status, :schedules, :exposition_rate
|
13
|
+
|
14
|
+
def self.create_from_array(array)
|
15
|
+
array&.map { |it| FeatureFlag.new(it) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(feature_flag_hash)
|
19
|
+
super(feature_flag_hash)
|
20
|
+
@feature_status = feature_flag_hash['featureStatus']
|
21
|
+
@identification_key = feature_flag_hash['identificationKey'] if feature_flag_hash['identificationKey']
|
22
|
+
@exposition_rate = feature_flag_hash['expositionRate']
|
23
|
+
@schedules = feature_flag_hash['schedules'] unless feature_flag_hash['schedules'].nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
def is_scheduled_active(date)
|
27
|
+
current_status = @status == STATUS_ACTIVE
|
28
|
+
if @feature_status == FEATURE_STATUS_DEACTIVATED || @schedules.empty?
|
29
|
+
return current_status
|
30
|
+
end
|
31
|
+
@schedules.each do |schedule|
|
32
|
+
if (schedule['dateStart'].nil? || Time.parse(schedule['dateStart']).to_i < date) &&
|
33
|
+
(schedule['dateEnd'].nil? || Time.parse(schedule['dateEnd']).to_i > date)
|
34
|
+
return true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'rule'
|
4
|
+
require_relative 'variation'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# Module which contains all internal data of SDK
|
8
|
+
module Configuration
|
9
|
+
# Class for manage all feature flags v2 with rules
|
10
|
+
class FeatureFlagV2
|
11
|
+
attr_accessor :id, :feature_key, :variations, :default_variation_key, :rules
|
12
|
+
|
13
|
+
def self.create_from_array(array)
|
14
|
+
array&.map { |it| FeatureFlagV2.new(it) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(hash)
|
18
|
+
@id = hash['id']
|
19
|
+
@feature_key = hash['featureKey']
|
20
|
+
@default_variation_key = hash['defaultVariationKey']
|
21
|
+
@variations = Variation.create_from_array(hash['variations'])
|
22
|
+
@rules = Rule.create_from_array(hash['rules'])
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_variation_key(key)
|
26
|
+
variations.select { |v| v.key == key }.first
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'variation_exposition'
|
4
|
+
require 'kameleoon/targeting/models'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# Module which contains all internal data of SDK
|
8
|
+
module Configuration
|
9
|
+
# RuleType has a possible rule types
|
10
|
+
module RuleType
|
11
|
+
EXPERIMENTATION = 'EXPERIMENTATION'
|
12
|
+
TARGETED_DELIVERY = 'TARGETED_DELIVERY'
|
13
|
+
end
|
14
|
+
|
15
|
+
# Rule is a class for new rules of feature flags
|
16
|
+
class Rule
|
17
|
+
attr_accessor :type, :exposition, :experiment_id, :variation_by_exposition, :targeting_segment
|
18
|
+
|
19
|
+
def self.create_from_array(array)
|
20
|
+
array&.map { |it| Rule.new(it) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(hash)
|
24
|
+
@type = hash['type']
|
25
|
+
@exposition = hash['exposition']
|
26
|
+
@experiment_id = hash['experimentId']
|
27
|
+
@variation_by_exposition = VariationByExposition.create_from_array(hash['variationByExposition'])
|
28
|
+
@targeting_segment = Kameleoon::Targeting::Segment.new((hash['segment'])) if hash['segment']
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_variation_key(hash_double)
|
32
|
+
total = 0.0
|
33
|
+
variation_by_exposition.each do |element|
|
34
|
+
total += element.exposition
|
35
|
+
return element.variation_key if total >= hash_double
|
36
|
+
end
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_variation_id_by_key(key)
|
41
|
+
variation_by_exposition.select { |v| v.variation_key == key }.first&.variation_id
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'experiment'
|
4
|
+
|
5
|
+
module Kameleoon
|
6
|
+
# Module which contains all internal data of SDK
|
7
|
+
module Configuration
|
8
|
+
# Variable class contains key / type / value of variable
|
9
|
+
class Variable
|
10
|
+
attr_accessor :key, :type, :value
|
11
|
+
|
12
|
+
def self.create_from_array(array)
|
13
|
+
array&.map { |it| Variable.new(it) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(hash)
|
17
|
+
@key = hash['key']
|
18
|
+
@type = hash['type']
|
19
|
+
@value = hash['value']
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'variable'
|
4
|
+
|
5
|
+
module Kameleoon
|
6
|
+
# Module which contains all internal data of SDK
|
7
|
+
module Configuration
|
8
|
+
# Constant values of types of variations
|
9
|
+
module VariationType
|
10
|
+
VARIATION_OFF = 'off'
|
11
|
+
end
|
12
|
+
|
13
|
+
# Variation of feature flag
|
14
|
+
class Variation
|
15
|
+
attr_accessor :key, :variables
|
16
|
+
|
17
|
+
def self.create_from_array(array)
|
18
|
+
array&.map { |it| Variation.new(it) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(hash)
|
22
|
+
@key = hash['key']
|
23
|
+
@variables = Variable.create_from_array(hash['variables'])
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_variable_by_key(key)
|
27
|
+
variables.select { |var| var.key == key }.first
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'experiment'
|
4
|
+
|
5
|
+
module Kameleoon
|
6
|
+
# Module which contains all internal data of SDK
|
7
|
+
module Configuration
|
8
|
+
# VariationByExposition represents a variation with exposition rate for rule
|
9
|
+
class VariationByExposition
|
10
|
+
attr_accessor :variation_key, :variation_id, :exposition
|
11
|
+
|
12
|
+
def self.create_from_array(array)
|
13
|
+
array&.map { |it| VariationByExposition.new(it) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(hash)
|
17
|
+
@variation_key = hash['variationKey']
|
18
|
+
@variation_id = hash['variationId']
|
19
|
+
@exposition = hash['exposition']
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/kameleoon/cookie.rb
CHANGED
@@ -23,12 +23,19 @@ module Kameleoon
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def obtain_hash_double(visitor_code, respool_times = {}, container_id = '')
|
26
|
+
obtain_hash_double_helper(visitor_code, respool_times, container_id, '')
|
27
|
+
end
|
28
|
+
|
29
|
+
def obtain_hash_double_v2(visitor_code, container_id = '', suffix = '')
|
30
|
+
obtain_hash_double_helper(visitor_code, {}, container_id, suffix)
|
31
|
+
end
|
32
|
+
|
33
|
+
def obtain_hash_double_helper(visitor_code, respool_times, container_id, suffix)
|
26
34
|
identifier = visitor_code.to_s
|
27
35
|
identifier += container_id.to_s
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
(Digest::SHA256.hexdigest(identifier.encode('UTF-8')).to_i(16) / (BigDecimal("2") ** BigDecimal("256"))).round(16)
|
36
|
+
identifier += suffix.to_s
|
37
|
+
identifier += respool_times.sort.to_h.values.join.to_s if !respool_times.nil? && !respool_times.empty?
|
38
|
+
(Digest::SHA256.hexdigest(identifier.encode('UTF-8')).to_i(16) / (BigDecimal('2')**BigDecimal('256'))).round(16)
|
32
39
|
end
|
33
40
|
|
34
41
|
def check_visitor_code(visitor_code)
|
data/lib/kameleoon/data.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kameleoon
|
2
4
|
NONCE_LENGTH = 16
|
3
5
|
|
4
6
|
module DataType
|
5
|
-
CUSTOM =
|
6
|
-
BROWSER =
|
7
|
-
CONVERSION =
|
8
|
-
|
9
|
-
PAGE_VIEW =
|
7
|
+
CUSTOM = 'CUSTOM'
|
8
|
+
BROWSER = 'BROWSER'
|
9
|
+
CONVERSION = 'CONVERSION'
|
10
|
+
DEVICE = 'DEVICE'
|
11
|
+
PAGE_VIEW = 'PAGE_VIEW'
|
10
12
|
end
|
11
13
|
|
12
14
|
module BrowserType
|
@@ -18,6 +20,12 @@ module Kameleoon
|
|
18
20
|
OTHER = 5
|
19
21
|
end
|
20
22
|
|
23
|
+
module DeviceType
|
24
|
+
PHONE = 'PHONE'
|
25
|
+
TABLET = 'TABLET'
|
26
|
+
DESKTOP = 'DESKTOP'
|
27
|
+
end
|
28
|
+
|
21
29
|
class Data
|
22
30
|
attr_accessor :instance, :sent
|
23
31
|
|
@@ -89,7 +97,7 @@ module Kameleoon
|
|
89
97
|
|
90
98
|
def obtain_full_post_text_line
|
91
99
|
nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
|
92
|
-
"eventType=staticData&
|
100
|
+
"eventType=staticData&browserIndex=" + @browser.to_s + "&nonce=" + nonce
|
93
101
|
end
|
94
102
|
end
|
95
103
|
|
@@ -98,22 +106,22 @@ module Kameleoon
|
|
98
106
|
|
99
107
|
# @param [String] url Url of the page
|
100
108
|
# @param [String] title Title of the page
|
101
|
-
# @param [
|
102
|
-
def initialize(url, title,
|
109
|
+
# @param [Array] referrers Optional field - Referrer ids
|
110
|
+
def initialize(url, title, referrers = nil)
|
103
111
|
@instance = DataType::PAGE_VIEW
|
104
112
|
@sent = false
|
105
113
|
@url = url
|
106
114
|
@title = title
|
107
|
-
@
|
115
|
+
@referrers = referrers
|
108
116
|
end
|
109
117
|
|
110
118
|
def obtain_full_post_text_line
|
111
119
|
nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
|
112
|
-
referrer_text =
|
113
|
-
unless @
|
114
|
-
referrer_text = "&
|
120
|
+
referrer_text = ''
|
121
|
+
unless @referrers.nil?
|
122
|
+
referrer_text = "&referrersIndices=" + @referrers.to_s
|
115
123
|
end
|
116
|
-
"eventType=page&href=" + encode(@url) + "&title=" + @title +
|
124
|
+
"eventType=page&href=" + encode(@url) + "&title=" + @title + referrer_text + "&nonce=" + nonce
|
117
125
|
end
|
118
126
|
end
|
119
127
|
|
@@ -137,19 +145,25 @@ module Kameleoon
|
|
137
145
|
end
|
138
146
|
end
|
139
147
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
def initialize(index)
|
145
|
-
@instance = DataType::INTEREST
|
148
|
+
# Device uses for sending deviceType parameter for tracking calls
|
149
|
+
class Device < Data
|
150
|
+
def initialize(device_type)
|
151
|
+
@instance = DataType::DEVICE
|
146
152
|
@sent = false
|
147
|
-
@
|
153
|
+
@device_type = device_type
|
148
154
|
end
|
149
155
|
|
150
156
|
def obtain_full_post_text_line
|
151
157
|
nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
|
152
|
-
"eventType=
|
158
|
+
"eventType=staticData&deviceType=#{@device_type}&nonce=#{nonce}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# UserAgent uses for changing User-Agent header for tracking calls
|
163
|
+
class UserAgent
|
164
|
+
attr_accessor :value
|
165
|
+
def initialize(value)
|
166
|
+
@value = value
|
153
167
|
end
|
154
168
|
end
|
155
|
-
end
|
169
|
+
end
|
data/lib/kameleoon/exceptions.rb
CHANGED
@@ -1,59 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kameleoon
|
2
4
|
module Exception
|
5
|
+
# Base Error
|
3
6
|
class KameleoonError < ::StandardError
|
4
7
|
def initialize(message = nil)
|
5
|
-
super("Kameleoon error: "
|
8
|
+
super("Kameleoon error: #{message}")
|
6
9
|
end
|
7
10
|
end
|
11
|
+
|
12
|
+
# Base Not Found Error
|
8
13
|
class NotFound < KameleoonError
|
9
|
-
def initialize(value =
|
10
|
-
super(value
|
14
|
+
def initialize(value = '')
|
15
|
+
super("#{value} not found.")
|
11
16
|
end
|
12
17
|
end
|
18
|
+
|
19
|
+
# Variation Not Found
|
13
20
|
class VariationConfigurationNotFound < NotFound
|
14
|
-
def initialize(id =
|
15
|
-
super("Variation "
|
21
|
+
def initialize(id = '')
|
22
|
+
super("Variation #{id}")
|
16
23
|
end
|
17
24
|
end
|
18
|
-
|
19
|
-
|
20
|
-
|
25
|
+
|
26
|
+
# Experiment Configuration Not Found
|
27
|
+
class ExperimentConfigurationNotFound < NotFound
|
28
|
+
def initialize(id = '')
|
29
|
+
super("Experiment #{id}")
|
21
30
|
end
|
22
31
|
end
|
32
|
+
|
33
|
+
# Feature Flag Configuration Not Found
|
23
34
|
class FeatureConfigurationNotFound < NotFound
|
24
|
-
def initialize(id =
|
25
|
-
super("Feature flag "
|
35
|
+
def initialize(id = '')
|
36
|
+
super("Feature flag #{id}")
|
26
37
|
end
|
27
38
|
end
|
39
|
+
|
40
|
+
# Feature Variable Not Found
|
28
41
|
class FeatureVariableNotFound < NotFound
|
29
|
-
def initialize(key =
|
30
|
-
super("Feature variable "
|
42
|
+
def initialize(key = '')
|
43
|
+
super("Feature variable #{key}")
|
31
44
|
end
|
32
45
|
end
|
46
|
+
|
47
|
+
# Credentials Not Found
|
33
48
|
class CredentialsNotFound < NotFound
|
34
49
|
def initialize
|
35
|
-
super(
|
50
|
+
super('Credentials')
|
36
51
|
end
|
37
52
|
end
|
53
|
+
|
54
|
+
# Not Targeted (when visitor is not targeted for experiment or feature flag)
|
38
55
|
class NotTargeted < KameleoonError
|
39
|
-
def initialize(visitor_code =
|
40
|
-
super("Visitor
|
56
|
+
def initialize(visitor_code = '')
|
57
|
+
super("Visitor #{visitor_code} is not targeted.")
|
41
58
|
end
|
42
59
|
end
|
43
|
-
|
44
|
-
|
45
|
-
|
60
|
+
|
61
|
+
# Not Allocated (when visitor is not allocated for experiment)
|
62
|
+
class NotAllocated < KameleoonError
|
63
|
+
def initialize(visitor_code = '')
|
64
|
+
super("Visitor #{visitor_code} is not targeted.")
|
46
65
|
end
|
47
66
|
end
|
67
|
+
|
68
|
+
# Visitor Code Not Valod (empty or length > 255)
|
48
69
|
class VisitorCodeNotValid < KameleoonError
|
49
|
-
def initialize(message =
|
50
|
-
super("Visitor code not valid: "
|
70
|
+
def initialize(message = '')
|
71
|
+
super("Visitor code not valid: #{message}")
|
51
72
|
end
|
52
73
|
end
|
74
|
+
|
75
|
+
# SiteCode Disabled
|
53
76
|
class SiteCodeDisabled < KameleoonError
|
54
|
-
def initialize(message =
|
55
|
-
super("Site with siteCode '
|
77
|
+
def initialize(message = '')
|
78
|
+
super("Site with siteCode '#{message}' is disabled")
|
56
79
|
end
|
57
80
|
end
|
58
81
|
end
|
59
|
-
end
|
82
|
+
end
|
data/lib/kameleoon/factory.rb
CHANGED
@@ -1,26 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'kameleoon/client'
|
2
4
|
|
3
5
|
module Kameleoon
|
6
|
+
# A Factory class for creating kameleoon clients
|
4
7
|
module ClientFactory
|
5
8
|
CONFIGURATION_UPDATE_INTERVAL = '60m'
|
6
|
-
CONFIG_PATH =
|
7
|
-
DEFAULT_TIMEOUT = 2000 #milli-seconds
|
9
|
+
CONFIG_PATH = '/etc/kameleoon/client-ruby.yaml'
|
10
|
+
DEFAULT_TIMEOUT = 2000 # milli-seconds
|
11
|
+
|
12
|
+
@clients = {}
|
13
|
+
|
14
|
+
def self.create(site_code, config_path = CONFIG_PATH, client_id = nil, client_secret = nil)
|
15
|
+
if @clients[site_code].nil?
|
16
|
+
client = Client.new(site_code, config_path, CONFIGURATION_UPDATE_INTERVAL,
|
17
|
+
DEFAULT_TIMEOUT, client_id, client_secret)
|
18
|
+
client.send(:log, "Client created with site code: #{site_code}")
|
19
|
+
client.send(:fetch_configuration)
|
20
|
+
@clients.store(site_code, client)
|
21
|
+
end
|
22
|
+
@clients[site_code]
|
23
|
+
end
|
8
24
|
|
9
|
-
|
10
|
-
|
11
|
-
# The starting point for using the SDK is the initialization step. All interaction with the SDK is done through an object of the Kameleoon::Client class, therefore you need to create this object via Kameleoon::ClientFactory create static method.
|
12
|
-
#
|
13
|
-
# @param [String] site_code Site code
|
14
|
-
# @param [Boolean] blocking - optional, default is false
|
15
|
-
#
|
16
|
-
# @return [Kameleoon::Client]
|
17
|
-
#
|
18
|
-
def self.create(site_code, blocking = false, config_path = CONFIG_PATH, client_id = nil, client_secret = nil)
|
19
|
-
client = Client.new(site_code, config_path, blocking, CONFIGURATION_UPDATE_INTERVAL, DEFAULT_TIMEOUT, client_id, client_secret)
|
20
|
-
client.send(:log, "Warning: you are using the blocking mode") if blocking
|
21
|
-
client.send(:log, "Client created with site code: " + site_code.to_s)
|
22
|
-
client.send(:fetch_configuration)
|
23
|
-
client
|
25
|
+
def self.forget(site_code)
|
26
|
+
@clients.delete(site_code)
|
24
27
|
end
|
25
28
|
end
|
26
|
-
end
|
29
|
+
end
|
data/lib/kameleoon/request.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'em-synchrony/em-http'
|
2
|
+
require 'kameleoon/version'
|
3
3
|
require 'net/http'
|
4
4
|
|
5
5
|
module Kameleoon
|
6
6
|
# @api private
|
7
7
|
module Request
|
8
8
|
protected
|
9
|
-
|
9
|
+
|
10
|
+
API_URL = 'https://api.kameleoon.com'.freeze
|
11
|
+
CLIENT_CONFIG_URL = 'https://client-config.kameleoon.com'.freeze
|
10
12
|
|
11
13
|
module Method
|
12
|
-
GET =
|
13
|
-
POST =
|
14
|
+
GET = 'get'.freeze
|
15
|
+
POST = 'post'.freeze
|
14
16
|
end
|
15
17
|
|
16
18
|
def get(request_options, url = API_URL, connexion_options = {})
|
@@ -32,7 +34,7 @@ module Kameleoon
|
|
32
34
|
private
|
33
35
|
|
34
36
|
def request(method, request_options, url, connexion_options)
|
35
|
-
connexion_options[:tls] = {verify_peer: false}
|
37
|
+
connexion_options[:tls] = { verify_peer: false }
|
36
38
|
add_user_agent(request_options)
|
37
39
|
case method
|
38
40
|
when Method::POST then
|
@@ -40,7 +42,7 @@ module Kameleoon
|
|
40
42
|
when Method::GET then
|
41
43
|
return EventMachine::HttpRequest.new(url, connexion_options).get request_options
|
42
44
|
else
|
43
|
-
print
|
45
|
+
print 'Unknown request type'
|
44
46
|
return false
|
45
47
|
end
|
46
48
|
end
|
@@ -68,22 +70,21 @@ module Kameleoon
|
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
71
|
-
def
|
73
|
+
def successful?(request)
|
72
74
|
!request.nil? && request != false && /20\d/.match(request.response_header.status.to_s)
|
73
75
|
end
|
74
76
|
|
75
|
-
def
|
77
|
+
def successful_sync?(response)
|
76
78
|
!response.nil? && response != false && response.is_a?(Net::HTTPSuccess)
|
77
79
|
end
|
78
80
|
|
79
81
|
def add_user_agent(request_options)
|
82
|
+
sdk_version = "sdk/ruby/#{Kameleoon::VERSION}"
|
80
83
|
if request_options[:head].nil?
|
81
|
-
request_options[:head] = {'Kameleoon-Client' =>
|
84
|
+
request_options[:head] = { 'Kameleoon-Client' => sdk_version }
|
82
85
|
else
|
83
|
-
request_options[:head].store('Kameleoon-Client',
|
86
|
+
request_options[:head].store('Kameleoon-Client', sdk_version)
|
84
87
|
end
|
85
88
|
end
|
86
89
|
end
|
87
90
|
end
|
88
|
-
|
89
|
-
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/storage/visitor_variation'
|
4
|
+
|
5
|
+
module Kameleoon
|
6
|
+
module Storage
|
7
|
+
# VariationStorage is a container for saved variations associated with a visitor
|
8
|
+
class VariationStorage
|
9
|
+
def initialize
|
10
|
+
@storage = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_variation_id(visitor_code, experiment_id)
|
14
|
+
variation_valid?(visitor_code, experiment_id, nil)
|
15
|
+
end
|
16
|
+
|
17
|
+
def variation_valid?(visitor_code, experiment_id, respool_time)
|
18
|
+
return nil if @storage[visitor_code].nil? || @storage[visitor_code][experiment_id].nil?
|
19
|
+
|
20
|
+
variation = @storage[visitor_code][experiment_id]
|
21
|
+
return nil unless variation.valid?(respool_time)
|
22
|
+
|
23
|
+
variation.variation_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def update_variation(visitor_code, experiment_id, variation_id)
|
27
|
+
@storage[visitor_code] = {} if @storage[visitor_code].nil?
|
28
|
+
@storage[visitor_code][experiment_id] = Kameleoon::Storage::VisitorVariation.new(variation_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_hash_saved_variation_id(visitor_code)
|
32
|
+
return nil if @storage[visitor_code].nil?
|
33
|
+
|
34
|
+
map_variations = {}
|
35
|
+
@storage[visitor_code].each do |key, value|
|
36
|
+
map_variations[key] = value.variation_id
|
37
|
+
end
|
38
|
+
map_variations
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kameleoon
|
4
|
+
module Storage
|
5
|
+
# VisitorVariation contains a saved variation id associated with a visitor
|
6
|
+
# and time when it was associated.
|
7
|
+
class VisitorVariation
|
8
|
+
attr_accessor :variation_id
|
9
|
+
|
10
|
+
def initialize(variation_id)
|
11
|
+
@variation_id = variation_id
|
12
|
+
@assignment_date = Time.now.to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid?(respool_time)
|
16
|
+
respool_time.nil? || @assignment_date > respool_time
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|