kameleoon-client-ruby 2.0.0 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|