kameleoon-client-ruby 2.0.0 → 2.1.1
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 +277 -260
- data/lib/kameleoon/configuration/feature_flag.rb +13 -24
- data/lib/kameleoon/configuration/rule.rb +17 -5
- data/lib/kameleoon/configuration/settings.rb +20 -0
- data/lib/kameleoon/cookie.rb +3 -3
- data/lib/kameleoon/data/browser.rb +33 -0
- data/lib/kameleoon/data/conversion.rb +26 -0
- data/lib/kameleoon/data/custom_data.rb +53 -0
- data/lib/kameleoon/data/data.rb +35 -0
- data/lib/kameleoon/data/device.rb +26 -0
- data/lib/kameleoon/data/page_view.rb +31 -0
- data/lib/kameleoon/data/user_agent.rb +14 -0
- data/lib/kameleoon/hybrid/manager.rb +60 -0
- data/lib/kameleoon/network/activity_event.rb +31 -0
- data/lib/kameleoon/network/experiment_event.rb +35 -0
- data/lib/kameleoon/network/uri_helper.rb +36 -0
- data/lib/kameleoon/network/url_provider.rb +71 -0
- data/lib/kameleoon/real_time/real_time_configuration_service.rb +98 -0
- data/lib/kameleoon/real_time/real_time_event.rb +22 -0
- data/lib/kameleoon/real_time/sse_client.rb +111 -0
- data/lib/kameleoon/real_time/sse_message.rb +23 -0
- data/lib/kameleoon/real_time/sse_request.rb +59 -0
- data/lib/kameleoon/request.rb +5 -19
- data/lib/kameleoon/storage/cache.rb +84 -0
- data/lib/kameleoon/storage/cache_factory.rb +23 -0
- data/lib/kameleoon/targeting/condition.rb +41 -12
- data/lib/kameleoon/targeting/condition_factory.rb +35 -12
- data/lib/kameleoon/targeting/conditions/browser_condition.rb +71 -0
- data/lib/kameleoon/targeting/conditions/conversion_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/custom_datum.rb +64 -34
- data/lib/kameleoon/targeting/conditions/device_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/exclusive_experiment.rb +0 -12
- data/lib/kameleoon/targeting/conditions/page_title_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/page_url_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/sdk_language_condition.rb +65 -0
- data/lib/kameleoon/targeting/conditions/string_value_condition.rb +40 -0
- data/lib/kameleoon/targeting/conditions/target_experiment.rb +5 -9
- data/lib/kameleoon/targeting/conditions/unknown_condition.rb +15 -0
- data/lib/kameleoon/targeting/conditions/visitor_code_condition.rb +16 -0
- data/lib/kameleoon/targeting/models.rb +0 -24
- data/lib/kameleoon/utils.rb +1 -1
- data/lib/kameleoon/version.rb +28 -1
- metadata +45 -4
- data/lib/kameleoon/configuration/feature_flag_v2.rb +0 -30
- data/lib/kameleoon/data.rb +0 -169
@@ -1,40 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'rule'
|
4
|
+
require_relative 'variation'
|
4
5
|
|
5
6
|
module Kameleoon
|
6
7
|
# Module which contains all internal data of SDK
|
7
8
|
module Configuration
|
8
|
-
# Class for manage all
|
9
|
-
class FeatureFlag
|
10
|
-
|
11
|
-
FEATURE_STATUS_DEACTIVATED = 'DEACTIVATED'
|
12
|
-
attr_accessor :identification_key, :feature_status, :schedules, :exposition_rate
|
9
|
+
# Class for manage all feature flags with rules
|
10
|
+
class FeatureFlag
|
11
|
+
attr_accessor :id, :feature_key, :variations, :default_variation_key, :rules
|
13
12
|
|
14
13
|
def self.create_from_array(array)
|
15
14
|
array&.map { |it| FeatureFlag.new(it) }
|
16
15
|
end
|
17
16
|
|
18
|
-
def initialize(
|
19
|
-
|
20
|
-
@
|
21
|
-
@
|
22
|
-
@
|
23
|
-
@
|
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'])
|
24
23
|
end
|
25
24
|
|
26
|
-
def
|
27
|
-
|
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
|
25
|
+
def get_variation_key(key)
|
26
|
+
variations.select { |v| v.key == key }.first
|
38
27
|
end
|
39
28
|
end
|
40
29
|
end
|
@@ -14,25 +14,29 @@ module Kameleoon
|
|
14
14
|
|
15
15
|
# Rule is a class for new rules of feature flags
|
16
16
|
class Rule
|
17
|
-
|
17
|
+
attr_reader :id, :order, :type, :exposition, :experiment_id, :variation_by_exposition, :respool_time
|
18
|
+
attr_accessor :targeting_segment
|
18
19
|
|
19
20
|
def self.create_from_array(array)
|
20
21
|
array&.map { |it| Rule.new(it) }
|
21
22
|
end
|
22
23
|
|
23
24
|
def initialize(hash)
|
25
|
+
@id = hash['id']
|
26
|
+
@order = hash['order']
|
24
27
|
@type = hash['type']
|
25
28
|
@exposition = hash['exposition']
|
26
29
|
@experiment_id = hash['experimentId']
|
30
|
+
@respool_time = hash['respoolTime']
|
27
31
|
@variation_by_exposition = VariationByExposition.create_from_array(hash['variationByExposition'])
|
28
32
|
@targeting_segment = Kameleoon::Targeting::Segment.new((hash['segment'])) if hash['segment']
|
29
33
|
end
|
30
34
|
|
31
|
-
def
|
35
|
+
def get_variation(hash_double)
|
32
36
|
total = 0.0
|
33
|
-
variation_by_exposition.each do |
|
34
|
-
total +=
|
35
|
-
return
|
37
|
+
variation_by_exposition.each do |var_by_exp|
|
38
|
+
total += var_by_exp.exposition
|
39
|
+
return var_by_exp if total >= hash_double
|
36
40
|
end
|
37
41
|
nil
|
38
42
|
end
|
@@ -40,6 +44,14 @@ module Kameleoon
|
|
40
44
|
def get_variation_id_by_key(key)
|
41
45
|
variation_by_exposition.select { |v| v.variation_key == key }.first&.variation_id
|
42
46
|
end
|
47
|
+
|
48
|
+
def experimentation_type?
|
49
|
+
@type == RuleType::EXPERIMENTATION
|
50
|
+
end
|
51
|
+
|
52
|
+
def targeted_delivery_type?
|
53
|
+
@type == RuleType::TARGETED_DELIVERY
|
54
|
+
end
|
43
55
|
end
|
44
56
|
end
|
45
57
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kameleoon
|
4
|
+
# Module which contains all internal data of SDK
|
5
|
+
module Configuration
|
6
|
+
# KameleoonConfigurationSettings is used for saving setting's parameters, e.g
|
7
|
+
# state of real time update for site code and etc
|
8
|
+
class Settings
|
9
|
+
attr_accessor :real_time_update
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@real_time_update = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def update(configuration)
|
16
|
+
@real_time_update = configuration['realTimeUpdate'] || false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/kameleoon/cookie.rb
CHANGED
@@ -26,7 +26,7 @@ module Kameleoon
|
|
26
26
|
obtain_hash_double_helper(visitor_code, respool_times, container_id, '')
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def obtain_hash_double_rule(visitor_code, container_id = '', suffix = '')
|
30
30
|
obtain_hash_double_helper(visitor_code, {}, container_id, suffix)
|
31
31
|
end
|
32
32
|
|
@@ -37,8 +37,8 @@ module Kameleoon
|
|
37
37
|
identifier += respool_times.sort.to_h.values.join.to_s if !respool_times.nil? && !respool_times.empty?
|
38
38
|
(Digest::SHA256.hexdigest(identifier.encode('UTF-8')).to_i(16) / (BigDecimal('2')**BigDecimal('256'))).round(16)
|
39
39
|
end
|
40
|
-
|
41
|
-
def check_visitor_code(visitor_code)
|
40
|
+
|
41
|
+
def check_visitor_code(visitor_code)
|
42
42
|
if visitor_code.nil?
|
43
43
|
check_default_visitor_code('')
|
44
44
|
elsif
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'json'
|
2
|
+
require_relative 'data'
|
3
|
+
|
4
|
+
module Kameleoon
|
5
|
+
module BrowserType
|
6
|
+
CHROME = 0
|
7
|
+
INTERNET_EXPLORER = 1
|
8
|
+
FIREFOX = 2
|
9
|
+
SAFARI = 3
|
10
|
+
OPERA = 4
|
11
|
+
OTHER = 5
|
12
|
+
end
|
13
|
+
|
14
|
+
# Represents browser data for tracking calls
|
15
|
+
class Browser < Data
|
16
|
+
attr_reader :type, :version
|
17
|
+
|
18
|
+
# @param [BrowserType] browser_type Browser type, can be: CHROME, INTERNET_EXPLORER, FIREFOX, SAFARI, OPERA, OTHER
|
19
|
+
# @param [float] version Version of browser
|
20
|
+
def initialize(browser_type, version = Float::NAN)
|
21
|
+
super(DataType::BROWSER)
|
22
|
+
@type = browser_type
|
23
|
+
@version = version
|
24
|
+
end
|
25
|
+
|
26
|
+
def obtain_full_post_text_line
|
27
|
+
nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
|
28
|
+
url = "eventType=staticData&browserIndex=#{@type}&nonce=#{nonce}"
|
29
|
+
url.concat("&browserVersion=#{@version}") if @version.is_a?(Integer) || (@version.is_a?(Float) && !@version.nan?)
|
30
|
+
url
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require_relative 'data'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# Conversion class uses for tracking conversion
|
8
|
+
class Conversion < Data
|
9
|
+
attr_reader :goal_id, :revenue, :negative
|
10
|
+
|
11
|
+
# @param [Integer] goal_id Id of the goal associated to the conversion
|
12
|
+
# @param [Float] revenue Optional field - Revenue associated to the conversion.
|
13
|
+
# @param [Boolean] negative Optional field - If the revenue is negative. By default it's positive.
|
14
|
+
def initialize(goal_id, revenue = 0.0, negative = false)
|
15
|
+
super(DataType::CONVERSION)
|
16
|
+
@goal_id = goal_id
|
17
|
+
@revenue = revenue || 0.0
|
18
|
+
@negative = negative || false
|
19
|
+
end
|
20
|
+
|
21
|
+
def obtain_full_post_text_line
|
22
|
+
nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
|
23
|
+
"eventType=conversion&goalId=#{@goal_id}&revenue=#{@revenue}&negative=#{@negative}&nonce=#{nonce}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require_relative 'data'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# Represents any custom data for targeting conditions
|
8
|
+
class CustomData < Data
|
9
|
+
attr_reader :id, :values
|
10
|
+
|
11
|
+
# @param [Integer] id Id of the custom data
|
12
|
+
# @param [String] value Value of the custom data
|
13
|
+
# @param [Array] values Array of values of the custom data
|
14
|
+
#
|
15
|
+
# @overload
|
16
|
+
# @param [Hash] hash Json value encoded in a hash.
|
17
|
+
# rubocop:disable Metrics/MethodLength
|
18
|
+
def initialize(arg0, *args)
|
19
|
+
super(DataType::CUSTOM)
|
20
|
+
if arg0.is_a?(Hash)
|
21
|
+
hash = arg0
|
22
|
+
id = hash['id']
|
23
|
+
raise Kameleoon::Exception::NotFound.new('id'), '"id" is mandatory' if id.nil?
|
24
|
+
|
25
|
+
@id = id.to_s
|
26
|
+
value = hash['value']
|
27
|
+
values = hash['values']
|
28
|
+
if values.nil? && value.nil?
|
29
|
+
raise Kameleoon::Exception::NotFound.new('value or values'), '"value" or "values" is mandatory'
|
30
|
+
end
|
31
|
+
|
32
|
+
if values.nil?
|
33
|
+
@values = [value]
|
34
|
+
else
|
35
|
+
@values = values.is_a?(Array) ? values.dup : [values]
|
36
|
+
@values.append(value) unless value.nil?
|
37
|
+
end
|
38
|
+
else
|
39
|
+
@id = arg0.to_s
|
40
|
+
@values = args
|
41
|
+
end
|
42
|
+
end
|
43
|
+
# rubocop:enable Metrics/MethodLength
|
44
|
+
|
45
|
+
def obtain_full_post_text_line
|
46
|
+
return '' if @values.empty?
|
47
|
+
|
48
|
+
str_values = JSON.generate(Hash[@values.collect { |k| [k, 1] }])
|
49
|
+
nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
|
50
|
+
"eventType=customData&index=#{@id}&valuesCountMap=#{self.class.encode(str_values)}&overwrite=true&nonce=#{nonce}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'kameleoon/exceptions'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
NONCE_LENGTH = 16
|
8
|
+
|
9
|
+
module DataType
|
10
|
+
CUSTOM = 'CUSTOM'
|
11
|
+
BROWSER = 'BROWSER'
|
12
|
+
CONVERSION = 'CONVERSION'
|
13
|
+
DEVICE = 'DEVICE'
|
14
|
+
PAGE_VIEW = 'PAGE_VIEW'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Represents base class for any Kameleoon data
|
18
|
+
class Data
|
19
|
+
attr_reader :instance
|
20
|
+
attr_accessor :sent
|
21
|
+
|
22
|
+
def initialize(data_type)
|
23
|
+
@instance = data_type
|
24
|
+
@sent = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def obtain_full_post_text_line
|
28
|
+
raise KameleoonError.new('ToDo: implement this method.'), 'ToDo: implement this method.'
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.encode(url)
|
32
|
+
Network::UriHelper.encode_uri(url)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require_relative 'data'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
module DeviceType
|
8
|
+
PHONE = 'PHONE'
|
9
|
+
TABLET = 'TABLET'
|
10
|
+
DESKTOP = 'DESKTOP'
|
11
|
+
end
|
12
|
+
|
13
|
+
# Device uses for sending deviceType parameter for tracking calls
|
14
|
+
class Device < Data
|
15
|
+
attr_reader :device_type
|
16
|
+
def initialize(device_type)
|
17
|
+
super(DataType::DEVICE)
|
18
|
+
@device_type = device_type
|
19
|
+
end
|
20
|
+
|
21
|
+
def obtain_full_post_text_line
|
22
|
+
nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
|
23
|
+
"eventType=staticData&deviceType=#{@device_type}&nonce=#{nonce}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require_relative 'data'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
# Represents page view data for tracking calls
|
8
|
+
class PageView < Data
|
9
|
+
attr_reader :url, :title, :referrer
|
10
|
+
|
11
|
+
# @param [String] url Url of the page
|
12
|
+
# @param [String] title Title of the page
|
13
|
+
# @param [Array] referrers Optional field - Referrer ids
|
14
|
+
def initialize(url, title, referrers = nil)
|
15
|
+
super(DataType::PAGE_VIEW)
|
16
|
+
@url = url || ''
|
17
|
+
@title = title || ''
|
18
|
+
@referrers = referrers.instance_of?(Integer) ? [referrers] : referrers
|
19
|
+
end
|
20
|
+
|
21
|
+
def obtain_full_post_text_line
|
22
|
+
nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH)
|
23
|
+
referrer_text = if !@referrers.nil? && !@referrers.empty?
|
24
|
+
"&referrersIndices=%5B#{@referrers.each(&:to_s).join('%2C')}%5D"
|
25
|
+
else
|
26
|
+
''
|
27
|
+
end
|
28
|
+
"eventType=page&href=#{self.class.encode(@url)}&title=#{self.class.encode(@title)}#{referrer_text}&nonce=#{nonce}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kameleoon
|
4
|
+
module Hybrid
|
5
|
+
TC_INIT = 'window.kameleoonQueue=window.kameleoonQueue||[];'
|
6
|
+
TC_ASSIGN_VARIATION_FORMAT = "window.kameleoonQueue.push(['Experiments.assignVariation',%d,%d]);"
|
7
|
+
TC_TRIGGER_FORMAT = "window.kameleoonQueue.push(['Experiments.trigger',%d,true]);"
|
8
|
+
TC_ASSIGN_VARIATION_TRIGGER_FORMAT = TC_ASSIGN_VARIATION_FORMAT + TC_TRIGGER_FORMAT
|
9
|
+
|
10
|
+
# Will be useful for Ruby 3.0
|
11
|
+
# Abstract Manager class (interface)
|
12
|
+
class Manager
|
13
|
+
def add_variation(_visitor, _experiment_id, _variation_id)
|
14
|
+
raise 'Abstract method `add` called'
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_engine_tracking_code(_visitor)
|
18
|
+
raise 'Abstract method `get_engine_tracking_code` called'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Implementation of Cache with auto cleaning feature
|
23
|
+
class ManagerImpl < Manager
|
24
|
+
def initialize(expiration_time, cleaning_interval, cache_factory, log_func)
|
25
|
+
super()
|
26
|
+
# synchronization is necessary for adding same visitor_code from different threads
|
27
|
+
@mutex = Mutex.new
|
28
|
+
@expiration_time = expiration_time
|
29
|
+
@cache_factory = cache_factory
|
30
|
+
@log = log_func
|
31
|
+
# it's recommend to use cleaning_interval 3-4 times more than experiation_time for more performance
|
32
|
+
# in this case on every cleaning iteration storage will be cleaned 2/3 - 3/4 of volume
|
33
|
+
@cache = cache_factory.create(expiration_time, cleaning_interval)
|
34
|
+
@log.call('Hybrid Manager was successfully initialized')
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_variation(visitor_code, experiment_id, variation_id)
|
38
|
+
@mutex.synchronize do
|
39
|
+
visitor_cache = @cache.get(visitor_code)
|
40
|
+
visitor_cache = @cache_factory.create(@expiration_time, 0) if visitor_cache.nil?
|
41
|
+
visitor_cache.set(experiment_id, variation_id)
|
42
|
+
@cache.set(visitor_code, visitor_cache)
|
43
|
+
end
|
44
|
+
@log.call("Hybrid Manager successfully added variation for visitor_code: #{visitor_code}, " \
|
45
|
+
"experiment: #{experiment_id}, variation: #{variation_id}")
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_engine_tracking_code(visitor_code)
|
49
|
+
tracking_code = TC_INIT
|
50
|
+
visitor_cache = @cache.get(visitor_code)
|
51
|
+
return tracking_code if visitor_cache.nil?
|
52
|
+
|
53
|
+
visitor_cache.active_items.each_pair do |key, value|
|
54
|
+
tracking_code += format(TC_ASSIGN_VARIATION_TRIGGER_FORMAT, key, value, key)
|
55
|
+
end
|
56
|
+
tracking_code
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'kameleoon/data/data'
|
5
|
+
require 'kameleoon/utils'
|
6
|
+
require 'kameleoon/network/uri_helper'
|
7
|
+
|
8
|
+
module Kameleoon
|
9
|
+
module Network
|
10
|
+
##
|
11
|
+
# ActivityEvent represents an activity tracking event.
|
12
|
+
class ActivityEvent
|
13
|
+
EVENT_TYPE = 'activity'
|
14
|
+
|
15
|
+
attr_accessor :sent
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@sent = false
|
19
|
+
@nonce = Kameleoon::Utils.generate_random_string(Kameleoon::NONCE_LENGTH)
|
20
|
+
end
|
21
|
+
|
22
|
+
def obtain_full_post_text_line
|
23
|
+
params = {
|
24
|
+
eventType: EVENT_TYPE,
|
25
|
+
nonce: @nonce
|
26
|
+
}
|
27
|
+
UriHelper.encode_query(params)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'kameleoon/data/data'
|
5
|
+
require 'kameleoon/utils'
|
6
|
+
require 'kameleoon/network/uri_helper'
|
7
|
+
|
8
|
+
module Kameleoon
|
9
|
+
module Network
|
10
|
+
##
|
11
|
+
# ExperimentEvent represents an experiment tracking event.
|
12
|
+
class ExperimentEvent
|
13
|
+
EVENT_TYPE = 'experiment'
|
14
|
+
|
15
|
+
attr_accessor :sent
|
16
|
+
|
17
|
+
def initialize(experiment_id, variation_id)
|
18
|
+
@sent = false
|
19
|
+
@experiment_id = experiment_id
|
20
|
+
@variation_id = variation_id
|
21
|
+
@nonce = Kameleoon::Utils.generate_random_string(Kameleoon::NONCE_LENGTH)
|
22
|
+
end
|
23
|
+
|
24
|
+
def obtain_full_post_text_line
|
25
|
+
params = {
|
26
|
+
eventType: EVENT_TYPE,
|
27
|
+
id: @experiment_id,
|
28
|
+
variationId: @variation_id,
|
29
|
+
nonce: @nonce
|
30
|
+
}
|
31
|
+
UriHelper.encode_query(params)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cgi'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
module Network
|
8
|
+
##
|
9
|
+
# UriHelper contains functions which helps working with URIs.
|
10
|
+
module UriHelper
|
11
|
+
def self.encode_uri(uri)
|
12
|
+
encoded = CGI.escape(uri)
|
13
|
+
encoded.gsub!(/%21|%27|%28|%29|%2A|\+/,
|
14
|
+
'%21' => '!',
|
15
|
+
'%27' => "'",
|
16
|
+
'%28' => '(',
|
17
|
+
'%29' => ')',
|
18
|
+
'%2A' => '*',
|
19
|
+
'+' => '%20')
|
20
|
+
encoded
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.encode_query(params)
|
24
|
+
encoded = URI.encode_www_form(params)
|
25
|
+
encoded.gsub!(/%21|%27|%28|%29|%7E|\+/,
|
26
|
+
'%21' => '!',
|
27
|
+
'%27' => "'",
|
28
|
+
'%28' => '(',
|
29
|
+
'%29' => ')',
|
30
|
+
'%7E' => '~',
|
31
|
+
'+' => '%20')
|
32
|
+
encoded
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/version'
|
4
|
+
require 'kameleoon/network/uri_helper'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
module Network
|
8
|
+
##
|
9
|
+
# UrlProvider is used as a source of URLs for network calls.
|
10
|
+
class UrlProvider
|
11
|
+
TRACKING_PATH = '/visit/events'
|
12
|
+
VISITOR_DATA_PATH = '/visit/visitor'
|
13
|
+
GET_DATA_PATH = '/map/map'
|
14
|
+
POST_DATA_PATH = '/map/maps'
|
15
|
+
CONFIGURATION_API_URL = 'https://client-config.kameleoon.com/mobile'
|
16
|
+
RT_CONFIGURATION_URL = 'https://events.kameleoon.com:8110/sse'
|
17
|
+
|
18
|
+
DEFAULT_DATA_API_URL = 'https://data.kameleoon.io'
|
19
|
+
TEST_DATA_API_URL = 'https://data.kameleoon.net'
|
20
|
+
|
21
|
+
attr_reader :site_code, :data_api_url
|
22
|
+
|
23
|
+
def initialize(site_code, data_api_url)
|
24
|
+
@site_code = site_code
|
25
|
+
@data_api_url = data_api_url
|
26
|
+
end
|
27
|
+
|
28
|
+
def make_tracking_url(visitor_code)
|
29
|
+
params = {
|
30
|
+
sdkName: SDK_NAME,
|
31
|
+
sdkVersion: SDK_VERSION,
|
32
|
+
siteCode: @site_code,
|
33
|
+
visitorCode: visitor_code
|
34
|
+
}
|
35
|
+
"#{@data_api_url}#{TRACKING_PATH}?#{UriHelper.encode_query(params)}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def make_visitor_data_get_url(visitor_code)
|
39
|
+
params = {
|
40
|
+
siteCode: @site_code,
|
41
|
+
visitorCode: visitor_code,
|
42
|
+
currentVisit: true,
|
43
|
+
maxNumberPreviousVisits: 1,
|
44
|
+
customData: true,
|
45
|
+
version: 0
|
46
|
+
}
|
47
|
+
"#{@data_api_url}#{VISITOR_DATA_PATH}?#{UriHelper.encode_query(params)}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def make_api_data_get_request_url(key)
|
51
|
+
params = {
|
52
|
+
siteCode: @site_code,
|
53
|
+
key: key
|
54
|
+
}
|
55
|
+
"#{@data_api_url}#{GET_DATA_PATH}?#{UriHelper.encode_query(params)}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def make_configuration_url(environment = nil, timestamp = nil)
|
59
|
+
params = { siteCode: @site_code }
|
60
|
+
params[:environment] = environment unless environment.nil?
|
61
|
+
params[:ts] = timestamp unless timestamp.nil?
|
62
|
+
"#{CONFIGURATION_API_URL}?#{UriHelper.encode_query(params)}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def make_real_time_url
|
66
|
+
params = { siteCode: @site_code }
|
67
|
+
"#{RT_CONFIGURATION_URL}?#{UriHelper.encode_query(params)}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|