prefab-cloud-ruby 0.6.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: fa80ee91d95324b503253f95a12deb9b0db91291
4
- data.tar.gz: 0315d992eb2a87073998e1d7db4864a8c3da289c
2
+ SHA256:
3
+ metadata.gz: 80a03ec9a75bc4c5d827c746354ff1353fe135a5ab6e31e9beaaf1ca1c27c931
4
+ data.tar.gz: d4c9f02e6bbb54d8d4884cc2d94179f39e859aafe3966188b1a00f7b7e5ccc48
5
5
  SHA512:
6
- metadata.gz: e43a7a8dafbfd3a9e6c12cd93b57bed2ee8fd738406fdba166c5eddad03154de66d9150285961f8c08da58d0754fde385b8b68e0bb22f9a27de8441f231a429a
7
- data.tar.gz: c3586f0e6b689e0ee5b1fd86e621d79ffab5a2263cf977c004fd7a4618cea403059f075f719a86d5a0b4533a16e398e3acb35dff9ca0930082fb81266ef1e545
6
+ metadata.gz: 67f8b5ed6f61f01943736f9abbb685c9d7f7fd4c029ff3e051356f6e65936595f18899160fd842c415d86c371b0f9d915d795c6b9adafbdebeadd5b6fc6cc75b
7
+ data.tar.gz: c56dd76208ad8bbfd9d7add1bbc317a951671c2590cecf93389fbb5170aa9da13898bb3501e396450df2eaa93a67d7041b24fbdc2ca77f2a414056d0cbf471f9
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.0.3
data/CODEOWNERS ADDED
@@ -0,0 +1 @@
1
+ * @prefab-cloud/prefabdevs @prefab-cloud/prefabmaintainers @prefab-cloud/prefabadmins
data/Gemfile CHANGED
@@ -2,13 +2,17 @@ source "https://rubygems.org"
2
2
 
3
3
  gem 'concurrent-ruby', '~> 1.0', '>= 1.0.5'
4
4
  gem 'faraday'
5
- gem 'grpc'
5
+ gem 'ld-eventsource'
6
+ gem 'grpc', :platforms => :ruby
7
+ gem 'google-protobuf', :platforms => :ruby
8
+ gem 'googleapis-common-protos-types', :platforms => :ruby
6
9
 
7
10
  group :development do
8
- gem 'grpc-tools', '~> 1.17.1'
11
+ gem 'grpc-tools', :platforms => :ruby
9
12
  gem "shoulda", ">= 0"
10
13
  gem "rdoc", "~> 3.12"
11
- gem "bundler", "~> 1.0"
14
+ gem "bundler"
12
15
  gem "juwelier", "~> 2.4.9"
13
16
  gem "simplecov", ">= 0"
17
+ gem 'thin'
14
18
  end
data/Gemfile.lock CHANGED
@@ -10,14 +10,22 @@ GEM
10
10
  public_suffix (>= 2.0.2, < 5.0)
11
11
  builder (3.2.4)
12
12
  concurrent-ruby (1.1.8)
13
+ daemons (1.4.1)
13
14
  descendants_tracker (0.0.4)
14
15
  thread_safe (~> 0.3, >= 0.3.1)
15
16
  docile (1.3.5)
17
+ domain_name (0.5.20190701)
18
+ unf (>= 0.0.5, < 1.0.0)
19
+ eventmachine (1.2.7)
16
20
  faraday (1.3.0)
17
21
  faraday-net_http (~> 1.0)
18
22
  multipart-post (>= 1.2, < 3)
19
23
  ruby2_keywords
20
24
  faraday-net_http (1.0.1)
25
+ ffi (1.15.5)
26
+ ffi-compiler (1.0.1)
27
+ ffi (>= 1.0.0)
28
+ rake
21
29
  git (1.8.1)
22
30
  rchardet (~> 1.8)
23
31
  github_api (0.19.0)
@@ -26,15 +34,23 @@ GEM
26
34
  faraday (>= 0.8, < 2)
27
35
  hashie (~> 3.5, >= 3.5.2)
28
36
  oauth2 (~> 1.0)
29
- google-protobuf (3.15.6)
30
- googleapis-common-protos-types (1.0.6)
31
- google-protobuf (~> 3.14)
32
- grpc (1.36.0)
37
+ google-protobuf (3.19.3)
38
+ googleapis-common-protos-types (1.3.0)
33
39
  google-protobuf (~> 3.14)
