splitclient-rb 1.0.4 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 137fa6f11720e9bb8b5c55bdc1a7ce2f7ec46414
4
- data.tar.gz: b655ef282f557b2e0ef082f716f3495fe95cd4b8
3
+ metadata.gz: 420c299078bd2e0eddaeb7d2a189ab7202cb1ab9
4
+ data.tar.gz: e97bec34c8db25dcc2e3ab593b6528137b0cd505
5
5
  SHA512:
6
- metadata.gz: 349e27c839ae98fd3c8fa4829c4ed48f73711519ac97452050caa0902b4786c1c4ef8e0f82126252ad6d5fddaac63bfe64c998335eda1c6ff716e575376e8592
7
- data.tar.gz: aeacaa9bf397b6a55fc987a5f5a376632e4e9f49a81c137b11507bdd8f944b0434142b42226cb74ac73d9b52e01c62783ef85e70b9a1773d9ef803b8a8bca3d2
6
+ metadata.gz: 01782b77e052714c779981ead8dd8e5baeae674647390dc3a89d91d00d687d16a2de2f09f8d4cd44257dc3f903537a3021cc88fb56aebfda9a52120298e0782e
7
+ data.tar.gz: 08306361a858ea57450cf182b19a52ca6c734d13038786c4edb7e25b62daff81ebb903f952370bb0e56fbd52896804fe03999a3a320215f8ed6bd57804fe5a88
data/CHANGES.txt CHANGED
@@ -1,3 +1,6 @@
1
+ 2.0.0
2
+ - Add Factory for creation of Client and Manager interface.
3
+
1
4
  1.0.4
2
5
 
3
6
  - added support for AND combiner on conditions
data/NEWS CHANGED
@@ -1,3 +1,11 @@
1
+ 2.0.0
2
+
3
+ Instantiation of the split client is now through a factory:
4
+
5
+ factory = SplitIoClient::SplitFactory.new("rbk5je8be5qflpa047m17fe4ra", options)
6
+ client = factory.client
7
+ manager = factory.manager
8
+
1
9
  1.0.4
2
10
 
3
11
  Added AND combiner for conditions support. Added events_uri config param which is the url where the metrics post are send to.
data/README.md CHANGED
@@ -47,15 +47,22 @@ require 'splitclient-rb'
47
47
 
48
48
  Create a new split client instance with your API key:
49
49
  ```ruby
50
- split_client = SplitIoClient::SplitClient.new("your_api_key")
50
+ factory = SplitIoClient::SplitFactory.new("your_api_key").client
51
+ split_client = factory.client
51
52
  ```
53
+
54
+ For advance use cases you can also obtain a `manager` instance from the factory.
55
+ ```ruby
56
+ manager = factory.manager
57
+ ```
58
+
52
59
  ###Ruby on Rails
53
60
  ----
54
61
  If you're using Ruby on Rails
55
62
 
56
63
  Create an initializer file at config/initializers/splitclient.rb and then initialize the split client :
57
64
  ```ruby
58
- Rails.configuration.split_client = SplitIoClient::SplitClient.new("your_api_key")
65
+ Rails.configuration.split_client = SplitIoClient::SplitFactory.new("your_api_key").client
59
66
  ```
60
67
  In your controllers, access the client using
61
68
 
@@ -108,7 +115,7 @@ options = {base_uri: 'https://my.app.api/',
108
115
  impressions_refresh_rate: 360,
109
116
  logger: Logger.new('logfile.log')}
110
117
 
111
- split_client = SplitIoClient::SplitClient.new("your_api_key", options)
118
+ split_client = SplitIoClient::SplitFactory.new("your_api_key", options).client
112
119
  ```
113
120
  ### Execution
114
121
  ---
@@ -124,6 +131,25 @@ if split_client.get_treatment('employee_user_01','view_main_list', {age: 35})
124
131
  end
125
132
  ```
126
133
 
