ff-ruby-server-sdk 0.0.2 → 1.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 +4 -4
- data/.run/build.sh.run.xml +17 -0
- data/.run/install.sh.run.xml +17 -0
- data/.run/openapi.sh.run.xml +17 -0
- data/.run/publish.sh.run.xml +17 -0
- data/.run/sdk_test.rb.run.xml +3 -3
- data/.run/unpublish.sh.run.xml +17 -0
- data/CHANGELOG.md +1 -1
- data/Gemfile +20 -3
- data/README.md +155 -7
- data/api.yaml +736 -0
- data/example/example.rb +99 -3
- data/lib/ff/ruby/server/sdk/api/auth_service.rb +91 -0
- data/lib/ff/ruby/server/sdk/api/cf_client.rb +93 -0
- data/lib/ff/ruby/server/sdk/api/client_callback.rb +45 -0
- data/lib/ff/ruby/server/sdk/api/config.rb +140 -0
- data/lib/ff/ruby/server/sdk/api/config_builder.rb +116 -0
- data/lib/ff/ruby/server/sdk/api/default_cache.rb +112 -0
- data/lib/ff/ruby/server/sdk/api/evaluation.rb +29 -0
- data/lib/ff/ruby/server/sdk/api/evaluator.rb +526 -0
- data/lib/ff/ruby/server/sdk/api/file_map_store.rb +60 -0
- data/lib/ff/ruby/server/sdk/api/flag_evaluate_callback.rb +13 -0
- data/lib/ff/ruby/server/sdk/api/inner_client.rb +311 -0
- data/lib/ff/ruby/server/sdk/api/inner_client_flag_evaluate_callback.rb +30 -0
- data/lib/ff/ruby/server/sdk/api/inner_client_metrics_callback.rb +33 -0
- data/lib/ff/ruby/server/sdk/api/inner_client_repository_callback.rb +44 -0
- data/lib/ff/ruby/server/sdk/api/inner_client_updater.rb +63 -0
- data/lib/ff/ruby/server/sdk/api/metrics_callback.rb +19 -0
- data/lib/ff/ruby/server/sdk/api/metrics_event.rb +16 -0
- data/lib/ff/ruby/server/sdk/api/metrics_processor.rb +297 -0
- data/lib/ff/ruby/server/sdk/api/operators.rb +20 -0
- data/lib/ff/ruby/server/sdk/api/polling_processor.rb +164 -0
- data/lib/ff/ruby/server/sdk/api/repository_callback.rb +28 -0
- data/lib/ff/ruby/server/sdk/api/storage_repository.rb +263 -0
- data/lib/ff/ruby/server/sdk/api/summary_metrics.rb +16 -0
- data/lib/ff/ruby/server/sdk/api/update_processor.rb +149 -0
- data/lib/ff/ruby/server/sdk/common/cache.rb +27 -0
- data/lib/ff/ruby/server/sdk/common/closeable.rb +7 -0
- data/lib/ff/ruby/server/sdk/common/destroyable.rb +12 -0
- data/lib/ff/ruby/server/sdk/common/repository.rb +45 -0
- data/lib/ff/ruby/server/sdk/common/storage.rb +29 -0
- data/lib/ff/ruby/server/sdk/connector/connector.rb +44 -0
- data/lib/ff/ruby/server/sdk/connector/events.rb +118 -0
- data/lib/ff/ruby/server/sdk/connector/harness_connector.rb +236 -0
- data/lib/ff/ruby/server/sdk/connector/service.rb +19 -0
- data/lib/ff/ruby/server/sdk/connector/updater.rb +32 -0
- data/lib/ff/ruby/server/sdk/dto/message.rb +13 -0
- data/lib/ff/ruby/server/sdk/dto/target.rb +24 -0
- data/lib/ff/ruby/server/sdk/version.rb +2 -1
- data/lib/ff/ruby/server/sdk.rb +39 -3
- data/openapitools.json +7 -0
- data/scripts/openapi.sh +35 -0
- data/scripts/sdk_specs.sh +1 -1
- metadata +46 -3
- data/lib/ff/ruby/server/sdk/cf_client.rb +0 -6
@@ -0,0 +1,311 @@
|
|
1
|
+
require_relative "evaluator"
|
2
|
+
require_relative "evaluation"
|
3
|
+
require_relative "auth_service"
|
4
|
+
require_relative "client_callback"
|
5
|
+
require_relative "update_processor"
|
6
|
+
require_relative "polling_processor"
|
7
|
+
require_relative "metrics_processor"
|
8
|
+
require_relative "storage_repository"
|
9
|
+
require_relative "inner_client_updater"
|
10
|
+
require_relative "inner_client_metrics_callback"
|
11
|
+
require_relative "inner_client_repository_callback"
|
12
|
+
require_relative "inner_client_flag_evaluate_callback"
|
13
|
+
|
14
|
+
require_relative "../connector/harness_connector"
|
15
|
+
|
16
|
+
class InnerClient < ClientCallback
|
17
|
+
|
18
|
+
def initialize(api_key = nil, config = nil, connector = nil)
|
19
|
+
|
20
|
+
if api_key == nil || api_key == ""
|
21
|
+
|
22
|
+
raise "SDK key is not provided"
|
23
|
+
end
|
24
|
+
|
25
|
+
if config == nil
|
26
|
+
|
27
|
+
@config = ConfigBuilder.new.build
|
28
|
+
else
|
29
|
+
|
30
|
+
unless config.kind_of?(Config)
|
31
|
+
|
32
|
+
raise "The 'config' parameter must be of '" + Config.to_s + "' data type"
|
33
|
+
end
|
34
|
+
|
35
|
+
@config = config
|
36
|
+
end
|
37
|
+
|
38
|
+
@config.logger.debug "Ruby SDK version: " + Ff::Ruby::Server::Sdk::VERSION
|
39
|
+
|
40
|
+
if connector == nil
|
41
|
+
|
42
|
+
@connector = HarnessConnector.new(api_key, config = @config, on_unauthorized = self)
|
43
|
+
|
44
|
+
else
|
45
|
+
|
46
|
+
unless connector.kind_of?(Connector)
|
47
|
+
|
48
|
+
raise "The 'connector' parameter must be of '" + Connector.to_s + "' data type"
|
49
|
+
end
|
50
|
+
|
51
|
+
@connector = connector
|
52
|
+
end
|
53
|
+
|
54
|
+
@closing = false
|
55
|
+
@failure = false
|
56
|
+
@initialized = false
|
57
|
+
@poller_ready = false
|
58
|
+
@stream_ready = false
|
59
|
+
@metrics_ready = false
|
60
|
+
|
61
|
+
@my_mutex = Mutex.new
|
62
|
+
|
63
|
+
@repository_callback = InnerClientRepositoryCallback.new(@config.logger)
|
64
|
+
|
65
|
+
setup
|
66
|
+
end
|
67
|
+
|
68
|
+
def bool_variation(identifier, target, default_value)
|
69
|
+
|
70
|
+
@evaluator.bool_variation(identifier, target, default_value, @evaluator_callback)
|
71
|
+
end
|
72
|
+
|
73
|
+
def string_variation(identifier, target, default_value)
|
74
|
+
|
75
|
+
@evaluator.string_variation(identifier, target, default_value, @evaluator_callback)
|
76
|
+
end
|
77
|
+
|
78
|
+
def number_variation(identifier, target, default_value)
|
79
|
+
|
80
|
+
@evaluator.number_variation(identifier, target, default_value, @evaluator_callback)
|
81
|
+
end
|
82
|
+
|
83
|
+
def json_variation(identifier, target, default_value)
|
84
|
+
|
85
|
+
@evaluator.json_variation(identifier, target, default_value, @evaluator_callback)
|
86
|
+
end
|
87
|
+
|
88
|
+
def on_auth_success
|
89
|
+
|
90
|
+
@config.logger.info "SDK successfully logged in"
|
91
|
+
|
92
|
+
if @closing
|
93
|
+
|
94
|
+
return
|
95
|
+
end
|
96
|
+
|
97
|
+
@poll_processor.start
|
98
|
+
|
99
|
+
if @config.stream_enabled
|
100
|
+
|
101
|
+
@update_processor.start
|
102
|
+
end
|
103
|
+
|
104
|
+
if @config.analytics_enabled
|
105
|
+
|
106
|
+
@metrics_processor.start
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
def close
|
112
|
+
|
113
|
+
@config.logger.info "Closing the client: " + self.to_s
|
114
|
+
|
115
|
+
@closing = true
|
116
|
+
|
117
|
+
off
|
118
|
+
|
119
|
+
@auth_service.close
|
120
|
+
@repository.close
|
121
|
+
@poll_processor.close
|
122
|
+
@update_processor.close
|
123
|
+
@metrics_processor.close
|
124
|
+
@connector.close
|
125
|
+
end
|
126
|
+
|
127
|
+
def is_closing
|
128
|
+
|
129
|
+
@closing
|
130
|
+
end
|
131
|
+
|
132
|
+
def off
|
133
|
+
|
134
|
+
# TODO: Implement - Reactivity support
|
135
|
+
end
|
136
|
+
|
137
|
+
def on_unauthorized
|
138
|
+
|
139
|
+
if @closing
|
140
|
+
|
141
|
+
return
|
142
|
+
end
|
143
|
+
|
144
|
+
@poll_processor.stop
|
145
|
+
|
146
|
+
if @config.stream_enabled
|
147
|
+
|
148
|
+
@update_processor.stop
|
149
|
+
end
|
150
|
+
|
151
|
+
if @config.analytics_enabled
|
152
|
+
|
153
|
+
@metrics_processor.stop
|
154
|
+
end
|
155
|
+
|
156
|
+
@auth_service.start_async
|
157
|
+
end
|
158
|
+
|
159
|
+
def on_poller_ready(poller)
|
160
|
+
|
161
|
+
on_processor_ready(poller)
|
162
|
+
end
|
163
|
+
|
164
|
+
def on_poller_error(e)
|
165
|
+
|
166
|
+
@config.logger.error "Poller error: " + e.to_s
|
167
|
+
end
|
168
|
+
|
169
|
+
def on_poller_iteration(poller)
|
170
|
+
|
171
|
+
@config.logger.debug "Poller iterated" + poller.to_s
|
172
|
+
end
|
173
|
+
|
174
|
+
def update(message, manual)
|
175
|
+
|
176
|
+
if @config.stream_enabled && manual
|
177
|
+
|
178
|
+
@config.logger.warn "You run the update method manually with the stream enabled. Please turn off the stream in this case."
|
179
|
+
end
|
180
|
+
|
181
|
+
@update_processor.update(message)
|
182
|
+
end
|
183
|
+
|
184
|
+
def on_update_processor_ready
|
185
|
+
|
186
|
+
on_processor_ready(@update_processor)
|
187
|
+
end
|
188
|
+
|
189
|
+
def on_metrics_processor_ready
|
190
|
+
|
191
|
+
on_processor_ready(@metrics_processor)
|
192
|
+
end
|
193
|
+
|
194
|
+
def on_processor_ready(processor)
|
195
|
+
|
196
|
+
if @closing
|
197
|
+
|
198
|
+
return
|
199
|
+
end
|
200
|
+
|
201
|
+
if processor == @poll_processor
|
202
|
+
|
203
|
+
@poller_ready = true
|
204
|
+
@config.logger.info "PollingProcessor ready"
|
205
|
+
end
|
206
|
+
|
207
|
+
if processor == @update_processor
|
208
|
+
|
209
|
+
@stream_ready = true
|
210
|
+
@config.logger.info "Updater ready"
|
211
|
+
end
|
212
|
+
|
213
|
+
if processor == @metrics_processor
|
214
|
+
|
215
|
+
@metrics_ready = true
|
216
|
+
@config.logger.info "Metrics ready"
|
217
|
+
end
|
218
|
+
|
219
|
+
if (@config.stream_enabled && !@stream_ready) ||
|
220
|
+
(@config.analytics_enabled && !@metrics_ready) ||
|
221
|
+
!@poller_ready
|
222
|
+
|
223
|
+
return
|
224
|
+
end
|
225
|
+
|
226
|
+
@initialized = true
|
227
|
+
|
228
|
+
# TODO: notify - Reactivity support
|
229
|
+
# TODO: notify_consumers - Reactivity support
|
230
|
+
|
231
|
+
@config.logger.info "Initialization is completed"
|
232
|
+
end
|
233
|
+
|
234
|
+
def wait_for_initialization
|
235
|
+
|
236
|
+
synchronize do
|
237
|
+
|
238
|
+
@config.logger.info "Waiting for the initialization to finish"
|
239
|
+
|
240
|
+
until @initialized
|
241
|
+
|
242
|
+
sleep(1)
|
243
|
+
end
|
244
|
+
|
245
|
+
if @failure
|
246
|
+
|
247
|
+
raise "Initialization failed"
|
248
|
+
end
|
249
|
+
|
250
|
+
@config.logger.info "Waiting for the initialization completed"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
protected
|
255
|
+
|
256
|
+
def setup
|
257
|
+
|
258
|
+
@config.logger.info "SDK is not initialized yet! If store is used then values will be loaded from store" +
|
259
|
+
" otherwise default values will be used in meantime. You can use waitForInitialization method for SDK" +
|
260
|
+
" to be ready."
|
261
|
+
|
262
|
+
@repository = StorageRepository.new(@config.cache, @repository_callback, @config.store, @config.logger)
|
263
|
+
|
264
|
+
@metrics_callback = InnerClientMetricsCallback.new(self, @config.logger)
|
265
|
+
@metrics_processor = MetricsProcessor.new(@connector, @config, @metrics_callback)
|
266
|
+
|
267
|
+
@evaluator = Evaluator.new(@repository, logger = @config.logger)
|
268
|
+
@evaluator_callback = InnerClientFlagEvaluateCallback.new(@metrics_processor, logger = @config.logger)
|
269
|
+
|
270
|
+
@auth_service = AuthService.new(
|
271
|
+
|
272
|
+
connector = @connector,
|
273
|
+
poll_interval_in_sec = @config.poll_interval_in_seconds,
|
274
|
+
callback = self,
|
275
|
+
logger = @config.logger
|
276
|
+
)
|
277
|
+
|
278
|
+
@poll_processor = PollingProcessor.new(
|
279
|
+
|
280
|
+
connector = @connector,
|
281
|
+
repository = @repository,
|
282
|
+
poll_interval_in_sec = @config.poll_interval_in_seconds,
|
283
|
+
callback = self,
|
284
|
+
logger = @config.logger
|
285
|
+
)
|
286
|
+
|
287
|
+
@updater = InnerClientUpdater.new(
|
288
|
+
|
289
|
+
poll_processor = @poll_processor,
|
290
|
+
client_callback = self,
|
291
|
+
logger = @config.logger
|
292
|
+
)
|
293
|
+
|
294
|
+
@update_processor = UpdateProcessor.new(
|
295
|
+
|
296
|
+
connector = @connector,
|
297
|
+
repository = @repository,
|
298
|
+
callback = @updater,
|
299
|
+
logger = @config.logger
|
300
|
+
)
|
301
|
+
|
302
|
+
@auth_service.start_async
|
303
|
+
end
|
304
|
+
|
305
|
+
private
|
306
|
+
|
307
|
+
def synchronize(&block)
|
308
|
+
|
309
|
+
@my_mutex.synchronize(&block)
|
310
|
+
end
|
311
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative "metrics_processor"
|
2
|
+
require_relative "flag_evaluate_callback"
|
3
|
+
|
4
|
+
class InnerClientFlagEvaluateCallback < FlagEvaluateCallback
|
5
|
+
|
6
|
+
def initialize(metrics_processor, logger = nil)
|
7
|
+
|
8
|
+
unless metrics_processor.kind_of?(MetricsProcessor)
|
9
|
+
|
10
|
+
raise "The 'metrics_processor' parameter must be of '" + MetricsProcessor.to_s + "' data type"
|
11
|
+
end
|
12
|
+
|
13
|
+
if logger != nil
|
14
|
+
|
15
|
+
@logger = logger
|
16
|
+
else
|
17
|
+
|
18
|
+
@logger = Logger.new(STDOUT)
|
19
|
+
end
|
20
|
+
|
21
|
+
@metrics_processor = metrics_processor
|
22
|
+
end
|
23
|
+
|
24
|
+
def process_evaluation(feature_config, target, variation)
|
25
|
+
|
26
|
+
@logger.debug "Processing evaluation: " + feature_config.feature.to_s + ", " + target.identifier.to_s
|
27
|
+
|
28
|
+
@metrics_processor.push_to_queue(target, feature_config, variation)
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative "client_callback"
|
2
|
+
require_relative "metrics_callback"
|
3
|
+
|
4
|
+
class InnerClientMetricsCallback < MetricsCallback
|
5
|
+
|
6
|
+
def initialize(client_callback, logger = nil)
|
7
|
+
|
8
|
+
unless client_callback.kind_of?(ClientCallback)
|
9
|
+
|
10
|
+
raise "The 'client_callback' parameter must be of '" + ClientCallback.to_s + "' data type"
|
11
|
+
end
|
12
|
+
|
13
|
+
if logger != nil
|
14
|
+
|
15
|
+
@logger = logger
|
16
|
+
else
|
17
|
+
|
18
|
+
@logger = Logger.new(STDOUT)
|
19
|
+
end
|
20
|
+
|
21
|
+
@client_callback = client_callback
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_metrics_ready
|
25
|
+
|
26
|
+
@client_callback.on_metrics_processor_ready
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_metrics_error(error)
|
30
|
+
|
31
|
+
@logger.error "Metrics error: " + error.to_s
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative "inner_client"
|
2
|
+
require_relative "repository_callback"
|
3
|
+
|
4
|
+
class InnerClientRepositoryCallback < RepositoryCallback
|
5
|
+
|
6
|
+
def initialize(logger = nil)
|
7
|
+
|
8
|
+
if logger != nil
|
9
|
+
|
10
|
+
@logger = logger
|
11
|
+
else
|
12
|
+
|
13
|
+
@logger = Logger.new(STDOUT)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_flag_stored(identifier)
|
18
|
+
|
19
|
+
@logger.debug "On flag stored: " + identifier
|
20
|
+
|
21
|
+
# TODO: Notify consumers
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_flag_deleted(identifier)
|
25
|
+
|
26
|
+
@logger.debug "On flag deleted: " + identifier
|
27
|
+
|
28
|
+
# TODO: Notify consumers
|
29
|
+
end
|
30
|
+
|
31
|
+
def on_segment_stored(identifier)
|
32
|
+
|
33
|
+
@logger.debug "On segment stored: " + identifier
|
34
|
+
|
35
|
+
# TODO: Notify consumers
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_segment_deleted(identifier)
|
39
|
+
|
40
|
+
@logger.debug "On segment deleted: " + identifier
|
41
|
+
|
42
|
+
# TODO: Notify consumers
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
require_relative "../connector/updater"
|
4
|
+
|
5
|
+
class InnerClientUpdater < Updater
|
6
|
+
|
7
|
+
def initialize(
|
8
|
+
|
9
|
+
poll_processor,
|
10
|
+
client_callback,
|
11
|
+
logger = nil
|
12
|
+
)
|
13
|
+
|
14
|
+
unless poll_processor.kind_of?(PollingProcessor)
|
15
|
+
|
16
|
+
raise "The 'poll_processor' parameter must be of '" + PollingProcessor.to_s + "' data type"
|
17
|
+
end
|
18
|
+
|
19
|
+
unless client_callback.kind_of?(ClientCallback)
|
20
|
+
|
21
|
+
raise "The 'client_callback' parameter must be of '" + ClientCallback.to_s + "' data type"
|
22
|
+
end
|
23
|
+
|
24
|
+
if logger != nil
|
25
|
+
|
26
|
+
@logger = logger
|
27
|
+
else
|
28
|
+
|
29
|
+
@logger = Logger.new(STDOUT)
|
30
|
+
end
|
31
|
+
|
32
|
+
@poll_processor = poll_processor
|
33
|
+
@client_callback = client_callback
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_connected
|
37
|
+
|
38
|
+
@poll_processor.stop
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_disconnected
|
42
|
+
|
43
|
+
unless @client_callback.is_closing
|
44
|
+
|
45
|
+
@poll_processor.start
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def on_ready
|
50
|
+
|
51
|
+
@client_callback.on_update_processor_ready()
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_error
|
55
|
+
|
56
|
+
@logger.error "Error occurred"
|
57
|
+
end
|
58
|
+
|
59
|
+
def update(message)
|
60
|
+
|
61
|
+
@client_callback.update(message, false)
|
62
|
+
end
|
63
|
+
end
|