kameleoon-client-ruby 2.1.0 → 2.2.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/client.rb +105 -151
- data/lib/kameleoon/configuration/rule.rb +1 -1
- data/lib/kameleoon/data/browser.rb +39 -0
- data/lib/kameleoon/data/conversion.rb +33 -0
- data/lib/kameleoon/data/custom_data.rb +60 -0
- data/lib/kameleoon/data/data.rb +38 -0
- data/lib/kameleoon/data/device.rb +31 -0
- data/lib/kameleoon/data/page_view.rb +34 -0
- data/lib/kameleoon/data/user_agent.rb +14 -0
- data/lib/kameleoon/network/activity_event.rb +31 -0
- data/lib/kameleoon/network/content_type.rb +11 -0
- data/lib/kameleoon/network/experiment_event.rb +35 -0
- data/lib/kameleoon/network/method.rb +10 -0
- data/lib/kameleoon/network/net_provider.rb +91 -0
- data/lib/kameleoon/network/network_manager.rb +114 -0
- data/lib/kameleoon/network/request.rb +20 -0
- data/lib/kameleoon/network/response.rb +30 -0
- data/lib/kameleoon/network/uri_helper.rb +37 -0
- data/lib/kameleoon/network/url_provider.rb +71 -0
- data/lib/kameleoon/targeting/condition.rb +40 -11
- data/lib/kameleoon/targeting/condition_factory.rb +35 -12
- data/lib/kameleoon/targeting/conditions/browser_condition.rb +71 -0
- data/lib/kameleoon/targeting/conditions/conversion_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/custom_datum.rb +60 -65
- data/lib/kameleoon/targeting/conditions/device_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/exclusive_experiment.rb +0 -12
- data/lib/kameleoon/targeting/conditions/page_title_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/page_url_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/sdk_language_condition.rb +65 -0
- data/lib/kameleoon/targeting/conditions/string_value_condition.rb +40 -0
- data/lib/kameleoon/targeting/conditions/target_experiment.rb +4 -8
- data/lib/kameleoon/targeting/conditions/unknown_condition.rb +15 -0
- data/lib/kameleoon/targeting/conditions/visitor_code_condition.rb +16 -0
- data/lib/kameleoon/targeting/models.rb +0 -24
- data/lib/kameleoon/utils.rb +1 -1
- data/lib/kameleoon/version.rb +28 -1
- metadata +28 -4
- data/lib/kameleoon/data.rb +0 -175
- data/lib/kameleoon/request.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3ada1f2651143c67ac458a8adab629e1d6ad17e95a204809a0a2b44f0ee3a28
|
4
|
+
data.tar.gz: 306fab877c00913cc4b13cecfdf9e773c2bb735be110747df37d509b537d2e01
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38ff8932ce2f9a0e9d72644ae47de0d0f34434943f33328f0459607e34769c83e64ff6325989f9722cc8cb202d440d5d8891dea073179d269e01d6b49fa361f9
|
7
|
+
data.tar.gz: b3ee0f99356eac881b01970269cde022435872c270268ffc6ec8c0dc0d31abe3816914a497edb15e744810f60190165c84424f4799876ff56d1e24e1590d56f8
|
data/lib/kameleoon/client.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'kameleoon/targeting/models'
|
4
|
-
require 'kameleoon/request'
|
5
4
|
require 'kameleoon/exceptions'
|
6
5
|
require 'kameleoon/cookie'
|
6
|
+
require 'kameleoon/data/custom_data'
|
7
|
+
require 'kameleoon/data/user_agent'
|
7
8
|
require 'kameleoon/configuration/feature_flag'
|
8
9
|
require 'kameleoon/configuration/variation'
|
9
10
|
require 'kameleoon/configuration/settings'
|
11
|
+
require 'kameleoon/network/activity_event'
|
12
|
+
require 'kameleoon/network/experiment_event'
|
13
|
+
require 'kameleoon/network/url_provider'
|
14
|
+
require 'kameleoon/network/network_manager'
|
10
15
|
require 'kameleoon/real_time/real_time_configuration_service'
|
11
16
|
require 'kameleoon/storage/variation_storage'
|
12
17
|
require 'kameleoon/hybrid/manager'
|
@@ -26,7 +31,6 @@ module Kameleoon
|
|
26
31
|
# Client for Kameleoon
|
27
32
|
#
|
28
33
|
class Client
|
29
|
-
include Request
|
30
34
|
include Cookie
|
31
35
|
include Exception
|
32
36
|
|
@@ -39,9 +43,6 @@ module Kameleoon
|
|
39
43
|
@default_timeout = config['default_timeout'] || default_timeout # in ms
|
40
44
|
refresh_interval = config['actions_configuration_refresh_interval']
|
41
45
|
@interval = refresh_interval.nil? ? interval : "#{refresh_interval}m"
|
42
|
-
@tracking_url = config['tracking_url'] || API_SSX_URL
|
43
|
-
@api_data_url = 'https://api-data.kameleoon.com'
|
44
|
-
@events_url = 'https://events.kameleoon.com:8110/'
|
45
46
|
@real_time_configuration_service = nil
|
46
47
|
@update_configuration_handler = nil
|
47
48
|
@fetch_configuration_update_job = nil
|
@@ -62,6 +63,12 @@ module Kameleoon
|
|
62
63
|
Kameleoon::Storage::CacheFactoryImpl.new,
|
63
64
|
method(:log)
|
64
65
|
)
|
66
|
+
@network_manager = Network::NetworkManager.new(
|
67
|
+
@environment,
|
68
|
+
@default_timeout,
|
69
|
+
Network::UrlProvider.new(@site_code, Network::UrlProvider::DEFAULT_DATA_API_URL),
|
70
|
+
method(:log)
|
71
|
+
)
|
65
72
|
end
|
66
73
|
|
67
74
|
##
|
@@ -129,22 +136,22 @@ module Kameleoon
|
|
129
136
|
"Experiment #{experiment_id} is not found"
|
130
137
|
end
|
131
138
|
check_site_code_enable(experiment)
|
132
|
-
|
139
|
+
targeted = check_targeting(visitor_code, experiment_id, experiment)
|
140
|
+
if targeted
|
133
141
|
# saved_variation = get_valid_saved_variation(visitor_code, experiment)
|
134
142
|
variation_id = calculate_variation_for_experiment(visitor_code, experiment)
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
else
|
140
|
-
track_experiment(visitor_code, experiment_id, REFERENCE, true)
|
141
|
-
raise Exception::NotAllocated.new(visitor_code),
|
142
|
-
"Experiment #{experiment_id} is not active for visitor #{visitor_code}"
|
143
|
-
end
|
144
|
-
else
|
143
|
+
save_variation(visitor_code, experiment_id, variation_id)
|
144
|
+
end
|
145
|
+
_send_tracking_request(visitor_code, experiment_id, variation_id)
|
146
|
+
unless targeted
|
145
147
|
raise Exception::NotTargeted.new(visitor_code),
|
146
148
|
"Experiment #{experiment_id} is not targeted for visitor #{visitor_code}"
|
147
149
|
end
|
150
|
+
if variation_id.nil?
|
151
|
+
raise Exception::NotAllocated.new(visitor_code),
|
152
|
+
"Experiment #{experiment_id} is not active for visitor #{visitor_code}"
|
153
|
+
end
|
154
|
+
variation_id
|
148
155
|
end
|
149
156
|
|
150
157
|
##
|
@@ -208,7 +215,7 @@ module Kameleoon
|
|
208
215
|
def flush(visitor_code = nil)
|
209
216
|
check_visitor_code(visitor_code) unless visitor_code.nil?
|
210
217
|
if !visitor_code.nil?
|
211
|
-
|
218
|
+
_send_tracking_request(visitor_code)
|
212
219
|
else
|
213
220
|
@data.select { |_, values| values.any? { |data| !data.sent } }.each_key { |key| flush(key) }
|
214
221
|
end
|
@@ -265,7 +272,7 @@ module Kameleoon
|
|
265
272
|
# associated targeting segment conditions were not fulfilled. He should see the reference variation
|
266
273
|
# @raise [Kameleoon::Exception::VisitorCodeNotValid] If the visitor code is empty or longer than 255 chars
|
267
274
|
#
|
268
|
-
# DEPRECATED. Please use `
|
275
|
+
# DEPRECATED. Please use `feature_active?` instead.
|
269
276
|
def activate_feature(visitor_code, feature_key)
|
270
277
|
warn '[DEPRECATION] `activate_feature` is deprecated. Please use `feature_active?` instead.'
|
271
278
|
feature_active?(visitor_code, feature_key)
|
@@ -384,7 +391,7 @@ module Kameleoon
|
|
384
391
|
end
|
385
392
|
|
386
393
|
##
|
387
|
-
# The
|
394
|
+
# The get_remote_data method allows you to retrieve data (according to a key passed as argument)
|
388
395
|
# stored on a remote Kameleoon server. Usually data will be stored on our remote
|
389
396
|
# servers via the use of our Data API.
|
390
397
|
# This method, along with the availability of our highly scalable servers for this purpose, provides a convenient
|
@@ -395,21 +402,36 @@ module Kameleoon
|
|
395
402
|
# This field is optional.
|
396
403
|
#
|
397
404
|
# @return [Hash] Hash object of the json object.
|
398
|
-
def
|
399
|
-
|
400
|
-
|
401
|
-
log "Retrieve API Data connexion: #{connexion_options.inspect}"
|
402
|
-
response = get_sync(@api_data_url + path, connexion_options)
|
403
|
-
return nil unless successful_sync?(response)
|
404
|
-
|
405
|
-
JSON.parse(response.body) unless response.nil?
|
405
|
+
def get_remote_data(key, timeout = @default_timeout)
|
406
|
+
response = @network_manager.get_remote_data(key, timeout)
|
407
|
+
JSON.parse(response) if response
|
406
408
|
end
|
407
409
|
|
408
410
|
##
|
409
411
|
# DEPRECATED. Please use `get_feature_variable` instead.
|
410
412
|
def retrieve_data_from_remote_source(key, timeout = @default_timeout)
|
411
413
|
warn '[DEPRECATION] `retrieve_data_from_remote_source` is deprecated. Please use `get_remote_date` instead.'
|
412
|
-
|
414
|
+
get_remote_data(key, timeout)
|
415
|
+
end
|
416
|
+
|
417
|
+
##
|
418
|
+
# The get_remote_visitor_data is a method for retrieving custom data for
|
419
|
+
# the latest visit of `visitor_code` from Kameleoon Data API and optionally adding it
|
420
|
+
# to the storage so that other methods could decide whether the current visitor is targeted or not.
|
421
|
+
#
|
422
|
+
# @param [String] visitor_code The visitor code for which you want to retrieve the assigned data.
|
423
|
+
# This field is mandatory.
|
424
|
+
# @param [Bool] add_data A boolean indicating whether the method should automatically add retrieved data
|
425
|
+
# for a visitor. If not specified, the default value is `True`. This field is optional.
|
426
|
+
# @param [Int] timeout Timeout for request (in milliseconds). Equals default_timeout in a config file.
|
427
|
+
# This field is optional.
|
428
|
+
#
|
429
|
+
# @return [Array] An array of data assigned to the given visitor.
|
430
|
+
def get_remote_visitor_data(visitor_code, timeout = nil, add_data: true)
|
431
|
+
response = @network_manager.get_remote_visitor_data(visitor_code, timeout)
|
432
|
+
data_array = parse_custom_data_array(visitor_code, response)
|
433
|
+
add_data(visitor_code, *data_array) if add_data && !data_array.empty?
|
434
|
+
data_array
|
413
435
|
end
|
414
436
|
|
415
437
|
##
|
@@ -490,7 +512,6 @@ module Kameleoon
|
|
490
512
|
|
491
513
|
private
|
492
514
|
|
493
|
-
API_SSX_URL = 'https://api-ssx.kameleoon.com'
|
494
515
|
REFERENCE = 0
|
495
516
|
DEFAULT_ENVIRONMENT = 'production'
|
496
517
|
CACHE_EXPIRATION_TIMEOUT = 5
|
@@ -507,7 +528,7 @@ module Kameleoon
|
|
507
528
|
def fetch_configuration_job(time_stamp = nil)
|
508
529
|
EM.synchrony do
|
509
530
|
begin
|
510
|
-
ok = obtain_configuration(
|
531
|
+
ok = obtain_configuration(time_stamp)
|
511
532
|
if !ok && @settings.real_time_update
|
512
533
|
@settings.real_time_update = false
|
513
534
|
log('Switching to polling mode due to failed fetch')
|
@@ -540,10 +561,10 @@ module Kameleoon
|
|
540
561
|
def start_real_time_configuration_service_if_needed
|
541
562
|
return unless @real_time_configuration_service.nil?
|
542
563
|
|
543
|
-
|
564
|
+
url = @network_manager.url_provider.make_real_time_url
|
544
565
|
fetch_func = proc { |real_time_event| fetch_configuration_job(real_time_event.time_stamp) }
|
545
566
|
@real_time_configuration_service =
|
546
|
-
Kameleoon::RealTime::RealTimeConfigurationService.new(
|
567
|
+
Kameleoon::RealTime::RealTimeConfigurationService.new(url, fetch_func, method(:log))
|
547
568
|
end
|
548
569
|
|
549
570
|
def stop_real_time_configuration_service_if_needed
|
@@ -577,15 +598,12 @@ module Kameleoon
|
|
577
598
|
# { 'field' => field, 'operator' => operator, 'parameters' => parameters }
|
578
599
|
# end
|
579
600
|
|
580
|
-
def obtain_configuration(
|
601
|
+
def obtain_configuration(time_stamp = nil)
|
581
602
|
log 'Fetching configuration from Client-Config service'
|
582
|
-
|
583
|
-
|
584
|
-
request_path += "&ts=#{time_stamp}" unless time_stamp.nil?
|
585
|
-
request = request_configuration(request_path)
|
586
|
-
return false unless request
|
603
|
+
response = @network_manager.fetch_configuration(time_stamp)
|
604
|
+
return false unless response
|
587
605
|
|
588
|
-
configuration = JSON.parse(
|
606
|
+
configuration = JSON.parse(response)
|
589
607
|
@experiments = Kameleoon::Configuration::Experiment.create_from_array(configuration['experiments']) ||
|
590
608
|
@experiments
|
591
609
|
@feature_flags = Kameleoon::Configuration::FeatureFlag.create_from_array(
|
@@ -593,7 +611,7 @@ module Kameleoon
|
|
593
611
|
)
|
594
612
|
@settings.update(configuration['configuration'])
|
595
613
|
call_update_handler_if_needed(!time_stamp.nil?)
|
596
|
-
log "Feature flags are fetched: #{
|
614
|
+
log "Feature flags are fetched: #{response.inspect}"
|
597
615
|
true
|
598
616
|
end
|
599
617
|
|
@@ -616,46 +634,6 @@ module Kameleoon
|
|
616
634
|
nil
|
617
635
|
end
|
618
636
|
|
619
|
-
def request_configuration(path)
|
620
|
-
request = EM::Synchrony.sync get({ path: path }, CLIENT_CONFIG_URL)
|
621
|
-
unless successful?(request)
|
622
|
-
log "Failed to fetch #{request.inspect}"
|
623
|
-
return false
|
624
|
-
end
|
625
|
-
request
|
626
|
-
end
|
627
|
-
|
628
|
-
def get_common_ssx_parameters(visitor_code)
|
629
|
-
{
|
630
|
-
nonce: Kameleoon::Utils.generate_random_string(16),
|
631
|
-
siteCode: @site_code,
|
632
|
-
visitorCode: visitor_code
|
633
|
-
}
|
634
|
-
end
|
635
|
-
|
636
|
-
def get_experiment_register_url(visitor_code, experiment_id, variation_id = nil, none_variation = false)
|
637
|
-
url = "/experimentTracking?#{URI.encode_www_form(get_common_ssx_parameters(visitor_code))}"
|
638
|
-
url += "&experimentId=#{experiment_id}"
|
639
|
-
return url if variation_id.nil?
|
640
|
-
|
641
|
-
url += "&variationId=#{variation_id}"
|
642
|
-
url += '&noneVariation=true' if none_variation
|
643
|
-
|
644
|
-
url
|
645
|
-
end
|
646
|
-
|
647
|
-
def get_data_register_url(visitor_code)
|
648
|
-
"/dataTracking?#{URI.encode_www_form(get_common_ssx_parameters(visitor_code))}"
|
649
|
-
end
|
650
|
-
|
651
|
-
def get_api_data_request_url(key)
|
652
|
-
mapKey = {
|
653
|
-
siteCode: site_code,
|
654
|
-
key: key
|
655
|
-
}
|
656
|
-
"/data?#{URI.encode_www_form(mapKey)}"
|
657
|
-
end
|
658
|
-
|
659
637
|
def find_feature_flag(feature_key)
|
660
638
|
if feature_key.is_a?(String)
|
661
639
|
feature_flag = @feature_flags.select { |ff| ff.feature_key == feature_key }.first
|
@@ -669,67 +647,6 @@ module Kameleoon
|
|
669
647
|
feature_flag
|
670
648
|
end
|
671
649
|
|
672
|
-
def track_experiment(visitor_code, experiment_id, variation_id = nil, none_variation: false)
|
673
|
-
data_not_sent = data_not_sent(visitor_code)
|
674
|
-
options = {
|
675
|
-
path: get_experiment_register_url(visitor_code, experiment_id, variation_id, none_variation),
|
676
|
-
body: (data_not_sent.map(&:obtain_full_post_text_line).join("\n") || '').encode('UTF-8'),
|
677
|
-
head: { 'Content-Type': 'text/plain' }
|
678
|
-
}
|
679
|
-
set_user_agent_to_headers(visitor_code, options[:head])
|
680
|
-
trial = 0
|
681
|
-
success = false
|
682
|
-
log "Start post tracking experiment: #{data_not_sent.inspect}"
|
683
|
-
Thread.new do
|
684
|
-
while trial < 10
|
685
|
-
log "Send Experiment Tracking #{options.inspect}"
|
686
|
-
response = post_sync(options, @tracking_url)
|
687
|
-
log "Response #{response.inspect}"
|
688
|
-
if successful_sync?(response)
|
689
|
-
data_not_sent.each { |it| it.sent = true }
|
690
|
-
success = true
|
691
|
-
break
|
692
|
-
end
|
693
|
-
trial += 1
|
694
|
-
end
|
695
|
-
if success
|
696
|
-
log "Post to experiment tracking is done after #{trial + 1} trials"
|
697
|
-
else
|
698
|
-
log "Post to experiment tracking is failed after #{trial} trials"
|
699
|
-
end
|
700
|
-
end
|
701
|
-
end
|
702
|
-
|
703
|
-
def track_data(visitor_code)
|
704
|
-
Thread.new do
|
705
|
-
trials = 0
|
706
|
-
data_not_sent = data_not_sent(visitor_code)
|
707
|
-
log "Start post tracking data: #{data_not_sent.inspect}"
|
708
|
-
while trials < 10 && !data_not_sent.empty?
|
709
|
-
options = {
|
710
|
-
path: get_data_register_url(visitor_code),
|
711
|
-
body: (data_not_sent.map(&:obtain_full_post_text_line).join("\n") || '').encode('UTF-8'),
|
712
|
-
head: { 'Content-Type': 'text/plain' }
|
713
|
-
}
|
714
|
-
set_user_agent_to_headers(visitor_code, options[:head])
|
715
|
-
log "Post tracking data for visitor_code: #{visitor_code} with options: #{options.inspect}"
|
716
|
-
response = post_sync(options, @tracking_url)
|
717
|
-
log "Response #{response.inspect}"
|
718
|
-
if successful_sync?(response)
|
719
|
-
data_not_sent.each { |it| it.sent = true }
|
720
|
-
success = true
|
721
|
-
break
|
722
|
-
end
|
723
|
-
trials += 1
|
724
|
-
end
|
725
|
-
if success
|
726
|
-
log "Post to data tracking is done after #{trials + 1} trials"
|
727
|
-
else
|
728
|
-
log "Post to data tracking is failed after #{trials} trials"
|
729
|
-
end
|
730
|
-
end
|
731
|
-
end
|
732
|
-
|
733
650
|
def check_site_code_enable(campaign)
|
734
651
|
raise Exception::SiteCodeDisabled.new(site_code), site_code unless campaign.site_enabled
|
735
652
|
end
|
@@ -770,8 +687,17 @@ module Kameleoon
|
|
770
687
|
def get_condition_data(type, visitor_code, campaign_id)
|
771
688
|
condition_data = nil
|
772
689
|
case type
|
773
|
-
when Kameleoon::Targeting::ConditionType::CUSTOM_DATUM
|
690
|
+
when Kameleoon::Targeting::ConditionType::CUSTOM_DATUM,
|
691
|
+
Kameleoon::Targeting::ConditionType::PAGE_TITLE,
|
692
|
+
Kameleoon::Targeting::ConditionType::PAGE_URL,
|
693
|
+
Kameleoon::Targeting::ConditionType::DEVICE_TYPE,
|
694
|
+
Kameleoon::Targeting::ConditionType::BROWSER,
|
695
|
+
Kameleoon::Targeting::ConditionType::CONVERSIONS
|
774
696
|
condition_data = (@data[visitor_code] || []).flatten
|
697
|
+
when Kameleoon::Targeting::ConditionType::SDK_LANGUAGE
|
698
|
+
condition_data = Kameleoon::Targeting::SdkInfo.new(Kameleoon::SDK_NAME, Kameleoon::SDK_VERSION)
|
699
|
+
when Kameleoon::Targeting::ConditionType::VISITOR_CODE
|
700
|
+
condition_data = visitor_code
|
775
701
|
when Kameleoon::Targeting::ConditionType::TARGET_EXPERIMENT
|
776
702
|
condition_data = @variation_storage.get_hash_saved_variation_id(visitor_code)
|
777
703
|
when Kameleoon::Targeting::ConditionType::EXCLUSIVE_EXPERIMENT
|
@@ -790,10 +716,11 @@ module Kameleoon
|
|
790
716
|
variation, rule = _calculate_variation_key_for_feature(visitor_code, feature_flag)
|
791
717
|
variation_key = _get_variation_key(variation, rule, feature_flag)
|
792
718
|
unless rule.nil?
|
793
|
-
|
719
|
+
experiment_id = rule.experiment_id
|
794
720
|
variation_id = variation.variation_id unless variation.nil?
|
795
|
-
|
721
|
+
save_variation(visitor_code, experiment_id, variation_id)
|
796
722
|
end
|
723
|
+
_send_tracking_request(visitor_code, experiment_id, variation_id)
|
797
724
|
[feature_flag, variation_key]
|
798
725
|
end
|
799
726
|
|
@@ -809,11 +736,12 @@ module Kameleoon
|
|
809
736
|
hash_rule = obtain_hash_double_rule(visitor_code, rule.id, rule.respool_time)
|
810
737
|
# check main expostion for rule with hashRule
|
811
738
|
if hash_rule <= rule.exposition
|
739
|
+
return [rule.variation_by_exposition[0], rule] if rule.targeted_delivery_type?
|
740
|
+
|
812
741
|
# uses for variation's expositions
|
813
742
|
hash_variation = obtain_hash_double_rule(visitor_code, rule.experiment_id, rule.respool_time)
|
814
743
|
# get variation key with new hashVariation
|
815
744
|
variation = rule.get_variation(hash_variation)
|
816
|
-
# variation_key can be nil for experiment rules only, for targeted rule will be always exist
|
817
745
|
return [variation, rule] unless variation.nil?
|
818
746
|
# if visitor is targeted for targeted rule then break cycle -> return default
|
819
747
|
elsif rule.targeted_delivery_type?
|
@@ -833,20 +761,23 @@ module Kameleoon
|
|
833
761
|
def _get_variation_key(var_by_exp, rule, feature_flag)
|
834
762
|
return var_by_exp.variation_key unless var_by_exp.nil?
|
835
763
|
|
836
|
-
return Kameleoon::Configuration::VariationType::VARIATION_OFF if !rule.nil? && rule.
|
764
|
+
return Kameleoon::Configuration::VariationType::VARIATION_OFF if !rule.nil? && rule.experimentation_type?
|
837
765
|
|
838
766
|
feature_flag.default_variation_key
|
839
767
|
end
|
840
768
|
|
841
769
|
##
|
842
770
|
# helper method for sending tracking requests for new FF
|
843
|
-
def _send_tracking_request(visitor_code, experiment_id, variation_id)
|
844
|
-
|
845
|
-
|
846
|
-
|
771
|
+
def _send_tracking_request(visitor_code, experiment_id = nil, variation_id = nil)
|
772
|
+
user_agent = @user_agents[visitor_code]&.value
|
773
|
+
data_not_sent = data_not_sent(visitor_code)
|
774
|
+
if experiment_id.nil? || variation_id.nil?
|
775
|
+
data_not_sent.append(Network::ActivityEvent.new) if data_not_sent.empty?
|
847
776
|
else
|
848
|
-
|
777
|
+
data_not_sent.append(Network::ExperimentEvent.new(experiment_id, variation_id))
|
849
778
|
end
|
779
|
+
log "Start post tracking: #{data_not_sent.inspect}"
|
780
|
+
@network_manager.send_tracking_data(visitor_code, data_not_sent, user_agent)
|
850
781
|
end
|
851
782
|
|
852
783
|
##
|
@@ -862,5 +793,28 @@ module Kameleoon
|
|
862
793
|
'Unknown type for feature variable'
|
863
794
|
end
|
864
795
|
end
|
796
|
+
|
797
|
+
##
|
798
|
+
# helper method used by `get_remote_visitor_data`
|
799
|
+
def parse_custom_data_array(visitor_code, response)
|
800
|
+
return [] unless response
|
801
|
+
|
802
|
+
raw = JSON.parse(response)
|
803
|
+
latest_record = raw['currentVisit']
|
804
|
+
if latest_record.nil?
|
805
|
+
previous_visits = raw['previousVisits']
|
806
|
+
return [] unless previous_visits
|
807
|
+
|
808
|
+
latest_record = previous_visits.first
|
809
|
+
end
|
810
|
+
events = latest_record['customDataEvents']
|
811
|
+
return [] if events.nil?
|
812
|
+
|
813
|
+
events.map { |ev| ev['data'] }.compact
|
814
|
+
.map { |jcd| CustomData.new(jcd['index'] || -1, *(jcd['valuesCountMap'] || {}).keys) }
|
815
|
+
rescue StandardError => e
|
816
|
+
log("Parsing of visitor data of '#{visitor_code}' failed: #{e}")
|
817
|
+
[]
|
818
|
+
end
|
865
819
|
end
|
866
820
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'kameleoon/network/uri_helper'
|
5
|
+
require_relative 'data'
|
6
|
+
|
7
|
+
module Kameleoon
|
8
|
+
module BrowserType
|
9
|
+
CHROME = 0
|
10
|
+
INTERNET_EXPLORER = 1
|
11
|
+
FIREFOX = 2
|
12
|
+
SAFARI = 3
|
13
|
+
OPERA = 4
|
14
|
+
OTHER = 5
|
15
|
+
end
|
16
|
+
|
17
|
+
# Represents browser data for tracking calls
|
18
|
+
class Browser < Data
|
19
|
+
attr_reader :type, :version
|
20
|
+
|
21
|
+
# @param [BrowserType] browser_type Browser type, can be: CHROME, INTERNET_EXPLORER, FIREFOX, SAFARI, OPERA, OTHER
|
22
|
+
# @param [float] version Version of browser
|
23
|
+
def initialize(browser_type, version = Float::NAN)
|
24
|
+
super(DataType::BROWSER)
|
25
|
+
@type = browser_type
|
26
|
+
@version = version
|
27
|
+
end
|
28
|
+
|
29
|
+
def obtain_full_post_text_line
|
30
|
+
params = {
|
31
|
+
eventType: 'staticData',
|
32
|
+
browserIndex: @type,
|
33
|
+
nonce: nonce
|
34
|
+
}
|
35
|
+
params[:browserVersion] = @version if @version.is_a?(Integer) || (@version.is_a?(Float) && !@version.nan?)
|
36
|
+
Kameleoon::Network::UriHelper.encode_query(params)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'kameleoon/network/uri_helper'
|
5
|
+
require_relative 'data'
|
6
|
+
|
7
|
+
module Kameleoon
|
8
|
+
# Conversion class uses for tracking conversion
|
9
|
+
class Conversion < Data
|
10
|
+
attr_reader :goal_id, :revenue, :negative
|
11
|
+
|
12
|
+
# @param [Integer] goal_id Id of the goal associated to the conversion
|
13
|
+
# @param [Float] revenue Optional field - Revenue associated to the conversion.
|
14
|
+
# @param [Boolean] negative Optional field - If the revenue is negative. By default it's positive.
|
15
|
+
def initialize(goal_id, revenue = 0.0, negative = false)
|
16
|
+
super(DataType::CONVERSION)
|
17
|
+
@goal_id = goal_id
|
18
|
+
@revenue = revenue || 0.0
|
19
|
+
@negative = negative || false
|
20
|
+
end
|
21
|
+
|
22
|
+
def obtain_full_post_text_line
|
23
|
+
params = {
|
24
|
+
eventType: 'conversion',
|
25
|
+
goalId: @goal_id,
|
26
|
+
revenue: @revenue,
|
27
|
+
negative: @negative,
|
28
|
+
nonce: nonce
|
29
|
+
}
|
30
|
+
Kameleoon::Network::UriHelper.encode_query(params)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'kameleoon/network/uri_helper'
|
5
|
+
require_relative 'data'
|
6
|
+
|
7
|
+
module Kameleoon
|
8
|
+
# Represents any custom data for targeting conditions
|
9
|
+
class CustomData < Data
|
10
|
+
attr_reader :id, :values
|
11
|
+
|
12
|
+
# @param [Integer] id Id of the custom data
|
13
|
+
# @param [String] value Value of the custom data
|
14
|
+
# @param [Array] values Array of values of the custom data
|
15
|
+
#
|
16
|
+
# @overload
|
17
|
+
# @param [Hash] hash Json value encoded in a hash.
|
18
|
+
# rubocop:disable Metrics/MethodLength
|
19
|
+
def initialize(arg0, *args)
|
20
|
+
super(DataType::CUSTOM)
|
21
|
+
if arg0.is_a?(Hash)
|
22
|
+
hash = arg0
|
23
|
+
id = hash['id']
|
24
|
+
raise Kameleoon::Exception::NotFound.new('id'), '"id" is mandatory' if id.nil?
|
25
|
+
|
26
|
+
@id = id.to_s
|
27
|
+
value = hash['value']
|
28
|
+
values = hash['values']
|
29
|
+
if values.nil? && value.nil?
|
30
|
+
raise Kameleoon::Exception::NotFound.new('value or values'), '"value" or "values" is mandatory'
|
31
|
+
end
|
32
|
+
|
33
|
+
if values.nil?
|
34
|
+
@values = [value]
|
35
|
+
else
|
36
|
+
@values = values.is_a?(Array) ? values.dup : [values]
|
37
|
+
@values.append(value) unless value.nil?
|
38
|
+
end
|
39
|
+
else
|
40
|
+
@id = arg0.to_s
|
41
|
+
@values = args
|
42
|
+
end
|
43
|
+
end
|
44
|
+
# rubocop:enable Metrics/MethodLength
|
45
|
+
|
46
|
+
def obtain_full_post_text_line
|
47
|
+
return '' if @values.empty?
|
48
|
+
|
49
|
+
str_values = JSON.generate(Hash[@values.collect { |k| [k, 1] }])
|
50
|
+
params = {
|
51
|
+
eventType: 'customData',
|
52
|
+
index: @id,
|
53
|
+
valuesCountMap: str_values,
|
54
|
+
overwrite: 'true',
|
55
|
+
nonce: nonce
|
56
|
+
}
|
57
|
+
Kameleoon::Network::UriHelper.encode_query(params)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'kameleoon/exceptions'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
NONCE_LENGTH = 16
|
8
|
+
|
9
|
+
module DataType
|
10
|
+
CUSTOM = 'CUSTOM'
|
11
|
+
BROWSER = 'BROWSER'
|
12
|
+
CONVERSION = 'CONVERSION'
|
13
|
+
DEVICE = 'DEVICE'
|
14
|
+
PAGE_VIEW = 'PAGE_VIEW'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Represents base class for any Kameleoon data
|
18
|
+
class Data
|
19
|
+
attr_reader :instance
|
20
|
+
attr_accessor :sent
|
21
|
+
|
22
|
+
def initialize(data_type)
|
23
|
+
@instance = data_type
|
24
|
+
@sent = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def obtain_full_post_text_line
|
28
|
+
raise KameleoonError.new('ToDo: implement this method.'), 'ToDo: implement this method.'
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def nonce
|
34
|
+
@nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH) if @nonce.nil?
|
35
|
+
@nonce
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'kameleoon/network/uri_helper'
|
5
|
+
require_relative 'data'
|
6
|
+
|
7
|
+
module Kameleoon
|
8
|
+
module DeviceType
|
9
|
+
PHONE = 'PHONE'
|
10
|
+
TABLET = 'TABLET'
|
11
|
+
DESKTOP = 'DESKTOP'
|
12
|
+
end
|
13
|
+
|
14
|
+
# Device uses for sending deviceType parameter for tracking calls
|
15
|
+
class Device < Data
|
16
|
+
attr_reader :device_type
|
17
|
+
def initialize(device_type)
|
18
|
+
super(DataType::DEVICE)
|
19
|
+
@device_type = device_type
|
20
|
+
end
|
21
|
+
|
22
|
+
def obtain_full_post_text_line
|
23
|
+
params = {
|
24
|
+
eventType: 'staticData',
|
25
|
+
deviceType: @device_type,
|
26
|
+
nonce: nonce
|
27
|
+
}
|
28
|
+
Kameleoon::Network::UriHelper.encode_query(params)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|