134
+ Also you can use the split manager:
135
+
136
+ ```ruby
137
+ split_manager = SplitIoClient::SplitFactory.new("your_api_key", options).manager
138
+ ```
139
+
140
+ With the manager you can get a list of your splits by doing:
141
+
142
+ ```ruby
143
+ manager.splits
144
+ ```
145
+
146
+ And you should get something like this:
147
+
148
+ ```bash
149
+ => [{:name=>"some_feature", :traffic_type_name=>nil, :killed=>false, :treatments=>nil, :change_number=>1469134003507}, {:name=>"another_feature", :traffic_type_name=>nil, :killed=>false, :treatments=>nil, :change_number=>1469134003414}, {:name=>"even_more_features", :traffic_type_name=>nil, :killed=>false, :treatments=>nil, :change_number=>1469133991063}, {:name=>"yet_another_feature", :traffic_type_name=>nil, :killed=>false, :treatments=>nil, :change_number=>1469133757521}]
150
+ ```
151
+
152
+
127
153
  ## Development
128
154
 
129
155
  After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -70,8 +70,10 @@ module SplitIoClient
70
70
  #splits fetcher
71
71
  splits_arr = []
72
72
  data = get_splits(@parsed_splits.since)
73
- data[:splits].each do |split|
74
- splits_arr << SplitIoClient::Split.new(split)
73
+ if data
74
+ data[:splits].each do |split|
75
+ splits_arr << SplitIoClient::Split.new(split)
76
+ end
75
77
  end
76
78
 
77
79
  if @parsed_splits.is_empty?
@@ -126,7 +128,7 @@ module SplitIoClient
126
128
  def call_api(path, params = {})
127
129
  @api_client.get @config.base_uri + path, params do |req|
128
130
  req.headers['Authorization'] = 'Bearer ' + @api_key
129
- req.headers['SplitSDKVersion'] = SplitIoClient::SplitClient.sdk_version
131
+ req.headers['SplitSDKVersion'] = SplitIoClient::SplitFactory.sdk_version
130
132
  req.headers['SplitSDKMachineName'] = @config.machine_name
131
133
  req.headers['SplitSDKMachineIP'] = @config.machine_ip
132
134
  req.headers['Accept-Encoding'] = 'gzip'
@@ -147,7 +149,7 @@ module SplitIoClient
147
149
  @api_client.post (@config.events_uri + path) do |req|
148
150
  req.headers['Authorization'] = 'Bearer ' + @api_key
149
151
  req.headers['Content-Type'] = 'application/json'
150
- req.headers['SplitSDKVersion'] = SplitIoClient::SplitClient.sdk_version
152
+ req.headers['SplitSDKVersion'] = SplitIoClient::SplitFactory.sdk_version
151
153
  req.headers['SplitSDKMachineName'] = @config.machine_name
152
154
  req.headers['SplitSDKMachineIP'] = @config.machine_ip
153
155
  req.body = param.to_json
@@ -1,5 +1,8 @@
1
1
  require 'splitclient-rb/version'
2
- require 'splitclient-rb/split_client'
2
+ require 'splitclient-rb/split_factory'
3
+ require 'splitclient-rb/split_factory_builder'
4
+ require 'splitclient-rb/localhost_split_factory_builder'
5
+ require 'splitclient-rb/localhost_split_factory'
3
6
  require 'splitclient-rb/split_config'
4
7
  require 'splitclient-cache/local_store'
5
8
  require 'splitclient-engine/parser/split'
