launchdarkly-server-sdk 6.4.0 → 7.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ldclient-rb/config.rb +102 -56
  3. data/lib/ldclient-rb/context.rb +487 -0
  4. data/lib/ldclient-rb/evaluation_detail.rb +20 -20
  5. data/lib/ldclient-rb/events.rb +77 -132
  6. data/lib/ldclient-rb/flags_state.rb +4 -4
  7. data/lib/ldclient-rb/impl/big_segments.rb +17 -17
  8. data/lib/ldclient-rb/impl/context.rb +96 -0
  9. data/lib/ldclient-rb/impl/context_filter.rb +145 -0
  10. data/lib/ldclient-rb/impl/diagnostic_events.rb +9 -10
  11. data/lib/ldclient-rb/impl/evaluator.rb +379 -131
  12. data/lib/ldclient-rb/impl/evaluator_bucketing.rb +40 -41
  13. data/lib/ldclient-rb/impl/evaluator_helpers.rb +28 -31
  14. data/lib/ldclient-rb/impl/evaluator_operators.rb +26 -55
  15. data/lib/ldclient-rb/impl/event_sender.rb +6 -6
  16. data/lib/ldclient-rb/impl/event_summarizer.rb +12 -7
  17. data/lib/ldclient-rb/impl/event_types.rb +18 -30
  18. data/lib/ldclient-rb/impl/integrations/consul_impl.rb +7 -7
  19. data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +29 -29
  20. data/lib/ldclient-rb/impl/integrations/file_data_source.rb +8 -8
  21. data/lib/ldclient-rb/impl/integrations/redis_impl.rb +92 -12
  22. data/lib/ldclient-rb/impl/model/clause.rb +39 -0
  23. data/lib/ldclient-rb/impl/model/feature_flag.rb +213 -0
  24. data/lib/ldclient-rb/impl/model/preprocessed_data.rb +8 -121
  25. data/lib/ldclient-rb/impl/model/segment.rb +126 -0
  26. data/lib/ldclient-rb/impl/model/serialization.rb +52 -12
  27. data/lib/ldclient-rb/impl/repeating_task.rb +1 -1
  28. data/lib/ldclient-rb/impl/store_data_set_sorter.rb +2 -2
  29. data/lib/ldclient-rb/impl/unbounded_pool.rb +1 -1
  30. data/lib/ldclient-rb/impl/util.rb +2 -2
  31. data/lib/ldclient-rb/in_memory_store.rb +2 -2
  32. data/lib/ldclient-rb/integrations/consul.rb +1 -1
  33. data/lib/ldclient-rb/integrations/dynamodb.rb +1 -1
  34. data/lib/ldclient-rb/integrations/file_data.rb +3 -3
  35. data/lib/ldclient-rb/integrations/redis.rb +4 -4
  36. data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +218 -62
  37. data/lib/ldclient-rb/integrations/test_data.rb +16 -12
  38. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +9 -9
  39. data/lib/ldclient-rb/interfaces.rb +14 -14
  40. data/lib/ldclient-rb/ldclient.rb +94 -144
  41. data/lib/ldclient-rb/memoized_value.rb +1 -1
  42. data/lib/ldclient-rb/non_blocking_thread_pool.rb +1 -1
  43. data/lib/ldclient-rb/polling.rb +2 -2
  44. data/lib/ldclient-rb/reference.rb +274 -0
  45. data/lib/ldclient-rb/requestor.rb +5 -5
  46. data/lib/ldclient-rb/stream.rb +7 -8
  47. data/lib/ldclient-rb/util.rb +4 -19
  48. data/lib/ldclient-rb/version.rb +1 -1
  49. data/lib/ldclient-rb.rb +2 -3
  50. metadata +34 -17
  51. data/lib/ldclient-rb/file_data_source.rb +0 -23
  52. data/lib/ldclient-rb/newrelic.rb +0 -17
  53. data/lib/ldclient-rb/redis_store.rb +0 -88
  54. 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
- return {
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.user_keys_capacity,
81
- userKeysFlushIntervalMillis: self.seconds_to_millis(config.user_keys_flush_interval),
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