kameleoon-client-ruby 2.3.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kameleoon/client_readiness.rb +40 -0
  3. data/lib/kameleoon/configuration/data_file.rb +41 -0
  4. data/lib/kameleoon/configuration/feature_flag.rb +3 -2
  5. data/lib/kameleoon/configuration/rule.rb +18 -3
  6. data/lib/kameleoon/configuration/settings.rb +3 -1
  7. data/lib/kameleoon/configuration/variable.rb +0 -2
  8. data/lib/kameleoon/configuration/variation_exposition.rb +0 -2
  9. data/lib/kameleoon/data/browser.rb +1 -1
  10. data/lib/kameleoon/data/conversion.rb +1 -1
  11. data/lib/kameleoon/data/custom_data.rb +10 -14
  12. data/lib/kameleoon/data/data.rb +22 -3
  13. data/lib/kameleoon/data/device.rb +2 -1
  14. data/lib/kameleoon/data/manager/assigned_variation.rb +38 -0
  15. data/lib/kameleoon/data/manager/data_array_storage.rb +43 -0
  16. data/lib/kameleoon/data/manager/data_map_storage.rb +43 -0
  17. data/lib/kameleoon/data/manager/page_view_visit.rb +19 -0
  18. data/lib/kameleoon/data/manager/visitor.rb +142 -0
  19. data/lib/kameleoon/data/manager/visitor_manager.rb +71 -0
  20. data/lib/kameleoon/data/page_view.rb +2 -1
  21. data/lib/kameleoon/exceptions.rb +30 -35
  22. data/lib/kameleoon/hybrid/manager.rb +13 -31
  23. data/lib/kameleoon/{client.rb → kameleoon_client.rb} +164 -336
  24. data/lib/kameleoon/kameleoon_client_config.rb +91 -0
  25. data/lib/kameleoon/kameleoon_client_factory.rb +42 -0
  26. data/lib/kameleoon/network/activity_event.rb +6 -3
  27. data/lib/kameleoon/network/cookie/cookie_manager.rb +84 -0
  28. data/lib/kameleoon/network/net_provider.rb +5 -37
  29. data/lib/kameleoon/network/network_manager.rb +8 -7
  30. data/lib/kameleoon/network/request.rb +3 -2
  31. data/lib/kameleoon/network/response.rb +0 -8
  32. data/lib/kameleoon/network/url_provider.rb +5 -3
  33. data/lib/kameleoon/targeting/conditions/browser_condition.rb +2 -3
  34. data/lib/kameleoon/targeting/conditions/conversion_condition.rb +12 -4
  35. data/lib/kameleoon/targeting/conditions/custom_datum.rb +19 -13
  36. data/lib/kameleoon/targeting/conditions/device_condition.rb +3 -4
  37. data/lib/kameleoon/targeting/conditions/exclusive_experiment.rb +2 -1
  38. data/lib/kameleoon/targeting/conditions/page_title_condition.rb +11 -4
  39. data/lib/kameleoon/targeting/conditions/page_url_condition.rb +18 -4
  40. data/lib/kameleoon/targeting/conditions/string_value_condition.rb +2 -0
  41. data/lib/kameleoon/targeting/conditions/target_experiment.rb +11 -6
  42. data/lib/kameleoon/utils.rb +41 -4
  43. data/lib/kameleoon/version.rb +1 -1
  44. data/lib/kameleoon.rb +4 -2
  45. metadata +14 -10
  46. data/lib/kameleoon/client_config.rb +0 -44
  47. data/lib/kameleoon/configuration/experiment.rb +0 -42
  48. data/lib/kameleoon/cookie.rb +0 -88
  49. data/lib/kameleoon/factory.rb +0 -43
  50. data/lib/kameleoon/network/experiment_event.rb +0 -35
  51. data/lib/kameleoon/storage/variation_storage.rb +0 -42
  52. data/lib/kameleoon/storage/visitor_variation.rb +0 -20
@@ -1,16 +1,53 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'fiber'
4
+ require 'bigdecimal'
5
+ require 'kameleoon/utils'
6
+ require 'kameleoon/exceptions'
7
+
3
8
  module Kameleoon
4
9
  # Utils is a helper module for project
5
10
  module Utils
