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