40
+ grpc (1.43.1)
41
+ google-protobuf (~> 3.18)
34
42
  googleapis-common-protos-types (~> 1.0)
35
- grpc-tools (1.17.1)
43
+ grpc-tools (1.43.1)
36
44
  hashie (3.6.0)
37
45
  highline (2.0.3)
46
+ http (5.0.1)
47
+ addressable (~> 2.3)
48
+ http-cookie (~> 1.0)
49
+ http-form_data (~> 2.2)
50
+ llhttp-ffi (~> 0.3.0)
51
+ http-cookie (1.0.4)
52
+ domain_name (~> 0.5)
53
+ http-form_data (2.3.0)
38
54
  i18n (1.8.9)
39
55
  concurrent-ruby (~> 1.0)
40
56
  json (1.8.6)
@@ -53,13 +69,20 @@ GEM
53
69
  jwt (2.2.2)
54
70
  kamelcase (0.0.2)
55
71
  semver2 (~> 3)
56
- mini_portile2 (2.4.0)
72
+ ld-eventsource (2.2.0)
73
+ concurrent-ruby (~> 1.0)
74
+ http (>= 4.4.1, < 6.0.0)
75
+ llhttp-ffi (0.3.1)
76
+ ffi-compiler (~> 1.0)
77
+ rake (~> 13.0)
78
+ mini_portile2 (2.7.1)
57
79
  minitest (5.14.4)
58
80
  multi_json (1.15.0)
59
81
  multi_xml (0.6.0)
60
82
  multipart-post (2.1.1)
61
- nokogiri (1.10.10)
62
- mini_portile2 (~> 2.4.0)
83
+ nokogiri (1.13.1)
84
+ mini_portile2 (~> 2.7.0)
85
+ racc (~> 1.4)
63
86
  oauth2 (1.4.7)
64
87
  faraday (>= 0.8, < 2.0)
65
88
  jwt (>= 1.0, < 3.0)
@@ -68,6 +91,7 @@ GEM
68
91
  rack (>= 1.2, < 3)
69
92
  psych (3.3.1)
70
93
  public_suffix (4.0.6)
94
+ racc (1.6.0)
71
95
  rack (2.2.3)
72
96
  rake (13.0.3)
73
97
  rchardet (1.8.0)
@@ -85,23 +109,34 @@ GEM
85
109
  docile (~> 1.1)
86
110
  simplecov-html (~> 0.11)
87
111
  simplecov-html (0.12.3)
112
+ thin (1.8.1)
113
+ daemons (~> 1.0, >= 1.0.9)
114
+ eventmachine (~> 1.0, >= 1.0.4)
115
+ rack (>= 1, < 3)
88
116
  thread_safe (0.3.6)
89
117
  tzinfo (1.2.9)
90
118
  thread_safe (~> 0.1)
119
+ unf (0.1.4)
120
+ unf_ext
121
+ unf_ext (0.0.8)
91
122
 
92
123
  PLATFORMS
93
124
  ruby
94
125
 
95
126
  DEPENDENCIES
96
- bundler (~> 1.0)
127
+ bundler
97
128
  concurrent-ruby (~> 1.0, >= 1.0.5)
98
129
  faraday
130
+ google-protobuf
131
+ googleapis-common-protos-types
99
132
  grpc
100
- grpc-tools (~> 1.17.1)
133
+ grpc-tools
101
134
  juwelier (~> 2.4.9)
135
+ ld-eventsource
102
136
  rdoc (~> 3.12)
103
137
  shoulda
104
138
  simplecov
139
+ thin
105
140
 
106
141
  BUNDLED WITH
107
- 1.16.0
142
+ 2.3.5
data/README.md CHANGED
@@ -53,7 +53,16 @@ end
53
53
  * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
54
54
  * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
55
55
 
56
+ ## Release
57
+
58
+ ```shell
59
+ update VERSION
60
+ bundle exec rake gemspec:generate
61
+ git commit & push
62
+ REMOTE_BRANCH=main LOCAL_BRANCH=main bundle exec rake release
63
+ ```
64
+
56
65
  ## Copyright
57
66
 
58
- Copyright (c) 2018 Jeff Dwyer. See LICENSE.txt for
67
+ Copyright (c) 2022 Jeff Dwyer. See LICENSE.txt for
59
68
  further details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0
1
+ 0.9.0
data/compile_protos.sh CHANGED
@@ -1,2 +1,5 @@
1
1
  #!/usr/bin/env bash
2
2
  grpc_tools_ruby_protoc -I ../prefab-cloud/ --ruby_out=lib --grpc_out=lib prefab.proto
