kameleoon-client-ruby 3.0.0 → 3.1.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/configuration/settings.rb +4 -1
- data/lib/kameleoon/kameleoon_client.rb +36 -4
- data/lib/kameleoon/managers/warehouse/warehouse_manager.rb +33 -0
- data/lib/kameleoon/network/access_token_source.rb +109 -0
- data/lib/kameleoon/network/net_provider.rb +20 -21
- data/lib/kameleoon/network/network_manager.rb +59 -38
- data/lib/kameleoon/network/request.rb +5 -1
- data/lib/kameleoon/network/url_provider.rb +25 -9
- data/lib/kameleoon/real_time/sse_client.rb +2 -0
- data/lib/kameleoon/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f1490fd854e391fea3b908cad394e328a3540b6368942b72c1a9979c9002b87
|
4
|
+
data.tar.gz: 3abf894648cd3662a1a3a3453254014fa20c5405af28f6e01c8e336c810c6031
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76f8eb07daaf102c292c9ed04a6d788dfcef4a7cf757875603a68d2a1272b8e543dbfabd89226a6f775cd71d243998b8b897e6339c616d0a87b03624054720e3
|
7
|
+
data.tar.gz: d8f94272a6afa522a6ea5c48e3c0f9b91fec6bd1b2382e0ff2a9a94cfbdfb3c23d9f278a5bf143d4161a05cff385ad335d278a5634e8f3a23f4f63373c6da281
|
@@ -6,16 +6,19 @@ module Kameleoon
|
|
6
6
|
# KameleoonConfigurationSettings is used for saving setting's parameters, e.g
|
7
7
|
# state of real time update for site code and etc
|
8
8
|
class Settings
|
9
|
-
attr_accessor :real_time_update
|
9
|
+
attr_accessor :real_time_update
|
10
|
+
attr_reader :is_consent_required, :data_api_domain
|
10
11
|
|
11
12
|
def initialize
|
12
13
|
@real_time_update = false
|
13
14
|
@is_consent_required = false
|
15
|
+
@data_api_domain = nil
|
14
16
|
end
|
15
17
|
|
16
18
|
def update(configuration)
|
17
19
|
@real_time_update = configuration['realTimeUpdate'] || false
|
18
20
|
@is_consent_required = configuration['consentType'] == 'REQUIRED'
|
21
|
+
@data_api_domain = configuration['dataApiDomain']
|
19
22
|
end
|
20
23
|
end
|
21
24
|
end
|
@@ -10,10 +10,12 @@ require 'kameleoon/data/manager/visitor_manager'
|
|
10
10
|
require 'kameleoon/configuration/feature_flag'
|
11
11
|
require 'kameleoon/configuration/variation'
|
12
12
|
require 'kameleoon/configuration/data_file'
|
13
|
+
require 'kameleoon/network/access_token_source'
|
13
14
|
require 'kameleoon/network/activity_event'
|
14
|
-
require 'kameleoon/network/url_provider'
|
15
15
|
require 'kameleoon/network/network_manager'
|
16
|
+
require 'kameleoon/network/url_provider'
|
16
17
|
require 'kameleoon/network/cookie/cookie_manager'
|
18
|
+
require 'kameleoon/managers/warehouse/warehouse_manager'
|
17
19
|
require 'kameleoon/real_time/real_time_configuration_service'
|
18
20
|
require 'kameleoon/hybrid/manager'
|
19
21
|
require 'kameleoon/storage/cache_factory'
|
@@ -50,9 +52,11 @@ module Kameleoon
|
|
50
52
|
@network_manager = Network::NetworkManager.new(
|
51
53
|
config.environment,
|
52
54
|
config.default_timeout_millisecond,
|
53
|
-
Network::
|
55
|
+
Network::AccessTokenSourceFactory.new(config.client_id, config.client_secret, method(:log)),
|
56
|
+
Network::UrlProvider.new(site_code),
|
54
57
|
method(:log)
|
55
58
|
)
|
59
|
+
@warehouse_manager = Managers::Warehouse::WarehouseManager.new(@network_manager, @visitor_manager, method(:log))
|
56
60
|
@cookie_manager = Network::Cookie::CookieManager.new(config.top_level_domain)
|
57
61
|
@readiness = ClientReadiness.new
|
58
62
|
end
|
@@ -264,7 +268,7 @@ module Kameleoon
|
|
264
268
|
# way to quickly store massive amounts of data that can be later retrieved for each of your visitors / users.
|
265
269
|
#
|
266
270
|
# @param [String] key Key you want to retrieve data. This field is mandatory.
|
267
|
-
# @param [
|
271
|
+
# @param [Integer] timeout Timeout for request (in milliseconds). Equals default_timeout in a config file.
|
268
272
|
# This field is optional.
|
269
273
|
#
|
270
274
|
# @return [Hash] Hash object of the json object.
|
@@ -282,7 +286,7 @@ module Kameleoon
|
|
282
286
|
# This field is mandatory.
|
283
287
|
# @param [Bool] add_data A boolean indicating whether the method should automatically add retrieved data
|
284
288
|
# for a visitor. If not specified, the default value is `True`. This field is optional.
|
285
|
-
# @param [
|
289
|
+
# @param [Integer] timeout Timeout for request (in milliseconds). Equals default_timeout in a config file.
|
286
290
|
# This field is optional.
|
287
291
|
#
|
288
292
|
# @return [Array] An array of data assigned to the given visitor.
|
@@ -293,6 +297,33 @@ module Kameleoon
|
|
293
297
|
data_array
|
294
298
|
end
|
295
299
|
|
300
|
+
##
|
301
|
+
# Retrieves data associated with a visitor's warehouse audiences and adds it to the visitor.
|
302
|
+
# Retrieves all audience data associated with the visitor in your data warehouse using the specified
|
303
|
+
# `visitor_code` and `warehouse_key`. The `warehouse_key` is typically your internal user ID.
|
304
|
+
# The `custom_data_index` parameter corresponds to the Kameleoon custom data that Kameleoon uses to target your
|
305
|
+
# visitors. You can refer to the
|
306
|
+
# <a href="https://help.kameleoon.com/warehouse-audience-targeting/">warehouse targeting documentation</a>
|
307
|
+
# for additional details. The method returns a `CustomData` object, confirming
|
308
|
+
# that the data has been added to the visitor and is available for targeting purposes.
|
309
|
+
#
|
310
|
+
# @param [String] visitor_code A unique visitor identification string, can't exceed 255 characters length.
|
311
|
+
# This field is mandatory.
|
312
|
+
# @param [Integer] custom_data_index An integer representing the index of the custom data you want to use to target
|
313
|
+
# your BigQuery Audiences. This field is mandatory.
|
314
|
+
# @param [String] warehouse_key A key to identify the warehouse data, typically your internal user ID.
|
315
|
+
# This field is optional.
|
316
|
+
# @param [Integer] timeout Timeout for request (in milliseconds). Equals default_timeout in a config file.
|
317
|
+
# This field is optional.
|
318
|
+
#
|
319
|
+
# @raise [Kameleoon::Exception::VisitorCodeInvalid] If the visitor code is empty or longer than 255 chars.
|
320
|
+
# @raise [JSON::ParserError]
|
321
|
+
#
|
322
|
+
# @return [Kameleoon::CustomData] A `CustomData` instance confirming that the data has been added to the visitor.
|
323
|
+
def get_visitor_warehouse_audience(visitor_code, custom_data_index, timeout = nil, warehouse_key: nil)
|
324
|
+
@warehouse_manager.get_visitor_warehouse_audience(visitor_code, custom_data_index, warehouse_key, timeout)
|
325
|
+
end
|
326
|
+
|
296
327
|
##
|
297
328
|
# Returns a list of all feature flag keys
|
298
329
|
#
|
@@ -443,6 +474,7 @@ module Kameleoon
|
|
443
474
|
@data_file = Configuration::DataFile.new(@config.environment).init(configuration)
|
444
475
|
@cookie_manager.consent_required =
|
445
476
|
@data_file.settings.is_consent_required && !@data_file.has_any_targeted_delivery_rule
|
477
|
+
@network_manager.url_provider.apply_data_api_domain(@data_file.settings.data_api_domain)
|
446
478
|
|
447
479
|
call_update_handler_if_needed(!time_stamp.nil?)
|
448
480
|
log "Feature flags are fetched: #{response.inspect}"
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/data/custom_data'
|
4
|
+
require 'kameleoon/utils'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
module Managers
|
8
|
+
module Warehouse
|
9
|
+
class WarehouseManager
|
10
|
+
WAREHOUSE_AUDIENCES_FIELD_NAME = 'warehouseAudiences'
|
11
|
+
|
12
|
+
def initialize(network_manager, visitor_manager, log_func = nil)
|
13
|
+
@network_manager = network_manager
|
14
|
+
@visitor_manager = visitor_manager
|
15
|
+
@log_func = log_func
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_visitor_warehouse_audience(visitor_code, custom_data_index, warehouse_key = nil, timeout = nil)
|
19
|
+
Utils::VisitorCode.validate(visitor_code)
|
20
|
+
remote_data_key = warehouse_key.nil? || warehouse_key.empty? ? visitor_code : warehouse_key
|
21
|
+
response = @network_manager.get_remote_data(remote_data_key, timeout)
|
22
|
+
remote_data = response.is_a?(String) ? JSON.parse(response) : nil
|
23
|
+
warehouse_audiences = remote_data.is_a?(Hash) ? remote_data[WAREHOUSE_AUDIENCES_FIELD_NAME] : nil
|
24
|
+
data_values = warehouse_audiences.is_a?(Hash) ? warehouse_audiences.keys : []
|
25
|
+
warehouse_audiences_data = CustomData.new(custom_data_index, *data_values)
|
26
|
+
visitor = @visitor_manager.get_or_create_visitor(visitor_code)
|
27
|
+
visitor.add_data(@log_func, warehouse_audiences_data)
|
28
|
+
warehouse_audiences_data
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
require 'time'
|
6
|
+
|
7
|
+
module Kameleoon
|
8
|
+
module Network
|
9
|
+
class AccessTokenSource
|
10
|
+
TOKEN_EXPIRATION_GAP = 60 # in seconds
|
11
|
+
TOKEN_OBSOLESCENCE_GAP = 1800 # in seconds
|
12
|
+
JWT_ACCESS_TOKEN_FIELD = 'access_token'
|
13
|
+
JWT_EXPIRES_IN_FIELD = 'expires_in'
|
14
|
+
|
15
|
+
def initialize(network_manager, client_id, client_secret, log_func)
|
16
|
+
@network_manager = network_manager
|
17
|
+
@client_id = client_id
|
18
|
+
@client_secret = client_secret
|
19
|
+
@fetching = false
|
20
|
+
@log_func = log_func
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_token
|
24
|
+
now = Time.new.to_i
|
25
|
+
token = @cached_token
|
26
|
+
return fetch_token if token.nil? || token.expired?(now)
|
27
|
+
|
28
|
+
Thread.new { fetch_token } if !@fetching && token.obsolete?(now)
|
29
|
+
token.value
|
30
|
+
end
|
31
|
+
|
32
|
+
def discard_token(token)
|
33
|
+
@cached_token = nil if @cached_token&.value == token
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def fetch_token
|
39
|
+
@fetching = true
|
40
|
+
response_content = @network_manager.fetch_access_jwtoken(@client_id, @client_secret)
|
41
|
+
unless response_content
|
42
|
+
@log_func&.call('Failed to fetch access JWT')
|
43
|
+
return nil
|
44
|
+
end
|
45
|
+
begin
|
46
|
+
jwt = JSON.parse(response_content)
|
47
|
+
token = jwt[JWT_ACCESS_TOKEN_FIELD]
|
48
|
+
expires_in = jwt[JWT_EXPIRES_IN_FIELD]
|
49
|
+
rescue JSON::ParserError => e
|
50
|
+
@log_func&.call("Failed to parse access JWT: #{e}")
|
51
|
+
return nil
|
52
|
+
end
|
53
|
+
unless token.is_a?(String) && !token.empty? && expires_in.is_a?(Integer) && expires_in.positive?
|
54
|
+
@log_func&.call('Failed to read access JWT')
|
55
|
+
return nil
|
56
|
+
end
|
57
|
+
handle_fetched_token(token, expires_in)
|
58
|
+
ensure
|
59
|
+
@fetching = false
|
60
|
+
end
|
61
|
+
|
62
|
+
def handle_fetched_token(token, expires_in)
|
63
|
+
now = Time.new.to_i
|
64
|
+
exp_time = now + expires_in - TOKEN_EXPIRATION_GAP
|
65
|
+
if expires_in > TOKEN_OBSOLESCENCE_GAP
|
66
|
+
obs_time = now + expires_in - TOKEN_OBSOLESCENCE_GAP
|
67
|
+
else
|
68
|
+
obs_time = exp_time
|
69
|
+
unless @log_func.nil?
|
70
|
+
issue = expires_in <= TOKEN_EXPIRATION_GAP ? 'cache the token' : 'refresh cached token in background'
|
71
|
+
@log_func.call("Access token life time (#{expires_in}s) is not long enough to #{issue}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
@cached_token = ExpiringToken.new(token, exp_time, obs_time)
|
75
|
+
token
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class ExpiringToken
|
80
|
+
attr_reader :value, :expiration_time, :obsolescence_time
|
81
|
+
|
82
|
+
def initialize(value, expiration_time, obsolescence_time)
|
83
|
+
@value = value
|
84
|
+
@expiration_time = expiration_time
|
85
|
+
@obsolescence_time = obsolescence_time
|
86
|
+
end
|
87
|
+
|
88
|
+
def expired?(now)
|
89
|
+
now >= @expiration_time
|
90
|
+
end
|
91
|
+
|
92
|
+
def obsolete?(now)
|
93
|
+
now >= @obsolescence_time
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class AccessTokenSourceFactory
|
98
|
+
def initialize(client_id, client_secret, log_func)
|
99
|
+
@client_id = client_id
|
100
|
+
@client_secret = client_secret
|
101
|
+
@log_func = log_func
|
102
|
+
end
|
103
|
+
|
104
|
+
def create(network_manager)
|
105
|
+
AccessTokenSource.new(network_manager, @client_id, @client_secret, @log_func)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -8,7 +8,7 @@ require 'kameleoon/exceptions'
|
|
8
8
|
module Kameleoon
|
9
9
|
module Network
|
10
10
|
class NetProvider
|
11
|
-
def make_request(
|
11
|
+
def make_request(request)
|
12
12
|
raise KameleoonError, 'Call of not implemented method!'
|
13
13
|
end
|
14
14
|
|
@@ -16,6 +16,7 @@ module Kameleoon
|
|
16
16
|
|
17
17
|
def collect_headers(request)
|
18
18
|
headers = request.extra_headers || {}
|
19
|
+
headers['Authorization'] = "Bearer #{request.access_token}" unless request.access_token.nil?
|
19
20
|
headers['Content-Type'] = request.content_type
|
20
21
|
headers['User-Agent'] = request.user_agent unless request.user_agent.nil?
|
21
22
|
headers
|
@@ -29,30 +30,28 @@ module Kameleoon
|
|
29
30
|
class SyncNetProvider < NetProvider
|
30
31
|
def make_request(request)
|
31
32
|
resp = nil
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
resp = http.request(req)
|
49
|
-
end
|
50
|
-
rescue => e
|
51
|
-
return Response.new(e, nil, nil, request)
|
33
|
+
case request.method
|
34
|
+
when Method::GET
|
35
|
+
req = Net::HTTP::Get.new(request.url)
|
36
|
+
when Method::POST
|
37
|
+
req = Net::HTTP::Post.new(request.url)
|
38
|
+
req.body = request.data
|
39
|
+
else
|
40
|
+
return unknown_method_response(request.method, request)
|
41
|
+
end
|
42
|
+
timeout = request.timeout.to_f / 1000.0
|
43
|
+
headers = collect_headers(request)
|
44
|
+
headers.each { |k, v| req[k] = v }
|
45
|
+
uri = URI(request.url)
|
46
|
+
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, open_timeout: timeout,
|
47
|
+
read_timeout: timeout, ssl_timeout: timeout) do |http|
|
48
|
+
resp = http.request(req)
|
52
49
|
end
|
53
50
|
body = resp.body
|
54
51
|
body = nil if body&.empty?
|
55
52
|
Response.new(nil, resp.code.to_i, body, request)
|
53
|
+
rescue => e
|
54
|
+
Response.new(e, nil, nil, request)
|
56
55
|
end
|
57
56
|
end
|
58
57
|
end
|
@@ -4,6 +4,7 @@ require 'kameleoon/network/content_type'
|
|
4
4
|
require 'kameleoon/network/method'
|
5
5
|
require 'kameleoon/network/request'
|
6
6
|
require 'kameleoon/network/net_provider'
|
7
|
+
require 'kameleoon/network/uri_helper'
|
7
8
|
require 'kameleoon/version'
|
8
9
|
|
9
10
|
module Kameleoon
|
@@ -11,17 +12,19 @@ module Kameleoon
|
|
11
12
|
##
|
12
13
|
# NetworkManager is used to make API calls.
|
13
14
|
class NetworkManager
|
14
|
-
FETCH_CONFIGURATION_ATTEMPT_NUMBER =
|
15
|
-
TRACKING_CALL_ATTEMPT_NUMBER =
|
15
|
+
FETCH_CONFIGURATION_ATTEMPT_NUMBER = 3
|
16
|
+
TRACKING_CALL_ATTEMPT_NUMBER = 3
|
16
17
|
TRACKING_CALL_RETRY_DELAY = 5.0 # in seconds
|
17
18
|
SDK_TYPE_HEADER = 'X-Kameleoon-SDK-Type'
|
18
19
|
SDK_VERSION_HEADER = 'X-Kameleoon-SDK-Version'
|
20
|
+
ACCESS_TOKEN_GRANT_TYPE = 'client_credentials'
|
19
21
|
|
20
|
-
attr_reader :environment, :default_timeout, :url_provider
|
22
|
+
attr_reader :environment, :default_timeout, :access_token_source, :url_provider
|
21
23
|
|
22
|
-
def initialize(environment, default_timeout, url_provider, log_func = nil)
|
24
|
+
def initialize(environment, default_timeout, access_token_source_factory, url_provider, log_func = nil)
|
23
25
|
@environment = environment
|
24
26
|
@default_timeout = default_timeout
|
27
|
+
@access_token_source = access_token_source_factory.create(self)
|
25
28
|
@url_provider = url_provider
|
26
29
|
@sync_net_provider = SyncNetProvider.new
|
27
30
|
@log_func = log_func
|
@@ -32,31 +35,21 @@ module Kameleoon
|
|
32
35
|
timeout = ensure_timeout(timeout)
|
33
36
|
sdk_headers = { SDK_TYPE_HEADER => SDK_NAME, SDK_VERSION_HEADER => SDK_VERSION }
|
34
37
|
request = Request.new(Method::GET, url, ContentType::JSON, timeout, extra_headers: sdk_headers)
|
35
|
-
|
36
|
-
while attempts_left.positive?
|
37
|
-
response = @sync_net_provider.make_request(request)
|
38
|
-
result = handle_response(response)
|
39
|
-
return result if result
|
40
|
-
|
41
|
-
attempts_left -= 1
|
42
|
-
end
|
43
|
-
false
|
38
|
+
make_call(request, false, FETCH_CONFIGURATION_ATTEMPT_NUMBER - 1)
|
44
39
|
end
|
45
40
|
|
46
41
|
def get_remote_data(key, timeout = nil)
|
47
42
|
url = @url_provider.make_api_data_get_request_url(key)
|
48
43
|
timeout = ensure_timeout(timeout)
|
49
44
|
request = Request.new(Method::GET, url, ContentType::JSON, timeout)
|
50
|
-
|
51
|
-
handle_response(response)
|
45
|
+
make_call(request, true)
|
52
46
|
end
|
53
47
|
|
54
48
|
def get_remote_visitor_data(visitor_code, timeout = nil)
|
55
49
|
url = @url_provider.make_visitor_data_get_url(visitor_code)
|
56
50
|
timeout = ensure_timeout(timeout)
|
57
51
|
request = Request.new(Method::GET, url, ContentType::JSON, timeout)
|
58
|
-
|
59
|
-
handle_response(response)
|
52
|
+
make_call(request, true)
|
60
53
|
end
|
61
54
|
|
62
55
|
def send_tracking_data(visitor_code, lines, user_agent, timeout = nil)
|
@@ -67,23 +60,55 @@ module Kameleoon
|
|
67
60
|
data = (lines.map(&:obtain_full_post_text_line).join("\n") || '').encode('UTF-8')
|
68
61
|
request = Request.new(Method::POST, url, ContentType::TEXT, timeout, user_agent: user_agent, data: data)
|
69
62
|
Thread.new do
|
70
|
-
|
71
|
-
|
72
|
-
response = @sync_net_provider.make_request(request)
|
73
|
-
if handle_response(response) != false
|
74
|
-
lines.each(&:mark_as_sent)
|
75
|
-
break
|
76
|
-
end
|
77
|
-
attempts_left -= 1
|
78
|
-
break unless attempts_left.positive?
|
79
|
-
|
80
|
-
delay(TRACKING_CALL_RETRY_DELAY)
|
81
|
-
end
|
63
|
+
result = make_call(request, true, TRACKING_CALL_ATTEMPT_NUMBER - 1, TRACKING_CALL_RETRY_DELAY)
|
64
|
+
lines.each(&:mark_as_sent) if result != false
|
82
65
|
end
|
83
66
|
end
|
84
67
|
|
68
|
+
def fetch_access_jwtoken(client_id, client_secret, timeout = nil)
|
69
|
+
url = @url_provider.make_access_token_url
|
70
|
+
timeout = ensure_timeout(timeout)
|
71
|
+
data_map = {
|
72
|
+
grant_type: ACCESS_TOKEN_GRANT_TYPE,
|
73
|
+
client_id: client_id,
|
74
|
+
client_secret: client_secret
|
75
|
+
}
|
76
|
+
data = UriHelper.encode_query(data_map).encode('UTF-8')
|
77
|
+
request = Request.new(Method::POST, url, ContentType::FORM, timeout, data: data)
|
78
|
+
make_call(request, false)
|
79
|
+
end
|
80
|
+
|
85
81
|
private
|
86
82
|
|
83
|
+
def make_call(request, try_access_token_auth, retry_limit = 0, retry_delay = 0)
|
84
|
+
attempt = 0
|
85
|
+
success = false
|
86
|
+
while !success && (attempt <= retry_limit)
|
87
|
+
delay(retry_delay) if attempt.positive? && retry_delay.positive?
|
88
|
+
try_authorize(request) if try_access_token_auth
|
89
|
+
response = @sync_net_provider.make_request(request)
|
90
|
+
if !response.error.nil?
|
91
|
+
log_failure(response.request, "Error occurred during request: #{response.error}")
|
92
|
+
elsif response.code / 100 != 2
|
93
|
+
if ((response.code == 401) || (response.code == 403)) && response.request.access_token
|
94
|
+
@log_func&.call("Unexpected rejection of access token '#{response.request.access_token}'")
|
95
|
+
@access_token_source.discard_token(response.request.access_token)
|
96
|
+
if attempt == retry_limit
|
97
|
+
try_access_token_auth = false
|
98
|
+
retry_delay = 0
|
99
|
+
request.authorize(nil)
|
100
|
+
attempt -= 1
|
101
|
+
end
|
102
|
+
end
|
103
|
+
log_failure(response.request, "Received unexpected status code '#{response.code}'")
|
104
|
+
else
|
105
|
+
success = true
|
106
|
+
end
|
107
|
+
attempt += 1
|
108
|
+
end
|
109
|
+
success ? response.body : false
|
110
|
+
end
|
111
|
+
|
87
112
|
def log_failure(request, message)
|
88
113
|
return if @log_func.nil?
|
89
114
|
|
@@ -100,15 +125,11 @@ module Kameleoon
|
|
100
125
|
timeout.nil? ? @default_timeout : timeout
|
101
126
|
end
|
102
127
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
else
|
109
|
-
return response.body
|
110
|
-
end
|
111
|
-
false
|
128
|
+
def try_authorize(request)
|
129
|
+
token = @access_token_source.get_token
|
130
|
+
return if request.authorize(token)
|
131
|
+
|
132
|
+
@log_func&.call("Failed to authorize #{request.method} call '#{request.url}'")
|
112
133
|
end
|
113
134
|
end
|
114
135
|
end
|
@@ -5,7 +5,7 @@ module Kameleoon
|
|
5
5
|
##
|
6
6
|
# Request represents HTTP request.
|
7
7
|
class Request
|
8
|
-
attr_reader :method, :url, :content_type, :timeout, :user_agent, :extra_headers, :data
|
8
|
+
attr_reader :method, :url, :content_type, :timeout, :user_agent, :extra_headers, :data, :access_token
|
9
9
|
|
10
10
|
def initialize(method, url, content_type, timeout, user_agent: nil, extra_headers: nil, data: nil)
|
11
11
|
@method = method
|
@@ -16,6 +16,10 @@ module Kameleoon
|
|
16
16
|
@extra_headers = extra_headers
|
17
17
|
@data = !data.nil? && data.is_a?(String) ? data.encode('UTF-8') : data
|
18
18
|
end
|
19
|
+
|
20
|
+
def authorize(access_token)
|
21
|
+
@access_token = access_token
|
22
|
+
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
@@ -12,17 +12,29 @@ module Kameleoon
|
|
12
12
|
VISITOR_DATA_PATH = '/visit/visitor'
|
13
13
|
GET_DATA_PATH = '/map/map'
|
14
14
|
POST_DATA_PATH = '/map/maps'
|
15
|
+
ACCESS_TOKEN_PATH = '/oauth/token'
|
16
|
+
|
15
17
|
CONFIGURATION_API_URL_FORMAT = 'https://sdk-config.kameleoon.eu/%s'
|
16
18
|
RT_CONFIGURATION_URL = 'https://events.kameleoon.com:8110/sse'
|
19
|
+
DEFAULT_DATA_API_DOMAIN = 'data.kameleoon.io'
|
20
|
+
TEST_DATA_API_DOMAIN = 'data.kameleoon.net'
|
21
|
+
DEFAULT_AUTOMATION_API_DOMAIN = 'api.kameleoon.com'
|
22
|
+
TEST_AUTOMATION_API_DOMAIN = 'api.kameleoon.net'
|
17
23
|
|
18
|
-
|
19
|
-
TEST_DATA_API_URL = 'https://data.kameleoon.net'
|
20
|
-
|
21
|
-
attr_reader :site_code, :data_api_url
|
24
|
+
attr_reader :site_code, :data_api_domain, :automation_api_domain
|
22
25
|
|
23
|
-
def initialize(
|
26
|
+
def initialize(
|
27
|
+
site_code,
|
28
|
+
data_api_domain = DEFAULT_DATA_API_DOMAIN,
|
29
|
+
automation_api_domain = DEFAULT_AUTOMATION_API_DOMAIN
|
30
|
+
)
|
24
31
|
@site_code = site_code
|
25
|
-
@
|
32
|
+
@data_api_domain = data_api_domain
|
33
|
+
@automation_api_domain = automation_api_domain
|
34
|
+
end
|
35
|
+
|
36
|
+
def apply_data_api_domain(domain)
|
37
|
+
@data_api_domain = domain if domain.is_a?(String)
|
26
38
|
end
|
27
39
|
|
28
40
|
def make_tracking_url(visitor_code)
|
@@ -32,7 +44,7 @@ module Kameleoon
|
|
32
44
|
siteCode: @site_code,
|
33
45
|
visitorCode: visitor_code
|
34
46
|
}
|
35
|
-
"
|
47
|
+
"https://#{@data_api_domain}#{TRACKING_PATH}?#{UriHelper.encode_query(params)}"
|
36
48
|
end
|
37
49
|
|
38
50
|
def make_visitor_data_get_url(visitor_code)
|
@@ -44,7 +56,7 @@ module Kameleoon
|
|
44
56
|
customData: true,
|
45
57
|
version: 0
|
46
58
|
}
|
47
|
-
"
|
59
|
+
"https://#{@data_api_domain}#{VISITOR_DATA_PATH}?#{UriHelper.encode_query(params)}"
|
48
60
|
end
|
49
61
|
|
50
62
|
def make_api_data_get_request_url(key)
|
@@ -52,7 +64,7 @@ module Kameleoon
|
|
52
64
|
siteCode: @site_code,
|
53
65
|
key: key
|
54
66
|
}
|
55
|
-
"
|
67
|
+
"https://#{@data_api_domain}#{GET_DATA_PATH}?#{UriHelper.encode_query(params)}"
|
56
68
|
end
|
57
69
|
|
58
70
|
def make_configuration_url(environment = nil, timestamp = nil)
|
@@ -68,6 +80,10 @@ module Kameleoon
|
|
68
80
|
params = { siteCode: @site_code }
|
69
81
|
"#{RT_CONFIGURATION_URL}?#{UriHelper.encode_query(params)}"
|
70
82
|
end
|
83
|
+
|
84
|
+
def make_access_token_url
|
85
|
+
"https://#{@automation_api_domain}#{ACCESS_TOKEN_PATH}"
|
86
|
+
end
|
71
87
|
end
|
72
88
|
end
|
73
89
|
end
|
data/lib/kameleoon/version.rb
CHANGED
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: 3.
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kameleoon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: em-http-request
|
@@ -101,6 +101,8 @@ files:
|
|
101
101
|
- lib/kameleoon/kameleoon_client.rb
|
102
102
|
- lib/kameleoon/kameleoon_client_config.rb
|
103
103
|
- lib/kameleoon/kameleoon_client_factory.rb
|
104
|
+
- lib/kameleoon/managers/warehouse/warehouse_manager.rb
|
105
|
+
- lib/kameleoon/network/access_token_source.rb
|
104
106
|
- lib/kameleoon/network/activity_event.rb
|
105
107
|
- lib/kameleoon/network/content_type.rb
|
106
108
|
- lib/kameleoon/network/cookie/cookie_manager.rb
|