launchdarkly-server-sdk 6.3.4 → 6.4.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/lib/ldclient-rb/config.rb +20 -0
- data/lib/ldclient-rb/impl/evaluator.rb +25 -34
- data/lib/ldclient-rb/impl/evaluator_helpers.rb +53 -0
- data/lib/ldclient-rb/impl/model/preprocessed_data.rb +177 -0
- data/lib/ldclient-rb/impl/model/serialization.rb +7 -37
- data/lib/ldclient-rb/impl/util.rb +58 -0
- data/lib/ldclient-rb/requestor.rb +2 -2
- data/lib/ldclient-rb/stream.rb +2 -2
- data/lib/ldclient-rb/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 147fe8142bffa0d8e754e86669f524f6d787930e8bc6b8a14d30429933a036e3
|
4
|
+
data.tar.gz: e4a404cb7bc911f7c156c3fe5059ee9a4a9d7ebfeacba4c52f44ceb116276835
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '039348a1a0c9284e79e641b69f11bdc4e8ba57c4cad3320eea6f8bb8caf8fc0f52a02c427a2b4f26584945e5750b7728706855cfaf6bdc22a1863b55bcf934a6'
|
7
|
+
data.tar.gz: 452c574e6ff6323a74dfdcf6a5c936ff38bfaa0efc3b58ff190068322ea82e25b15dc20868eb22bf93361d3daa699bd51fa362e97f30f4fc6bcf402f9f5597d9
|
data/lib/ldclient-rb/config.rb
CHANGED
@@ -44,6 +44,7 @@ module LaunchDarkly
|
|
44
44
|
# @option opts [String] :wrapper_version See {#wrapper_version}.
|
45
45
|
# @option opts [#open] :socket_factory See {#socket_factory}.
|
46
46
|
# @option opts [BigSegmentsConfig] :big_segments See {#big_segments}.
|
47
|
+
# @option opts [Hash] :application See {#application}
|
47
48
|
#
|
48
49
|
def initialize(opts = {})
|
49
50
|
@base_uri = (opts[:base_uri] || Config.default_base_uri).chomp("/")
|
@@ -77,6 +78,7 @@ module LaunchDarkly
|
|
77
78
|
@wrapper_version = opts[:wrapper_version]
|
78
79
|
@socket_factory = opts[:socket_factory]
|
79
80
|
@big_segments = opts[:big_segments] || BigSegmentsConfig.new(store: nil)
|
81
|
+
@application = LaunchDarkly::Impl::Util.validate_application_info(opts[:application] || {}, @logger)
|
80
82
|
end
|
81
83
|
|
82
84
|
#
|
@@ -284,6 +286,24 @@ module LaunchDarkly
|
|
284
286
|
#
|
285
287
|
attr_reader :big_segments
|
286
288
|
|
289
|
+
#
|
290
|
+
# An object that allows configuration of application metadata.
|
291
|
+
#
|
292
|
+
# Application metadata may be used in LaunchDarkly analytics or other product features, but does not affect feature flag evaluations.
|
293
|
+
#
|
294
|
+
# If you want to set non-default values for any of these fields, provide the appropriately configured hash to the {Config} object.
|
295
|
+
#
|
296
|
+
# @example Configuring application information
|
297
|
+
# opts[:application] = {
|
298
|
+
# id: "MY APPLICATION ID",
|
299
|
+
# version: "MY APPLICATION VERSION"
|
300
|
+
# }
|
301
|
+
# config = LDConfig.new(opts)
|
302
|
+
#
|
303
|
+
# @return [Hash]
|
304
|
+
#
|
305
|
+
attr_reader :application
|
306
|
+
|
287
307
|
# @deprecated This is replaced by {#data_source}.
|
288
308
|
attr_reader :update_processor
|
289
309
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "ldclient-rb/evaluation_detail"
|
2
2
|
require "ldclient-rb/impl/evaluator_bucketing"
|
3
|
+
require "ldclient-rb/impl/evaluator_helpers"
|
3
4
|
require "ldclient-rb/impl/evaluator_operators"
|
4
5
|
|
5
6
|
module LaunchDarkly
|
@@ -87,19 +88,17 @@ module LaunchDarkly
|
|
87
88
|
|
88
89
|
def eval_internal(flag, user, state)
|
89
90
|
if !flag[:on]
|
90
|
-
return
|
91
|
+
return EvaluatorHelpers.off_result(flag)
|
91
92
|
end
|
92
93
|
|
93
|
-
|
94
|
-
if !
|
95
|
-
return get_off_value(flag, prereq_failure_reason)
|
96
|
-
end
|
94
|
+
prereq_failure_result = check_prerequisites(flag, user, state)
|
95
|
+
return prereq_failure_result if !prereq_failure_result.nil?
|
97
96
|
|
98
97
|
# Check user target matches
|
99
98
|
(flag[:targets] || []).each do |target|
|
100
99
|
(target[:values] || []).each do |value|
|
101
100
|
if value == user[:key]
|
102
|
-
return
|
101
|
+
return EvaluatorHelpers.target_match_result(target, flag)
|
103
102
|
end
|
104
103
|
end
|
105
104
|
end
|
@@ -111,13 +110,15 @@ module LaunchDarkly
|
|
111
110
|
if rule_match_user(rule, user, state)
|
112
111
|
reason = rule[:_reason] # try to use cached reason for this rule
|
113
112
|
reason = EvaluationReason::rule_match(i, rule[:id]) if reason.nil?
|
114
|
-
return get_value_for_variation_or_rollout(flag, rule, user, reason
|
113
|
+
return get_value_for_variation_or_rollout(flag, rule, user, reason,
|
114
|
+
EvaluatorHelpers.rule_precomputed_results(rule))
|
115
115
|
end
|
116
116
|
end
|
117
117
|
|
118
118
|
# Check the fallthrough rule
|
119
119
|
if !flag[:fallthrough].nil?
|
120
|
-
return get_value_for_variation_or_rollout(flag, flag[:fallthrough], user, EvaluationReason::fallthrough
|
120
|
+
return get_value_for_variation_or_rollout(flag, flag[:fallthrough], user, EvaluationReason::fallthrough,
|
121
|
+
EvaluatorHelpers.fallthrough_precomputed_results(flag))
|
121
122
|
end
|
122
123
|
|
123
124
|
return EvaluationDetail.new(nil, nil, EvaluationReason::fallthrough)
|
@@ -149,8 +150,7 @@ module LaunchDarkly
|
|
149
150
|
end
|
150
151
|
end
|
151
152
|
if !prereq_ok
|
152
|
-
|
153
|
-
return reason.nil? ? EvaluationReason::prerequisite_failed(prereq_key) : reason
|
153
|
+
return EvaluatorHelpers.prerequisite_failed_result(prerequisite, flag)
|
154
154
|
end
|
155
155
|
end
|
156
156
|
nil
|
@@ -253,35 +253,26 @@ module LaunchDarkly
|
|
253
253
|
end
|
254
254
|
|
255
255
|
private
|
256
|
-
|
257
|
-
def
|
258
|
-
if index < 0 || index >= flag[:variations].length
|
259
|
-
@logger.error("[LDClient] Data inconsistency in feature flag \"#{flag[:key]}\": invalid variation index")
|
260
|
-
return Evaluator.error_result(EvaluationReason::ERROR_MALFORMED_FLAG)
|
261
|
-
end
|
262
|
-
EvaluationDetail.new(flag[:variations][index], index, reason)
|
263
|
-
end
|
264
|
-
|
265
|
-
def get_off_value(flag, reason)
|
266
|
-
if flag[:offVariation].nil? # off variation unspecified - return default value
|
267
|
-
return EvaluationDetail.new(nil, nil, reason)
|
268
|
-
end
|
269
|
-
get_variation(flag, flag[:offVariation], reason)
|
270
|
-
end
|
271
|
-
|
272
|
-
def get_value_for_variation_or_rollout(flag, vr, user, reason)
|
256
|
+
|
257
|
+
def get_value_for_variation_or_rollout(flag, vr, user, reason, precomputed_results)
|
273
258
|
index, in_experiment = EvaluatorBucketing.variation_index_for_user(flag, vr, user)
|
274
|
-
#if in experiment is true, set reason to a different reason instance/singleton with in_experiment set
|
275
|
-
if in_experiment && reason.kind == :FALLTHROUGH
|
276
|
-
reason = EvaluationReason::fallthrough(in_experiment)
|
277
|
-
elsif in_experiment && reason.kind == :RULE_MATCH
|
278
|
-
reason = EvaluationReason::rule_match(reason.rule_index, reason.rule_id, in_experiment)
|
279
|
-
end
|
280
259
|
if index.nil?
|
281
260
|
@logger.error("[LDClient] Data inconsistency in feature flag \"#{flag[:key]}\": variation/rollout object with no variation or rollout")
|
282
261
|
return Evaluator.error_result(EvaluationReason::ERROR_MALFORMED_FLAG)
|
283
262
|
end
|
284
|
-
|
263
|
+
if precomputed_results
|
264
|
+
return precomputed_results.for_variation(index, in_experiment)
|
265
|
+
else
|
266
|
+
#if in experiment is true, set reason to a different reason instance/singleton with in_experiment set
|
267
|
+
if in_experiment
|
268
|
+
if reason.kind == :FALLTHROUGH
|
269
|
+
reason = EvaluationReason::fallthrough(in_experiment)
|
270
|
+
elsif reason.kind == :RULE_MATCH
|
271
|
+
reason = EvaluationReason::rule_match(reason.rule_index, reason.rule_id, in_experiment)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
return EvaluatorHelpers.evaluation_detail_for_variation(flag, index, reason)
|
275
|
+
end
|
285
276
|
end
|
286
277
|
end
|
287
278
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "ldclient-rb/evaluation_detail"
|
2
|
+
|
3
|
+
# This file contains any pieces of low-level evaluation logic that don't need to be inside the Evaluator
|
4
|
+
# class, because they don't depend on any SDK state outside of their input parameters.
|
5
|
+
|
6
|
+
module LaunchDarkly
|
7
|
+
module Impl
|
8
|
+
module EvaluatorHelpers
|
9
|
+
def self.off_result(flag, logger = nil)
|
10
|
+
pre = flag[:_preprocessed]
|
11
|
+
pre ? pre.off_result : evaluation_detail_for_off_variation(flag, EvaluationReason::off, logger)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.target_match_result(target, flag, logger = nil)
|
15
|
+
pre = target[:_preprocessed]
|
16
|
+
pre ? pre.match_result : evaluation_detail_for_variation(
|
17
|
+
flag, target[:variation], EvaluationReason::target_match, logger)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.prerequisite_failed_result(prereq, flag, logger = nil)
|
21
|
+
pre = prereq[:_preprocessed]
|
22
|
+
pre ? pre.failed_result : evaluation_detail_for_off_variation(
|
23
|
+
flag, EvaluationReason::prerequisite_failed(prereq[:key]), logger
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.fallthrough_precomputed_results(flag)
|
28
|
+
pre = flag[:_preprocessed]
|
29
|
+
pre ? pre.fallthrough_factory : nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.rule_precomputed_results(rule)
|
33
|
+
pre = rule[:_preprocessed]
|
34
|
+
pre ? pre.all_match_results : nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.evaluation_detail_for_off_variation(flag, reason, logger = nil)
|
38
|
+
index = flag[:offVariation]
|
39
|
+
index.nil? ? EvaluationDetail.new(nil, nil, reason) : evaluation_detail_for_variation(flag, index, reason, logger)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.evaluation_detail_for_variation(flag, index, reason, logger = nil)
|
43
|
+
vars = flag[:variations] || []
|
44
|
+
if index < 0 || index >= vars.length
|
45
|
+
logger.error("[LDClient] Data inconsistency in feature flag \"#{flag[:key]}\": invalid variation index") unless logger.nil?
|
46
|
+
EvaluationDetail.new(nil, nil, EvaluationReason::error(EvaluationReason::ERROR_MALFORMED_FLAG))
|
47
|
+
else
|
48
|
+
EvaluationDetail.new(vars[index], index, reason)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require "ldclient-rb/impl/evaluator_helpers"
|
2
|
+
|
3
|
+
module LaunchDarkly
|
4
|
+
module Impl
|
5
|
+
module DataModelPreprocessing
|
6
|
+
#
|
7
|
+
# Container for a precomputed result that includes a specific variation index and value, an
|
8
|
+
# evaluation reason, and optionally an alternate evaluation reason that corresponds to the
|
9
|
+
# "in experiment" state.
|
10
|
+
#
|
11
|
+
class EvalResultsForSingleVariation
|
12
|
+
def initialize(value, variation_index, regular_reason, in_experiment_reason = nil)
|
13
|
+
@regular_result = EvaluationDetail.new(value, variation_index, regular_reason)
|
14
|
+
@in_experiment_result = in_experiment_reason ?
|
15
|
+
EvaluationDetail.new(value, variation_index, in_experiment_reason) :
|
16
|
+
@regular_result
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param in_experiment [Boolean] indicates whether we want the result to include
|
20
|
+
# "inExperiment: true" in the reason or not
|
21
|
+
# @return [EvaluationDetail]
|
22
|
+
def get_result(in_experiment = false)
|
23
|
+
in_experiment ? @in_experiment_result : @regular_result
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Container for a set of precomputed results, one for each possible flag variation.
|
29
|
+
#
|
30
|
+
class EvalResultFactoryMultiVariations
|
31
|
+
def initialize(variation_factories)
|
32
|
+
@factories = variation_factories
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param index [Integer] the variation index
|
36
|
+
# @param in_experiment [Boolean] indicates whether we want the result to include
|
37
|
+
# "inExperiment: true" in the reason or not
|
38
|
+
def for_variation(index, in_experiment)
|
39
|
+
if index < 0 || index >= @factories.length
|
40
|
+
EvaluationDetail.new(nil, nil, EvaluationReason.error(EvaluationReason::ERROR_MALFORMED_FLAG))
|
41
|
+
else
|
42
|
+
@factories[index].get_result(in_experiment)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Base class for all of the preprocessed data classes we embed in our data model. Using this class
|
48
|
+
# ensures that none of its properties will be included in JSON representations. It also overrides
|
49
|
+
# == to say that it is always equal with another instance of the same class; equality tests on
|
50
|
+
# this class are only ever done in test code, and we want the contents of these classes to be
|
51
|
+
# ignored in test code unless we are looking at specific attributes.
|
52
|
+
class PreprocessedDataBase
|
53
|
+
def as_json(*)
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_json(*a)
|
58
|
+
"null"
|
59
|
+
end
|
60
|
+
|
61
|
+
def ==(other)
|
62
|
+
other.class == self.class
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class FlagPreprocessed < PreprocessedDataBase
|
67
|
+
def initialize(off_result, fallthrough_factory)
|
68
|
+
@off_result = off_result
|
69
|
+
@fallthrough_factory = fallthrough_factory
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [EvalResultsForSingleVariation]
|
73
|
+
attr_reader :off_result
|
74
|
+
# @return [EvalResultFactoryMultiVariations]
|
75
|
+
attr_reader :fallthrough_factory
|
76
|
+
end
|
77
|
+
|
78
|
+
class PrerequisitePreprocessed < PreprocessedDataBase
|
79
|
+
def initialize(failed_result)
|
80
|
+
@failed_result = failed_result
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [EvalResultsForSingleVariation]
|
84
|
+
attr_reader :failed_result
|
85
|
+
end
|
86
|
+
|
87
|
+
class TargetPreprocessed < PreprocessedDataBase
|
88
|
+
def initialize(match_result)
|
89
|
+
@match_result = match_result
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [EvalResultsForSingleVariation]
|
93
|
+
attr_reader :match_result
|
94
|
+
end
|
95
|
+
|
96
|
+
class FlagRulePreprocessed < PreprocessedDataBase
|
97
|
+
def initialize(all_match_results)
|
98
|
+
@all_match_results = all_match_results
|
99
|
+
end
|
100
|
+
|
101
|
+
# @return [EvalResultsForSingleVariation]
|
102
|
+
attr_reader :all_match_results
|
103
|
+
end
|
104
|
+
|
105
|
+
class Preprocessor
|
106
|
+
def initialize(logger = nil)
|
107
|
+
@logger = logger
|
108
|
+
end
|
109
|
+
|
110
|
+
def preprocess_item!(kind, item)
|
111
|
+
if kind.eql? FEATURES
|
112
|
+
preprocess_flag!(item)
|
113
|
+
elsif kind.eql? SEGMENTS
|
114
|
+
preprocess_segment!(item)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def preprocess_all_items!(kind, items_map)
|
119
|
+
return items_map if !items_map
|
120
|
+
items_map.each do |key, item|
|
121
|
+
preprocess_item!(kind, item)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def preprocess_flag!(flag)
|
126
|
+
flag[:_preprocessed] = FlagPreprocessed.new(
|
127
|
+
EvaluatorHelpers.off_result(flag),
|
128
|
+
precompute_multi_variation_results(flag, EvaluationReason::fallthrough(false), EvaluationReason::fallthrough(true))
|
129
|
+
)
|
130
|
+
(flag[:prerequisites] || []).each do |prereq|
|
131
|
+
preprocess_prerequisite!(prereq, flag)
|
132
|
+
end
|
133
|
+
(flag[:targets] || []).each do |target|
|
134
|
+
preprocess_target!(target, flag)
|
135
|
+
end
|
136
|
+
rules = flag[:rules]
|
137
|
+
(rules || []).each_index do |index|
|
138
|
+
preprocess_flag_rule!(rules[index], index, flag)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def preprocess_segment!(segment)
|
143
|
+
# nothing to do for segments currently
|
144
|
+
end
|
145
|
+
|
146
|
+
private def preprocess_prerequisite!(prereq, flag)
|
147
|
+
prereq[:_preprocessed] = PrerequisitePreprocessed.new(
|
148
|
+
EvaluatorHelpers.prerequisite_failed_result(prereq, flag, @logger)
|
149
|
+
)
|
150
|
+
end
|
151
|
+
|
152
|
+
private def preprocess_target!(target, flag)
|
153
|
+
target[:_preprocessed] = TargetPreprocessed.new(
|
154
|
+
EvaluatorHelpers.target_match_result(target, flag, @logger)
|
155
|
+
)
|
156
|
+
end
|
157
|
+
|
158
|
+
private def preprocess_flag_rule!(rule, index, flag)
|
159
|
+
match_reason = EvaluationReason::rule_match(index, rule[:id])
|
160
|
+
match_reason_in_experiment = EvaluationReason::rule_match(index, rule[:id], true)
|
161
|
+
rule[:_preprocessed] = FlagRulePreprocessed.new(
|
162
|
+
precompute_multi_variation_results(flag, match_reason, match_reason_in_experiment)
|
163
|
+
)
|
164
|
+
end
|
165
|
+
|
166
|
+
private def precompute_multi_variation_results(flag, regular_reason, in_experiment_reason)
|
167
|
+
factories = []
|
168
|
+
vars = flag[:variations] || []
|
169
|
+
vars.each_index do |index|
|
170
|
+
factories << EvalResultsForSingleVariation.new(vars[index], index, regular_reason, in_experiment_reason)
|
171
|
+
end
|
172
|
+
EvalResultFactoryMultiVariations.new(factories)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -1,13 +1,14 @@
|
|
1
|
+
require "ldclient-rb/impl/model/preprocessed_data"
|
1
2
|
|
2
3
|
module LaunchDarkly
|
3
4
|
module Impl
|
4
5
|
module Model
|
5
6
|
# Abstraction of deserializing a feature flag or segment that was read from a data store or
|
6
7
|
# received from LaunchDarkly.
|
7
|
-
def self.deserialize(kind, json)
|
8
|
+
def self.deserialize(kind, json, logger = nil)
|
8
9
|
return nil if json.nil?
|
9
10
|
item = JSON.parse(json, symbolize_names: true)
|
10
|
-
|
11
|
+
DataModelPreprocessing::Preprocessor.new(logger).preprocess_item!(kind, item)
|
11
12
|
item
|
12
13
|
end
|
13
14
|
|
@@ -18,45 +19,14 @@ module LaunchDarkly
|
|
18
19
|
end
|
19
20
|
|
20
21
|
# Translates a { flags: ..., segments: ... } object received from LaunchDarkly to the data store format.
|
21
|
-
def self.make_all_store_data(received_data)
|
22
|
+
def self.make_all_store_data(received_data, logger = nil)
|
23
|
+
preprocessor = DataModelPreprocessing::Preprocessor.new(logger)
|
22
24
|
flags = received_data[:flags]
|
23
|
-
|
25
|
+
preprocessor.preprocess_all_items!(FEATURES, flags)
|
24
26
|
segments = received_data[:segments]
|
25
|
-
|
27
|
+
preprocessor.preprocess_all_items!(SEGMENTS, segments)
|
26
28
|
{ FEATURES => flags, SEGMENTS => segments }
|
27
29
|
end
|
28
|
-
|
29
|
-
# Called after we have deserialized a model item from JSON (because we received it from LaunchDarkly,
|
30
|
-
# or read it from a persistent data store). This allows us to precompute some derived attributes that
|
31
|
-
# will never change during the lifetime of that item.
|
32
|
-
def self.postprocess_item_after_deserializing!(kind, item)
|
33
|
-
return if !item
|
34
|
-
# Currently we are special-casing this for FEATURES; eventually it will be handled by delegating
|
35
|
-
# to the "kind" object or the item class.
|
36
|
-
if kind.eql? FEATURES
|
37
|
-
# For feature flags, we precompute all possible parameterized EvaluationReason instances.
|
38
|
-
prereqs = item[:prerequisites]
|
39
|
-
if !prereqs.nil?
|
40
|
-
prereqs.each do |prereq|
|
41
|
-
prereq[:_reason] = EvaluationReason::prerequisite_failed(prereq[:key])
|
42
|
-
end
|
43
|
-
end
|
44
|
-
rules = item[:rules]
|
45
|
-
if !rules.nil?
|
46
|
-
rules.each_index do |i|
|
47
|
-
rule = rules[i]
|
48
|
-
rule[:_reason] = EvaluationReason::rule_match(i, rule[:id])
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.postprocess_items_after_deserializing!(kind, items_map)
|
55
|
-
return items_map if !items_map
|
56
|
-
items_map.each do |key, item|
|
57
|
-
postprocess_item_after_deserializing!(kind, item)
|
58
|
-
end
|
59
|
-
end
|
60
30
|
end
|
61
31
|
end
|
62
32
|
end
|
@@ -15,8 +15,66 @@ module LaunchDarkly
|
|
15
15
|
ret["X-LaunchDarkly-Wrapper"] = config.wrapper_name +
|
16
16
|
(config.wrapper_version ? "/" + config.wrapper_version : "")
|
17
17
|
end
|
18
|
+
|
19
|
+
app_value = application_header_value config.application
|
20
|
+
ret["X-LaunchDarkly-Tags"] = app_value unless app_value.nil? || app_value.empty?
|
21
|
+
|
18
22
|
ret
|
19
23
|
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Generate an HTTP Header value containing the application meta information (@see #application).
|
27
|
+
#
|
28
|
+
# @return [String]
|
29
|
+
#
|
30
|
+
def self.application_header_value(application)
|
31
|
+
parts = []
|
32
|
+
unless application[:id].empty?
|
33
|
+
parts << "application-id/#{application[:id]}"
|
34
|
+
end
|
35
|
+
|
36
|
+
unless application[:version].empty?
|
37
|
+
parts << "application-version/#{application[:version]}"
|
38
|
+
end
|
39
|
+
|
40
|
+
parts.join(" ")
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# @param value [String]
|
45
|
+
# @param name [Symbol]
|
46
|
+
# @param logger [Logger]
|
47
|
+
# @return [String]
|
48
|
+
#
|
49
|
+
def self.validate_application_value(value, name, logger)
|
50
|
+
value = value.to_s
|
51
|
+
|
52
|
+
return "" if value.empty?
|
53
|
+
|
54
|
+
if value.length > 64
|
55
|
+
logger.warn { "Value of application[#{name}] was longer than 64 characters and was discarded" }
|
56
|
+
return ""
|
57
|
+
end
|
58
|
+
|
59
|
+
if value.match(/[^a-zA-Z0-9._-]/)
|
60
|
+
logger.warn { "Value of application[#{name}] contained invalid characters and was discarded" }
|
61
|
+
return ""
|
62
|
+
end
|
63
|
+
|
64
|
+
value
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# @param app [Hash]
|
69
|
+
# @param logger [Logger]
|
70
|
+
# @return [Hash]
|
71
|
+
#
|
72
|
+
def self.validate_application_info(app, logger)
|
73
|
+
{
|
74
|
+
id: validate_application_value(app[:id], :id, logger),
|
75
|
+
version: validate_application_value(app[:version], :version, logger),
|
76
|
+
}
|
77
|
+
end
|
20
78
|
end
|
21
79
|
end
|
22
80
|
end
|
@@ -31,7 +31,7 @@ module LaunchDarkly
|
|
31
31
|
|
32
32
|
def request_all_data()
|
33
33
|
all_data = JSON.parse(make_request("/sdk/latest-all"), symbolize_names: true)
|
34
|
-
Impl::Model.make_all_store_data(all_data)
|
34
|
+
Impl::Model.make_all_store_data(all_data, @config.logger)
|
35
35
|
end
|
36
36
|
|
37
37
|
def stop
|
@@ -44,7 +44,7 @@ module LaunchDarkly
|
|
44
44
|
private
|
45
45
|
|
46
46
|
def request_single_item(kind, path)
|
47
|
-
Impl::Model.deserialize(kind, make_request(path))
|
47
|
+
Impl::Model.deserialize(kind, make_request(path), @config.logger)
|
48
48
|
end
|
49
49
|
|
50
50
|
def make_request(path)
|
data/lib/ldclient-rb/stream.rb
CHANGED
@@ -86,7 +86,7 @@ module LaunchDarkly
|
|
86
86
|
@config.logger.debug { "[LDClient] Stream received #{method} message: #{message.data}" }
|
87
87
|
if method == PUT
|
88
88
|
message = JSON.parse(message.data, symbolize_names: true)
|
89
|
-
all_data = Impl::Model.make_all_store_data(message[:data])
|
89
|
+
all_data = Impl::Model.make_all_store_data(message[:data], @config.logger)
|
90
90
|
@feature_store.init(all_data)
|
91
91
|
@initialized.make_true
|
92
92
|
@config.logger.info { "[LDClient] Stream initialized" }
|
@@ -97,7 +97,7 @@ module LaunchDarkly
|
|
97
97
|
key = key_for_path(kind, data[:path])
|
98
98
|
if key
|
99
99
|
data = data[:data]
|
100
|
-
Impl::
|
100
|
+
Impl::DataModelPreprocessing::Preprocessor.new(@config.logger).preprocess_item!(kind, data)
|
101
101
|
@feature_store.upsert(kind, data)
|
102
102
|
break
|
103
103
|
end
|
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: 6.
|
4
|
+
version: 6.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- LaunchDarkly
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-dynamodb
|
@@ -263,6 +263,7 @@ files:
|
|
263
263
|
- lib/ldclient-rb/impl/diagnostic_events.rb
|
264
264
|
- lib/ldclient-rb/impl/evaluator.rb
|
265
265
|
- lib/ldclient-rb/impl/evaluator_bucketing.rb
|
266
|
+
- lib/ldclient-rb/impl/evaluator_helpers.rb
|
266
267
|
- lib/ldclient-rb/impl/evaluator_operators.rb
|
267
268
|
- lib/ldclient-rb/impl/event_sender.rb
|
268
269
|
- lib/ldclient-rb/impl/event_summarizer.rb
|
@@ -272,6 +273,7 @@ files:
|
|
272
273
|
- lib/ldclient-rb/impl/integrations/file_data_source.rb
|
273
274
|
- lib/ldclient-rb/impl/integrations/redis_impl.rb
|
274
275
|
- lib/ldclient-rb/impl/integrations/test_data/test_data_source.rb
|
276
|
+
- lib/ldclient-rb/impl/model/preprocessed_data.rb
|
275
277
|
- lib/ldclient-rb/impl/model/serialization.rb
|
276
278
|
- lib/ldclient-rb/impl/repeating_task.rb
|
277
279
|
- lib/ldclient-rb/impl/store_client_wrapper.rb
|
@@ -319,7 +321,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
319
321
|
- !ruby/object:Gem::Version
|
320
322
|
version: '0'
|
321
323
|
requirements: []
|
322
|
-
rubygems_version: 3.3.
|
324
|
+
rubygems_version: 3.3.22
|
323
325
|
signing_key:
|
324
326
|
specification_version: 4
|
325
327
|
summary: LaunchDarkly SDK for Ruby
|