3
+ # on M1 you need to
4
+ # 1. run in rosetta
5
+ # 2. mv gems/2.6.0/gems/grpc-tools-1.43.1/bin/x86_64-macos x86-macos
data/lib/prefab/client.rb CHANGED
@@ -8,7 +8,7 @@ module Prefab
8
8
  }
9
9
 
10
10
 
11
- attr_reader :account_id, :shared_cache, :stats, :namespace, :interceptor, :api_key
11
+ attr_reader :project_id, :shared_cache, :stats, :namespace, :interceptor, :api_key, :environment, :prefab_api_url
12
12
 
13
13
  def initialize(api_key: ENV['PREFAB_API_KEY'],
14
14
  logdev: nil,
@@ -19,26 +19,31 @@ module Prefab
19
19
  log_formatter: DEFAULT_LOG_FORMATTER
20
20
  )
21
21
  raise "No API key. Set PREFAB_API_KEY env var" if api_key.nil? || api_key.empty?
22
+ raise "PREFAB_API_KEY format invalid. Expecting 123-development-yourapikey-SDK" unless api_key.count("-") == 3
22
23
  @logdev = (logdev || $stdout)
23
24
  @log_formatter = log_formatter
24
25
  @local = local
25
26
  @stats = (stats || NoopStats.new)
26
27
  @shared_cache = (shared_cache || NoopCache.new)
27
28
  @api_key = api_key
28
- @account_id = api_key.split("|")[0].to_i
29
+ @project_id = api_key.split("-")[0].to_i
30
+ @environment = api_key.split("-")[1]
29
31
  @namespace = namespace
30
32
  @interceptor = Prefab::AuthInterceptor.new(api_key)
31
33
  @stubs = {}
32
-
34
+ @prefab_api_url = ENV["PREFAB_API_URL"] || 'https://api.prefab.cloud'
35
+ @prefab_grpc_url = ENV["PREFAB_GRPC_URL"] || 'grpc.prefab.cloud:443'
36
+ log_internal Logger::INFO, "Prefab Initializing in environment: '#{@environment}' and namespace: '#{@namespace}'"
37
+ log_internal Logger::INFO, "Prefab Connecting to: #{@prefab_api_url} and #{@prefab_grpc_url} Secure: #{http_secure?}"
33
38
  at_exit do
34
39
  channel.destroy
35
40
  end
36
41
  end
37
42
 
38
43
  def channel
39
- credentials = ENV["PREFAB_CLOUD_HTTP"] == "true" ? :this_channel_is_insecure : creds
40
- url = ENV["PREFAB_API_URL"] || 'api.prefab.cloud:443'
41
- @_channel ||= GRPC::Core::Channel.new(url, nil, credentials)
44
+ credentials = http_secure? ? creds : :this_channel_is_insecure
45
+ log_internal Logger::DEBUG, "GRPC Channel #{@prefab_grpc_url} #{credentials}"
46
+ @_channel ||= GRPC::Core::Channel.new(@prefab_grpc_url, nil, credentials)
42
47
  end
43
48
 
44
49
  def config_client(timeout: 5.0)
@@ -88,7 +93,7 @@ module Prefab
88
93
  end
89
94
 
90
95
  def cache_key(post_fix)
91
- "prefab:#{account_id}:#{post_fix}"
96
+ "prefab:#{project_id}:#{post_fix}"
92
97
  end
93
98
 
94
99
  def reset!
@@ -98,6 +103,10 @@ module Prefab
98
103
 
99
104
  private
100
105
 
106
+ def http_secure?
107
+ ENV["PREFAB_CLOUD_HTTP"] != "true"
108
+ end
109
+
101
110
  def stub_for(service, timeout)
