launchdarkly-server-sdk 6.3.4 → 6.4.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 +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
|