kameleoon-client-ruby 1.0.1 → 1.0.6
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 +80 -27
- data/lib/kameleoon/factory.rb +2 -0
- data/lib/kameleoon/request.rb +3 -3
- data/lib/kameleoon/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dbb0fcb2b7bd0c35767c990d39eb0b5d06d996b4bbe1b3c43ec04ec03541a671
|
4
|
+
data.tar.gz: bcdf01f341003189b8a41d9184e792091603b1369b47bc5838786fa2f382c65d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b81e0518ca8b69e837daa26fe467d2ab5b306ed0dd4770e83d7bd8d022fc7fe485a9c95cf89a44b8bdf5d4ea2af6b335842c19b354c9db30ff37134dd29d7cb3
|
7
|
+
data.tar.gz: 420d763b0a306809a0d784c44d7058a214e76b2e9ddf88727fe14bfe71d327a18172c621eb7d48cf18874f34d20f1e7c1b87b594c639f9dc769dee41aba1e1f1
|
data/lib/kameleoon/client.rb
CHANGED
@@ -30,6 +30,7 @@ module Kameleoon
|
|
30
30
|
@client_id = client_id || config['client_id']
|
31
31
|
@client_secret = client_secret || config['client_secret']
|
32
32
|
@data_maximum_size = config['visitor_data_maximum_size'] || 500 # mb
|
33
|
+
@verbose_mode = config['verbose_mode'] || false
|
33
34
|
@experiments = []
|
34
35
|
@feature_flags = []
|
35
36
|
@data = {}
|
@@ -96,10 +97,13 @@ module Kameleoon
|
|
96
97
|
.join("\n") || ""
|
97
98
|
path = get_experiment_register_url(visitor_code, experiment_id)
|
98
99
|
request_options = { :path => path, :body => body }
|
100
|
+
log "Trigger experiment request: " + request_options.inspect
|
101
|
+
log "Trigger experiment connexion:" + connexion_options.inspect
|
99
102
|
request = EM::Synchrony.sync post(request_options, @tracking_url, connexion_options)
|
100
103
|
if is_successful(request)
|
101
104
|
variation_id = request.response
|
102
105
|
else
|
106
|
+
log "Failed to trigger experiment: " + request.inspect
|
103
107
|
raise Exception::ExperimentConfigurationNotFound.new(experiment_id) if variation_id.nil?
|
104
108
|
end
|
105
109
|
EM.stop
|
@@ -112,16 +116,16 @@ module Kameleoon
|
|
112
116
|
variation_id.to_i
|
113
117
|
else
|
114
118
|
visitor_data = @data.select { |key, value| key.to_s == visitor_code }.values.flatten! || []
|
115
|
-
if experiment['targetingSegment'].check_tree(visitor_data)
|
119
|
+
if experiment['targetingSegment'].nil? || experiment['targetingSegment'].check_tree(visitor_data)
|
116
120
|
threshold = obtain_hash_double(visitor_code, experiment['respoolTime'], experiment['id'])
|
117
121
|
experiment['deviations'].each do |key, value|
|
118
122
|
threshold -= value
|
119
123
|
if threshold < 0
|
120
|
-
|
124
|
+
track_experiment(visitor_code, experiment_id, key)
|
121
125
|
return key.to_s.to_i
|
122
126
|
end
|
123
127
|
end
|
124
|
-
|
128
|
+
track_experiment(visitor_code, experiment_id, REFERENCE, true)
|
125
129
|
raise Exception::NotActivated.new(visitor_code)
|
126
130
|
end
|
127
131
|
raise Exception::NotTargeted.new(visitor_code)
|
@@ -178,7 +182,7 @@ module Kameleoon
|
|
178
182
|
# @param [String] visitor_code Optional field - Visitor code, without visitor code it flush all of the data
|
179
183
|
#
|
180
184
|
def flush(visitor_code = nil)
|
181
|
-
|
185
|
+
track_data(visitor_code)
|
182
186
|
end
|
183
187
|
|
184
188
|
##
|
@@ -227,11 +231,15 @@ module Kameleoon
|
|
227
231
|
connexion_options = { :connect_timeout => (timeout.to_f / 1000.0) }
|
228
232
|
request_options = {
|
229
233
|
:path => get_experiment_register_url(visitor_code, id),
|
230
|
-
:body => (
|
234
|
+
:body => (data_not_sent(visitor_code).values.map { |data| data.obtain_full_post_text_line }.join("\n") || "").encode("UTF-8")
|
231
235
|
}
|
236
|
+
log "Activate feature request: " + request_options.inspect
|
237
|
+
log "Activate feature connexion:" + connexion_options.inspect
|
232
238
|
request = EM::Synchrony.sync post(request_options, @tracking_url, connexion_options)
|
233
239
|
if is_successful(request)
|
234
240
|
result = request.response
|
241
|
+
else
|
242
|
+
log "Failed to get activation:" + result.inspect
|
235
243
|
end
|
236
244
|
EM.stop
|
237
245
|
end
|
@@ -243,10 +251,10 @@ module Kameleoon
|
|
243
251
|
if feature_flag['targetingSegment'].nil? || feature_flag['targetingSegment'].check_tree(visitor_data)
|
244
252
|
threshold = obtain_hash_double(visitor_code, {}, id)
|
245
253
|
if threshold <= feature_flag['expositionRate']
|
246
|
-
|
254
|
+
track_experiment(visitor_code, id, feature_flag["variationsId"].first)
|
247
255
|
return true
|
248
256
|
else
|
249
|
-
|
257
|
+
track_experiment(visitor_code, id, REFERENCE, true)
|
250
258
|
return false
|
251
259
|
end
|
252
260
|
else
|
@@ -290,15 +298,16 @@ module Kameleoon
|
|
290
298
|
API_SSX_URL = "https://api-ssx.kameleoon.com"
|
291
299
|
REFERENCE = 0
|
292
300
|
attr :site_code, :client_id, :client_secret, :access_token, :experiments, :feature_flags, :scheduler, :data,
|
293
|
-
:blocking, :tracking_url, :default_timeout, :interval, :memory_limit
|
301
|
+
:blocking, :tracking_url, :default_timeout, :interval, :memory_limit, :verbose_mode
|
294
302
|
|
295
303
|
def fetch_configuration
|
296
|
-
print "=> Starting Scheduler"
|
297
304
|
@scheduler = Rufus::Scheduler.singleton
|
298
305
|
@scheduler.every @interval do
|
306
|
+
log("Scheduled job to fetch configuration is starting.")
|
299
307
|
fetch_configuration_job
|
300
308
|
end
|
301
309
|
@scheduler.schedule '0s' do
|
310
|
+
log("Start-up, fetching is starting")
|
302
311
|
fetch_configuration_job
|
303
312
|
end
|
304
313
|
end
|
@@ -334,15 +343,19 @@ module Kameleoon
|
|
334
343
|
end
|
335
344
|
|
336
345
|
def obtain_site
|
346
|
+
log "Fetching site"
|
337
347
|
query_params = { 'perPage' => 1 }
|
338
348
|
filters = [hash_filter('code', 'EQUAL', [@site_code])]
|
339
349
|
request = fetch_one('sites', query_params, filters)
|
340
350
|
if request != false
|
341
|
-
JSON.parse(request.response)
|
351
|
+
sites = JSON.parse(request.response)
|
352
|
+
log "Sites are fetched: " + sites.inspect
|
353
|
+
sites
|
342
354
|
end
|
343
355
|
end
|
344
356
|
|
345
357
|
def obtain_access_token
|
358
|
+
log "Fetching bearer token"
|
346
359
|
body = {
|
347
360
|
'grant_type' => 'client_credentials',
|
348
361
|
'client_id' => @client_id,
|
@@ -353,6 +366,9 @@ module Kameleoon
|
|
353
366
|
request = EM::Synchrony.sync post({ :path => '/oauth/token', :body => body, :head => header })
|
354
367
|
if is_successful(request)
|
355
368
|
@access_token = JSON.parse(request.response)['access_token']
|
369
|
+
log "Bearer Token is fetched: " + @access_token.to_s
|
370
|
+
else
|
371
|
+
log "Failed to fetch bearer token: " + request.inspect
|
356
372
|
end
|
357
373
|
end
|
358
374
|
|
@@ -381,26 +397,32 @@ module Kameleoon
|
|
381
397
|
end
|
382
398
|
|
383
399
|
def obtain_tests(site_id, per_page = -1)
|
400
|
+
log "Fetching experiments"
|
384
401
|
query_values = { 'perPage' => per_page }
|
385
402
|
filters = [
|
386
403
|
hash_filter('siteId', 'EQUAL', [site_id]),
|
387
|
-
hash_filter('status', '
|
404
|
+
hash_filter('status', 'IN', ['ACTIVE', 'DEVIATED']),
|
388
405
|
hash_filter('type', 'IN', ['SERVER_SIDE', 'HYBRID'])
|
389
406
|
]
|
390
|
-
fetch_all('experiments', query_values, filters).map { |it| JSON.parse(it.response) }.flatten.map do |test|
|
407
|
+
experiments = fetch_all('experiments', query_values, filters).map { |it| JSON.parse(it.response) }.flatten.map do |test|
|
391
408
|
complete_experiment(test)
|
392
409
|
end
|
410
|
+
log "Experiment are fetched: " + experiments.inspect
|
411
|
+
experiments
|
393
412
|
end
|
394
413
|
|
395
414
|
def obtain_feature_flags(site_id, per_page = -1)
|
415
|
+
log "Fetching feature flags"
|
396
416
|
query_values = { 'perPage' => per_page }
|
397
417
|
filters = [
|
398
418
|
hash_filter('siteId', 'EQUAL', [site_id]),
|
399
419
|
hash_filter('status', 'EQUAL', ['ACTIVE'])
|
400
420
|
]
|
401
|
-
fetch_all('feature-flags', query_values, filters).map { |it| JSON.parse(it.response) }.flatten.map do |ff|
|
421
|
+
feature_flags = fetch_all('feature-flags', query_values, filters).map { |it| JSON.parse(it.response) }.flatten.map do |ff|
|
402
422
|
complete_experiment(ff)
|
403
423
|
end
|
424
|
+
log "Feature flags are fetched: " + feature_flags.inspect
|
425
|
+
feature_flags
|
404
426
|
end
|
405
427
|
|
406
428
|
def fetch_all(path, query_values = {}, filters = [])
|
@@ -423,6 +445,7 @@ module Kameleoon
|
|
423
445
|
end
|
424
446
|
request = EM::Synchrony.sync get({ :path => path, :query => query_values, :head => hash_headers })
|
425
447
|
unless is_successful(request)
|
448
|
+
log "Failed to fetch" + request.inspect
|
426
449
|
return false
|
427
450
|
end
|
428
451
|
request
|
@@ -449,6 +472,10 @@ module Kameleoon
|
|
449
472
|
url
|
450
473
|
end
|
451
474
|
|
475
|
+
def get_data_register_url(visitor_code)
|
476
|
+
"/dataTracking?" + URI.encode_www_form(get_common_ssx_parameters(visitor_code))
|
477
|
+
end
|
478
|
+
|
452
479
|
def get_feature_flag(feature_key)
|
453
480
|
if feature_key.is_a?(String)
|
454
481
|
feature_flag = @feature_flags.select { |ff| ff['identificationKey'] == feature_key}.first
|
@@ -463,19 +490,48 @@ module Kameleoon
|
|
463
490
|
feature_flag
|
464
491
|
end
|
465
492
|
|
466
|
-
def
|
493
|
+
def track_experiment(visitor_code, experiment_id, variation_id = nil, none_variation = false)
|
494
|
+
data_not_sent = data_not_sent(visitor_code)
|
495
|
+
options = {
|
496
|
+
:path => get_experiment_register_url(visitor_code, experiment_id, variation_id, none_variation),
|
497
|
+
:body => ((data_not_sent.values[0] || []).map{ |it| it.obtain_full_post_text_line }.join("\n") || "").encode("UTF-8"),
|
498
|
+
:head => { "Content-Type" => "text/plain"}
|
499
|
+
}
|
500
|
+
trial = 0
|
501
|
+
log "Start post tracking experiment: " + data_not_sent.inspect
|
502
|
+
Thread.new do
|
503
|
+
EM.synchrony do
|
504
|
+
while trial < 10
|
505
|
+
request = EM::Synchrony.sync post(options, @tracking_url)
|
506
|
+
log "Request " + request.inspect
|
507
|
+
if is_successful(request)
|
508
|
+
(data_not_sent.values[0] || []).each { |it| it.sent = true }
|
509
|
+
EM.stop
|
510
|
+
end
|
511
|
+
trial += 1
|
512
|
+
end
|
513
|
+
EM.stop
|
514
|
+
end
|
515
|
+
log "Post to experiment tracking is done after " + trial.to_s + " trials"
|
516
|
+
Thread.exit
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
def track_data(visitor_code = nil)
|
467
521
|
Thread.new do
|
468
522
|
EM.synchrony do
|
469
|
-
entries = select_data_to_sent(visitor_code)
|
470
523
|
trials = 10
|
471
524
|
concurrency = 1
|
472
|
-
|
473
|
-
|
525
|
+
data_not_sent = data_not_sent(visitor_code)
|
526
|
+
log "Start post tracking data: " + data_not_sent.inspect
|
527
|
+
while trials > 0 && !data_not_sent.empty?
|
528
|
+
EM::Synchrony::Iterator.new(data_not_sent, concurrency).map do |entry, iter|
|
474
529
|
options = {
|
475
|
-
:path =>
|
530
|
+
:path => get_data_register_url(entry.first),
|
476
531
|
:body => (entry.last.map { |data| data.obtain_full_post_text_line }.join("\n") || "").encode("UTF-8"),
|
477
532
|
:head => { "Content-Type" => "text/plain" }
|
478
533
|
}
|
534
|
+
log "Post tracking data for visitor_code: " + entry.first + " with options: " + options.inspect
|
479
535
|
request = post(options, @tracking_url)
|
480
536
|
request.callback {
|
481
537
|
if is_successful(request)
|
@@ -485,16 +541,17 @@ module Kameleoon
|
|
485
541
|
}
|
486
542
|
request.errback { iter.return(request) }
|
487
543
|
end
|
488
|
-
|
544
|
+
data_not_sent = data_not_sent(visitor_code)
|
489
545
|
trials -= 1
|
490
546
|
end
|
547
|
+
log "Post to data tracking is done."
|
491
548
|
EM.stop
|
492
549
|
end
|
493
550
|
Thread.exit
|
494
551
|
end
|
495
552
|
end
|
496
553
|
|
497
|
-
def
|
554
|
+
def data_not_sent(visitor_code = nil)
|
498
555
|
if visitor_code.nil?
|
499
556
|
@data.select {|key, values| values.any? {|data| !data.sent}}
|
500
557
|
else
|
@@ -502,13 +559,9 @@ module Kameleoon
|
|
502
559
|
end
|
503
560
|
end
|
504
561
|
|
505
|
-
def
|
506
|
-
if
|
507
|
-
|
508
|
-
elsif type == "experimentTracking"
|
509
|
-
return get_experiment_register_url(visitor_code, experiment_id, variation_id, none_variation)
|
510
|
-
else
|
511
|
-
raise TypeError("Unknown type for post_beacon: " + type.to_s)
|
562
|
+
def log(text)
|
563
|
+
if @verbose_mode
|
564
|
+
print "Kameleoon Log: " + text.to_s + "\n"
|
512
565
|
end
|
513
566
|
end
|
514
567
|
end
|
data/lib/kameleoon/factory.rb
CHANGED
@@ -17,6 +17,8 @@ module Kameleoon
|
|
17
17
|
#
|
18
18
|
def self.create(site_code, blocking = false, config_path = CONFIG_PATH, client_id = nil, client_secret = nil)
|
19
19
|
client = Client.new(site_code, config_path, blocking, CONFIGURATION_UPDATE_INTERVAL, DEFAULT_TIMEOUT, client_id, client_secret)
|
20
|
+
client.send(:log, "Warning: you are using the blocking mode") if blocking
|
21
|
+
client.send(:log, "Client created with site code: " + site_code.to_s)
|
20
22
|
client.send(:fetch_configuration)
|
21
23
|
client
|
22
24
|
end
|
data/lib/kameleoon/request.rb
CHANGED
@@ -23,7 +23,7 @@ module Kameleoon
|
|
23
23
|
private
|
24
24
|
|
25
25
|
def request(method, request_options, url, connexion_options)
|
26
|
-
|
26
|
+
connexion_options[:tls] = {verify_peer: false}
|
27
27
|
add_user_agent(request_options)
|
28
28
|
case method
|
29
29
|
when Method::POST then
|
@@ -42,9 +42,9 @@ module Kameleoon
|
|
42
42
|
|
43
43
|
def add_user_agent(request_options)
|
44
44
|
if request_options[:head].nil?
|
45
|
-
request_options[:head] = {'
|
45
|
+
request_options[:head] = {'Kameleoon-Client' => 'sdk/ruby/' + Kameleoon::VERSION}
|
46
46
|
else
|
47
|
-
request_options[:head].store('
|
47
|
+
request_options[:head].store('Kameleoon-Client', 'sdk/ruby/' + Kameleoon::VERSION)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
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: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kameleoon - Guillaume Grandjean
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: em-http-request
|