102
111
  @stubs["#{service}_#{timeout}"] ||= service::Stub.new(nil,
103
112
  nil,
@@ -6,6 +6,7 @@ module Prefab
6
6
 
7
7
  def initialize(base_client, timeout)
8
8
  @base_client = base_client
9
+ @base_client.log_internal Logger::DEBUG, "Initialize ConfigClient"
9
10
  @timeout = timeout
10
11
  @initialization_lock = Concurrent::ReadWriteLock.new
11
12
 
@@ -14,23 +15,27 @@ module Prefab
14
15
  @config_loader = Prefab::ConfigLoader.new(@base_client)
15
16
  @config_resolver = Prefab::ConfigResolver.new(@base_client, @config_loader)
16
17
 
18
+ @base_client.log_internal Logger::DEBUG, "Initialize ConfigClient: AcquireWriteLock"
17
19
  @initialization_lock.acquire_write_lock
20
+ @base_client.log_internal Logger::DEBUG, "Initialize ConfigClient: AcquiredWriteLock"
18
21
 
19
22
  @cancellable_interceptor = Prefab::CancellableInterceptor.new(@base_client)
20
23
 
21
24
  @s3_cloud_front = ENV["PREFAB_S3CF_BUCKET"] || DEFAULT_S3CF_BUCKET
25
+
22
26
  load_checkpoint
23
27
  start_checkpointing_thread
24
28
  end
25
29
 
26
30
  def start_streaming
27
31
  @streaming = true
28
- start_api_connection_thread(@config_loader.highwater_mark)
32
+ # start_grpc_streaming_connection_thread(@config_loader.highwater_mark)
33
+ start_sse_streaming_connection_thread(@config_loader.highwater_mark)
29
34
  end
30
35
 
31
- def get(prop)
36
+ def get(key)
32
37
  @initialization_lock.with_read_lock do
33
- @config_resolver.get(prop)
38
+ @config_resolver.get(key)
34
39
  end
35
40
  end
36
41
 
@@ -58,8 +63,14 @@ module Prefab
58
63
  end
59
64
 
60
65
  def self.value_to_delta(key, config_value, namespace = nil)
61
- Prefab::ConfigDelta.new(key: [namespace, key].compact.join(":"),
62
- value: config_value)
66
+ Prefab::Config.new(key: [namespace, key].compact.join(":"),
67
+ rows: [Prefab::ConfigRow.new(value: config_value)])
68
+ end
69
+
70
+ def get_config_obj(key)
71
+ @initialization_lock.with_read_lock do
72
+ @config_resolver.get_config(key)
73
+ end
63
74
  end
64
75
 
65
76
  private
@@ -86,11 +97,14 @@ module Prefab
86
97
  end
87
98
 
88
99
  def load_checkpoint_from_config
89
- config_req = Prefab::ConfigServicePointer.new(account_id: @base_client.account_id,
90
- start_at_id: @config_loader.highwater_mark)
100
+ @base_client.log_internal Logger::DEBUG, "Load Checkpoint From Config"
101
+
102
+ config_req = Prefab::ConfigServicePointer.new(start_at_id: @config_loader.highwater_mark)
103
+
91
104
  resp = stub.get_all_config(config_req)
92
- load_deltas(resp, :api)
93
- resp.deltas.each do |delta|
105
+ @base_client.log_internal Logger::DEBUG, "Got Response #{resp}"
106
+ load_configs(resp, :api)
107
+ resp.configs.each do |delta|
94
108
  @config_loader.set(delta)
95
109
  end
96
110
  @config_resolver.update
@@ -105,17 +119,16 @@ module Prefab
105
119
  url = "#{@s3_cloud_front}/#{@base_client.api_key.gsub("|", "/")}"
106
120
  resp = Faraday.get url
107
121
  if resp.status == 200
108
- deltas = Prefab::ConfigDeltas.decode(resp.body)
109
- load_deltas(deltas, :s3)
122
+ configs = Prefab::Configs.decode(resp.body)
123
+ load_configs(configs, :s3)
110
124
  else
111
125
  @base_client.log_internal Logger::INFO, "No S3 checkpoint. Response #{resp.status} Plan may not support this."
112
126
  end
113
127
  end
114
128
 
115
-
116
- def load_deltas(deltas, source)
117
- deltas.deltas.each do |delta|
118
- @config_loader.set(delta)
129
+ def load_configs(configs, source)
130
+ configs.configs.each do |config|
131
+ @config_loader.set(config)
119
132
  end
120
133
  @base_client.log_internal Logger::INFO, "Found checkpoint with highwater id #{@config_loader.highwater_mark} from #{source}"
121
134
  @base_client.stats.increment("prefab.config.checkpoint.load")
@@ -150,11 +163,35 @@ module Prefab
150
163
  end
151
164
  end
152
165
 
166
+
167
+ def start_sse_streaming_connection_thread(start_at_id)
168
+ auth = "#{@base_client.project_id}:#{@base_client.api_key}"
169
+
170
+ auth_string = Base64.strict_encode64(auth)
171
+ headers = {
172
+ "x-prefab-start-at-id": start_at_id,
173
+ "Authorization": "Basic #{auth_string}",
174
+ }
175
+ url = "#{@base_client.prefab_api_url}/api/v1/sse/config"
176
+ @base_client.log_internal Logger::INFO, "SSE Streaming Connect to #{url}"
177
+ SSE::Client.new(url, headers: headers) do |client|
178
+ client.on_event do |event|
179
+ configs = Prefab::Configs.decode(Base64.decode64(event.data))
180
+ @base_client.log_internal Logger::INFO, "SSE received configs."
181
+ @base_client.log_internal Logger::DEBUG, "SSE received configs: #{configs}"
182
+ configs.configs.each do |config|
183
+ @config_loader.set(config)
184
+ end
185
+ @config_resolver.update
186
+ finish_init!(:streaming)
187
+ end
188
+ end
189
+ end
190
+
153
191
  # Setup a streaming connection to the API
154
192
  # Save new config values into the loader
155
- def start_api_connection_thread(start_at_id)
156
- config_req = Prefab::ConfigServicePointer.new(account_id: @base_client.account_id,
157
- start_at_id: start_at_id)
193
+ def start_grpc_streaming_connection_thread(start_at_id)
194
+ config_req = Prefab::ConfigServicePointer.new(start_at_id: start_at_id)
158
195
  @base_client.log_internal Logger::DEBUG, "start api connection thread #{start_at_id}"
159
196
  @base_client.stats.increment("prefab.config.api.start")
160
197
 
@@ -168,8 +205,8 @@ module Prefab
168
205
  begin
169
206
  resp = stub.get_config(config_req)
170
207
  resp.each do |r|
171
- r.deltas.each do |delta|
172
- @config_loader.set(delta)
208
+ r.configs.each do |config|
209
+ @config_loader.set(config)
173
210
  end
174
211
  @config_resolver.update
175
212
  finish_init!(:streaming)
@@ -0,0 +1,20 @@
1
+ module Prefab
2
+ module ConfigHelper
3
+ def value_of(config_value)
4
+ case config_value.type
5
+ when :string
6
+ config_value.string
7
+ when :int
8
+ config_value.int
9
+ when :double
10
+ config_value.double
11
+ when :bool
12
+ config_value.bool
13
+ when :feature_flag
14
+ config_value.feature_flag
15
+ when :segment
16
+ config_value.segment
17
+ end
18
+ end
19
+ end
20
+ end
@@ -14,24 +14,24 @@ module Prefab
14
14
  def calc_config
15
15
  rtn = @classpath_config.clone
16
16
  @api_config.each_key do |k|
17
- rtn[k] = @api_config[k].value
17
+ rtn[k] = @api_config[k]
18
18
  end
19
19
  rtn = rtn.merge(@local_overrides)
20
20
  rtn
21
21
  end
22
22
 
23
- def set(delta)
23
+ def set(config)
24
24
  # don't overwrite newer values
25
- if @api_config[delta.key] && @api_config[delta.key].id > delta.id
25
+ if @api_config[config.key] && @api_config[config.key].id > config.id
26
26
  return
27
27
  end
28
28
 
29
- if delta.value.nil?
30
- @api_config.delete(delta.key)
29
+ if config.rows.empty?
30
+ @api_config.delete(config.key)
31
31
  else
32
- @api_config[delta.key] = delta
32
+ @api_config[config.key] = config
33
33
  end
34
- @highwater_mark = [delta.id, @highwater_mark].max
34
+ @highwater_mark = [config.id, @highwater_mark].max
35
35
  end
36
36
 
37
37
  def rm(key)
@@ -39,11 +39,11 @@ module Prefab
39
39
  end
40
40
 
41
41
  def get_api_deltas
42
- deltas = Prefab::ConfigDeltas.new
42
+ configs = Prefab::Configs.new
43
43
  @api_config.each_value do |config_value|
44
- deltas.deltas << config_value
44
+ configs.configs << config_value
45
45
  end
46
- deltas
46
+ configs
47
47
  end
48
48
 
49
49
  private
@@ -63,7 +63,9 @@ module Prefab
63
63
  Dir.glob(glob).each do |file|
64
64
  yaml = load(file)
65
65
  yaml.each do |k, v|
66
- rtn[k] = Prefab::ConfigValue.new(value_from(v))
66
+ rtn[k] = Prefab::Config.new(key: k, rows: [
67
+ Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(value_from(v)))
68
+ ])
67
69
  end
