prefab-cloud-ruby 0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|