devcycle-ruby-server-sdk 2.0.2 → 2.0.3
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/lib/devcycle-ruby-server-sdk/api/devcycle_api.rb +62 -13
- data/lib/devcycle-ruby-server-sdk/localbucketing/config_manager.rb +45 -31
- data/lib/devcycle-ruby-server-sdk/localbucketing/local_bucketing.rb +6 -4
- data/lib/devcycle-ruby-server-sdk/models/variable.rb +8 -2
- data/lib/devcycle-ruby-server-sdk/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 960c105106387fcb10b360f0befbb77d2dda8c80dce5a51a5eed3c8c49528253
|
4
|
+
data.tar.gz: 1c9274022cece19d953ceba7adfed10cd6418e4a3097ad3305f1a539ace32e23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67cb4a92cb5c9247bd10c838cfa0979d89d331c75c5626967af9b4602c55c30a2842f94f2c15471bb459686382be20432e43bf9951f1c27f516cbc5b2d8a504e
|
7
|
+
data.tar.gz: 802ec0ab8f6b2a7623fe58c94cd007484832c06c5742a38831bebd0991ef2c3b57cc99563ffcee89a545742c0fe1080beea95be01aab88f27983d5d808b359f1
|
@@ -60,10 +60,16 @@ module DevCycle
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def set_client_custom_data(customdata)
|
63
|
-
if @
|
64
|
-
|
63
|
+
if @dvc_options.enable_cloud_bucketing
|
64
|
+
raise StandardError.new("Client Custom Data is only available in Local bucketing mode.")
|
65
|
+
end
|
66
|
+
|
67
|
+
if local_bucketing_initialized?
|
68
|
+
@localbucketing.set_client_custom_data(customdata)
|
69
|
+
else
|
70
|
+
@logger.warn("Local bucketing not initialized. Unable to set client custom data.")
|
65
71
|
end
|
66
|
-
|
72
|
+
nil
|
67
73
|
end
|
68
74
|
|
69
75
|
def validate_model(model)
|
@@ -87,7 +93,7 @@ module DevCycle
|
|
87
93
|
return data
|
88
94
|
end
|
89
95
|
|
90
|
-
if local_bucketing_initialized?
|
96
|
+
if local_bucketing_initialized? && @localbucketing.has_config
|
91
97
|
bucketed_config = @localbucketing.generate_bucketed_config(user_data)
|
92
98
|
bucketed_config.features
|
93
99
|
else
|
@@ -170,30 +176,59 @@ module DevCycle
|
|
170
176
|
return data
|
171
177
|
end
|
172
178
|
|
173
|
-
if local_bucketing_initialized?
|
179
|
+
if local_bucketing_initialized? && @localbucketing.has_config
|
174
180
|
bucketed_config = @localbucketing.generate_bucketed_config(user_data)
|
175
181
|
variable_json = bucketed_config.variables[key]
|
176
182
|
if variable_json == nil
|
183
|
+
@logger.warn("No variable found for key #{key}, returning default value")
|
177
184
|
variable_event = Event.new({ type: DevCycle::EventTypes[:agg_variable_defaulted], target: key })
|
178
185
|
@event_queue.queue_aggregate_event(variable_event, bucketed_config)
|
179
186
|
|
180
|
-
return Variable.new({
|
187
|
+
return Variable.new({
|
188
|
+
key: key,
|
189
|
+
type: determine_variable_type(default),
|
190
|
+
value: default,
|
191
|
+
defaultValue: default,
|
192
|
+
isDefaulted: true
|
193
|
+
})
|
181
194
|
end
|
195
|
+
default_type = determine_variable_type(default)
|
196
|
+
variable_type = variable_json['type']
|
197
|
+
if default_type != variable_type
|
198
|
+
@logger.warn("Type mismatch for variable #{key}, returning default value")
|
199
|
+
variable_event = Event.new({ type: DevCycle::EventTypes[:agg_variable_defaulted], target: key })
|
200
|
+
@event_queue.queue_aggregate_event(variable_event, bucketed_config)
|
182
201
|
|
202
|
+
return Variable.new({
|
203
|
+
key: key,
|
204
|
+
type: default_type,
|
205
|
+
value: default,
|
206
|
+
defaultValue: default,
|
207
|
+
isDefaulted: true
|
208
|
+
})
|
209
|
+
end
|
183
210
|
variable_event = Event.new({ type: DevCycle::EventTypes[:agg_variable_evaluated], target: key })
|
184
211
|
@event_queue.queue_aggregate_event(variable_event, bucketed_config)
|
185
212
|
|
186
213
|
Variable.new({
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
214
|
+
key: key,
|
215
|
+
type: variable_type,
|
216
|
+
value: variable_json['value'],
|
217
|
+
defaultValue: default,
|
218
|
+
isDefaulted: false
|
219
|
+
})
|
192
220
|
else
|
221
|
+
@logger.warn("Local bucketing not initialized, returning default value for variable #{key}")
|
193
222
|
variable_event = Event.new({ type: DevCycle::EventTypes[:agg_variable_defaulted], target: key })
|
194
223
|
@event_queue.queue_aggregate_event(variable_event, bucketed_config)
|
195
224
|
|
196
|
-
Variable.new({
|
225
|
+
Variable.new({
|
226
|
+
key: key,
|
227
|
+
type: determine_variable_type(default),
|
228
|
+
value: default,
|
229
|
+
defaultValue: default,
|
230
|
+
isDefaulted: true
|
231
|
+
})
|
197
232
|
end
|
198
233
|
end
|
199
234
|
|
@@ -284,7 +319,7 @@ module DevCycle
|
|
284
319
|
return data
|
285
320
|
end
|
286
321
|
|
287
|
-
if local_bucketing_initialized?
|
322
|
+
if local_bucketing_initialized? && @localbucketing.has_config
|
288
323
|
bucketed_config = @localbucketing.generate_bucketed_config(user_data)
|
289
324
|
bucketed_config.variables
|
290
325
|
else
|
@@ -453,5 +488,19 @@ module DevCycle
|
|
453
488
|
def local_bucketing_initialized?
|
454
489
|
!@localbucketing.nil? && @localbucketing.initialized
|
455
490
|
end
|
491
|
+
|
492
|
+
def determine_variable_type(variable_value)
|
493
|
+
if variable_value.is_a?(String)
|
494
|
+
'String'
|
495
|
+
elsif variable_value.is_a?(TrueClass) || variable_value.is_a?(FalseClass)
|
496
|
+
'Boolean'
|
497
|
+
elsif variable_value.is_a?(Integer) || variable_value.is_a?(Float)
|
498
|
+
'Number'
|
499
|
+
elsif variable_value.is_a?(Hash)
|
500
|
+
'JSON'
|
501
|
+
else
|
502
|
+
raise ArgumentError, "Invalid type for variable: #{variable_value}"
|
503
|
+
end
|
504
|
+
end
|
456
505
|
end
|
457
506
|
end
|
@@ -20,19 +20,33 @@ module DevCycle
|
|
20
20
|
@sdkKey = sdkKey
|
21
21
|
@config_e_tag = ""
|
22
22
|
@logger = local_bucketing.options.logger
|
23
|
+
@polling_enabled = true
|
24
|
+
@max_config_retries = 2
|
23
25
|
|
24
|
-
@config_poller = Concurrent::TimerTask.new(
|
25
|
-
{
|
26
|
+
@config_poller = Concurrent::TimerTask.new({
|
26
27
|
execution_interval: @local_bucketing.options.config_polling_interval_ms.fdiv(1000)
|
27
28
|
}) do |task|
|
28
|
-
fetch_config
|
29
|
+
fetch_config
|
29
30
|
end
|
30
31
|
|
31
|
-
t = Thread.new {
|
32
|
+
t = Thread.new { initialize_config }
|
32
33
|
t.join if wait_for_init
|
33
34
|
end
|
34
35
|
|
35
|
-
def
|
36
|
+
def initialize_config
|
37
|
+
begin
|
38
|
+
fetch_config
|
39
|
+
@config_poller.execute if @polling_enabled
|
40
|
+
rescue => e
|
41
|
+
@logger.error("DVC Error Initializing Config: #{e.message}")
|
42
|
+
ensure
|
43
|
+
@local_bucketing.initialized = true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def fetch_config
|
48
|
+
return unless @polling_enabled
|
49
|
+
|
36
50
|
req = Typhoeus::Request.new(
|
37
51
|
get_config_url,
|
38
52
|
headers: {
|
@@ -43,25 +57,26 @@ module DevCycle
|
|
43
57
|
req.options[:headers]['If-None-Match'] = @config_e_tag
|
44
58
|
end
|
45
59
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
60
|
+
@max_config_retries.times do
|
61
|
+
resp = req.run
|
62
|
+
case resp.code
|
63
|
+
when 304
|
64
|
+
@logger.debug("Config not modified, using cache, etag: #{this.configEtag}")
|
65
|
+
return
|
66
|
+
when 200
|
67
|
+
set_config(resp.body, resp.headers['Etag'])
|
68
|
+
return
|
69
|
+
when 403
|
70
|
+
stop_polling
|
71
|
+
@logger.error("Failed to download DevCycle config; Invalid SDK Key.")
|
72
|
+
return
|
73
|
+
when 500...599
|
74
|
+
@logger.error("Failed to download DevCycle config. Status: #{resp.code}")
|
75
|
+
else
|
76
|
+
stop_polling
|
77
|
+
@logger.error("Unexpected response code - DevCycle Response: #{Oj.dump(resp)}")
|
78
|
+
return
|
58
79
|
end
|
59
|
-
@logger.warn("Failed to download DevCycle config. Status: #{resp.code}")
|
60
|
-
else
|
61
|
-
if task != nil
|
62
|
-
task.shutdown
|
63
|
-
end
|
64
|
-
raise("Unexpected response code - DevCycle Response: #{Oj.dump(resp)}")
|
65
80
|
end
|
66
81
|
|
67
82
|
nil
|
@@ -74,13 +89,7 @@ module DevCycle
|
|
74
89
|
|
75
90
|
@local_bucketing.store_config(config)
|
76
91
|
@config_e_tag = etag
|
77
|
-
|
78
|
-
if @first_load
|
79
|
-
@logger.info("Config Set. Client Initialized.")
|
80
|
-
@first_load = false
|
81
|
-
@local_bucketing.initialized = true
|
82
|
-
@config_poller.execute
|
83
|
-
end
|
92
|
+
@local_bucketing.has_config = true
|
84
93
|
end
|
85
94
|
|
86
95
|
def get_config_url
|
@@ -88,8 +97,13 @@ module DevCycle
|
|
88
97
|
"#{configBasePath}/config/#{@config_version}/server/#{@sdkKey}.json"
|
89
98
|
end
|
90
99
|
|
100
|
+
def stop_polling
|
101
|
+
@polling_enabled = false
|
102
|
+
@config_poller.shutdown if @config_poller.running?
|
103
|
+
end
|
104
|
+
|
91
105
|
def close
|
92
|
-
@config_poller.shutdown
|
106
|
+
@config_poller.shutdown if @config_poller.running?
|
93
107
|
nil
|
94
108
|
end
|
95
109
|
end
|
@@ -14,6 +14,7 @@ module DevCycle
|
|
14
14
|
|
15
15
|
attr_reader :options
|
16
16
|
attr_accessor :initialized
|
17
|
+
attr_accessor :has_config
|
17
18
|
|
18
19
|
@@rand = Random.new(seed = Random.new_seed)
|
19
20
|
@@engine = Wasmtime::Engine.new
|
@@ -86,18 +87,19 @@ module DevCycle
|
|
86
87
|
).void }
|
87
88
|
def initialize(sdkkey, options, wait_for_init)
|
88
89
|
@initialized = false
|
90
|
+
@has_config = false
|
89
91
|
@sdkkey = sdkkey
|
90
92
|
@options = options
|
91
93
|
@logger = options.logger
|
92
94
|
set_sdk_key_internal(sdkkey)
|
93
95
|
platform_data = PlatformData.new('server', VERSION, RUBY_VERSION, nil, 'Ruby', Socket.gethostname)
|
94
96
|
set_platform_data(platform_data)
|
95
|
-
@
|
97
|
+
@config_manager = ConfigManager.new(@sdkkey, self, wait_for_init)
|
96
98
|
end
|
97
99
|
|
98
100
|
def close
|
99
|
-
@
|
100
|
-
@
|
101
|
+
@config_manager.close
|
102
|
+
@config_manager = nil
|
101
103
|
end
|
102
104
|
|
103
105
|
sig { params(user: UserData).returns(BucketedUserConfig) }
|
@@ -236,7 +238,7 @@ module DevCycle
|
|
236
238
|
wasm_object_id = 1
|
237
239
|
@@stack_tracer = lambda { |message| raise message }
|
238
240
|
wasm_new = @@instance.export("__new").to_func
|
239
|
-
utf8_bytes = string.
|
241
|
+
utf8_bytes = string.bytes
|
240
242
|
byte_len = utf8_bytes.length
|
241
243
|
|
242
244
|
start_addr = wasm_new.call(byte_len * 2, wasm_object_id)
|
@@ -27,6 +27,8 @@ module DevCycle
|
|
27
27
|
# Set to true if the Variable could not be fetched
|
28
28
|
attr_accessor :isDefaulted
|
29
29
|
|
30
|
+
attr_accessor :defaultValue
|
31
|
+
|
30
32
|
class EnumAttributeValidator
|
31
33
|
attr_reader :datatype
|
32
34
|
attr_reader :allowable_values
|
@@ -55,6 +57,7 @@ module DevCycle
|
|
55
57
|
:'key' => :'key',
|
56
58
|
:'type' => :'type',
|
57
59
|
:'value' => :'value',
|
60
|
+
:'defaultValue' => :'defaultValue',
|
58
61
|
:'isDefaulted' => :'isDefaulted'
|
59
62
|
}
|
60
63
|
end
|
@@ -70,6 +73,7 @@ module DevCycle
|
|
70
73
|
:'key' => :'String',
|
71
74
|
:'type' => :'String',
|
72
75
|
:'value' => :'Object',
|
76
|
+
:'defaultValue' => :'Object',
|
73
77
|
:'isDefaulted' => :'Boolean'
|
74
78
|
}
|
75
79
|
end
|
@@ -112,6 +116,10 @@ module DevCycle
|
|
112
116
|
else
|
113
117
|
self.isDefaulted = false
|
114
118
|
end
|
119
|
+
|
120
|
+
if attributes.key?(:'defaultValue')
|
121
|
+
self.defaultValue = attributes[:'defaultValue']
|
122
|
+
end
|
115
123
|
end
|
116
124
|
|
117
125
|
# Show invalid properties with the reasons. Usually used together with valid?
|
@@ -296,7 +304,5 @@ module DevCycle
|
|
296
304
|
value
|
297
305
|
end
|
298
306
|
end
|
299
|
-
|
300
307
|
end
|
301
|
-
|
302
308
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devcycle-ruby-server-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- DevCycleHQ
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-03-
|
11
|
+
date: 2023-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: typhoeus
|