splitclient-rb 3.1.0.pre.rc12 → 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/CHANGES.txt +2 -0
- data/Detailed-README.md +406 -0
- data/LICENSE +10 -199
- data/NEWS +1 -0
- data/README.md +30 -342
- data/lib/cache/adapters/memory_adapters/map_adapter.rb +4 -2
- data/lib/cache/adapters/memory_adapters/queue_adapter.rb +12 -4
- data/lib/cache/senders/impressions_formatter.rb +65 -0
- data/lib/cache/senders/impressions_sender.rb +59 -0
- data/lib/engine/api/client.rb +30 -8
- data/lib/engine/api/impressions.rb +34 -0
- data/lib/engine/api/segments.rb +1 -1
- data/lib/engine/api/splits.rb +1 -1
- data/lib/engine/parser/split_adapter.rb +7 -102
- data/lib/splitclient-rb.rb +3 -1
- data/lib/splitclient-rb/localhost_split_factory.rb +19 -1
- data/lib/splitclient-rb/split_config.rb +2 -0
- data/lib/splitclient-rb/split_factory.rb +35 -141
- data/lib/splitclient-rb/split_factory_builder.rb +9 -2
- data/lib/splitclient-rb/version.rb +1 -1
- metadata +8 -5
- data/lib/splitclient-rb/localhost_split_factory_builder.rb +0 -13
@@ -0,0 +1,65 @@
|
|
1
|
+
module SplitIoClient
|
2
|
+
module Cache
|
3
|
+
module Senders
|
4
|
+
class ImpressionsFormatter
|
5
|
+
def initialize(impressions_repository)
|
6
|
+
@impressions_repository = impressions_repository
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(raw_impressions)
|
10
|
+
impressions = raw_impressions ? raw_impressions : @impressions_repository.clear
|
11
|
+
formatted_impressions = []
|
12
|
+
filtered_impressions = filter_impressions(impressions)
|
13
|
+
|
14
|
+
return [] if impressions.empty? || filtered_impressions.empty?
|
15
|
+
|
16
|
+
formatted_impressions = unique_features(filtered_impressions).each_with_object([]) do |feature, memo|
|
17
|
+
current_impressions =
|
18
|
+
filtered_impressions
|
19
|
+
.select { |i| i[:feature] == feature }
|
20
|
+
.map do |i|
|
21
|
+
{
|
22
|
+
keyName: i[:impressions]['key_name'],
|
23
|
+
treatment: i[:impressions]['treatment'],
|
24
|
+
time: i[:impressions]['time']
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
memo << {
|
29
|
+
testName: feature,
|
30
|
+
keyImpressions: current_impressions
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
formatted_impressions
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def unique_features(impressions)
|
40
|
+
impressions.map { |i| i[:feature] }.uniq
|
41
|
+
end
|
42
|
+
|
43
|
+
# Filter seen impressions by impression_hash
|
44
|
+
def filter_impressions(unfiltered_impressions)
|
45
|
+
impressions_seen = []
|
46
|
+
|
47
|
+
unfiltered_impressions.each_with_object([]) do |impression, impressions|
|
48
|
+
impression_hash = impression_hash(impression)
|
49
|
+
|
50
|
+
next if impressions_seen.include?(impression_hash)
|
51
|
+
|
52
|
+
impressions_seen << impression_hash
|
53
|
+
impressions << impression
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def impression_hash(impression)
|
58
|
+
"#{impression[:feature]}:" \
|
59
|
+
"#{impression[:impressions]['key_name']}:" \
|
60
|
+
"#{impression[:impressions]['treatment']}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module SplitIoClient
|
2
|
+
module Cache
|
3
|
+
module Senders
|
4
|
+
class ImpressionsSender
|
5
|
+
def initialize(impressions_repository, config, api_key)
|
6
|
+
@impressions_repository = impressions_repository
|
7
|
+
@config = config
|
8
|
+
@api_key = api_key
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
# Disable impressions if @config.impressions_queue_size == -1
|
13
|
+
if @config.impressions_queue_size < 0
|
14
|
+
@config.logger.info('Disabling impressions service by config')
|
15
|
+
return
|
16
|
+
end
|
17
|
+
|
18
|
+
if ENV['SPLITCLIENT_ENV'] == 'test'
|
19
|
+
post_impressions
|
20
|
+
else
|
21
|
+
Thread.new do
|
22
|
+
@config.logger.info('Starting impressions service') unless ENV['SPLITCLIENT_ENV'] == 'test'
|
23
|
+
|
24
|
+
loop do
|
25
|
+
post_impressions
|
26
|
+
|
27
|
+
sleep(randomize_interval(@config.impressions_refresh_rate))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@config.logger.info('Started impressions service') unless ENV['SPLITCLIENT_ENV'] == 'test'
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def post_impressions
|
38
|
+
impressions_client.post
|
39
|
+
rescue StandardError => error
|
40
|
+
@config.log_found_exception(__method__.to_s, error)
|
41
|
+
end
|
42
|
+
|
43
|
+
def formatted_impressions(raw_impressions = nil)
|
44
|
+
ImpressionsFormatter.new(@impressions_repository).call(raw_impressions)
|
45
|
+
end
|
46
|
+
|
47
|
+
def impressions_client
|
48
|
+
SplitIoClient::Api::Impressions.new(@api_key, @config, formatted_impressions)
|
49
|
+
end
|
50
|
+
|
51
|
+
def randomize_interval(interval)
|
52
|
+
@random_generator ||= Random.new
|
53
|
+
random_factor = @random_generator.rand(50..100)/100.0
|
54
|
+
interval * random_factor
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/engine/api/client.rb
CHANGED
@@ -1,18 +1,31 @@
|
|
1
1
|
module SplitIoClient
|
2
2
|
module Api
|
3
3
|
class Client
|
4
|
-
def
|
5
|
-
api_client.get(
|
6
|
-
req.headers
|
7
|
-
req.headers['SplitSDKVersion'] = SplitIoClient::SplitFactory.sdk_version
|
8
|
-
req.headers['SplitSDKMachineName'] = config.machine_name
|
9
|
-
req.headers['SplitSDKMachineIP'] = config.machine_ip
|
10
|
-
req.headers['Accept-Encoding'] = 'gzip'
|
4
|
+
def get_api(url, config, api_key, params = {})
|
5
|
+
api_client.get(url, params) do |req|
|
6
|
+
req.headers = common_headers(api_key, config).merge('Accept-Encoding' => 'gzip')
|
11
7
|
|
8
|
+
req.options.timeout = config.read_timeout
|
12
9
|
req.options.open_timeout = config.connection_timeout
|
10
|
+
|
11
|
+
config.logger.debug("GET #{url}") if config.debug_enabled
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def post_api(url, config, api_key, data, params = {})
|
16
|
+
api_client.post(url) do |req|
|
17
|
+
req.headers = common_headers(api_key, config).merge('Content-Type' => 'application/json')
|
18
|
+
|
19
|
+
req.body = data.to_json
|
20
|
+
|
13
21
|
req.options.timeout = config.read_timeout
|
22
|
+
req.options.open_timeout = config.connection_timeout
|
14
23
|
|
15
|
-
|
24
|
+
if config.transport_debug_enabled
|
25
|
+
config.logger.debug("POST #{url} #{req.body}")
|
26
|
+
elsif config.debug_enabled
|
27
|
+
config.logger.debug("POST #{url}")
|
28
|
+
end
|
16
29
|
end
|
17
30
|
end
|
18
31
|
|
@@ -24,6 +37,15 @@ module SplitIoClient
|
|
24
37
|
builder.adapter :net_http_persistent
|
25
38
|
end
|
26
39
|
end
|
40
|
+
|
41
|
+
def common_headers(api_key, config)
|
42
|
+
{
|
43
|
+
'Authorization' => "Bearer #{api_key}",
|
44
|
+
'SplitSDKVersion' => SplitIoClient::SplitFactory.sdk_version,
|
45
|
+
'SplitSDKMachineName' => config.machine_name,
|
46
|
+
'SplitSDKMachineIP' => config.machine_ip
|
47
|
+
}
|
48
|
+
end
|
27
49
|
end
|
28
50
|
end
|
29
51
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module SplitIoClient
|
2
|
+
module Api
|
3
|
+
class Impressions < Client
|
4
|
+
def initialize(api_key, config, impressions)
|
5
|
+
@config = config
|
6
|
+
@api_key = api_key
|
7
|
+
@impressions = impressions
|
8
|
+
end
|
9
|
+
|
10
|
+
def post
|
11
|
+
if @impressions.empty?
|
12
|
+
@config.logger.debug('No impressions to report') if @config.debug_enabled
|
13
|
+
return
|
14
|
+
end
|
15
|
+
|
16
|
+
result = post_api("#{config.events_uri}/testImpressions/bulk", @config, @api_key, @impressions)
|
17
|
+
|
18
|
+
if result.status / 100 != 2
|
19
|
+
@config.logger.error("Unexpected status code while posting impressions: #{result.status}")
|
20
|
+
else
|
21
|
+
@config.logger.debug("Impressions reported: #{total_impressions(@impressions)}") if @config.debug_enabled
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def total_impressions(impressions)
|
26
|
+
return 0 if impressions.nil?
|
27
|
+
|
28
|
+
impressions.reduce(0) do |impressions_count, impression|
|
29
|
+
impressions_count += impression[:keyImpressions].length
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/engine/api/segments.rb
CHANGED
@@ -33,7 +33,7 @@ module SplitIoClient
|
|
33
33
|
|
34
34
|
def fetch_segments(name, prefix, since)
|
35
35
|
segments = []
|
36
|
-
segment =
|
36
|
+
segment = get_api("#{@config.base_uri}/segmentChanges/#{name}", @config, @api_key, since: since)
|
37
37
|
|
38
38
|
if segment.status / 100 == 2
|
39
39
|
segment_content = JSON.parse(segment.body, symbolize_names: true)
|
data/lib/engine/api/splits.rb
CHANGED
@@ -10,7 +10,7 @@ module SplitIoClient
|
|
10
10
|
def since(since)
|
11
11
|
start = Time.now
|
12
12
|
prefix = 'splitChangeFetcher'
|
13
|
-
splits =
|
13
|
+
splits = get_api("#{@config.base_uri}/splitChanges", @config, @api_key, since: since)
|
14
14
|
|
15
15
|
if splits.status / 100 == 2
|
16
16
|
result = splits_with_segment_names(splits.body)
|
@@ -75,20 +75,21 @@ module SplitIoClient
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
#
|
79
|
-
# creates a safe thread that will be executing api calls
|
80
|
-
# for fetching splits and segments give the execution time
|
81
|
-
# provided within the configuration
|
82
|
-
#
|
83
|
-
# @return [void]
|
78
|
+
# Starts thread which loops constantly and stores splits in the splits_repository of choice
|
84
79
|
def split_store
|
85
80
|
SplitIoClient::Cache::Stores::SplitStore.new(@splits_repository, @config, @api_key, @metrics, @sdk_blocker).call
|
86
81
|
end
|
87
82
|
|
83
|
+
# Starts thread which loops constantly and stores segments in the segments_repository of choice
|
88
84
|
def segment_store
|
89
85
|
SplitIoClient::Cache::Stores::SegmentStore.new(@segments_repository, @config, @api_key, @metrics, @sdk_blocker).call
|
90
86
|
end
|
91
87
|
|
88
|
+
# Starts thread which loops constantly and sends impressions to the Split API
|
89
|
+
def impressions_sender
|
90
|
+
SplitIoClient::Cache::Senders::ImpressionsSender.new(@impressions_repository, @config, @api_key).call
|
91
|
+
end
|
92
|
+
|
92
93
|
#
|
93
94
|
# helper method to execute a post request to the provided endpoint
|
94
95
|
#
|
@@ -152,102 +153,6 @@ module SplitIoClient
|
|
152
153
|
end
|
153
154
|
end
|
154
155
|
|
155
|
-
def impressions_sender
|
156
|
-
# Disable impressions if @config.impressions_queue_size == -1
|
157
|
-
if @config.impressions_queue_size < 0
|
158
|
-
@config.logger.info("Disabling impressions service by config.")
|
159
|
-
return
|
160
|
-
end
|
161
|
-
|
162
|
-
@config.logger.info("Starting impressions service...")
|
163
|
-
|
164
|
-
# TODO: Send impressions in main thread for test ENV
|
165
|
-
return if ENV['SPLITCLIENT_ENV'] == 'test'
|
166
|
-
|
167
|
-
Thread.new do
|
168
|
-
loop do
|
169
|
-
begin
|
170
|
-
post_impressions
|
171
|
-
|
172
|
-
random_interval = randomize_interval @config.impressions_refresh_rate
|
173
|
-
sleep(random_interval)
|
174
|
-
rescue StandardError => error
|
175
|
-
@config.log_found_exception(__method__.to_s, error)
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
@config.logger.info("Started impressions service")
|
181
|
-
end
|
182
|
-
|
183
|
-
#
|
184
|
-
# creates the appropriate json data for the cached impressions values
|
185
|
-
# and then sends them to the appropriate api endpoint with a valid body format
|
186
|
-
#
|
187
|
-
# @return [void]
|
188
|
-
def post_impressions
|
189
|
-
impressions = impressions_array
|
190
|
-
|
191
|
-
if impressions.empty?
|
192
|
-
@config.logger.debug('No impressions to report') if @config.debug_enabled
|
193
|
-
return
|
194
|
-
end
|
195
|
-
|
196
|
-
res = post_api('/testImpressions/bulk', impressions)
|
197
|
-
if res.status / 100 != 2
|
198
|
-
@config.logger.error("Unexpected status code while posting impressions: #{res.status}")
|
199
|
-
else
|
200
|
-
@config.logger.debug("Impressions reported: #{calculate_tot_impressions(impressions)}") if @config.debug_enabled
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
def calculate_tot_impressions(impressions = nil)
|
205
|
-
tot = 0
|
206
|
-
return tot if impressions.nil?
|
207
|
-
impressions.each do |test_impression|
|
208
|
-
tot += test_impression[:keyImpressions].length
|
209
|
-
end
|
210
|
-
tot
|
211
|
-
end
|
212
|
-
|
213
|
-
# REFACTOR
|
214
|
-
def impressions_array(impressions = nil)
|
215
|
-
popped_impressions = impressions ? impressions : @impressions_repository.clear
|
216
|
-
test_impression_array, filtered_impressions, keys_treatments_seen = [], [], []
|
217
|
-
|
218
|
-
return [] if popped_impressions.empty?
|
219
|
-
|
220
|
-
popped_impressions.each do |item|
|
221
|
-
item_hash = "#{item[:feature]}:#{item[:impressions]['key_name']}:#{item[:impressions]['treatment']}"
|
222
|
-
|
223
|
-
next if keys_treatments_seen.include?(item_hash)
|
224
|
-
|
225
|
-
keys_treatments_seen << item_hash
|
226
|
-
filtered_impressions << item
|
227
|
-
end
|
228
|
-
|
229
|
-
return [] if filtered_impressions.empty?
|
230
|
-
|
231
|
-
features = filtered_impressions.map { |i| i[:feature] }.uniq
|
232
|
-
test_impression_array = features.each_with_object([]) do |feature, memo|
|
233
|
-
current_impressions = filtered_impressions.select { |i| i[:feature] == feature }
|
234
|
-
current_impressions.map! do |i|
|
235
|
-
{
|
236
|
-
keyName: i[:impressions]['key_name'],
|
237
|
-
treatment: i[:impressions]['treatment'],
|
238
|
-
time: i[:impressions]['time']
|
239
|
-
}
|
240
|
-
end
|
241
|
-
|
242
|
-
memo << {
|
243
|
-
testName: feature,
|
244
|
-
keyImpressions: current_impressions
|
245
|
-
}
|
246
|
-
end
|
247
|
-
|
248
|
-
test_impression_array
|
249
|
-
end
|
250
|
-
|
251
156
|
#
|
252
157
|
# creates the appropriate json data for the cached metrics values
|
253
158
|
# include latencies, counts and gauges
|
data/lib/splitclient-rb.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'splitclient-rb/version'
|
2
2
|
require 'splitclient-rb/split_factory'
|
3
3
|
require 'splitclient-rb/split_factory_builder'
|
4
|
-
require 'splitclient-rb/localhost_split_factory_builder'
|
5
4
|
require 'splitclient-rb/localhost_split_factory'
|
6
5
|
require 'splitclient-rb/split_config'
|
7
6
|
require 'exceptions/sdk_blocker_timeout_expired_exception'
|
@@ -19,10 +18,13 @@ require 'cache/repositories/impressions/redis_repository'
|
|
19
18
|
require 'cache/repositories/metrics_repository'
|
20
19
|
require 'cache/repositories/metrics/memory_repository'
|
21
20
|
require 'cache/repositories/metrics/redis_repository'
|
21
|
+
require 'cache/senders/impressions_formatter'
|
22
|
+
require 'cache/senders/impressions_sender'
|
22
23
|
require 'cache/stores/sdk_blocker'
|
23
24
|
require 'cache/stores/segment_store'
|
24
25
|
require 'cache/stores/split_store'
|
25
26
|
require 'engine/api/client'
|
27
|
+
require 'engine/api/impressions'
|
26
28
|
require 'engine/api/segments'
|
27
29
|
require 'engine/api/splits'
|
28
30
|
require 'engine/parser/condition'
|
@@ -42,6 +42,14 @@ module SplitIoClient
|
|
42
42
|
@localhost_mode_features
|
43
43
|
end
|
44
44
|
|
45
|
+
#
|
46
|
+
# method to get a split view
|
47
|
+
#
|
48
|
+
# @returns a split view
|
49
|
+
def split(split_name)
|
50
|
+
@localhost_mode_features.find {|x| x[:feature] == split_name}
|
51
|
+
end
|
52
|
+
|
45
53
|
#
|
46
54
|
# method to get the split list from the client
|
47
55
|
#
|
@@ -49,6 +57,16 @@ module SplitIoClient
|
|
49
57
|
def splits
|
50
58
|
@localhost_mode_features
|
51
59
|
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# method to get the list of just split names. Ideal for ietrating and calling client.get_treatment
|
63
|
+
#
|
64
|
+
# @returns [object] array of split names (String)
|
65
|
+
def split_names
|
66
|
+
@localhost_mode_features.each_with_object([]) do |split, memo|
|
67
|
+
memo << split[:feature]
|
68
|
+
end
|
69
|
+
end
|
52
70
|
end
|
53
71
|
|
54
72
|
class LocalhostSplitClient < NoMethodError
|
@@ -74,7 +92,7 @@ module SplitIoClient
|
|
74
92
|
end
|
75
93
|
|
76
94
|
def get_treatments(key, split_names, attributes = nil)
|
77
|
-
split_names.each_with_object({}) do |
|
95
|
+
split_names.each_with_object({}) do |name, memo|
|
78
96
|
puts "name #{name} memo #{memo}"
|
79
97
|
memo.merge!(name => get_treatment(key, name, attributes))
|
80
98
|
end
|
@@ -6,42 +6,17 @@ module SplitIoClient
|
|
6
6
|
#
|
7
7
|
class SplitFactory < NoMethodError
|
8
8
|
class SplitManager < NoMethodError
|
9
|
-
#
|
10
|
-
# constant that defines the localhost mode
|
11
|
-
LOCALHOST_MODE = 'localhost'
|
12
|
-
|
13
9
|
#
|
14
10
|
# Creates a new split manager instance that connects to split.io API.
|
15
11
|
#
|
16
12
|
# @param api_key [String] the API key for your split account
|
17
13
|
#
|
18
14
|
# @return [SplitIoManager] split.io client instance
|
19
|
-
def initialize(api_key, config = {}, adapter = nil, splits_repository = nil
|
15
|
+
def initialize(api_key, config = {}, adapter = nil, splits_repository = nil)
|
20
16
|
@localhost_mode_features = []
|
21
17
|
@config = config
|
22
18
|
@splits_repository = splits_repository
|
23
|
-
@
|
24
|
-
if @localhost_mode
|
25
|
-
load_localhost_mode_features
|
26
|
-
else
|
27
|
-
@adapter = adapter
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
#
|
32
|
-
# method to set localhost mode features by reading .splits file located at home directory
|
33
|
-
#
|
34
|
-
# @returns [void]
|
35
|
-
def load_localhost_mode_features
|
36
|
-
splits_file = File.join(Dir.home, ".split")
|
37
|
-
if File.exists?(splits_file)
|
38
|
-
line_num=0
|
39
|
-
File.open(splits_file).each do |line|
|
40
|
-
line_data = line.strip.split(" ")
|
41
|
-
@localhost_mode_features << {feature: line_data[0], treatment: line_data[1]} unless line.start_with?('#') || line.strip.empty?
|
42
|
-
end
|
43
|
-
end
|
44
|
-
@localhost_mode_features
|
19
|
+
@adapter = adapter
|
45
20
|
end
|
46
21
|
|
47
22
|
#
|
@@ -49,7 +24,6 @@ module SplitIoClient
|
|
49
24
|
#
|
50
25
|
# @returns [object] array of splits
|
51
26
|
def splits
|
52
|
-
return @localhost_mode_features if @localhost_mode
|
53
27
|
return if @splits_repository.nil?
|
54
28
|
|
55
29
|
@splits_repository.splits.each_with_object([]) do |(name, split), memo|
|
@@ -64,14 +38,6 @@ module SplitIoClient
|
|
64
38
|
#
|
65
39
|
# @returns [object] array of split names (String)
|
66
40
|
def split_names
|
67
|
-
if @localhost_mode
|
68
|
-
local_feature_names = []
|
69
|
-
@localhost_mode_features.each do |split|
|
70
|
-
local_feature_names << split[:feature]
|
71
|
-
end
|
72
|
-
return local_feature_names
|
73
|
-
end
|
74
|
-
|
75
41
|
return if @splits_repository.nil?
|
76
42
|
|
77
43
|
@splits_repository.split_names
|
@@ -82,11 +48,6 @@ module SplitIoClient
|
|
82
48
|
#
|
83
49
|
# @returns a split view
|
84
50
|
def split(split_name)
|
85
|
-
|
86
|
-
if @localhost_mode
|
87
|
-
return @localhost_mode_features.find {|x| x[:feature] == split_name}
|
88
|
-
end
|
89
|
-
|
90
51
|
if @splits_repository
|
91
52
|
split = @splits_repository.get_split(split_name)
|
92
53
|
|
@@ -114,27 +75,14 @@ module SplitIoClient
|
|
114
75
|
end
|
115
76
|
end
|
116
77
|
|
117
|
-
|
118
78
|
class SplitClient < NoMethodError
|
119
|
-
#
|
120
|
-
# constant that defines the localhost mode
|
121
|
-
LOCALHOST_MODE = 'localhost'
|
122
|
-
|
123
|
-
#
|
124
|
-
# variables to if the sdk is being used in localhost mode and store the list of features
|
125
|
-
attr_reader :localhost_mode
|
126
|
-
attr_reader :localhost_mode_features
|
127
|
-
|
128
79
|
#
|
129
80
|
# Creates a new split client instance that connects to split.io API.
|
130
81
|
#
|
131
82
|
# @param api_key [String] the API key for your split account
|
132
83
|
#
|
133
84
|
# @return [SplitIoClient] split.io client instance
|
134
|
-
def initialize(api_key, config = {}, adapter = nil,
|
135
|
-
@localhost_mode = localhost_mode
|
136
|
-
@localhost_mode_features = []
|
137
|
-
|
85
|
+
def initialize(api_key, config = {}, adapter = nil, splits_repository, segments_repository, impressions_repository, metrics_repository)
|
138
86
|
@config = config
|
139
87
|
|
140
88
|
@splits_repository = splits_repository
|
@@ -142,22 +90,10 @@ module SplitIoClient
|
|
142
90
|
@impressions_repository = impressions_repository
|
143
91
|
@metrics_repository = metrics_repository
|
144
92
|
|
145
|
-
|
146
|
-
@localhost_mode = true
|
147
|
-
load_localhost_mode_features
|
148
|
-
else
|
149
|
-
@adapter = adapter
|
150
|
-
end
|
93
|
+
@adapter = adapter
|
151
94
|
end
|
152
95
|
|
153
96
|
def get_treatments(key, split_names, attributes = nil)
|
154
|
-
# This localhost behavior must live in in localhost_spit_factory#client
|
155
|
-
if is_localhost_mode?
|
156
|
-
return split_names.each_with_object({}) do |name, memo|
|
157
|
-
memo.merge!(name => get_localhost_treatment(name))
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
97
|
bucketing_key, matching_key = keys_from_key(key)
|
162
98
|
bucketing_key = matching_key if bucketing_key.nil?
|
163
99
|
|
@@ -165,7 +101,9 @@ module SplitIoClient
|
|
165
101
|
memo.merge!(name => get_treatment(matching_key, name, attributes, data, false))
|
166
102
|
end
|
167
103
|
|
168
|
-
@
|
104
|
+
if @config.impressions_queue_size > 0
|
105
|
+
@impressions_repository.add_bulk(matching_key, treatments, (Time.now.to_f * 1000.0).to_i)
|
106
|
+
end
|
169
107
|
|
170
108
|
treatments
|
171
109
|
end
|
@@ -191,41 +129,36 @@ module SplitIoClient
|
|
191
129
|
return Treatments::CONTROL
|
192
130
|
end
|
193
131
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
begin
|
201
|
-
split = split_data ? split_data : @splits_repository.get_split(split_name)
|
202
|
-
|
203
|
-
result = if split.nil?
|
204
|
-
Treatments::CONTROL
|
205
|
-
else
|
206
|
-
SplitIoClient::Engine::Parser::SplitTreatment.new(@segments_repository).call(
|
207
|
-
{ bucketing_key: bucketing_key, matching_key: matching_key }, split, attributes
|
208
|
-
)
|
209
|
-
end
|
210
|
-
rescue StandardError => error
|
211
|
-
@config.log_found_exception(__method__.to_s, error)
|
212
|
-
end
|
132
|
+
start = Time.now
|
133
|
+
result = nil
|
134
|
+
|
135
|
+
begin
|
136
|
+
split = split_data ? split_data : @splits_repository.get_split(split_name)
|
213
137
|
|
214
|
-
result =
|
138
|
+
result = if split.nil?
|
139
|
+
Treatments::CONTROL
|
140
|
+
else
|
141
|
+
SplitIoClient::Engine::Parser::SplitTreatment.new(@segments_repository).call(
|
142
|
+
{ bucketing_key: bucketing_key, matching_key: matching_key }, split, attributes
|
143
|
+
)
|
144
|
+
end
|
145
|
+
rescue StandardError => error
|
146
|
+
@config.log_found_exception(__method__.to_s, error)
|
147
|
+
end
|
215
148
|
|
216
|
-
|
217
|
-
latency = (Time.now - start) * 1000.0
|
218
|
-
if @config.impressions_queue_size > 0 && store_impressions
|
219
|
-
# Disable impressions if @config.impressions_queue_size == -1
|
220
|
-
@impressions_repository.add(split_name, 'key_name' => matching_key, 'treatment' => result, 'time' => (Time.now.to_f * 1000.0).to_i)
|
221
|
-
end
|
149
|
+
result = result.nil? ? Treatments::CONTROL : result
|
222
150
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
@config.
|
151
|
+
begin
|
152
|
+
latency = (Time.now - start) * 1000.0
|
153
|
+
if @config.impressions_queue_size > 0 && store_impressions
|
154
|
+
# Disable impressions if @config.impressions_queue_size == -1
|
155
|
+
@impressions_repository.add(split_name, 'key_name' => matching_key, 'treatment' => result, 'time' => (Time.now.to_f * 1000.0).to_i)
|
227
156
|
end
|
228
157
|
|
158
|
+
# Measure
|
159
|
+
@adapter.metrics.time("sdk.get_treatment", latency)
|
160
|
+
rescue StandardError => error
|
161
|
+
@config.log_found_exception(__method__.to_s, error)
|
229
162
|
end
|
230
163
|
|
231
164
|
result
|
@@ -247,42 +180,6 @@ module SplitIoClient
|
|
247
180
|
def self.sdk_version
|
248
181
|
'ruby-'+SplitIoClient::VERSION
|
249
182
|
end
|
250
|
-
|
251
|
-
private
|
252
|
-
|
253
|
-
#
|
254
|
-
# method to check if the sdk is running in localhost mode based on api key
|
255
|
-
#
|
256
|
-
# @return [boolean] True if is in localhost mode, false otherwise
|
257
|
-
def is_localhost_mode?
|
258
|
-
@localhost_mode
|
259
|
-
end
|
260
|
-
|
261
|
-
#
|
262
|
-
# method to set localhost mode features by reading .splits file located at home directory
|
263
|
-
#
|
264
|
-
# @returns [void]
|
265
|
-
def load_localhost_mode_features
|
266
|
-
splits_file = File.join(Dir.home, ".split")
|
267
|
-
if File.exists?(splits_file)
|
268
|
-
line_num=0
|
269
|
-
File.open(splits_file).each do |line|
|
270
|
-
line_data = line.strip.split(" ")
|
271
|
-
@localhost_mode_features << {feature: line_data[0], treatment: line_data[1]} unless line.start_with?('#') || line.strip.empty?
|
272
|
-
end
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
#
|
277
|
-
# method to check the treatment for the given feature in localhost mode
|
278
|
-
#
|
279
|
-
# @return [boolean] true if the feature is available in localhost mode, false otherwise
|
280
|
-
def get_localhost_treatment(feature)
|
281
|
-
localhost_result = Treatments::CONTROL
|
282
|
-
treatment = @localhost_mode_features.select{|h| h[:feature] == feature}.last
|
283
|
-
localhost_result = treatment[:treatment] if !treatment.nil?
|
284
|
-
localhost_result
|
285
|
-
end
|
286
183
|
end
|
287
184
|
|
288
185
|
private_constant :SplitClient
|
@@ -297,10 +194,7 @@ module SplitIoClient
|
|
297
194
|
@impressions_repository = SplitIoClient::Cache::Repositories::ImpressionsRepository.new(@config.impressions_adapter, @config)
|
298
195
|
@metrics_repository = SplitIoClient::Cache::Repositories::MetricsRepository.new(@config.metrics_adapter, @config)
|
299
196
|
@sdk_blocker = SplitIoClient::Cache::Stores::SDKBlocker.new(@config)
|
300
|
-
@adapter = api_key
|
301
|
-
? SplitAdapter.new(api_key, @config, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @sdk_blocker)
|
302
|
-
: nil
|
303
|
-
@localhost_mode = api_key == 'localhost'
|
197
|
+
@adapter = SplitAdapter.new(api_key, @config, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @sdk_blocker)
|
304
198
|
|
305
199
|
@sdk_blocker.block if @config.block_until_ready
|
306
200
|
end
|
@@ -325,11 +219,11 @@ module SplitIoClient
|
|
325
219
|
attr_reader :adapter
|
326
220
|
|
327
221
|
def init_client
|
328
|
-
SplitClient.new(@api_key, @config, @adapter, @
|
222
|
+
SplitClient.new(@api_key, @config, @adapter, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository)
|
329
223
|
end
|
330
224
|
|
331
225
|
def init_manager
|
332
|
-
SplitManager.new(@api_key, @config, @adapter, @splits_repository
|
226
|
+
SplitManager.new(@api_key, @config, @adapter, @splits_repository)
|
333
227
|
end
|
334
228
|
end
|
335
229
|
end
|