devcycle-ruby-server-sdk 2.0.2 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 86e5a04ee7157791c8ed075df281ecc09bad3ae898c7e48d520046953ed5aee7
4
- data.tar.gz: 44271e4418ab7b2219403d9a90bbc702befabb034446bc58a2f32a365038f9cb
3
+ metadata.gz: 960c105106387fcb10b360f0befbb77d2dda8c80dce5a51a5eed3c8c49528253
4
+ data.tar.gz: 1c9274022cece19d953ceba7adfed10cd6418e4a3097ad3305f1a539ace32e23
5
5
  SHA512:
6
- metadata.gz: f5946e97ac8b2d0abda40af307609035945e1881587edc5d1d37c01fc1f75e9e0461527f3c232713ba0c839834b2447e4ab95a3f7a471e314fe28c01c15f3281
7
- data.tar.gz: 147519317a620feef9d975bcb3a5cb844c94e03b7f6fb8631d34e98b57b770a5994c4324dd9c1359e7e744b0b5652f6a5f612fdbc0f68a600816187717b22c43
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 @api_client.config.enable_cloud_bucketing
64
- fail ArgumentError("Client Custom Data is only available in Local bucketing mode.")
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
- @localbucketing.set_client_custom_data(customdata)
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({ key: key, value: default, isDefaulted: true })
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
- key: key,
188
- type: variable_json['type'],
189
- value: variable_json['value'],
190
- isDefaulted: false
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({ key: key, value: default, isDefaulted: true })
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(false, task)
29
+ fetch_config
29
30
  end
30
31
 
31
- t = Thread.new { fetch_config(false, nil) }
32
+ t = Thread.new { initialize_config }
32
33
  t.join if wait_for_init
33
34
  end
34
35
 
35
- def fetch_config(retrying, task)
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
- resp = req.run
47
-
48
- case resp.code
49
- when 304
50
- return nil
51
- when 200
52
- return set_config(resp.body, resp.headers['Etag'])
53
- when 403
54
- raise("Failed to download DevCycle config; Invalid SDK Key.")
55
- when 500...599
56
- if !retrying
57
- return fetch_config(true, task)
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
- @configmanager = ConfigManager.new(@sdkkey, self, wait_for_init)
97
+ @config_manager = ConfigManager.new(@sdkkey, self, wait_for_init)
96
98
  end
97
99
 
98
100
  def close
99
- @configmanager.close
100
- @configmanager = nil
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.encode("iso-8859-1").force_encoding("utf-8").bytes
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
@@ -11,5 +11,5 @@ OpenAPI Generator version: 5.3.0
11
11
  =end
12
12
 
13
13
  module DevCycle
14
- VERSION = '2.0.2'
14
+ VERSION = '2.0.3'
15
15
  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.2
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-07 00:00:00.000000000 Z
11
+ date: 2023-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus