launchdarkly-server-sdk 8.4.2 → 8.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ldclient-rb/config.rb +11 -0
- data/lib/ldclient-rb/context.rb +63 -0
- data/lib/ldclient-rb/events.rb +18 -5
- data/lib/ldclient-rb/impl/integrations/file_data_source.rb +15 -11
- data/lib/ldclient-rb/integrations/file_data.rb +1 -1
- data/lib/ldclient-rb/ldclient.rb +12 -7
- data/lib/ldclient-rb/reference.rb +10 -0
- data/lib/ldclient-rb/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a732ff00a5e21bfc907dff44adc5bd3f1651bd80c2483273a1a9730f443448f
|
4
|
+
data.tar.gz: 1ca26bf847c2387ed585e07b18c6aa42a78496110a7bf9643751a0e2b04d2908
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 901e6f7562f0861916bf06fd07088561713579633cc5e052ae5cf86c6acdbdd0497b55e273c2f92244a5653d0fa806c9776f92a853bad22232634489c630f85d
|
7
|
+
data.tar.gz: a325418b21c256a8b2d846d187e8bc91ba1e323955f460a418732b77f30354b64fc2dbfdadd04c4be4a41217779a4f217d522799ace4ce46a3ebc5019baf060c
|
data/lib/ldclient-rb/config.rb
CHANGED
@@ -43,6 +43,7 @@ module LaunchDarkly
|
|
43
43
|
# @option opts [BigSegmentsConfig] :big_segments See {#big_segments}.
|
44
44
|
# @option opts [Hash] :application See {#application}
|
45
45
|
# @option opts [String] :payload_filter_key See {#payload_filter_key}
|
46
|
+
# @option opts [Boolean] :omit_anonymous_contexts See {#omit_anonymous_contexts}
|
46
47
|
# @option hooks [Array<Interfaces::Hooks::Hook]
|
47
48
|
#
|
48
49
|
def initialize(opts = {})
|
@@ -77,6 +78,7 @@ module LaunchDarkly
|
|
77
78
|
@application = LaunchDarkly::Impl::Util.validate_application_info(opts[:application] || {}, @logger)
|
78
79
|
@payload_filter_key = opts[:payload_filter_key]
|
79
80
|
@hooks = (opts[:hooks] || []).keep_if { |hook| hook.is_a? Interfaces::Hooks::Hook }
|
81
|
+
@omit_anonymous_contexts = opts.has_key?(:omit_anonymous_contexts) && opts[:omit_anonymous_contexts]
|
80
82
|
@data_source_update_sink = nil
|
81
83
|
end
|
82
84
|
|
@@ -385,6 +387,15 @@ module LaunchDarkly
|
|
385
387
|
#
|
386
388
|
attr_reader :hooks
|
387
389
|
|
390
|
+
#
|
391
|
+
# Sets whether anonymous contexts should be omitted from index and identify events.
|
392
|
+
#
|
393
|
+
# The default value is false. Anonymous contexts will be included in index and identify events.
|
394
|
+
# @return [Boolean]
|
395
|
+
#
|
396
|
+
attr_reader :omit_anonymous_contexts
|
397
|
+
|
398
|
+
|
388
399
|
#
|
389
400
|
# The default LaunchDarkly client configuration. This configuration sets
|
390
401
|
# reasonable defaults for most users.
|
data/lib/ldclient-rb/context.rb
CHANGED
@@ -101,6 +101,26 @@ module LaunchDarkly
|
|
101
101
|
@error.nil?
|
102
102
|
end
|
103
103
|
|
104
|
+
#
|
105
|
+
# For a multi-kind context:
|
106
|
+
#
|
107
|
+
# A multi-kind context is made up of two or more single-kind contexts. This method will first discard any
|
108
|
+
# single-kind contexts which are anonymous. It will then create a new multi-kind context from the remaining
|
109
|
+
# single-kind contexts. This may result in an invalid context (e.g. all single-kind contexts are anonymous).
|
110
|
+
#
|
111
|
+
# For a single-kind context:
|
112
|
+
#
|
113
|
+
# If the context is not anonymous, this method will return the current context as is and unmodified.
|
114
|
+
#
|
115
|
+
# If the context is anonymous, this method will return an invalid context.
|
116
|
+
#
|
117
|
+
def without_anonymous_contexts
|
118
|
+
contexts = multi_kind? ? @contexts : [self]
|
119
|
+
contexts = contexts.reject { |c| c.anonymous }
|
120
|
+
|
121
|
+
LDContext.create_multi(contexts)
|
122
|
+
end
|
123
|
+
|
104
124
|
#
|
105
125
|
# Returns a hash mapping each context's kind to its key.
|
106
126
|
#
|
@@ -334,6 +354,49 @@ module LaunchDarkly
|
|
334
354
|
multi_kind? ? individual_context(key.to_s) : get_value(key)
|
335
355
|
end
|
336
356
|
|
357
|
+
#
|
358
|
+
# Convert the LDContext to a JSON string.
|
359
|
+
#
|
360
|
+
# @param args [Array]
|
361
|
+
# @return [String]
|
362
|
+
#
|
363
|
+
def to_json(*args)
|
364
|
+
JSON.generate(to_h, *args)
|
365
|
+
end
|
366
|
+
|
367
|
+
#
|
368
|
+
# Convert the LDContext to a hash. If the LDContext is invalid, the hash will contain an error key with the error
|
369
|
+
# message.
|
370
|
+
#
|
371
|
+
# @return [Hash]
|
372
|
+
#
|
373
|
+
def to_h
|
374
|
+
return {error: error} unless valid?
|
375
|
+
return hash_single_kind unless multi_kind?
|
376
|
+
|
377
|
+
hash = {kind: 'multi'}
|
378
|
+
@contexts.each do |context|
|
379
|
+
single_kind_hash = context.to_h
|
380
|
+
kind = single_kind_hash.delete(:kind)
|
381
|
+
hash[kind] = single_kind_hash
|
382
|
+
end
|
383
|
+
|
384
|
+
hash
|
385
|
+
end
|
386
|
+
|
387
|
+
protected def hash_single_kind
|
388
|
+
hash = attributes.nil? ? {} : attributes.clone
|
389
|
+
|
390
|
+
hash[:kind] = kind
|
391
|
+
hash[:key] = key
|
392
|
+
|
393
|
+
hash[:name] = name unless name.nil?
|
394
|
+
hash[:anonymous] = anonymous if anonymous
|
395
|
+
hash[:_meta] = {privateAttributes: private_attributes} unless private_attributes.empty?
|
396
|
+
|
397
|
+
hash
|
398
|
+
end
|
399
|
+
|
337
400
|
#
|
338
401
|
# Retrieve the value of any top level, addressable attribute.
|
339
402
|
#
|
data/lib/ldclient-rb/events.rb
CHANGED
@@ -144,6 +144,7 @@ module LaunchDarkly
|
|
144
144
|
Impl::EventSender.new(sdk_key, config, client || Util.new_http_client(config.events_uri, config))
|
145
145
|
|
146
146
|
@timestamp_fn = (test_properties || {})[:timestamp_fn] || proc { Impl::Util.current_time_millis }
|
147
|
+
@omit_anonymous_contexts = config.omit_anonymous_contexts
|
147
148
|
|
148
149
|
EventDispatcher.new(@inbox, sdk_key, config, diagnostic_accumulator, event_sender)
|
149
150
|
end
|
@@ -167,7 +168,8 @@ module LaunchDarkly
|
|
167
168
|
end
|
168
169
|
|
169
170
|
def record_identify_event(context)
|
170
|
-
|
171
|
+
target_context = !@omit_anonymous_contexts ? context : context.without_anonymous_contexts
|
172
|
+
post_to_inbox(LaunchDarkly::Impl::IdentifyEvent.new(timestamp, target_context)) if target_context.valid?
|
171
173
|
end
|
172
174
|
|
173
175
|
def record_custom_event(context, key, data = nil, metric_value = nil)
|
@@ -319,16 +321,27 @@ module LaunchDarkly
|
|
319
321
|
will_add_full_event = true
|
320
322
|
end
|
321
323
|
|
322
|
-
|
323
|
-
|
324
|
-
if !event.context.nil? && !notice_context(event.context) && !event.is_a?(LaunchDarkly::Impl::IdentifyEvent) && !event.is_a?(LaunchDarkly::Impl::MigrationOpEvent)
|
325
|
-
outbox.add_event(LaunchDarkly::Impl::IndexEvent.new(event.timestamp, event.context))
|
324
|
+
get_indexable_context(event) do |ctx|
|
325
|
+
outbox.add_event(LaunchDarkly::Impl::IndexEvent.new(event.timestamp, ctx))
|
326
326
|
end
|
327
327
|
|
328
328
|
outbox.add_event(event) if will_add_full_event && @sampler.sample(event.sampling_ratio.nil? ? 1 : event.sampling_ratio)
|
329
329
|
outbox.add_event(debug_event) if !debug_event.nil? && @sampler.sample(event.sampling_ratio.nil? ? 1 : event.sampling_ratio)
|
330
330
|
end
|
331
331
|
|
332
|
+
private def get_indexable_context(event, &block)
|
333
|
+
return if event.context.nil?
|
334
|
+
|
335
|
+
context = !@config.omit_anonymous_contexts ? event.context : event.context.without_anonymous_contexts
|
336
|
+
return unless context.valid?
|
337
|
+
|
338
|
+
return if notice_context(context)
|
339
|
+
return if event.is_a?(LaunchDarkly::Impl::IdentifyEvent)
|
340
|
+
return if event.is_a?(LaunchDarkly::Impl::MigrationOpEvent)
|
341
|
+
|
342
|
+
yield context unless block.nil?
|
343
|
+
end
|
344
|
+
|
332
345
|
#
|
333
346
|
# Add to the set of contexts we've noticed, and return true if the context
|
334
347
|
# was already known to us.
|
@@ -36,18 +36,13 @@ module LaunchDarkly
|
|
36
36
|
@paths = [ @paths ]
|
37
37
|
end
|
38
38
|
@auto_update = options[:auto_update]
|
39
|
-
|
40
|
-
# We have seen unreliable behavior in the 'listen' gem in JRuby 9.1 (https://github.com/guard/listen/issues/449).
|
41
|
-
# Therefore, on that platform we'll fall back to file polling instead.
|
42
|
-
if defined?(JRUBY_VERSION) && JRUBY_VERSION.start_with?("9.1.")
|
43
|
-
@use_listen = false
|
44
|
-
else
|
45
|
-
@use_listen = true
|
46
|
-
end
|
47
|
-
end
|
39
|
+
@use_listen = @auto_update && @@have_listen && !options[:force_polling]
|
48
40
|
@poll_interval = options[:poll_interval] || 1
|
49
41
|
@initialized = Concurrent::AtomicBoolean.new(false)
|
50
42
|
@ready = Concurrent::Event.new
|
43
|
+
|
44
|
+
@version_lock = Mutex.new
|
45
|
+
@last_version = 1
|
51
46
|
end
|
52
47
|
|
53
48
|
def initialized?
|
@@ -101,14 +96,22 @@ module LaunchDarkly
|
|
101
96
|
end
|
102
97
|
|
103
98
|
def load_file(path, all_data)
|
99
|
+
version = 1
|
100
|
+
@version_lock.synchronize {
|
101
|
+
version = @last_version
|
102
|
+
@last_version += 1
|
103
|
+
}
|
104
|
+
|
104
105
|
parsed = parse_content(IO.read(path))
|
105
106
|
(parsed[:flags] || {}).each do |key, flag|
|
107
|
+
flag[:version] = version
|
106
108
|
add_item(all_data, FEATURES, flag)
|
107
109
|
end
|
108
110
|
(parsed[:flagValues] || {}).each do |key, value|
|
109
|
-
add_item(all_data, FEATURES, make_flag_with_value(key.to_s, value))
|
111
|
+
add_item(all_data, FEATURES, make_flag_with_value(key.to_s, value, version))
|
110
112
|
end
|
111
113
|
(parsed[:segments] || {}).each do |key, segment|
|
114
|
+
segment[:version] = version
|
112
115
|
add_item(all_data, SEGMENTS, segment)
|
113
116
|
end
|
114
117
|
end
|
@@ -142,10 +145,11 @@ module LaunchDarkly
|
|
142
145
|
items[key] = Model.deserialize(kind, item)
|
143
146
|
end
|
144
147
|
|
145
|
-
def make_flag_with_value(key, value)
|
148
|
+
def make_flag_with_value(key, value, version)
|
146
149
|
{
|
147
150
|
key: key,
|
148
151
|
on: true,
|
152
|
+
version: version,
|
149
153
|
fallthrough: { variation: 0 },
|
150
154
|
variations: [ value ],
|
151
155
|
}
|
@@ -93,7 +93,7 @@ module LaunchDarkly
|
|
93
93
|
# Note that the default implementation of this feature is based on polling the filesystem,
|
94
94
|
# which may not perform well. If you install the 'listen' gem (not included by default, to
|
95
95
|
# avoid adding unwanted dependencies to the SDK), its native file watching mechanism will be
|
96
|
-
# used instead.
|
96
|
+
# used instead.
|
97
97
|
# @option options [Float] :poll_interval The minimum interval, in seconds, between checks for
|
98
98
|
# file modifications - used only if auto_update is true, and if the native file-watching
|
99
99
|
# mechanism from 'listen' is not being used. The default value is 1 second.
|
data/lib/ldclient-rb/ldclient.rb
CHANGED
@@ -124,13 +124,18 @@ module LaunchDarkly
|
|
124
124
|
end
|
125
125
|
|
126
126
|
ready = @data_source.start
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
127
|
+
|
128
|
+
return unless wait_for_sec > 0
|
129
|
+
|
130
|
+
if wait_for_sec > 60
|
131
|
+
@config.logger.warn { "[LDClient] Client was configured to block for up to #{wait_for_sec} seconds when initializing. We recommend blocking no longer than 60." }
|
132
|
+
end
|
133
|
+
|
134
|
+
ok = ready.wait(wait_for_sec)
|
135
|
+
if !ok
|
136
|
+
@config.logger.error { "[LDClient] Timeout encountered waiting for LaunchDarkly client initialization" }
|
137
|
+
elsif !@data_source.initialized?
|
138
|
+
@config.logger.error { "[LDClient] LaunchDarkly client initialization failed" }
|
134
139
|
end
|
135
140
|
end
|
136
141
|
|
@@ -238,6 +238,16 @@ module LaunchDarkly
|
|
238
238
|
([error] + components).hash
|
239
239
|
end
|
240
240
|
|
241
|
+
#
|
242
|
+
# Convert the Reference to a JSON string.
|
243
|
+
#
|
244
|
+
# @param args [Array]
|
245
|
+
# @return [String]
|
246
|
+
#
|
247
|
+
def to_json(*args)
|
248
|
+
JSON.generate(@raw_path, *args)
|
249
|
+
end
|
250
|
+
|
241
251
|
#
|
242
252
|
# Performs unescaping of attribute reference path components:
|
243
253
|
#
|
data/lib/ldclient-rb/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: launchdarkly-server-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.
|
4
|
+
version: 8.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- LaunchDarkly
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-dynamodb
|
@@ -376,7 +376,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
376
376
|
- !ruby/object:Gem::Version
|
377
377
|
version: '0'
|
378
378
|
requirements: []
|
379
|
-
rubygems_version: 3.5.
|
379
|
+
rubygems_version: 3.5.11
|
380
380
|
signing_key:
|
381
381
|
specification_version: 4
|
382
382
|
summary: LaunchDarkly SDK for Ruby
|