6
11
  ALPHA_NUMERIC_CHARS = 'ABCDEF0123456789'
7
12
 
8
- def self.in_seconds(days)
9
- days * 60 * 60 * 24
10
- end
11
-
12
13
  def self.generate_random_string(length)
13
14
  (1..length).map { ALPHA_NUMERIC_CHARS[rand(ALPHA_NUMERIC_CHARS.length)] }.join
14
15
  end
16
+
17
+ module VisitorCode
18
+ VISITOR_CODE_MAX_LENGTH = 255
19
+ VISITOR_CODE_LENGTH = 16
20
+
21
+ def self.validate(visitor_code)
22
+ raise Kameleoon::Exception::VisitorCodeInvalid, 'Empty visitor Code' if visitor_code&.empty?
23
+ if visitor_code.size > VISITOR_CODE_MAX_LENGTH
24
+ raise Kameleoon::Exception::VisitorCodeInvalid, "Visitor Code is longer than #{VISITOR_CODE_MAX_LENGTH} chars"
25
+ end
26
+ end
27
+
28
+ def self.generate
29
+ Utils.generate_random_string(VISITOR_CODE_LENGTH)
30
+ end
31
+ end
32
+
33
+ module HashDouble
34
+ def self.obtain(visitor_code, respool_times = {}, container_id = '')
35
+ obtain_helper(visitor_code, respool_times, container_id, '')
36
+ end
37
+
38
+ def self.obtain_rule(visitor_code, container_id = '', suffix = '')
39
+ obtain_helper(visitor_code, {}, container_id, suffix)
40
+ end
41
+
42
+ private
43
+
44
+ def self.obtain_helper(visitor_code, respool_times, container_id, suffix)
45
+ identifier = visitor_code.to_s
46
+ identifier += container_id.to_s
47
+ identifier += suffix.to_s
48
+ identifier += respool_times.sort.to_h.values.join.to_s if !respool_times.nil? && !respool_times.empty?
49
+ (Digest::SHA256.hexdigest(identifier.encode('UTF-8')).to_i(16) / (BigDecimal('2')**BigDecimal('256'))).round(16)
50
+ end
51
+ end
15
52
  end
16
53
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Kameleoon
4
4
  SDK_NAME = 'RUBY'
5
- SDK_VERSION = '2.3.0'
5
+ SDK_VERSION = '3.0.0'
6
6
 
7
7
  # SdkManager is a helper method for fetching / obtaining version of SDK from string
8
8
  class SdkVersion
data/lib/kameleoon.rb CHANGED
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Kameleoon Ruby Client SDK
3
5
  #
4
- require "kameleoon/factory"
5
- require "kameleoon/client"
6
+ require 'kameleoon/kameleoon_client_factory'
7
+ require 'kameleoon/kameleoon_client'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kameleoon-client-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kameleoon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-02 00:00:00.000000000 Z
11
+ date: 2023-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: em-http-request
@@ -75,29 +75,35 @@ extra_rdoc_files: []
75
75
  files:
76
76
  - README.md
77
77
  - lib/kameleoon.rb
78
- - lib/kameleoon/client.rb
79
- - lib/kameleoon/client_config.rb
80
- - lib/kameleoon/configuration/experiment.rb
78
+ - lib/kameleoon/client_readiness.rb
79
+ - lib/kameleoon/configuration/data_file.rb
81
80
  - lib/kameleoon/configuration/feature_flag.rb
82
81
  - lib/kameleoon/configuration/rule.rb
83
82
  - lib/kameleoon/configuration/settings.rb
84
83
  - lib/kameleoon/configuration/variable.rb
85
84
  - lib/kameleoon/configuration/variation.rb
86
85
  - lib/kameleoon/configuration/variation_exposition.rb
87
- - lib/kameleoon/cookie.rb
88
86
  - lib/kameleoon/data/browser.rb
89
87
  - lib/kameleoon/data/conversion.rb
90
88
  - lib/kameleoon/data/custom_data.rb
91
89
  - lib/kameleoon/data/data.rb
92
90
  - lib/kameleoon/data/device.rb
