ff-ruby-server-sdk 0.0.2 → 1.0.2.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.run/sdk_test.rb.run.xml +3 -3
  3. data/CHANGELOG.md +12 -2
  4. data/Gemfile +17 -3
  5. data/README.md +155 -7
  6. data/api.yaml +736 -0
  7. data/example/example.rb +100 -3
  8. data/lib/ff/ruby/server/generated/lib/openapi_client/api/client_api.rb +545 -0
  9. data/lib/ff/ruby/server/generated/lib/openapi_client/api/metrics_api.rb +89 -0
  10. data/lib/ff/ruby/server/generated/lib/openapi_client/api_client.rb +390 -0
  11. data/lib/ff/ruby/server/generated/lib/openapi_client/api_error.rb +57 -0
  12. data/lib/ff/ruby/server/generated/lib/openapi_client/configuration.rb +282 -0
  13. data/lib/ff/ruby/server/generated/lib/openapi_client/models/authentication_request.rb +232 -0
  14. data/lib/ff/ruby/server/generated/lib/openapi_client/models/authentication_request_target.rb +250 -0
  15. data/lib/ff/ruby/server/generated/lib/openapi_client/models/authentication_response.rb +223 -0
  16. data/lib/ff/ruby/server/generated/lib/openapi_client/models/clause.rb +281 -0
  17. data/lib/ff/ruby/server/generated/lib/openapi_client/models/distribution.rb +239 -0
  18. data/lib/ff/ruby/server/generated/lib/openapi_client/models/error.rb +237 -0
  19. data/lib/ff/ruby/server/generated/lib/openapi_client/models/evaluation.rb +260 -0
  20. data/lib/ff/ruby/server/generated/lib/openapi_client/models/feature_config.rb +418 -0
  21. data/lib/ff/ruby/server/generated/lib/openapi_client/models/feature_state.rb +37 -0
  22. data/lib/ff/ruby/server/generated/lib/openapi_client/models/key_value.rb +237 -0
  23. data/lib/ff/ruby/server/generated/lib/openapi_client/models/metrics.rb +231 -0
  24. data/lib/ff/ruby/server/generated/lib/openapi_client/models/metrics_data.rb +303 -0
  25. data/lib/ff/ruby/server/generated/lib/openapi_client/models/pagination.rb +274 -0
  26. data/lib/ff/ruby/server/generated/lib/openapi_client/models/prerequisite.rb +239 -0
  27. data/lib/ff/ruby/server/generated/lib/openapi_client/models/segment.rb +320 -0
  28. data/lib/ff/ruby/server/generated/lib/openapi_client/models/serve.rb +227 -0
  29. data/lib/ff/ruby/server/generated/lib/openapi_client/models/serving_rule.rb +267 -0
  30. data/lib/ff/ruby/server/generated/lib/openapi_client/models/tag.rb +233 -0
  31. data/lib/ff/ruby/server/generated/lib/openapi_client/models/target.rb +331 -0
  32. data/lib/ff/ruby/server/generated/lib/openapi_client/models/target_data.rb +253 -0
  33. data/lib/ff/ruby/server/generated/lib/openapi_client/models/target_map.rb +232 -0
  34. data/lib/ff/ruby/server/generated/lib/openapi_client/models/variation.rb +255 -0
  35. data/lib/ff/ruby/server/generated/lib/openapi_client/models/variation_map.rb +245 -0
  36. data/lib/ff/ruby/server/generated/lib/openapi_client/models/weighted_variation.rb +237 -0
  37. data/lib/ff/ruby/server/generated/lib/openapi_client/version.rb +15 -0
  38. data/lib/ff/ruby/server/generated/lib/openapi_client.rb +65 -0
  39. data/lib/ff/ruby/server/sdk/api/auth_service.rb +91 -0
  40. data/lib/ff/ruby/server/sdk/api/cf_client.rb +93 -0
  41. data/lib/ff/ruby/server/sdk/api/client_callback.rb +45 -0
  42. data/lib/ff/ruby/server/sdk/api/config.rb +140 -0
  43. data/lib/ff/ruby/server/sdk/api/config_builder.rb +116 -0
  44. data/lib/ff/ruby/server/sdk/api/default_cache.rb +112 -0
  45. data/lib/ff/ruby/server/sdk/api/evaluation.rb +29 -0
  46. data/lib/ff/ruby/server/sdk/api/evaluator.rb +526 -0
  47. data/lib/ff/ruby/server/sdk/api/file_map_store.rb +60 -0
  48. data/lib/ff/ruby/server/sdk/api/flag_evaluate_callback.rb +13 -0
  49. data/lib/ff/ruby/server/sdk/api/inner_client.rb +311 -0
  50. data/lib/ff/ruby/server/sdk/api/inner_client_flag_evaluate_callback.rb +30 -0
  51. data/lib/ff/ruby/server/sdk/api/inner_client_metrics_callback.rb +33 -0
  52. data/lib/ff/ruby/server/sdk/api/inner_client_repository_callback.rb +44 -0
  53. data/lib/ff/ruby/server/sdk/api/inner_client_updater.rb +63 -0
  54. data/lib/ff/ruby/server/sdk/api/metrics_callback.rb +19 -0
  55. data/lib/ff/ruby/server/sdk/api/metrics_event.rb +16 -0
  56. data/lib/ff/ruby/server/sdk/api/metrics_processor.rb +297 -0
  57. data/lib/ff/ruby/server/sdk/api/operators.rb +20 -0
  58. data/lib/ff/ruby/server/sdk/api/polling_processor.rb +164 -0
  59. data/lib/ff/ruby/server/sdk/api/repository_callback.rb +28 -0
  60. data/lib/ff/ruby/server/sdk/api/storage_repository.rb +263 -0
  61. data/lib/ff/ruby/server/sdk/api/summary_metrics.rb +16 -0
  62. data/lib/ff/ruby/server/sdk/api/update_processor.rb +149 -0
  63. data/lib/ff/ruby/server/sdk/common/cache.rb +27 -0
  64. data/lib/ff/ruby/server/sdk/common/closeable.rb +7 -0
  65. data/lib/ff/ruby/server/sdk/common/destroyable.rb +12 -0
  66. data/lib/ff/ruby/server/sdk/common/repository.rb +45 -0
  67. data/lib/ff/ruby/server/sdk/common/storage.rb +29 -0
  68. data/lib/ff/ruby/server/sdk/connector/connector.rb +44 -0
  69. data/lib/ff/ruby/server/sdk/connector/events.rb +118 -0
  70. data/lib/ff/ruby/server/sdk/connector/harness_connector.rb +236 -0
  71. data/lib/ff/ruby/server/sdk/connector/service.rb +19 -0
  72. data/lib/ff/ruby/server/sdk/connector/updater.rb +32 -0
  73. data/lib/ff/ruby/server/sdk/dto/message.rb +13 -0
  74. data/lib/ff/ruby/server/sdk/dto/target.rb +24 -0
  75. data/lib/ff/ruby/server/sdk/version.rb +2 -1
  76. data/lib/ff/ruby/server/sdk.rb +39 -3
  77. data/openapitools.json +7 -0
  78. data/scripts/install.sh +8 -2
  79. data/scripts/openapi.sh +76 -0
  80. data/scripts/publish.sh +1 -1
  81. data/scripts/sdk_specs.sh +1 -1
  82. metadata +263 -11
  83. data/lib/ff/ruby/server/sdk/cf_client.rb +0 -6
