devcycle-ruby-server-sdk 2.7.0 → 3.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/Gemfile +1 -1
- data/devcycle-ruby-server-sdk.gemspec +3 -3
- data/lib/devcycle-ruby-server-sdk/api/client.rb +2 -2
- data/lib/devcycle-ruby-server-sdk/localbucketing/bucketing-lib.release.wasm +0 -0
- data/lib/devcycle-ruby-server-sdk/localbucketing/config_manager.rb +32 -8
- data/lib/devcycle-ruby-server-sdk/localbucketing/event_queue.rb +4 -1
- data/lib/devcycle-ruby-server-sdk/localbucketing/local_bucketing.rb +5 -3
- data/lib/devcycle-ruby-server-sdk/localbucketing/update_wasm.sh +5 -0
- data/lib/devcycle-ruby-server-sdk/version.rb +1 -1
- data/spec/api/devcycle_api_spec.rb +1 -1
- metadata +11 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f9dd2899f5a8f286a66a667fa27623331572f5c35dec9ad363ab0be2e191296
|
4
|
+
data.tar.gz: e0971e7a1bdafc366b2021df303dbfc0f30f230d1c353e435d810805026ab866
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c2d2b26b6ef08f548c58ecfbca13b2a09ab5643184f2018f9ede3e41ca1a115f17024f577e84ce12c27a23161be3cb7dc0d717569d23f4698b1f0398847dfdf
|
7
|
+
data.tar.gz: 1bfe5568cc56cf86566c9fe9d7480ffb6b3f7edf6907544a3305e99fbe64a163a867aa8f713015172591673889bd688fd81971efd4fbb91ef152433c59637b61
|
data/Gemfile
CHANGED
@@ -21,12 +21,12 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.summary = "DevCycle Bucketing API Ruby Gem"
|
22
22
|
s.description = "DevCycle Ruby Server SDK, for interacting with feature flags created with the DevCycle platform."
|
23
23
|
s.license = "MIT"
|
24
|
-
s.required_ruby_version = ">=
|
24
|
+
s.required_ruby_version = ">= 3.1"
|
25
25
|
|
26
26
|
s.add_runtime_dependency 'typhoeus', '~> 1.0', '>= 1.0.1'
|
27
|
-
s.add_runtime_dependency 'wasmtime', '
|
27
|
+
s.add_runtime_dependency 'wasmtime', '20.0.2'
|
28
28
|
s.add_runtime_dependency 'concurrent-ruby', '~> 1.2.0'
|
29
|
-
s.add_runtime_dependency 'sorbet-runtime', '
|
29
|
+
s.add_runtime_dependency 'sorbet-runtime', '>= 0.5.11481'
|
30
30
|
s.add_runtime_dependency 'oj', '~> 3.0'
|
31
31
|
s.add_runtime_dependency 'google-protobuf', '~> 3.22'
|
32
32
|
|
@@ -158,13 +158,13 @@ module DevCycle
|
|
158
158
|
end
|
159
159
|
|
160
160
|
# Get variable by key for user data
|
161
|
-
# @param user [User]
|
161
|
+
# @param user [DevCycle::User]
|
162
162
|
# @param key [String] Variable key
|
163
163
|
# @param default Default value for variable if none is retrieved
|
164
164
|
# @param [Hash] opts the optional parameters
|
165
165
|
# @return [Variable]
|
166
166
|
def variable(user, key, default, opts = {})
|
167
|
-
|
167
|
+
unless user.is_a?(DevCycle::User)
|
168
168
|
fail ArgumentError, "user param must be an instance of DevCycle::User!"
|
169
169
|
end
|
170
170
|
|
Binary file
|
@@ -4,6 +4,7 @@ require 'sorbet-runtime'
|
|
4
4
|
require 'concurrent-ruby'
|
5
5
|
require 'typhoeus'
|
6
6
|
require 'json'
|
7
|
+
require 'time'
|
7
8
|
|
8
9
|
module DevCycle
|
9
10
|
class ConfigManager
|
@@ -19,13 +20,14 @@ module DevCycle
|
|
19
20
|
@local_bucketing = local_bucketing
|
20
21
|
@sdkKey = sdkKey
|
21
22
|
@config_e_tag = ""
|
23
|
+
@config_last_modified = ""
|
22
24
|
@logger = local_bucketing.options.logger
|
23
25
|
@polling_enabled = true
|
24
26
|
@max_config_retries = 2
|
25
27
|
|
26
28
|
@config_poller = Concurrent::TimerTask.new({
|
27
|
-
|
28
|
-
|
29
|
+
execution_interval: @local_bucketing.options.config_polling_interval_ms.fdiv(1000)
|
30
|
+
}) do |task|
|
29
31
|
fetch_config
|
30
32
|
end
|
31
33
|
|
@@ -53,22 +55,43 @@ module DevCycle
|
|
53
55
|
Accept: "application/json",
|
54
56
|
})
|
55
57
|
|
58
|
+
begin
|
59
|
+
Date.parse(@config_last_modified)
|
60
|
+
if @config_last_modified != ""
|
61
|
+
req.options[:headers]["If-Modified-Since"] = Time.httpdate(@config_last_modified)
|
62
|
+
end
|
63
|
+
rescue
|
64
|
+
end
|
65
|
+
|
66
|
+
|
56
67
|
if @config_e_tag != ""
|
57
68
|
req.options[:headers]['If-None-Match'] = @config_e_tag
|
58
69
|
end
|
59
70
|
|
60
71
|
@max_config_retries.times do
|
61
|
-
@logger.debug("Requesting new config from #{get_config_url}, current etag: #{@config_e_tag}")
|
72
|
+
@logger.debug("Requesting new config from #{get_config_url}, current etag: #{@config_e_tag}, last modified: #{@config_last_modified}")
|
62
73
|
resp = req.run
|
63
74
|
@logger.debug("Config request complete, status: #{resp.code}")
|
64
75
|
case resp.code
|
65
76
|
when 304
|
66
|
-
@logger.debug("Config not modified, using cache, etag: #{@config_e_tag}")
|
77
|
+
@logger.debug("Config not modified, using cache, etag: #{@config_e_tag}, last modified: #{@config_last_modified}")
|
67
78
|
break
|
68
79
|
when 200
|
69
|
-
@logger.debug("New config received, etag: #{resp.headers['Etag']}")
|
70
|
-
|
71
|
-
|
80
|
+
@logger.debug("New config received, etag: #{resp.headers['Etag']} LM:#{resp.headers['Last-Modified']}")
|
81
|
+
lm_header = resp.headers['Last-Modified']
|
82
|
+
begin
|
83
|
+
lm_timestamp = Time.rfc2822(lm_header)
|
84
|
+
current_lm = Time.rfc2822(@config_last_modified)
|
85
|
+
if lm_timestamp == "" && @config_last_modified == "" || (current_lm.utc < lm_timestamp.utc)
|
86
|
+
set_config(resp.body, resp.headers['Etag'], lm_header)
|
87
|
+
@logger.debug("New config stored, etag: #{@config_e_tag}, last modified: #{lm_header}")
|
88
|
+
else
|
89
|
+
@logger.warn("Config response was an older config than currently stored config.")
|
90
|
+
end
|
91
|
+
rescue
|
92
|
+
@logger.warn("Failed to parse last modified header, setting config.")
|
93
|
+
set_config(resp.body, resp.headers['Etag'], lm_header)
|
94
|
+
end
|
72
95
|
break
|
73
96
|
when 403
|
74
97
|
stop_polling
|
@@ -91,13 +114,14 @@ module DevCycle
|
|
91
114
|
nil
|
92
115
|
end
|
93
116
|
|
94
|
-
def set_config(config, etag)
|
117
|
+
def set_config(config, etag, lastmodified)
|
95
118
|
if !JSON.parse(config).is_a?(Hash)
|
96
119
|
raise("Invalid JSON body parsed from Config Response")
|
97
120
|
end
|
98
121
|
|
99
122
|
@local_bucketing.store_config(config)
|
100
123
|
@config_e_tag = etag
|
124
|
+
@config_last_modified = lastmodified
|
101
125
|
@local_bucketing.has_config = true
|
102
126
|
end
|
103
127
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'typhoeus'
|
2
2
|
require 'sorbet-runtime'
|
3
3
|
require 'concurrent-ruby'
|
4
|
+
require 'securerandom'
|
5
|
+
|
4
6
|
|
5
7
|
module DevCycle
|
6
8
|
class EventQueue
|
@@ -9,6 +11,7 @@ module DevCycle
|
|
9
11
|
sig { params(sdkKey: String, options: EventQueueOptions, local_bucketing: LocalBucketing).void }
|
10
12
|
def initialize(sdkKey, options, local_bucketing)
|
11
13
|
@sdkKey = sdkKey
|
14
|
+
@client_uuid = SecureRandom.uuid
|
12
15
|
@events_api_uri = options.events_api_uri
|
13
16
|
@logger = options.logger
|
14
17
|
@event_flush_interval_ms = options.event_flush_interval_ms
|
@@ -22,7 +25,7 @@ module DevCycle
|
|
22
25
|
@flush_timer_task.execute
|
23
26
|
@flush_mutex = Mutex.new
|
24
27
|
@local_bucketing = local_bucketing
|
25
|
-
@local_bucketing.init_event_queue(options)
|
28
|
+
@local_bucketing.init_event_queue(@client_uuid, options)
|
26
29
|
end
|
27
30
|
|
28
31
|
def close
|
@@ -32,6 +32,7 @@ module DevCycle
|
|
32
32
|
.inherit_stderr
|
33
33
|
.set_argv(ARGV)
|
34
34
|
.set_env(ENV)
|
35
|
+
.build
|
35
36
|
@@store = Wasmtime::Store.new(@@engine, wasi_ctx: @@wasi_ctx)
|
36
37
|
@@linker = Wasmtime::Linker.new(@@engine, wasi: true)
|
37
38
|
|
@@ -245,13 +246,14 @@ module DevCycle
|
|
245
246
|
end
|
246
247
|
end
|
247
248
|
|
248
|
-
sig { params(options: EventQueueOptions).returns(NilClass) }
|
249
|
-
def init_event_queue(options)
|
249
|
+
sig { params(client_uuid: String, options: EventQueueOptions).returns(NilClass) }
|
250
|
+
def init_event_queue(client_uuid, options)
|
250
251
|
@wasm_mutex.synchronize do
|
251
252
|
options_json = Oj.dump(options)
|
253
|
+
client_uuid_addr = malloc_asc_string(client_uuid)
|
252
254
|
options_addr = malloc_asc_string(options_json)
|
253
255
|
@@stack_tracer = @@stack_tracer_raise
|
254
|
-
@@instance.invoke("initEventQueue", @sdkKeyAddr, options_addr)
|
256
|
+
@@instance.invoke("initEventQueue", @sdkKeyAddr, client_uuid_addr, options_addr)
|
255
257
|
end
|
256
258
|
end
|
257
259
|
|
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:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- DevCycleHQ
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-07-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: typhoeus
|
@@ -36,14 +36,14 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - '='
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
39
|
+
version: 20.0.2
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - '='
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
46
|
+
version: 20.0.2
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: concurrent-ruby
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -62,16 +62,16 @@ dependencies:
|
|
62
62
|
name: sorbet-runtime
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
|
-
- - "
|
65
|
+
- - ">="
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version:
|
67
|
+
version: 0.5.11481
|
68
68
|
type: :runtime
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
|
-
- - "
|
72
|
+
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
74
|
+
version: 0.5.11481
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: oj
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -149,6 +149,7 @@ files:
|
|
149
149
|
- lib/devcycle-ruby-server-sdk/localbucketing/proto/helpers.rb
|
150
150
|
- lib/devcycle-ruby-server-sdk/localbucketing/proto/variableForUserParams.proto
|
151
151
|
- lib/devcycle-ruby-server-sdk/localbucketing/proto/variableForUserParams_pb.rb
|
152
|
+
- lib/devcycle-ruby-server-sdk/localbucketing/update_wasm.sh
|
152
153
|
- lib/devcycle-ruby-server-sdk/models/error_response.rb
|
153
154
|
- lib/devcycle-ruby-server-sdk/models/event.rb
|
154
155
|
- lib/devcycle-ruby-server-sdk/models/feature.rb
|
@@ -173,14 +174,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
173
174
|
requirements:
|
174
175
|
- - ">="
|
175
176
|
- !ruby/object:Gem::Version
|
176
|
-
version: '
|
177
|
+
version: '3.1'
|
177
178
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
179
|
requirements:
|
179
180
|
- - ">="
|
180
181
|
- !ruby/object:Gem::Version
|
181
182
|
version: '0'
|
182
183
|
requirements: []
|
183
|
-
rubygems_version: 3.
|
184
|
+
rubygems_version: 3.4.1
|
184
185
|
signing_key:
|
185
186
|
specification_version: 4
|
186
187
|
summary: DevCycle Bucketing API Ruby Gem
|