68
70
  end
69
71
  rtn
@@ -1,11 +1,12 @@
1
1
  module Prefab
2
2
  class ConfigResolver
3
+ include Prefab::ConfigHelper
3
4
  NAMESPACE_DELIMITER = ".".freeze
4
- NAME_KEY_DELIMITER = ":".freeze
5
5
 
6
6
  def initialize(base_client, config_loader)
7
7
  @lock = Concurrent::ReadWriteLock.new
8
8
  @local_store = {}
9
+ @environment = base_client.environment
9
10
  @namespace = base_client.namespace
10
11
  @config_loader = config_loader
11
12
  make_local
@@ -16,19 +17,22 @@ module Prefab
16
17
  @lock.with_read_lock do
17
18
  @local_store.each do |k, v|
18
19
  value = v[:value]
19
- str << "|#{k}| in #{v[:namespace]} |#{value_of(value)}|#{value_of(value).class}\n"
20
+ str << "|#{k}| from #{v[:match]} |#{value_of(value)}|#{value_of(value).class}\n"
20
21
  end
21
22
  end
22
23
  str
23
24
  end
24
25
 
25
26
  def get(property)
26
- config = @lock.with_read_lock do
27
- @local_store[property]
28
- end
27
+ config = _get(property)
29
28
  config ? value_of(config[:value]) : nil
