kameleoon-client-ruby 1.0.1 → 1.0.6
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 +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
|