devcycle-ruby-server-sdk 2.7.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|