30
29
  end
31
30
 
31
+ def get_config(property)
32
+ config = _get(property)
33
+ config ? config[:config] : nil
34
+ end
35
+
32
36
  def update
33
37
  make_local
34
38
  end
@@ -39,21 +43,6 @@ module Prefab
39
43
 
40
44
  private
41
45
 
42
- def value_of(config_value)
43
- case config_value.type
44
- when :string
45
- config_value.string
46
- when :int
47
- config_value.int
48
- when :double
49
- config_value.double
50
- when :bool
51
- config_value.bool
52
- when :feature_flag
53
- config_value.feature_flag
54
- end
55
- end
56
-
57
46
  # Should client a.b.c see key in namespace a.b? yes
58
47
  # Should client a.b.c see key in namespace a.b.c? yes
59
48
  # Should client a.b.c see key in namespace a.b.d? no
@@ -61,36 +50,43 @@ module Prefab
61
50
  #
62
51
  def starts_with_ns?(key_namespace, client_namespace)
63
52
  zipped = key_namespace.split(NAMESPACE_DELIMITER).zip(client_namespace.split(NAMESPACE_DELIMITER))
64
- zipped.map do |k, c|
65
- (k.nil? || k.empty?) || c == k
66
- end.all?
53
+ mapped = zipped.map do |k, c|
54
+ (k.nil? || k.empty?) || k == c
55
+ end
56
+ [mapped.all?, mapped.size]
67
57
  end
68
58
 
69
59
  def make_local
70
60
  store = {}
71
- @config_loader.calc_config.each do |prop, value|
72
- property = prop
73
- key_namespace = ""
74
-
75
- split = prop.split(NAME_KEY_DELIMITER)
76
-
77
- if split.size > 1
78
- property = split[1..-1].join(NAME_KEY_DELIMITER)
79
- key_namespace = split[0]
80
- end
81
-
82
- if starts_with_ns?(key_namespace, @namespace)
83
- existing = store[property]
84
- if existing.nil?
85
- store[property] = { namespace: key_namespace, value: value }
86
- elsif existing[:namespace].split(NAMESPACE_DELIMITER).size < key_namespace.split(NAMESPACE_DELIMITER).size
87
- store[property] = { namespace: key_namespace, value: value }
61
+ @config_loader.calc_config.each do |key, config|
62
+ sortable = config.rows.map do |row|
63
+ if !row.env_key.empty?
64
+ if row.env_key == @environment
65
+ if !row.namespace.empty?
66
+ (starts_with, count) = starts_with_ns?(row.namespace, @namespace)
67
+ # rubocop:disable BlockNesting
68
+ { sortable: 2 + count, match: row.namespace, value: row.value, config: config} if starts_with
69
+ else
70
+ { sortable: 1, match: row.env_key, value: row.value, config: config}
71
+ end
72
+ end
73
+ else
74
+ { sortable: 0, match: "default", value: row.value, config: config}
88
75
  end
89
- end
76
+ end.compact
77
+ to_store = sortable.sort_by { |h| h[:sortable] }.last
78
+ store[key] = to_store
90
79
  end
80
+
91
81
  @lock.with_write_lock do
92
82
  @local_store = store
93
83
  end
94
84
  end
85
+
86
+ def _get(property)
87
+ @lock.with_read_lock do
88
+ @local_store[property]
89
+ end
90
+ end
95
91
  end
96
92
  end