launchdarkly-server-sdk 6.4.0 → 7.0.1
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/ldclient-rb/config.rb +102 -56
- data/lib/ldclient-rb/context.rb +487 -0
- data/lib/ldclient-rb/evaluation_detail.rb +20 -20
- data/lib/ldclient-rb/events.rb +77 -132
- data/lib/ldclient-rb/flags_state.rb +4 -4
- data/lib/ldclient-rb/impl/big_segments.rb +17 -17
- data/lib/ldclient-rb/impl/context.rb +96 -0
- data/lib/ldclient-rb/impl/context_filter.rb +145 -0
- data/lib/ldclient-rb/impl/diagnostic_events.rb +9 -10
- data/lib/ldclient-rb/impl/evaluator.rb +379 -131
- data/lib/ldclient-rb/impl/evaluator_bucketing.rb +40 -41
- data/lib/ldclient-rb/impl/evaluator_helpers.rb +31 -34
- data/lib/ldclient-rb/impl/evaluator_operators.rb +26 -55
- data/lib/ldclient-rb/impl/event_sender.rb +6 -6
- data/lib/ldclient-rb/impl/event_summarizer.rb +12 -7
- data/lib/ldclient-rb/impl/event_types.rb +18 -30
- data/lib/ldclient-rb/impl/integrations/consul_impl.rb +7 -7
- data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +29 -29
- data/lib/ldclient-rb/impl/integrations/file_data_source.rb +8 -8
- data/lib/ldclient-rb/impl/integrations/redis_impl.rb +92 -12
- data/lib/ldclient-rb/impl/model/clause.rb +45 -0
- data/lib/ldclient-rb/impl/model/feature_flag.rb +232 -0
- data/lib/ldclient-rb/impl/model/preprocessed_data.rb +8 -121
- data/lib/ldclient-rb/impl/model/segment.rb +132 -0
- data/lib/ldclient-rb/impl/model/serialization.rb +52 -12
- data/lib/ldclient-rb/impl/repeating_task.rb +1 -1
- data/lib/ldclient-rb/impl/store_data_set_sorter.rb +2 -2
- data/lib/ldclient-rb/impl/unbounded_pool.rb +1 -1
- data/lib/ldclient-rb/impl/util.rb +2 -2
- data/lib/ldclient-rb/in_memory_store.rb +2 -2
- data/lib/ldclient-rb/integrations/consul.rb +1 -1
- data/lib/ldclient-rb/integrations/dynamodb.rb +1 -1
- data/lib/ldclient-rb/integrations/file_data.rb +3 -3
- data/lib/ldclient-rb/integrations/redis.rb +4 -4
- data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +218 -62
- data/lib/ldclient-rb/integrations/test_data.rb +16 -12
- data/lib/ldclient-rb/integrations/util/store_wrapper.rb +9 -9
- data/lib/ldclient-rb/interfaces.rb +14 -14
- data/lib/ldclient-rb/ldclient.rb +94 -144
- data/lib/ldclient-rb/memoized_value.rb +1 -1
- data/lib/ldclient-rb/non_blocking_thread_pool.rb +1 -1
- data/lib/ldclient-rb/polling.rb +2 -2
- data/lib/ldclient-rb/reference.rb +274 -0
- data/lib/ldclient-rb/requestor.rb +5 -5
- data/lib/ldclient-rb/stream.rb +7 -8
- data/lib/ldclient-rb/util.rb +4 -19
- data/lib/ldclient-rb/version.rb +1 -1
- data/lib/ldclient-rb.rb +2 -3
- metadata +34 -17
- data/lib/ldclient-rb/file_data_source.rb +0 -23
- data/lib/ldclient-rb/newrelic.rb +0 -17
- data/lib/ldclient-rb/redis_store.rb +0 -88
- data/lib/ldclient-rb/user_filter.rb +0 -52
@@ -0,0 +1,145 @@
|
|
1
|
+
module LaunchDarkly
|
2
|
+
module Impl
|
3
|
+
class ContextFilter
|
4
|
+
#
|
5
|
+
# @param all_attributes_private [Boolean]
|
6
|
+
# @param private_attributes [Array<String>]
|
7
|
+
#
|
8
|
+
def initialize(all_attributes_private, private_attributes)
|
9
|
+
@all_attributes_private = all_attributes_private
|
10
|
+
|
11
|
+
@private_attributes = []
|
12
|
+
private_attributes.each do |attribute|
|
13
|
+
reference = LaunchDarkly::Reference.create(attribute)
|
14
|
+
@private_attributes << reference if reference.error.nil?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Return a hash representation of the provided context with attribute
|
20
|
+
# redaction applied.
|
21
|
+
#
|
22
|
+
# @param context [LaunchDarkly::LDContext]
|
23
|
+
# @return [Hash]
|
24
|
+
#
|
25
|
+
def filter(context)
|
26
|
+
return filter_single_context(context, true) unless context.multi_kind?
|
27
|
+
|
28
|
+
filtered = {kind: 'multi'}
|
29
|
+
(0...context.individual_context_count).each do |i|
|
30
|
+
c = context.individual_context(i)
|
31
|
+
next if c.nil?
|
32
|
+
|
33
|
+
filtered[c.kind] = filter_single_context(c, false)
|
34
|
+
end
|
35
|
+
|
36
|
+
filtered
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Apply redaction rules for a single context.
|
41
|
+
#
|
42
|
+
# @param context [LaunchDarkly::LDContext]
|
43
|
+
# @param include_kind [Boolean]
|
44
|
+
# @return [Hash]
|
45
|
+
#
|
46
|
+
private def filter_single_context(context, include_kind)
|
47
|
+
filtered = {key: context.key}
|
48
|
+
|
49
|
+
filtered[:kind] = context.kind if include_kind
|
50
|
+
filtered[:anonymous] = true if context.get_value(:anonymous)
|
51
|
+
|
52
|
+
redacted = []
|
53
|
+
private_attributes = @private_attributes.concat(context.private_attributes)
|
54
|
+
|
55
|
+
name = context.get_value(:name)
|
56
|
+
if !name.nil? && !check_whole_attribute_private(:name, private_attributes, redacted)
|
57
|
+
filtered[:name] = name
|
58
|
+
end
|
59
|
+
|
60
|
+
context.get_custom_attribute_names.each do |attribute|
|
61
|
+
unless check_whole_attribute_private(attribute, private_attributes, redacted)
|
62
|
+
value = context.get_value(attribute)
|
63
|
+
filtered[attribute] = redact_json_value(nil, attribute, value, private_attributes, redacted)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
filtered[:_meta] = {redactedAttributes: redacted} unless redacted.empty?
|
68
|
+
|
69
|
+
filtered
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Check if an entire attribute should be redacted.
|
74
|
+
#
|
75
|
+
# @param attribute [Symbol]
|
76
|
+
# @param private_attributes [Array<Reference>]
|
77
|
+
# @param redacted [Array<Symbol>]
|
78
|
+
# @return [Boolean]
|
79
|
+
#
|
80
|
+
private def check_whole_attribute_private(attribute, private_attributes, redacted)
|
81
|
+
if @all_attributes_private
|
82
|
+
redacted << attribute
|
83
|
+
return true
|
84
|
+
end
|
85
|
+
|
86
|
+
private_attributes.each do |private_attribute|
|
87
|
+
if private_attribute.component(0) == attribute && private_attribute.depth == 1
|
88
|
+
redacted << attribute
|
89
|
+
return true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
false
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Apply redaction rules to the provided value.
|
98
|
+
#
|
99
|
+
# @param parent_path [Array<String>, nil]
|
100
|
+
# @param name [String]
|
101
|
+
# @param value [any]
|
102
|
+
# @param private_attributes [Array<Reference>]
|
103
|
+
# @param redacted [Array<Symbol>]
|
104
|
+
# @return [any]
|
105
|
+
#
|
106
|
+
private def redact_json_value(parent_path, name, value, private_attributes, redacted)
|
107
|
+
return value unless value.is_a?(Hash)
|
108
|
+
|
109
|
+
ret = {}
|
110
|
+
current_path = parent_path.clone || []
|
111
|
+
current_path << name
|
112
|
+
|
113
|
+
value.each do |k, v|
|
114
|
+
was_redacted = false
|
115
|
+
private_attributes.each do |private_attribute|
|
116
|
+
next unless private_attribute.depth == (current_path.count + 1)
|
117
|
+
|
118
|
+
component = private_attribute.component(current_path.count)
|
119
|
+
next unless component == k
|
120
|
+
|
121
|
+
match = true
|
122
|
+
(0...current_path.count).each do |i|
|
123
|
+
unless private_attribute.component(i) == current_path[i]
|
124
|
+
match = false
|
125
|
+
break
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
if match
|
130
|
+
redacted << private_attribute.raw_path.to_sym
|
131
|
+
was_redacted = true
|
132
|
+
break
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
unless was_redacted
|
137
|
+
ret[k] = redact_json_value(current_path, k, v, private_attributes, redacted)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
ret
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -9,7 +9,7 @@ module LaunchDarkly
|
|
9
9
|
def self.create_diagnostic_id(sdk_key)
|
10
10
|
{
|
11
11
|
diagnosticId: SecureRandom.uuid,
|
12
|
-
sdkKeySuffix: sdk_key[-6..-1] || sdk_key
|
12
|
+
sdkKeySuffix: sdk_key[-6..-1] || sdk_key,
|
13
13
|
}
|
14
14
|
end
|
15
15
|
|
@@ -25,16 +25,16 @@ module LaunchDarkly
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def create_init_event(config)
|
28
|
-
|
28
|
+
{
|
29
29
|
kind: 'diagnostic-init',
|
30
30
|
creationDate: Util.current_time_millis,
|
31
31
|
id: @id,
|
32
32
|
configuration: DiagnosticAccumulator.make_config_data(config),
|
33
33
|
sdk: DiagnosticAccumulator.make_sdk_data(config),
|
34
|
-
platform: DiagnosticAccumulator.make_platform_data
|
34
|
+
platform: DiagnosticAccumulator.make_platform_data,
|
35
35
|
}
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
def record_stream_init(timestamp, failed, duration_millis)
|
39
39
|
@lock.synchronize do
|
40
40
|
@stream_inits.push({ timestamp: timestamp, failed: failed, durationMillis: duration_millis })
|
@@ -57,7 +57,7 @@ module LaunchDarkly
|
|
57
57
|
droppedEvents: dropped_events,
|
58
58
|
deduplicatedUsers: deduplicated_users,
|
59
59
|
eventsInLastBatch: events_in_last_batch,
|
60
|
-
streamInits: previous_stream_inits
|
60
|
+
streamInits: previous_stream_inits,
|
61
61
|
}
|
62
62
|
@data_since_date = current_time
|
63
63
|
event
|
@@ -73,12 +73,11 @@ module LaunchDarkly
|
|
73
73
|
diagnosticRecordingIntervalMillis: self.seconds_to_millis(config.diagnostic_recording_interval),
|
74
74
|
eventsCapacity: config.capacity,
|
75
75
|
eventsFlushIntervalMillis: self.seconds_to_millis(config.flush_interval),
|
76
|
-
inlineUsersInEvents: config.inline_users_in_events,
|
77
76
|
pollingIntervalMillis: self.seconds_to_millis(config.poll_interval),
|
78
77
|
socketTimeoutMillis: self.seconds_to_millis(config.read_timeout),
|
79
78
|
streamingDisabled: !config.stream?,
|
80
|
-
userKeysCapacity: config.
|
81
|
-
userKeysFlushIntervalMillis: self.seconds_to_millis(config.
|
79
|
+
userKeysCapacity: config.context_keys_capacity,
|
80
|
+
userKeysFlushIntervalMillis: self.seconds_to_millis(config.context_keys_flush_interval),
|
82
81
|
usingProxy: ENV.has_key?('http_proxy') || ENV.has_key?('https_proxy') || ENV.has_key?('HTTP_PROXY') || ENV.has_key?('HTTPS_PROXY'),
|
83
82
|
usingRelayDaemon: config.use_ldd?,
|
84
83
|
}
|
@@ -88,7 +87,7 @@ module LaunchDarkly
|
|
88
87
|
def self.make_sdk_data(config)
|
89
88
|
ret = {
|
90
89
|
name: 'ruby-server-sdk',
|
91
|
-
version: LaunchDarkly::VERSION
|
90
|
+
version: LaunchDarkly::VERSION,
|
92
91
|
}
|
93
92
|
if config.wrapper_name
|
94
93
|
ret[:wrapperName] = config.wrapper_name
|
@@ -105,7 +104,7 @@ module LaunchDarkly
|
|
105
104
|
osName: self.normalize_os_name(conf['host_os']),
|
106
105
|
osVersion: 'unknown', # there seems to be no portable way to detect this in Ruby
|
107
106
|
rubyVersion: conf['ruby_version'],
|
108
|
-
rubyImplementation: Object.constants.include?(:RUBY_ENGINE) ? RUBY_ENGINE : 'unknown'
|
107
|
+
rubyImplementation: Object.constants.include?(:RUBY_ENGINE) ? RUBY_ENGINE : 'unknown',
|
109
108
|
}
|
110
109
|
end
|
111
110
|
|