@@ -0,0 +1,169 @@
1
+ require 'logger'
2
+ module SplitIoClient
3
+
4
+ #
5
+ # main class for localhost split client sdk
6
+ #
7
+ class LocalhostSplitFactory < NoMethodError
8
+ class LocalhostSplitManager < NoMethodError
9
+ #
10
+ # constant that defines the localhost mode
11
+ LOCALHOST_MODE = 'localhost'
12
+
13
+ #
14
+ # object that acts as an api adapter connector. used to get and post to api endpoints
15
+ attr_reader :adapter
16
+
17
+ #
18
+ # Creates a new split manager instance that holds the splits from a given file
19
+ #
20
+ # @param splits_file [File] the .split file that contains the splits
21
+ #
22
+ # @return [LocalhostSplitIoManager] split.io localhost manager instance
23
+ def initialize(splits_file)
24
+ @localhost_mode = true
25
+ @localhost_mode_features = []
26
+ load_localhost_mode_features(splits_file)
27
+ end
28
+
29
+ #
30
+ # method to set localhost mode features by reading the given .splits
31
+ #
32
+ # @param splits_file [File] the .split file that contains the splits
33
+ # @returns [void]
34
+ def load_localhost_mode_features(splits_file)
35
+ if File.exists?(splits_file)
36
+ line_num=0
37
+ File.open(splits_file).each do |line|
38
+ line_data = line.strip.split(" ")
39
+ @localhost_mode_features << {feature: line_data[0], treatment: line_data[1]} unless line.start_with?('#') || line.strip.empty?
40
+ end
41
+ end
42
+ @localhost_mode_features
43
+ end
44
+
45
+ #
46
+ # method to get the split list from the client
47
+ #
48
+ # @returns [object] array of splits
49
+ def splits
50
+ @localhost_mode_features
51
+ end
52
+ end
53
+
54
+ class LocalhostSplitClient < NoMethodError
55
+ #
56
+ # constant that defines the localhost mode
57
+ LOCALHOST_MODE = 'localhost'
58
+
59
+ #
60
+ # variables to if the sdk is being used in localhost mode and store the list of features
61
+ attr_reader :localhost_mode
62
+ attr_reader :localhost_mode_features
63
+
64
+ #
65
+ # Creates a new split client instance that reads from the given splits file
66
+ #
67
+ # @param splits_file [File] file that contains some splits
68
+ #
69
+ # @return [LocalhostSplitIoClient] split.io localhost client instance
70
+ def initialize(splits_file)
71
+ @localhost_mode = true
72
+ @localhost_mode_features = []
73
+ load_localhost_mode_features(splits_file)
74
+ end
75
+
76
+ #
77
+ # obtains the treatment for a given feature
78
+ #
79
+ # @param id [string] user id
80
+ # @param feature [string] name of the feature that is being validated
81
+ #
82
+ # @return [Treatment] treatment constant value
83
+ def get_treatment(id, feature, attributes = nil)
84
+ unless id
85
+ @config.logger.warn('id was null for feature: ' + feature)
86
+ return Treatments::CONTROL
87
+ end
88
+
89
+ unless feature
90
+ @config.logger.warn('feature was null for id: ' + id)
91
+ return Treatments::CONTROL
92
+ end
93
+ result = get_localhost_treatment(feature)
94
+ end
95
+
96
+
97
+ #
98
+ # auxiliary method to get the treatments avoding exceptions
99
+ #
100
+ # @param id [string] user id
101
+ # @param feature [string] name of the feature that is being validated
102
+ #
103
+ # @return [Treatment] tretment constant value
104
+ def get_treatment_without_exception_handling(id, feature, attributes = nil)
105
+ get_treatment(id, feature, attributes)
106
+ end
107
+
108
+ #
109
+ # method that returns the sdk gem version
110
+ #
111
+ # @return [string] version value for this sdk
112
+ def self.sdk_version
113
+ 'RubyClientSDK-'+SplitIoClient::VERSION
114
+ end
115
+
116
+ #
117
+ # method to check if the sdk is running in localhost mode based on api key
118
+ #
119
+ # @return [boolean] True if is in localhost mode, false otherwise
120
+ def is_localhost_mode?
121
+ true
122
+ end
123
+
124
+ #
125
+ # method to set localhost mode features by reading .splits file located at home directory
126
+ #
127
+ # @returns [void]
128
+ def load_localhost_mode_features(splits_file)
129
+ if File.exists?(splits_file)
130
+ line_num=0
131
+ File.open(splits_file).each do |line|
132
+ line_data = line.strip.split(" ")
133
+ @localhost_mode_features << {feature: line_data[0], treatment: line_data[1]} unless line.start_with?('#') || line.strip.empty?
134
+ end
135
+ end
136
+ end
137
+
138
+ #
139
+ # method to check the treatment for the given feature in localhost mode
140
+ #
141
+ # @return [boolean] true if the feature is available in localhost mode, false otherwise
142
+ def get_localhost_treatment(feature)
143
+ localhost_result = Treatments::CONTROL
144
+ treatment = @localhost_mode_features.select{|h| h[:feature] == feature}.last
145
+ localhost_result = treatment[:treatment] if !treatment.nil?
146
+ localhost_result
147
+ end
148
+
149
+ private :get_treatment_without_exception_handling, :is_localhost_mode?,
150
+ :load_localhost_mode_features, :get_localhost_treatment
151
+
152
+ end
153
+
154
+ private_constant :LocalhostSplitClient
155
+ private_constant :LocalhostSplitManager
156
+
157
+ def initialize(splits_file)
158
+ @splits_file = splits_file
159
+ end
160
+
161
+ def client
162
+ @client ||= LocalhostSplitClient.new(@splits_file)
163
+ end
164
+
165
+ def manager
166
+ @manager ||= LocalhostSplitManager.new(@splits_file)
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,13 @@
1
+ module SplitIoClient
2
+ class LocalhostSplitFactoryBuilder < NoMethodError
3
+ def self.build(directory)
4
+ splits_file = File.join(directory, ".split")
5
+ LocalhostSplitFactory.new(splits_file)
6
+ end
7
+
8
+ def self.build_from_path(path)
9
+ splits_file = File.join(path)
10
+ LocalhostSplitFactory.new(splits_file)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,245 @@
1
+ require 'logger'
2
+ module SplitIoClient
3
+ #
4
+ # main class for split client sdk
5
+ #
6
+ class SplitFactory < NoMethodError
7
+ class SplitManager < NoMethodError
8
+ #
9
+ # constant that defines the localhost mode
10
+ LOCALHOST_MODE = 'localhost'
11
+
12
+ #
13
+ # Creates a new split manager instance that connects to split.io API.
14
+ #
15
+ # @param api_key [String] the API key for your split account
16
+ #
17
+ # @return [SplitIoManager] split.io client instance
18
+ def initialize(api_key, config = {}, adapter = nil, localhost_mode = false)
19
+ @localhost_mode_features = []
20
+ @config = config
21
+ @localhost_mode = localhost_mode
22
+ if @localhost_mode
23
+ load_localhost_mode_features
24
+ else
25
+ @adapter = adapter
26
+ end
27
+ end
28
+
29
+ #
30
+ # method to set localhost mode features by reading .splits file located at home directory
31
+ #
32
+ # @returns [void]
33
+ def load_localhost_mode_features
34
+ splits_file = File.join(Dir.home, ".split")
35
+ if File.exists?(splits_file)
36
+ line_num=0
37
+ File.open(splits_file).each do |line|
38
+ line_data = line.strip.split(" ")
39
+ @localhost_mode_features << {feature: line_data[0], treatment: line_data[1]} unless line.start_with?('#') || line.strip.empty?
40
+ end
41
+ end
42
+ @localhost_mode_features
43
+ end
44
+
45
+ #
46
+ # method to get the split list from the client
47
+ #
48
+ # @returns [object] array of splits
49
+ def splits
50
+ return load_localhost_mode_features if @localhost_mode
51
+ if @adapter
52
+ @adapter.parsed_splits.splits.map do |split|
53
+ data = split.data
54
+ treatments = split.data[:conditions] && split.data[:conditions][0][:partitions] \
55
+ ? split.data[:conditions][0][:partitions].map{ |partition| partition[:treatment] }
56
+ : []
57
+ {
58
+ name: data[:name],
59
+ traffic_type_name: data[:trafficTypeName],
60
+ killed: data[:killed],
61
+ treatments: treatments,
62
+ change_number: data[:changeNumber]
63
+ }
64
+ end
65
+ else
66
+ @localhost_mode_features
67
+ end
68
+ end
69
+ end
70
+
71
+ class SplitClient < NoMethodError
72
+ #
73
+ # constant that defines the localhost mode
74
+ LOCALHOST_MODE = 'localhost'
75
+
76
+ #
77
+ # variables to if the sdk is being used in localhost mode and store the list of features
78
+ attr_reader :localhost_mode
79
+ attr_reader :localhost_mode_features
80
+
81
+ #
82
+ # Creates a new split client instance that connects to split.io API.
83
+ #
84
+ # @param api_key [String] the API key for your split account
85
+ #
86
+ # @return [SplitIoClient] split.io client instance
87
+ def initialize(api_key, config = {}, adapter = nil, localhost_mode = false)
88
+ @localhost_mode = localhost_mode
89
+ @localhost_mode_features = []
90
+
91
+ @config = config
92
+
93
+ if api_key == LOCALHOST_MODE
94
+ @localhost_mode = true
95
+ load_localhost_mode_features
96
+ else
97
+ @adapter = adapter
98
+ end
99
+ end
100
+
101
+ #
102
+ # obtains the treatment for a given feature
103
+ #
104
+ # @param id [string] user id
105
+ # @param feature [string] name of the feature that is being validated
106
+ #
107
+ # @return [Treatment] treatment constant value
108
+ def get_treatment(id, feature, attributes = nil)
109
+ unless id
110
+ @config.logger.warn('id was null for feature: ' + feature)
111
+ return Treatments::CONTROL
112
+ end
113
+
114
+ unless feature
115
+ @config.logger.warn('feature was null for id: ' + id)
116
+ return Treatments::CONTROL
117
+ end
118
+
119
+ if is_localhost_mode?
120
+ result = get_localhost_treatment(feature)
121
+ else
122
+ start = Time.now
123
+ result = nil
124
+
125
+ begin
126
+ result = get_treatment_without_exception_handling(id, feature, attributes)
127
+ rescue StandardError => error
128
+ @config.log_found_exception(__method__.to_s, error)
129
+ end
130
+
131
+ result = result.nil? ? Treatments::CONTROL : result
132
+
133
+ begin
134
+ @adapter.impressions.log(id, feature, result, (Time.now.to_f * 1000.0))
135
+ latency = (Time.now - start) * 1000.0
136
+ if (@adapter.impressions.queue.length >= @adapter.impressions.max_number_of_keys)
137
+ @adapter.impressions_producer.wakeup
138
+ end
139
+ rescue StandardError => error
140
+ @config.log_found_exception(__method__.to_s, error)
141
+ end
142
+
143
+ end
144
+
145
+ result
146
+ end
147
+
148
+ #
149
+ # auxiliary method to get the treatments avoding exceptions
150
+ #
151
+ # @param id [string] user id
152
+ # @param feature [string] name of the feature that is being validated
153
+ #
154
+ # @return [Treatment] tretment constant value
155
+ def get_treatment_without_exception_handling(id, feature, attributes = nil)
156
+ @adapter.parsed_splits.segments = @adapter.parsed_segments
157
+ split = @adapter.parsed_splits.get_split(feature)
158
+
159
+ if split.nil?
160
+ return Treatments::CONTROL
161
+ else
162
+ default_treatment = split.data[:defaultTreatment]
163
+ return @adapter.parsed_splits.get_split_treatment(id, feature, default_treatment, attributes)
164
+ end
165
+ end
166
+
167
+ #
168
+ # method that returns the sdk gem version
169
+ #
170
+ # @return [string] version value for this sdk
171
+ def self.sdk_version
172
+ 'RubyClientSDK-'+SplitIoClient::VERSION
173
+ end
174
+
175
+ #
176
+ # method to check if the sdk is running in localhost mode based on api key
177
+ #
178
+ # @return [boolean] True if is in localhost mode, false otherwise
179
+ def is_localhost_mode?
180
+ @localhost_mode
181
+ end
182
+
183
+ #
184
+ # method to set localhost mode features by reading .splits file located at home directory
185
+ #
186
+ # @returns [void]
187
+ def load_localhost_mode_features
188
+ splits_file = File.join(Dir.home, ".split")
189
+ if File.exists?(splits_file)
190
+ line_num=0
191
+ File.open(splits_file).each do |line|
192
+ line_data = line.strip.split(" ")
193
+ @localhost_mode_features << {feature: line_data[0], treatment: line_data[1]} unless line.start_with?('#') || line.strip.empty?
194
+ end
195
+ end
196
+ end
197
+
198
+ #
199
+ # method to check the treatment for the given feature in localhost mode
200
+ #
201
+ # @return [boolean] true if the feature is available in localhost mode, false otherwise
202
+ def get_localhost_treatment(feature)
203
+ localhost_result = Treatments::CONTROL
204
+ treatment = @localhost_mode_features.select{|h| h[:feature] == feature}.last
205
+ localhost_result = treatment[:treatment] if !treatment.nil?
206
+ localhost_result
207
+ end
208
+
209
+ private :get_treatment_without_exception_handling, :is_localhost_mode?,
210
+ :load_localhost_mode_features, :get_localhost_treatment
211
+
212
+ end
213
+
214
+ private_constant :SplitClient
215
+ private_constant :SplitManager
216
+
217
+ def initialize(api_key, config = {})
218
+ @api_key = api_key
219
+ @config = SplitConfig.new(config)
220
+ @adapter = api_key != 'localhost' \
221
+ ? SplitAdapter.new(api_key, @config)
222
+ : nil
223
+ @localhost_mode = api_key == 'localhost'
224
+ end
225
+
226
+ def client
227
+ @client ||= SplitClient.new(@api_key, @config, @adapter, @localhost_mode)
228
+ end
229
+
230
+ def manager
231
+ @manager ||= SplitManager.new(@api_key, @config, @adapter, @localhost_mode)
232
+ end
233
+
234
+ #
235
+ # method that returns the sdk gem version
236
+ #
237
+ # @return [string] version value for this sdk
238
+ def self.sdk_version
239
+ 'RubyClientSDK-'+SplitIoClient::VERSION
240
+ end
241
+
242
+ private
243
+ attr_reader :adapter
244
+ end
245
+ end
@@ -0,0 +1,8 @@
1
+ require 'logger'
2
+ module SplitIoClient
3
+ class SplitFactoryBuilder
4
+ def self.build(api_key, config = {})
5
+ @factory ||= SplitFactory.new(api_key, config)
6
+ end
7
+ end
8
+ end
@@ -1,3 +1,3 @@
1
1
  module SplitIoClient
2
- VERSION = '1.0.4'
2
+ VERSION = '2.0.0'
3
3
  end
@@ -28,7 +28,7 @@ def execute
28
28
 
29
29
  threads = []
30
30
  times_per_thread = iterations / 4
31
- split_client = SplitIoClient::SplitClient.new(api_key, {base_uri: base_uri, logger: Logger.new("/dev/null") })
31
+ split_client = SplitIoClient::SplitFactory.new(api_key, {base_uri: base_uri, logger: Logger.new("/dev/null").client })
32
32
 
33
33
  puts Benchmark.measure{
34
34
  4.times do |i|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: splitclient-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Split Software
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-06-17 00:00:00.000000000 Z
11
+ date: 2016-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -230,8 +230,11 @@ files:
230
230
  - lib/splitclient-engine/parser/split_parser.rb
231
231
  - lib/splitclient-engine/partitions/treatments.rb
232
232
  - lib/splitclient-rb.rb
233
- - lib/splitclient-rb/split_client.rb
233
+ - lib/splitclient-rb/localhost_split_factory.rb
234
+ - lib/splitclient-rb/localhost_split_factory_builder.rb
234
235
  - lib/splitclient-rb/split_config.rb
236
+ - lib/splitclient-rb/split_factory.rb
237
+ - lib/splitclient-rb/split_factory_builder.rb
235
238
  - lib/splitclient-rb/version.rb
236
239
  - lib/splitclient-rb_utilitites.rb
237
240
  - splitclient-rb.gemspec
@@ -258,7 +261,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
258
261
  version: '0'
259
262
  requirements: []
260
263
  rubyforge_project:
261
- rubygems_version: 2.4.8
264
+ rubygems_version: 2.5.2
262
265
  signing_key:
263
266
  specification_version: 4
264
267
  summary: Ruby client for split SDK.
@@ -1,156 +0,0 @@
1
- require 'logger'
2
-
3
- module SplitIoClient
4
-
5
- #
6
- # main class for split client sdk
7
- #
8
- class SplitClient < NoMethodError
9
-
10
- #
11
- # constant that defines the localhost mode
12
- LOCALHOST_MODE = 'localhost'
13
-
14
- #
15
- # object that acts as an api adapter connector. used to get and post to api endpoints
16
- attr_reader :adapter
17
-
18
- #
19
- # variables to if the sdk is being used in localhost mode and store the list of features
20
- attr_reader :localhost_mode
21
- attr_reader :localhost_mode_features
22
-
23
- #
24
- # Creates a new split client instance that connects to split.io API.
25
- #
26
- # @param api_key [String] the API key for your split account
27
- #
28
- # @return [SplitIoClient] split.io client instance
29
- def initialize(api_key, config = {})
30
- @localhost_mode = false
31
- @localhost_mode_features = []
32
-
33
- @config = SplitConfig.new(config)
34
-
35
- if api_key == LOCALHOST_MODE
36
- @localhost_mode = true
37
- load_localhost_mode_features
38
- else
39
- @adapter = SplitAdapter.new(api_key, @config)
40
- end
41
- end
42
-
43
- #
44
- # obtains the treatment for a given feature
45
- #
46
- # @param id [string] user id
47
- # @param feature [string] name of the feature that is being validated
48
- #
49
- # @return [Treatment] treatment constant value
50
- def get_treatment(id, feature, attributes = nil)
51
- unless id
52
- @config.logger.warn('id was null for feature: ' + feature)
53
- return Treatments::CONTROL
54
- end
55
-
56
- unless feature
57
- @config.logger.warn('feature was null for id: ' + id)
58
- return Treatments::CONTROL
59
- end
60
-
61
- if is_localhost_mode?
62
- result = get_localhost_treatment(feature)
63
- else
64
- start = Time.now
65
- result = nil
66
-
67
- begin
68
- result = get_treatment_without_exception_handling(id, feature, attributes)
69
- rescue StandardError => error
70
- @config.log_found_exception(__method__.to_s, error)
71
- end
72
-
73
- result = result.nil? ? Treatments::CONTROL : result
74
-
75
- begin
76
- @adapter.impressions.log(id, feature, result, (Time.now.to_f * 1000.0))
77
- latency = (Time.now - start) * 1000.0
78
- if (@adapter.impressions.queue.length >= @adapter.impressions.max_number_of_keys)
79
- @adapter.impressions_producer.wakeup
80
- end
81
- rescue StandardError => error
82
- @config.log_found_exception(__method__.to_s, error)
83
- end
84
-
85
- end
86
-
87
- result
88
- end
89
-
90
- #
91
- # auxiliary method to get the treatments avoding exceptions
92
- #
93
- # @param id [string] user id
94
- # @param feature [string] name of the feature that is being validated
95
- #
96
- # @return [Treatment] tretment constant value
97
- def get_treatment_without_exception_handling(id, feature, attributes = nil)
98
- @adapter.parsed_splits.segments = @adapter.parsed_segments
99
- split = @adapter.parsed_splits.get_split(feature)
100
-
101
- if split.nil?
102
- return Treatments::CONTROL
103
- else
104
- default_treatment = split.data[:defaultTreatment]
105
- return @adapter.parsed_splits.get_split_treatment(id, feature, default_treatment, attributes)
106
- end
107
- end
108
-
109
- #
110
- # method that returns the sdk gem version
111
- #
112
- # @return [string] version value for this sdk
113
- def self.sdk_version
114
- 'RubyClientSDK-'+SplitIoClient::VERSION
115
- end
116
-
117
- #
118
- # method to check if the sdk is running in localhost mode based on api key
119
- #
120
- # @return [boolean] True if is in localhost mode, false otherwise
121
- def is_localhost_mode?
122
- @localhost_mode
123
- end
124
-
125
- #
126
- # method to set localhost mode features by reading .splits file located at home directory
127
- #
128
- # @returns [void]
129
- def load_localhost_mode_features
130
- splits_file = File.join(Dir.home, ".split")
131
- if File.exists?(splits_file)
132
- line_num=0
133
- File.open(splits_file).each do |line|
134
- line_data = line.strip.split(" ")
135
- @localhost_mode_features << {feature: line_data[0], treatment: line_data[1]} unless line.start_with?('#') || line.strip.empty?
136
- end
137
- end
138
- end
139
-
140
- #
141
- # method to check the treatment for the given feature in localhost mode
142
- #
143
- # @return [boolean] true if the feature is available in localhost mode, false otherwise
144
- def get_localhost_treatment(feature)
145
- localhost_result = Treatments::CONTROL
146
- treatment = @localhost_mode_features.select{|h| h[:feature] == feature}.last
147
- localhost_result = treatment[:treatment] if !treatment.nil?
148
- localhost_result
149
- end
150
-
151
- private :get_treatment_without_exception_handling, :is_localhost_mode?,
152
- :load_localhost_mode_features, :get_localhost_treatment
153
-
154
- end
155
-
156
- end