prefab-cloud-ruby 0 → 0.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 +5 -5
- data/.ruby-version +1 -0
- data/Gemfile +9 -22
- data/Gemfile.lock +88 -160
- data/LICENSE.txt +1 -1
- data/Rakefile +14 -14
- data/VERSION +1 -1
- data/lib/prefab/auth_interceptor.rb +25 -0
- data/lib/prefab/client.rb +34 -139
- data/lib/prefab/config_client.rb +23 -275
- data/lib/prefab/config_loader.rb +27 -60
- data/lib/prefab/config_resolver.rb +40 -53
- data/lib/prefab/noop_cache.rb +13 -0
- data/lib/prefab/noop_stats.rb +8 -0
- data/lib/prefab/prefab_pb.rb +39 -0
- data/lib/prefab/prefab_services_pb.rb +37 -0
- data/lib/prefab/ratelimit_client.rb +58 -0
- data/lib/prefab/ratelimit_pb.rb +125 -0
- data/lib/prefab/store.rb +29 -0
- data/lib/prefab_client.rb +35 -0
- metadata +36 -198
- data/.envrc.sample +0 -3
- data/.github/workflows/ruby.yml +0 -46
- data/.gitmodules +0 -3
- data/.rubocop.yml +0 -13
- data/.tool-versions +0 -1
- data/CHANGELOG.md +0 -169
- data/CODEOWNERS +0 -1
- data/README.md +0 -94
- data/bin/console +0 -21
- data/compile_protos.sh +0 -18
- data/lib/prefab/config_client_presenter.rb +0 -18
- data/lib/prefab/config_value_unwrapper.rb +0 -115
- data/lib/prefab/config_value_wrapper.rb +0 -18
- data/lib/prefab/context.rb +0 -179
- data/lib/prefab/context_shape.rb +0 -20
- data/lib/prefab/context_shape_aggregator.rb +0 -65
- data/lib/prefab/criteria_evaluator.rb +0 -136
- data/lib/prefab/encryption.rb +0 -65
- data/lib/prefab/error.rb +0 -6
- data/lib/prefab/errors/env_var_parse_error.rb +0 -11
- data/lib/prefab/errors/initialization_timeout_error.rb +0 -13
- data/lib/prefab/errors/invalid_api_key_error.rb +0 -19
- data/lib/prefab/errors/missing_default_error.rb +0 -13
- data/lib/prefab/errors/missing_env_var_error.rb +0 -11
- data/lib/prefab/errors/uninitialized_error.rb +0 -13
- data/lib/prefab/evaluation.rb +0 -52
- data/lib/prefab/evaluation_summary_aggregator.rb +0 -87
- data/lib/prefab/example_contexts_aggregator.rb +0 -78
- data/lib/prefab/exponential_backoff.rb +0 -21
- data/lib/prefab/feature_flag_client.rb +0 -42
- data/lib/prefab/http_connection.rb +0 -41
- data/lib/prefab/internal_logger.rb +0 -16
- data/lib/prefab/local_config_parser.rb +0 -151
- data/lib/prefab/log_path_aggregator.rb +0 -69
- data/lib/prefab/logger_client.rb +0 -264
- data/lib/prefab/murmer3.rb +0 -50
- data/lib/prefab/options.rb +0 -208
- data/lib/prefab/periodic_sync.rb +0 -69
- data/lib/prefab/prefab.rb +0 -56
- data/lib/prefab/rate_limit_cache.rb +0 -41
- data/lib/prefab/resolved_config_presenter.rb +0 -86
- data/lib/prefab/time_helpers.rb +0 -7
- data/lib/prefab/weighted_value_resolver.rb +0 -42
- data/lib/prefab/yaml_config_parser.rb +0 -34
- data/lib/prefab-cloud-ruby.rb +0 -57
- data/lib/prefab_pb.rb +0 -93
- data/prefab-cloud-ruby.gemspec +0 -155
- data/test/.prefab.default.config.yaml +0 -2
- data/test/.prefab.unit_tests.config.yaml +0 -28
- data/test/integration_test.rb +0 -150
- data/test/integration_test_helpers.rb +0 -151
- data/test/support/common_helpers.rb +0 -180
- data/test/support/mock_base_client.rb +0 -42
- data/test/support/mock_config_client.rb +0 -19
- data/test/support/mock_config_loader.rb +0 -1
- data/test/test_client.rb +0 -444
- data/test/test_config_client.rb +0 -109
- data/test/test_config_loader.rb +0 -117
- data/test/test_config_resolver.rb +0 -430
- data/test/test_config_value_unwrapper.rb +0 -224
- data/test/test_config_value_wrapper.rb +0 -42
- data/test/test_context.rb +0 -203
- data/test/test_context_shape.rb +0 -50
- data/test/test_context_shape_aggregator.rb +0 -147
- data/test/test_criteria_evaluator.rb +0 -726
- data/test/test_encryption.rb +0 -16
- data/test/test_evaluation_summary_aggregator.rb +0 -162
- data/test/test_example_contexts_aggregator.rb +0 -238
- data/test/test_exponential_backoff.rb +0 -18
- data/test/test_feature_flag_client.rb +0 -48
- data/test/test_helper.rb +0 -17
- data/test/test_integration.rb +0 -58
- data/test/test_local_config_parser.rb +0 -147
- data/test/test_log_path_aggregator.rb +0 -62
- data/test/test_logger.rb +0 -621
- data/test/test_logger_initialization.rb +0 -12
- data/test/test_options.rb +0 -75
- data/test/test_prefab.rb +0 -12
- data/test/test_rate_limit_cache.rb +0 -44
- data/test/test_weighted_value_resolver.rb +0 -71
data/lib/prefab/options.rb
DELETED
@@ -1,208 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Prefab
|
4
|
-
# This class contains all the options that can be passed to the Prefab client.
|
5
|
-
class Options
|
6
|
-
attr_reader :api_key
|
7
|
-
attr_reader :logdev
|
8
|
-
attr_reader :log_prefix
|
9
|
-
attr_reader :log_formatter
|
10
|
-
attr_reader :namespace
|
11
|
-
attr_reader :prefab_api_url
|
12
|
-
attr_reader :on_no_default
|
13
|
-
attr_reader :initialization_timeout_sec
|
14
|
-
attr_reader :on_init_failure
|
15
|
-
attr_reader :prefab_config_override_dir
|
16
|
-
attr_reader :prefab_config_classpath_dir
|
17
|
-
attr_reader :prefab_envs
|
18
|
-
attr_reader :collect_sync_interval
|
19
|
-
attr_reader :use_local_cache
|
20
|
-
attr_reader :datafile
|
21
|
-
attr_reader :disable_action_controller_logging
|
22
|
-
attr_accessor :is_fork
|
23
|
-
|
24
|
-
DEFAULT_LOG_FORMATTER = proc { |data|
|
25
|
-
severity = data[:severity]
|
26
|
-
datetime = data[:datetime]
|
27
|
-
progname = data[:progname]
|
28
|
-
path = data[:path]
|
29
|
-
msg = data[:message]
|
30
|
-
log_context = data[:log_context]
|
31
|
-
|
32
|
-
progname = (progname.nil? || progname.empty?) ? path : "#{progname}: #{path}"
|
33
|
-
|
34
|
-
formatted_log_context = log_context.sort.map do |k, v|
|
35
|
-
"#{k}=#{v}"
|
36
|
-
end.join(" ")
|
37
|
-
"#{severity.ljust(5)} #{datetime}:#{' ' if progname}#{progname} #{msg}#{log_context.any? ? " " + formatted_log_context : ""}\n"
|
38
|
-
}
|
39
|
-
|
40
|
-
JSON_LOG_FORMATTER = proc { |data|
|
41
|
-
log_context = data.delete(:log_context)
|
42
|
-
data.merge(log_context).compact.to_json << "\n"
|
43
|
-
}
|
44
|
-
|
45
|
-
COMPACT_LOG_FORMATTER = proc { |data|
|
46
|
-
severity = data[:severity]
|
47
|
-
msg = data[:message]
|
48
|
-
log_context = data[:log_context]
|
49
|
-
log_context["path"] = data[:path] || ""
|
50
|
-
|
51
|
-
formatted_log_context = log_context.sort.map do |k, v|
|
52
|
-
"#{k}=#{v}"
|
53
|
-
end.join(" ")
|
54
|
-
"#{severity.ljust(5)} #{msg&.strip} #{formatted_log_context}\n"
|
55
|
-
}
|
56
|
-
|
57
|
-
module ON_INITIALIZATION_FAILURE
|
58
|
-
RAISE = :raise
|
59
|
-
RETURN = :return
|
60
|
-
end
|
61
|
-
|
62
|
-
module ON_NO_DEFAULT
|
63
|
-
RAISE = :raise
|
64
|
-
RETURN_NIL = :return_nil
|
65
|
-
end
|
66
|
-
|
67
|
-
module DATASOURCES
|
68
|
-
ALL = :all
|
69
|
-
LOCAL_ONLY = :local_only
|
70
|
-
end
|
71
|
-
|
72
|
-
DEFAULT_MAX_PATHS = 1_000
|
73
|
-
DEFAULT_MAX_KEYS = 100_000
|
74
|
-
DEFAULT_MAX_EXAMPLE_CONTEXTS = 100_000
|
75
|
-
DEFAULT_MAX_EVAL_SUMMARIES = 100_000
|
76
|
-
|
77
|
-
private def init(
|
78
|
-
api_key: ENV['PREFAB_API_KEY'],
|
79
|
-
logdev: $stdout,
|
80
|
-
namespace: '',
|
81
|
-
log_formatter: DEFAULT_LOG_FORMATTER,
|
82
|
-
log_prefix: nil,
|
83
|
-
prefab_api_url: ENV['PREFAB_API_URL'] || 'https://api.prefab.cloud',
|
84
|
-
on_no_default: ON_NO_DEFAULT::RAISE, # options :raise, :warn_and_return_nil,
|
85
|
-
initialization_timeout_sec: 10, # how long to wait before on_init_failure
|
86
|
-
on_init_failure: ON_INITIALIZATION_FAILURE::RAISE,
|
87
|
-
prefab_datasources: ENV['PREFAB_DATASOURCES'] == 'LOCAL_ONLY' ? DATASOURCES::LOCAL_ONLY : DATASOURCES::ALL,
|
88
|
-
prefab_config_override_dir: Dir.home,
|
89
|
-
prefab_config_classpath_dir: '.', # where to load local overrides
|
90
|
-
prefab_envs: ENV['PREFAB_ENVS'].nil? ? [] : ENV['PREFAB_ENVS'].split(','),
|
91
|
-
collect_logger_counts: true,
|
92
|
-
collect_max_paths: DEFAULT_MAX_PATHS,
|
93
|
-
collect_sync_interval: nil,
|
94
|
-
context_upload_mode: :periodic_example, # :periodic_example, :shape_only, :none
|
95
|
-
context_max_size: DEFAULT_MAX_EVAL_SUMMARIES,
|
96
|
-
collect_evaluation_summaries: true,
|
97
|
-
collect_max_evaluation_summaries: DEFAULT_MAX_EVAL_SUMMARIES,
|
98
|
-
allow_telemetry_in_local_mode: false,
|
99
|
-
x_datafile: ENV['PREFAB_DATAFILE'],
|
100
|
-
x_use_local_cache: false,
|
101
|
-
disable_action_controller_logging: false
|
102
|
-
)
|
103
|
-
@api_key = api_key
|
104
|
-
@logdev = logdev
|
105
|
-
@namespace = namespace
|
106
|
-
@log_formatter = log_formatter
|
107
|
-
@log_prefix = log_prefix
|
108
|
-
@prefab_api_url = remove_trailing_slash(prefab_api_url)
|
109
|
-
@on_no_default = on_no_default
|
110
|
-
@initialization_timeout_sec = initialization_timeout_sec
|
111
|
-
@on_init_failure = on_init_failure
|
112
|
-
@prefab_datasources = prefab_datasources
|
113
|
-
@datafile = x_datafile
|
114
|
-
@prefab_config_classpath_dir = prefab_config_classpath_dir
|
115
|
-
@prefab_config_override_dir = prefab_config_override_dir
|
116
|
-
@prefab_envs = Array(prefab_envs)
|
117
|
-
@collect_logger_counts = collect_logger_counts
|
118
|
-
@collect_max_paths = collect_max_paths
|
119
|
-
@collect_sync_interval = collect_sync_interval
|
120
|
-
@collect_evaluation_summaries = collect_evaluation_summaries
|
121
|
-
@collect_max_evaluation_summaries = collect_max_evaluation_summaries
|
122
|
-
@allow_telemetry_in_local_mode = allow_telemetry_in_local_mode
|
123
|
-
@use_local_cache = x_use_local_cache
|
124
|
-
@disable_action_controller_logging = disable_action_controller_logging
|
125
|
-
@is_fork = false
|
126
|
-
|
127
|
-
# defaults that may be overridden by context_upload_mode
|
128
|
-
@collect_shapes = false
|
129
|
-
@collect_max_shapes = 0
|
130
|
-
@collect_example_contexts = false
|
131
|
-
@collect_max_example_contexts = 0
|
132
|
-
|
133
|
-
case context_upload_mode
|
134
|
-
when :none
|
135
|
-
# do nothing
|
136
|
-
when :periodic_example
|
137
|
-
@collect_example_contexts = true
|
138
|
-
@collect_max_example_contexts = context_max_size
|
139
|
-
when :shape_only
|
140
|
-
@collect_shapes = true
|
141
|
-
@collect_max_shapes = context_max_size
|
142
|
-
else
|
143
|
-
raise "Unknown context_upload_mode #{context_upload_mode}. Please provide :periodic_example, :shape_only, or :none."
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def initialize(options = {})
|
148
|
-
init(**options)
|
149
|
-
end
|
150
|
-
|
151
|
-
def local_only?
|
152
|
-
@prefab_datasources == DATASOURCES::LOCAL_ONLY
|
153
|
-
end
|
154
|
-
|
155
|
-
def datafile?
|
156
|
-
!@datafile.nil?
|
157
|
-
end
|
158
|
-
|
159
|
-
def collect_max_paths
|
160
|
-
return 0 unless telemetry_allowed?(@collect_logger_counts)
|
161
|
-
|
162
|
-
@collect_max_paths
|
163
|
-
end
|
164
|
-
|
165
|
-
def collect_max_shapes
|
166
|
-
return 0 unless telemetry_allowed?(@collect_shapes)
|
167
|
-
|
168
|
-
@collect_max_shapes
|
169
|
-
end
|
170
|
-
|
171
|
-
def collect_max_example_contexts
|
172
|
-
return 0 unless telemetry_allowed?(@collect_example_contexts)
|
173
|
-
|
174
|
-
@collect_max_example_contexts
|
175
|
-
end
|
176
|
-
|
177
|
-
def collect_max_evaluation_summaries
|
178
|
-
return 0 unless telemetry_allowed?(@collect_evaluation_summaries)
|
179
|
-
|
180
|
-
@collect_max_evaluation_summaries
|
181
|
-
end
|
182
|
-
|
183
|
-
# https://api.prefab.cloud -> https://api-prefab-cloud.global.ssl.fastly.net
|
184
|
-
def url_for_api_cdn
|
185
|
-
ENV['PREFAB_CDN_URL'] || "#{@prefab_api_url.gsub(/\./, '-')}.global.ssl.fastly.net"
|
186
|
-
end
|
187
|
-
|
188
|
-
def api_key_id
|
189
|
-
@api_key&.split("-")&.first
|
190
|
-
end
|
191
|
-
|
192
|
-
def for_fork
|
193
|
-
clone = self.clone
|
194
|
-
clone.is_fork = true
|
195
|
-
clone
|
196
|
-
end
|
197
|
-
|
198
|
-
private
|
199
|
-
|
200
|
-
def telemetry_allowed?(option)
|
201
|
-
option && (!local_only? || @allow_telemetry_in_local_mode)
|
202
|
-
end
|
203
|
-
|
204
|
-
def remove_trailing_slash(url)
|
205
|
-
url.end_with?('/') ? url[0..-2] : url
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
data/lib/prefab/periodic_sync.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Prefab
|
4
|
-
module PeriodicSync
|
5
|
-
LOG = Prefab::InternalLogger.new("periodsync")
|
6
|
-
def sync
|
7
|
-
return if @data.size.zero?
|
8
|
-
|
9
|
-
LOG.debug "Syncing #{@data.size} items"
|
10
|
-
|
11
|
-
start_at_was = @start_at
|
12
|
-
@start_at = Prefab::TimeHelpers.now_in_ms
|
13
|
-
|
14
|
-
flush(prepare_data, start_at_was)
|
15
|
-
end
|
16
|
-
|
17
|
-
def prepare_data
|
18
|
-
to_ship = @data.dup
|
19
|
-
@data.clear
|
20
|
-
|
21
|
-
on_prepare_data
|
22
|
-
|
23
|
-
to_ship
|
24
|
-
end
|
25
|
-
|
26
|
-
def on_prepare_data
|
27
|
-
# noop -- override as you wish
|
28
|
-
end
|
29
|
-
|
30
|
-
def post(url, data)
|
31
|
-
@client.post(url, data)
|
32
|
-
end
|
33
|
-
|
34
|
-
def start_periodic_sync(sync_interval)
|
35
|
-
@start_at = Prefab::TimeHelpers.now_in_ms
|
36
|
-
|
37
|
-
@sync_interval = calculate_sync_interval(sync_interval)
|
38
|
-
|
39
|
-
Thread.new do
|
40
|
-
LOG.debug "Initialized #{@name} instance_hash=#{@client.instance_hash}"
|
41
|
-
|
42
|
-
loop do
|
43
|
-
sleep @sync_interval.call
|
44
|
-
sync
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def pool
|
50
|
-
@pool ||= Concurrent::ThreadPoolExecutor.new(
|
51
|
-
fallback_policy: :discard,
|
52
|
-
max_queue: 5,
|
53
|
-
max_threads: 4,
|
54
|
-
min_threads: 1,
|
55
|
-
name: @name
|
56
|
-
)
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def calculate_sync_interval(sync_interval)
|
62
|
-
if sync_interval.is_a?(Numeric)
|
63
|
-
proc { sync_interval }
|
64
|
-
else
|
65
|
-
sync_interval || ExponentialBackoff.new(initial_delay: 8, max_delay: 60 * 5)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
data/lib/prefab/prefab.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Prefab
|
4
|
-
@@lock = Concurrent::ReadWriteLock.new
|
5
|
-
|
6
|
-
def self.init(options = Prefab::Options.new)
|
7
|
-
unless @singleton.nil?
|
8
|
-
Prefab::LoggerClient.instance.warn 'Prefab already initialized.'
|
9
|
-
return @singleton
|
10
|
-
end
|
11
|
-
|
12
|
-
@@lock.with_write_lock {
|
13
|
-
@singleton = Prefab::Client.new(options)
|
14
|
-
}
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.fork
|
18
|
-
ensure_initialized
|
19
|
-
@@lock.with_write_lock {
|
20
|
-
@singleton = @singleton.fork
|
21
|
-
}
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.set_rails_loggers
|
25
|
-
ensure_initialized
|
26
|
-
@singleton.set_rails_loggers
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.get(key, properties = NO_DEFAULT_PROVIDED)
|
30
|
-
ensure_initialized key
|
31
|
-
@singleton.get(key, properties)
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.enabled?(feature_name, jit_context = NO_DEFAULT_PROVIDED)
|
35
|
-
ensure_initialized feature_name
|
36
|
-
@singleton.enabled?(feature_name, jit_context)
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.with_context(properties, &block)
|
40
|
-
ensure_initialized
|
41
|
-
@singleton.with_context(properties, &block)
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.instance
|
45
|
-
ensure_initialized
|
46
|
-
@singleton
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def self.ensure_initialized(key = nil)
|
52
|
-
if not defined? @singleton or @singleton.nil?
|
53
|
-
raise Prefab::Errors::UninitializedError.new(key)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Prefab
|
4
|
-
# A key-based rate limiter that considers a key to be fresh if it has been
|
5
|
-
# seen within the last `duration` seconds.
|
6
|
-
#
|
7
|
-
# This is used to rate limit the number of times we send a given context
|
8
|
-
# to the server.
|
9
|
-
#
|
10
|
-
# Because expected usage is to immediately `set` on a `fresh?` miss, we do
|
11
|
-
# not prune the data structure on `fresh?` calls. Instead, we manually invoke
|
12
|
-
# `prune` periodically from the cache consumer.
|
13
|
-
class RateLimitCache
|
14
|
-
attr_reader :data
|
15
|
-
|
16
|
-
def initialize(duration)
|
17
|
-
@data = Concurrent::Map.new
|
18
|
-
@duration = duration
|
19
|
-
end
|
20
|
-
|
21
|
-
def fresh?(key)
|
22
|
-
timestamp = @data[key]
|
23
|
-
|
24
|
-
return false unless timestamp
|
25
|
-
return false if Time.now.utc.to_i - timestamp > @duration
|
26
|
-
|
27
|
-
true
|
28
|
-
end
|
29
|
-
|
30
|
-
def set(key)
|
31
|
-
@data[key] = Time.now.utc.to_i
|
32
|
-
end
|
33
|
-
|
34
|
-
def prune
|
35
|
-
now = Time.now.utc.to_i
|
36
|
-
@data.each_pair do |key, (timestamp, _)|
|
37
|
-
@data.delete(key) if now - timestamp > @duration
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Prefab
|
4
|
-
class ResolvedConfigPresenter
|
5
|
-
class ConfigRow
|
6
|
-
include Comparable
|
7
|
-
|
8
|
-
attr_reader :key, :value, :match, :source
|
9
|
-
|
10
|
-
def initialize(key, value, match, source)
|
11
|
-
@key = key
|
12
|
-
@value = value
|
13
|
-
@match = match
|
14
|
-
@source = source
|
15
|
-
end
|
16
|
-
|
17
|
-
def <=>(other)
|
18
|
-
inspect <=> other.inspect
|
19
|
-
end
|
20
|
-
|
21
|
-
def inspect
|
22
|
-
[@key, @value, @match, @source].inspect
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def initialize(resolver, lock, local_store)
|
27
|
-
@resolver = resolver
|
28
|
-
@lock = lock
|
29
|
-
@local_store = local_store
|
30
|
-
end
|
31
|
-
|
32
|
-
def each(&block)
|
33
|
-
to_h.each(&block)
|
34
|
-
end
|
35
|
-
|
36
|
-
def to_h
|
37
|
-
hash = {}
|
38
|
-
|
39
|
-
Prefab::Context.with_context({}) do
|
40
|
-
@lock.with_read_lock do
|
41
|
-
@local_store.keys.sort.each do |k|
|
42
|
-
v = @local_store[k]
|
43
|
-
|
44
|
-
if v.nil?
|
45
|
-
hash[k] = ConfigRow.new(k, nil, nil, nil)
|
46
|
-
else
|
47
|
-
value = @resolver.evaluate(v[:config])&.reportable_value
|
48
|
-
hash[k] = ConfigRow.new(k, value, v[:match], v[:source])
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
hash
|
55
|
-
end
|
56
|
-
|
57
|
-
def to_s
|
58
|
-
str = "\n"
|
59
|
-
|
60
|
-
Prefab::Context.with_context({}) do
|
61
|
-
@lock.with_read_lock do
|
62
|
-
@local_store.keys.sort.each do |k|
|
63
|
-
v = @local_store[k]
|
64
|
-
elements = [k.slice(0..49).ljust(50)]
|
65
|
-
if v.nil?
|
66
|
-
elements << 'tombstone'
|
67
|
-
else
|
68
|
-
value = begin
|
69
|
-
@resolver.evaluate(v[:config])&.reportable_value
|
70
|
-
rescue StandardError => e
|
71
|
-
"ERROR EVALUATING: #{e.class} #{e.message}"
|
72
|
-
end
|
73
|
-
elements << value.to_s.slice(0..34).ljust(35)
|
74
|
-
elements << value.class.to_s.slice(0..6).ljust(7)
|
75
|
-
elements << "Match: #{v[:match]}".slice(0..29).ljust(30)
|
76
|
-
elements << "Source: #{v[:source]}"
|
77
|
-
end
|
78
|
-
str += elements.join(' | ') << "\n"
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
str
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
data/lib/prefab/time_helpers.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Prefab
|
4
|
-
class WeightedValueResolver
|
5
|
-
MAX_32_FLOAT = 4_294_967_294.0
|
6
|
-
|
7
|
-
def initialize(weights, config_key, context_hash_value)
|
8
|
-
@weights = weights
|
9
|
-
@config_key = config_key
|
10
|
-
@context_hash_value = context_hash_value
|
11
|
-
end
|
12
|
-
|
13
|
-
def resolve
|
14
|
-
percent = @context_hash_value ? user_percent : rand
|
15
|
-
|
16
|
-
index = variant_index(percent)
|
17
|
-
|
18
|
-
[@weights[index], index]
|
19
|
-
end
|
20
|
-
|
21
|
-
def user_percent
|
22
|
-
to_hash = "#{@config_key}#{@context_hash_value}"
|
23
|
-
int_value = Murmur3.murmur3_32(to_hash)
|
24
|
-
int_value / MAX_32_FLOAT
|
25
|
-
end
|
26
|
-
|
27
|
-
def variant_index(percent_through_distribution)
|
28
|
-
distribution_space = @weights.inject(0) { |sum, v| sum + v.weight }
|
29
|
-
bucket = distribution_space * percent_through_distribution
|
30
|
-
|
31
|
-
sum = 0
|
32
|
-
@weights.each_with_index do |variant_weight, index|
|
33
|
-
return index if bucket < sum + variant_weight.weight
|
34
|
-
|
35
|
-
sum += variant_weight.weight
|
36
|
-
end
|
37
|
-
|
38
|
-
# In the event that all weights are zero, return the last variant
|
39
|
-
@weights.size - 1
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
|
-
module Prefab
|
4
|
-
class YAMLConfigParser
|
5
|
-
LOG = Prefab::InternalLogger.new(YAMLConfigParser)
|
6
|
-
|
7
|
-
def initialize(file, client)
|
8
|
-
@file = file
|
9
|
-
@client = client
|
10
|
-
end
|
11
|
-
|
12
|
-
def merge(config)
|
13
|
-
yaml = load
|
14
|
-
|
15
|
-
yaml.each do |k, v|
|
16
|
-
config = Prefab::LocalConfigParser.parse(k, v, config, @file)
|
17
|
-
end
|
18
|
-
|
19
|
-
config
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def load
|
25
|
-
if File.exist?(@file)
|
26
|
-
LOG.info "Load #{@file}"
|
27
|
-
YAML.load_file(@file)
|
28
|
-
else
|
29
|
-
LOG.info "No file #{@file}"
|
30
|
-
{}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
data/lib/prefab-cloud-ruby.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Prefab
|
4
|
-
NO_DEFAULT_PROVIDED = :no_default_provided
|
5
|
-
VERSION = File.read(File.dirname(__FILE__) + '/../VERSION').strip
|
6
|
-
end
|
7
|
-
|
8
|
-
require 'concurrent/atomics'
|
9
|
-
require 'concurrent'
|
10
|
-
require 'faraday'
|
11
|
-
require 'openssl'
|
12
|
-
require 'ld-eventsource'
|
13
|
-
require 'prefab_pb'
|
14
|
-
require 'prefab/time_helpers'
|
15
|
-
require 'prefab/error'
|
16
|
-
require 'prefab/evaluation'
|
17
|
-
require 'prefab/encryption'
|
18
|
-
require 'prefab/exponential_backoff'
|
19
|
-
require 'prefab/errors/initialization_timeout_error'
|
20
|
-
require 'prefab/errors/invalid_api_key_error'
|
21
|
-
require 'prefab/errors/missing_default_error'
|
22
|
-
require 'prefab/errors/env_var_parse_error'
|
23
|
-
require 'prefab/errors/missing_env_var_error'
|
24
|
-
require 'prefab/errors/uninitialized_error'
|
25
|
-
require 'prefab/options'
|
26
|
-
require 'prefab/static_logger'
|
27
|
-
require 'prefab/internal_logger'
|
28
|
-
require 'prefab/rate_limit_cache'
|
29
|
-
require 'prefab/context_shape_aggregator'
|
30
|
-
require 'prefab/example_contexts_aggregator'
|
31
|
-
require 'prefab/evaluation_summary_aggregator'
|
32
|
-
require 'prefab/log_path_aggregator'
|
33
|
-
require 'prefab/sse_logger'
|
34
|
-
require 'prefab/weighted_value_resolver'
|
35
|
-
require 'prefab/config_value_wrapper'
|
36
|
-
require 'prefab/config_value_unwrapper'
|
37
|
-
require 'prefab/criteria_evaluator'
|
38
|
-
require 'prefab/config_loader'
|
39
|
-
require 'prefab/context_shape'
|
40
|
-
require 'prefab/local_config_parser'
|
41
|
-
require 'prefab/yaml_config_parser'
|
42
|
-
require 'prefab/resolved_config_presenter'
|
43
|
-
require 'prefab/config_resolver'
|
44
|
-
require 'prefab/http_connection'
|
45
|
-
require 'prefab/context'
|
46
|
-
require 'prefab/logger_client'
|
47
|
-
require 'active_support/deprecation'
|
48
|
-
require 'active_support'
|
49
|
-
require 'action_controller/metal/strong_parameters'
|
50
|
-
require 'prefab/logging/formatter_base'
|
51
|
-
require 'prefab/log_subscribers/action_controller_subscriber'
|
52
|
-
require 'prefab/client'
|
53
|
-
require 'prefab/config_client_presenter'
|
54
|
-
require 'prefab/config_client'
|
55
|
-
require 'prefab/feature_flag_client'
|
56
|
-
require 'prefab/prefab'
|
57
|
-
require 'prefab/murmer3'
|