@@ -0,0 +1,297 @@
1
+ require "time"
2
+ require "concurrent-ruby"
3
+
4
+ require_relative "../dto/target"
5
+ require_relative "../../sdk/version"
6
+ require_relative "../common/closeable"
7
+ require_relative "../api/metrics_event"
8
+ require_relative "../api/summary_metrics"
9
+
10
+ class MetricsProcessor < Closeable
11
+
12
+ def initialize(
13
+
14
+ connector,
15
+ config,
16
+ callback
17
+ )
18
+
19
+ unless connector.kind_of?(Connector)
20
+
21
+ raise "The 'connector' must be of '" + Connector.to_s + "' data type"
22
+ end
23
+
24
+ unless callback.kind_of?(MetricsCallback)
25
+
26
+ raise "The 'callback' must be of '" + MetricsCallback.to_s + "' data type"
27
+ end
28
+
29
+ unless config.kind_of?(Config)
30
+
31
+ raise "The 'config' must be of '" + Config.to_s + "' data type"
32
+ end
33
+
34
+ @config = config
35
+ @callback = callback
36
+ @connector = connector
37
+
38
+ @sdk_type = "SDK_TYPE"
39
+ @global_target_set = Set[]
40
+ @staging_target_set = Set[]
41
+ @target_attribute = "target"
42
+ @global_target = "__global__cf_target" # <--- This target identifier is used to aggregate and send data for all
43
+ # targets as a summary
44
+
45
+ @ready = false
46
+ @jar_version = ""
47
+ @server = "server"
48
+ @sdk_version = "SDK_VERSION"
49
+ @sdk_language = "SDK_LANGUAGE"
50
+ @global_target_name = "Global Target"
51
+ @feature_name_attribute = "featureName"
52
+ @variation_identifier_attribute = "variationIdentifier"
53
+
54
+ @queue = SizedQueue.new(@config.buffer_size)
55
+ @executor = Concurrent::FixedThreadPool.new(100)
56
+
57
+ @callback.on_metrics_ready
58
+ end
59
+
60
+ def start
61
+
62
+ @config.logger.info "Starting metrics processor with request interval: " + @config.frequency.to_s
63
+ start_async
64
+ end
65
+
66
+ def stop
67
+
68
+ @config.logger.info "Stopping metrics processor"
69
+ stop_async
70
+ end
71
+
72
+ def close
73
+
74
+ stop
75
+ @config.logger.info "Closing metrics processor"
76
+ end
77
+
78
+ def push_to_queue(
79
+
80
+ target,
81
+ feature_config,
82
+ variation
83
+ )
84
+
85
+ @executor.post do
86
+
87
+ @config.logger.debug "Pushing to the metrics queue: START"
88
+
89
+ event = MetricsEvent.new(feature_config, target, variation)
90
+ @queue.push(event)
91
+
92
+ @config.logger.debug "Pushing to the metrics queue: END, queue size: " + @queue.size.to_s
93
+
94
+ end
95
+ end
96
+
97
+ def send_data_and_reset_cache(data)
98
+
99
+ @config.logger.debug "Reading from queue and building cache"
100
+
101
+ @jar_version = get_version
102
+
103
+ unless data.empty?
104
+
105
+ map = {}
106
+
107
+ data.each do |event|
108
+
109
+ new_value = 1
110
+ current = map[event]
111
+
112
+ if current != nil
113
+
114
+ new_value = current + 1
115
+ end
116
+
117
+ map[event] = new_value
118
+ end
119
+
120
+ metrics = prepare_summary_metrics_body(map)
121
+
122
+ if !metrics.metrics_data.empty? && !metrics.target_data.empty?
123
+
124
+ start_time = (Time.now.to_f * 1000).to_i
125
+
126
+ @connector.post_metrics(metrics)
127
+
128
+ end_time = (Time.now.to_f * 1000).to_i
129
+
130
+ if end_time - start_time > @config.metrics_service_acceptable_duration
131
+
132
+ @config.logger.debug "Metrics service API duration=[" + (end_time - start_time).to_s + "]"
133
+ end
134
+ end
135
+
136
+ @global_target_set.merge(@staging_target_set)
137
+ @staging_target_set.clear
138
+ end
139
+ end
140
+
141
+ protected
142
+
143
+ def run_one_iteration
144
+
145
+ @config.logger.debug "Async metrics iteration: " + @thread.to_s
146
+
147
+ data = []
148
+
149
+ until @queue.empty?
150
+
151
+ item = @queue.pop
152
+ data.push(item)
153
+ end
154
+
155
+ send_data_and_reset_cache(data)
156
+ end
157
+
158
+ def prepare_summary_metrics_body(data)
159
+
160
+ summary_metrics_data = {}
161
+ metrics = OpenapiClient::Metrics.new({ :target_data => [], :metrics_data => [] })
162
+
163
+ add_target_data(
164
+
165
+ metrics,
166
+ Target.new(
167
+
168
+ name = @global_target_name,
169
+ identifier = @global_target
170
+ )
171
+ )
172
+
173
+ data.each do |key, value|
174
+
175
+ target = key.target
176
+
177
+ add_target_data(metrics, target)
178
+
179
+ summary_metrics = prepare_summary_metrics_key(key)
180
+
181
+ summary_metrics_data[summary_metrics] = value
182
+ end
183
+
184
+ summary_metrics_data.each do |key, value|
185
+
186
+ metrics_data = OpenapiClient::MetricsData.new({ :attributes => [] })
187
+ metrics_data.timestamp = (Time.now.to_f * 1000).to_i
188
+ metrics_data.count = value
189
+ metrics_data.metrics_type = "FFMETRICS"
190
+ metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @feature_name_attribute, :value => key.feature_name }))
191
+ metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @variation_identifier_attribute, :value => key.variation_identifier }))
192
+ metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @target_attribute, :value => @global_target }))
193
+ metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @sdk_type, :value => @server }))
194
+ metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @sdk_language, :value => "ruby" }))
195
+ metrics_data.attributes.push(OpenapiClient::KeyValue.new({ :key => @sdk_version, :value => @jar_version }))
196
+
197
+ metrics.metrics_data.push(metrics_data)
198
+ end
199
+
200
+ metrics
201
+ end
202
+
203
+ private
204
+
205
+ def start_async
206
+
207
+ @config.logger.debug "Async starting: " + self.to_s
208
+
209
+ @ready = true
210
+
211
+ @thread = Thread.new do
212
+
213
+ @config.logger.debug "Async started: " + self.to_s
214
+
215
+ while @ready do
216
+
217
+ unless @initialized
218
+
219
+ @initialized = true
220
+ @config.logger.info "Metrics processor initialized"
221
+ end
222
+
223
+ sleep(@config.frequency)
224
+
225
+ run_one_iteration
226
+ end
227
+ end
228
+
229
+ @thread.run
230
+ end
231
+
232
+ def stop_async
233
+
234
+ @queue.clear
235
+
236
+ @ready = false
237
+ @initialized = false
238
+ end
239
+
240
+ def prepare_summary_metrics_key(key)
241
+
242
+ SummaryMetrics.new(
243
+
244
+ feature_name = key.feature_config.feature,
245
+ variation_identifier = key.variation.identifier,
246
+ variation_value = key.variation.value
247
+ )
248
+ end
249
+
250
+ def add_target_data(metrics, target)
251
+
252
+ target_data = OpenapiClient::TargetData.new({ :attributes => [] })
253
+ private_attributes = target.private_attributes
254
+
255
+ if !@staging_target_set.include?(target) && !@global_target_set.include?(target) && !target.is_private
256
+
257
+ @staging_target_set.add(target)
258
+
259
+ attributes = target.attributes
260
+
261
+ attributes.each do |k, v|
262
+
263
+ key_value = OpenapiClient::KeyValue.new
264
+
265
+ if !private_attributes.empty?
266
+
267
+ unless private_attributes.include?(k)
268
+
269
+ key_value = OpenapiClient::KeyValue.new({ :key => k, :value => v.to_s })
270
+ end
271
+ else
272
+
273
+ key_value = OpenapiClient::KeyValue.new({ :key => k, :value => v.to_s })
274
+ end
275
+
276
+ target_data.attributes.push(key_value)
277
+ end
278
+
279
+ target_data.identifier = target.identifier
280
+
281
+ if target.name == nil || target.name == ""
282
+
283
+ target_data.name = target.identifier
284
+ else
285
+
286
+ target_data.name = target.name
287
+ end
288
+
289
+ metrics.target_data.push(target_data)
290
+ end
291
+ end
292
+
293
+ def get_version
294
+
295
+ Ff::Ruby::Server::Sdk::VERSION
296
+ end
297
+ end
@@ -0,0 +1,20 @@
1
+ class Operators
2
+
3
+ def initialize
4
+ super
5
+
6
+ raise "Abstract"
7
+ end
8
+
9
+ # Static:
10
+ class << self
11
+
12
+ @@SEGMENT_MATCH = "SEGMENT_MATCH"
13
+
14
+ def SEGMENT_MATCH
15
+
16
+ @@SEGMENT_MATCH
17
+ end
18
+
19
+ end # Static - End
20
+ end
@@ -0,0 +1,164 @@
1
+ require_relative "../common/closeable"
2
+
3
+ class PollingProcessor < Closeable
4
+
5
+ def initialize(
6
+
7
+ connector,
8
+ repository,
9
+ poll_interval_in_sec,
10
+ callback,
11
+ logger = nil
12
+ )
13
+
14
+ @callback = callback
15
+ @connector = connector
16
+ @repository = repository
17
+ @poll_interval_in_sec = poll_interval_in_sec
18
+
19
+ if logger != nil
20
+
21
+ @logger = logger
22
+ else
23
+
24
+ @logger = Logger.new(STDOUT)
25
+ end
26
+ end
27
+
28
+ def retrieve_flags
29
+
30
+ flags = []
31
+
32
+ @logger.info "Fetching flags started"
33
+
34
+ result = @connector.get_flags
35
+
36
+ if result != nil
37
+
38
+ @logger.info "Flags are fetched"
39
+
40
+ result.each { |fc|
41
+
42
+ if fc != nil
43
+
44
+ @repository.set_flag(fc.feature, fc)
45
+ flags.push(fc)
46
+ end
47
+ }
48
+ end
49
+
50
+ @logger.info "Fetching flags finished"
51
+
52
+ flags
53
+ end
54
+
55
+ def retrieve_segments
56
+
57
+ segments = []
58
+
59
+ @logger.info "Fetching segments started"
60
+
61
+ result = @connector.get_segments
62
+
63
+ if result != nil
64
+
65
+ @logger.info "Segments are fetched"
66
+
67
+ result.each { |s|
68
+
69
+ if s != nil
70
+
71
+ @repository.set_flag(s.identifier, s)
72
+ flags.push(s)
73
+ end
74
+ }
75
+ end
76
+
77
+ @logger.info "Fetching segments finished"
78
+
79
+ segments
80
+ end
81
+
82
+ def start_async
83
+
84
+ @logger.debug "Async starting: " + self.to_s
85
+
86
+ @ready = true
87
+
88
+ @thread = Thread.new do
89
+
90
+ @logger.debug "Async started: " + self.to_s
91
+
92
+ while @ready do
93
+
94
+ @logger.debug "Async poll iteration"
95
+
96
+ if @callback != nil
97
+
98
+ @callback.on_poller_iteration(self)
99
+ end
100
+
101
+ begin
102
+
103
+ retrieve_flags
104
+ retrieve_segments
105
+
106
+ unless @initialized
107
+
108
+ @initialized = true
109
+ @logger.info "PollingProcessor initialized"
110
+
111
+ if @callback != nil
112
+
113
+ @callback.on_poller_ready(self)
114
+ end
115
+ end
116
+
117
+ rescue OpenapiClient::ApiError => e
118
+
119
+ if @callback != nil
120
+
121
+ @callback.on_poller_error(e)
122
+ end
123
+ end
124
+
125
+ sleep(@poll_interval_in_sec)
126
+ end
127
+ end
128
+
129
+ @thread.run
130
+ end
131
+
132
+ def stop_async
133
+
134
+ @ready = false
135
+ @initialized = false
136
+ end
137
+
138
+ def start
139
+
140
+ @logger.info "Starting PollingProcessor with request interval: " + @poll_interval_in_sec.to_s
141
+ start_async
142
+ end
143
+
144
+ def stop
145
+
146
+ @logger.info "Stopping PollingProcessor"
147
+ stop_async
148
+ unless @ready
149
+
150
+ @logger.info "PollingProcessor stopped"
151
+ end
152
+ end
153
+
154
+ def close
155
+
156
+ stop
157
+ @logger.info "Closing PollingProcessor"
158
+ end
159
+
160
+ def is_ready
161
+
162
+ @ready && @initialized
163
+ end
164
+ end
@@ -0,0 +1,28 @@
1
+ class RepositoryCallback
2
+
3
+ def initialize
4
+ super
5
+
6
+ @tbi = "To be implemented"
7
+ end
8
+
9
+ def on_flag_stored(identifier)
10
+
11
+ raise @tbi
12
+ end
13
+
14
+ def on_flag_deleted(identifier)
15
+
16
+ raise @tbi
17
+ end
18
+
19
+ def on_segment_stored(identifier)
20
+
21
+ raise @tbi
22
+ end
23
+
24
+ def on_segment_deleted(identifier)
25
+
26
+ raise @tbi
27
+ end
28
+ end