91
+ - lib/kameleoon/data/manager/assigned_variation.rb
92
+ - lib/kameleoon/data/manager/data_array_storage.rb
93
+ - lib/kameleoon/data/manager/data_map_storage.rb
94
+ - lib/kameleoon/data/manager/page_view_visit.rb
95
+ - lib/kameleoon/data/manager/visitor.rb
96
+ - lib/kameleoon/data/manager/visitor_manager.rb
93
97
  - lib/kameleoon/data/page_view.rb
94
98
  - lib/kameleoon/data/user_agent.rb
95
99
  - lib/kameleoon/exceptions.rb
96
- - lib/kameleoon/factory.rb
97
100
  - lib/kameleoon/hybrid/manager.rb
101
+ - lib/kameleoon/kameleoon_client.rb
102
+ - lib/kameleoon/kameleoon_client_config.rb
103
+ - lib/kameleoon/kameleoon_client_factory.rb
98
104
  - lib/kameleoon/network/activity_event.rb
99
105
  - lib/kameleoon/network/content_type.rb
100
- - lib/kameleoon/network/experiment_event.rb
106
+ - lib/kameleoon/network/cookie/cookie_manager.rb
101
107
  - lib/kameleoon/network/method.rb
102
108
  - lib/kameleoon/network/net_provider.rb
103
109
  - lib/kameleoon/network/network_manager.rb
@@ -112,8 +118,6 @@ files:
112
118
  - lib/kameleoon/real_time/sse_request.rb
113
119
  - lib/kameleoon/storage/cache.rb
114
120
  - lib/kameleoon/storage/cache_factory.rb
115
- - lib/kameleoon/storage/variation_storage.rb
116
- - lib/kameleoon/storage/visitor_variation.rb
117
121
  - lib/kameleoon/targeting/condition.rb
118
122
  - lib/kameleoon/targeting/condition_factory.rb
119
123
  - lib/kameleoon/targeting/conditions/browser_condition.rb
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kameleoon
4
- # Client configuration which can be used instead of an external configuration file
5
- class ClientConfig
6
- CONFIGURATION_UPDATE_INTERVAL = 60
7
- VISITOR_DATA_MAXIMUM_SIZE = 500
8
- DEFAULT_TIMEOUT = 2000 # milli-seconds
9
-
10
- attr_reader :client_id, :client_secret, :data_refresh_interval, :default_timeout, :configuration_refresh_interval,
11
- :visitor_data_maximum_size, :environment, :verbose_mode
12
-
13
- def initialize(
14
- client_id: nil,
15
- client_secret: nil,
16
- configuration_refresh_interval: CONFIGURATION_UPDATE_INTERVAL,
17
- default_timeout: DEFAULT_TIMEOUT,
18
- visitor_data_maximum_size: VISITOR_DATA_MAXIMUM_SIZE,
19
- environment: nil,
20
- verbose_mode: false
21
- )
22
- @client_id = client_id
23
- @client_secret = client_secret
24
- @configuration_refresh_interval = configuration_refresh_interval || CONFIGURATION_UPDATE_INTERVAL
25
- @default_timeout = default_timeout || DEFAULT_TIMEOUT
26
- @visitor_data_maximum_size = visitor_data_maximum_size || VISITOR_DATA_MAXIMUM_SIZE
27
- @environment = environment
28
- @verbose_mode = verbose_mode || false
29
- end
30
-
31
- def self.make_from_yaml(yaml)
32
- yaml ||= {}
33
- ClientConfig.new(
34
- client_id: yaml['client_id'],
35
- client_secret: yaml['client_secret'],
36
- configuration_refresh_interval: yaml['actions_configuration_refresh_interval'],
37
- default_timeout: yaml['default_timeout'],
38
- visitor_data_maximum_size: yaml['visitor_data_maximum_size'],
39
- environment: yaml['environment'],
40
- verbose_mode: yaml['verbose_mode']
41
- )
42
- end
43
- end
44
- end
@@ -1,42 +0,0 @@
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
@@ -1,88 +0,0 @@
1
- require 'fiber'
2
- require 'em-http'
3
- require 'eventmachine'
4
- require 'bigdecimal'
5
- require 'kameleoon/utils'
6
- require 'kameleoon/exceptions'
7
-
8
- module Kameleoon
9
- # @api private
10
- module Cookie
11
- # @return [String] visitor code
12
- def read_and_write(request_cookies, top_level_domain, response_cookies, default_visitor_code = nil)
13
- kameleoon_visitor_code = read(request_cookies)
14
- if kameleoon_visitor_code.nil?
15
- kameleoon_visitor_code = check_default_visitor_code(default_visitor_code) || Kameleoon::Utils.generate_random_string(KAMELEOON_COOKIE_VALUE_LENGTH)
16
- end
17
- cookie = { :value => kameleoon_visitor_code, :expires => Time.now + Kameleoon::Utils.in_seconds(EXPIRE_DAYS), :path => '/' }
18
- unless top_level_domain.nil?
19
- cookie[:domain] = top_level_domain
20
- end
21
- response_cookies[KAMELEOON_COOKIE_NAME] = cookie
22
- kameleoon_visitor_code
23
- end
24
-
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_rule(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)
34
- identifier = visitor_code.to_s
35
- identifier += container_id.to_s
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)
39
- end
40
-
41
- def check_visitor_code(visitor_code)
42
- if visitor_code.nil?
43
- check_default_visitor_code('')
44
- elsif
45
- check_default_visitor_code(visitor_code)
46
- end
47
- end
48
-
49
- private
50
-
51
- KAMELEOON_KEY_JS_COOKIE = "_js_"
52
- KAMELEOON_VISITOR_CODE_LENGTH = 255
53
- KAMELEOON_COOKIE_VALUE_LENGTH = 16
54
- KAMELEOON_COOKIE_NAME = 'kameleoonVisitorCode'
55
- EXPIRE_DAYS = 380
56
-
57
- def check_default_visitor_code(default_visitor_code)
58
- if default_visitor_code.nil?
59
- return
60
- end
61
- default_visitor_code = default_visitor_code.to_s
62
- if default_visitor_code.length == 0
63
- raise Kameleoon::Exception::VisitorCodeNotValid.new("Empty visitor Code")
64
- end
65
- if default_visitor_code.length > KAMELEOON_VISITOR_CODE_LENGTH
66
- raise Kameleoon::Exception::VisitorCodeNotValid.new("Visitor Code is longer than 255 chars.")
67
- end
68
- default_visitor_code
69
- end
70
-
71
- def read(cookies)
72
- value = cookies[KAMELEOON_COOKIE_NAME]
73
- if value.nil?
74
- return
75
- end
76
- if value.start_with?(KAMELEOON_KEY_JS_COOKIE)
77
- start_index = KAMELEOON_KEY_JS_COOKIE.length
78
- value = value[start_index..-1]
79
- end
80
- if value.length == 0
81
- nil
82
- end
83
- value[0..(KAMELEOON_VISITOR_CODE_LENGTH - 1)]
84
- end
85
- end
86
- end
87
-
88
-
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'kameleoon/client'
4
- require 'kameleoon/client_config'
5
-
6
- module Kameleoon
7
- # A Factory class for creating kameleoon clients
8
- module ClientFactory
9
- CONFIG_PATH = '/etc/kameleoon/client-ruby.yaml'
10
-
11
- @clients = {}
12
-
13
- def self.create(site_code, config_path = CONFIG_PATH, config: nil)
14
- if config.nil?
15
- config_yaml = YAML.load_file(config_path) if File.exist?(config_path)
16
- if config_yaml.nil?
17
- warn "Kameleoon SDK: Configuration file with path #{config_path} does not exist" if config_yaml.nil?
18
- config_yaml = {}
19
- end
20
- end
21
- environment = config&.environment || (config_yaml || {})['environment']
22
- client = @clients[get_client_key(site_code, environment)]
23
- if client.nil?
24
- config = ClientConfig.make_from_yaml(config_yaml) if config.nil?
25
- client = Client.new(site_code, config)
26
- client.send(:log, "Client created with site code: #{site_code}")
27
- client.send(:fetch_configuration)
28
- @clients.store(site_code, client)
29
- end
30
- client
31
- end
32
-
33
- def self.forget(site_code, environment = '')
34
- @clients.delete(get_client_key(site_code, environment))
35
- end
36
-
37
- private_class_method
38
-
39
- def self.get_client_key(site_code, environment)
40
- site_code + (environment || '')
41
- end
42
- end
43
- end
@@ -1,35 +0,0 @@
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
@@ -1,42 +0,0 @@
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
@@ -1,20 +0,0 @@
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