configcat 3.1.0 → 4.0.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/configcat.rb +36 -14
- data/lib/configcat/autopollingcachepolicy.rb +6 -4
- data/lib/configcat/configcache.rb +5 -5
- data/lib/configcat/configcatclient.rb +36 -17
- data/lib/configcat/configfetcher.rb +89 -11
- data/lib/configcat/constants.rb +17 -0
- data/lib/configcat/datagovernance.rb +10 -0
- data/lib/configcat/interfaces.rb +2 -2
- data/lib/configcat/lazyloadingcachepolicy.rb +7 -4
- data/lib/configcat/manualpollingcachepolicy.rb +5 -3
- data/lib/configcat/rolloutevaluator.rb +9 -11
- data/lib/configcat/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 118a3db79c8d7d9a0795897380a4dfaf14fecda8a636024abfd9d2433b3af924
|
4
|
+
data.tar.gz: 4c85c82b81fe08fcf9b6eed0a40bea06369939301aa09bc12e82b33a3b2176eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afe03eda0affc92755ae0eb91196a15bfe61f68a12244270bb5d19b3870bc023fe9ccf3231d8f11f414c4439b49fd2f9481e9a64295c3ab87697511ebcf57b25
|
7
|
+
data.tar.gz: 5ac8e3beef89cbc84ef89f2eb5b071fcf5cb348db1c302755ba4fc619c759f9919f80785b2b08a4a583725d35ea6b9ef038d869706956485eec3b4a9d4cadbaa
|
data/lib/configcat.rb
CHANGED
@@ -10,13 +10,17 @@ module ConfigCat
|
|
10
10
|
attr_accessor :logger
|
11
11
|
end
|
12
12
|
|
13
|
-
def ConfigCat.create_client(sdk_key)
|
13
|
+
def ConfigCat.create_client(sdk_key, data_governance: DataGovernance::GLOBAL)
|
14
14
|
#
|
15
15
|
# Create an instance of ConfigCatClient and setup Auto Poll mode with default options
|
16
16
|
#
|
17
17
|
# :param sdk_key: ConfigCat SDK Key to access your configuration.
|
18
|
+
# :param data_governance:
|
19
|
+
# Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
|
20
|
+
# https://app.configcat.com/organization/data-governance
|
21
|
+
# (Only Organization Admins have access)
|
18
22
|
#
|
19
|
-
return create_client_with_auto_poll(sdk_key)
|
23
|
+
return create_client_with_auto_poll(sdk_key, data_governance: data_governance)
|
20
24
|
end
|
21
25
|
|
22
26
|
def ConfigCat.create_client_with_auto_poll(sdk_key,
|
@@ -25,10 +29,11 @@ module ConfigCat
|
|
25
29
|
on_configuration_changed_callback: nil,
|
26
30
|
config_cache_class: nil,
|
27
31
|
base_url: nil,
|
28
|
-
proxy_address:nil,
|
29
|
-
proxy_port:nil,
|
30
|
-
proxy_user:nil,
|
31
|
-
proxy_pass:nil
|
32
|
+
proxy_address: nil,
|
33
|
+
proxy_port: nil,
|
34
|
+
proxy_user: nil,
|
35
|
+
proxy_pass: nil,
|
36
|
+
data_governance: DataGovernance::GLOBAL)
|
32
37
|
#
|
33
38
|
# Create an instance of ConfigCatClient and setup Auto Poll mode with custom options
|
34
39
|
#
|
@@ -43,6 +48,10 @@ module ConfigCat
|
|
43
48
|
# :param proxy_port: Proxy port
|
44
49
|
# :param proxy_user: username for proxy authentication
|
45
50
|
# :param proxy_pass: password for proxy authentication
|
51
|
+
# :param data_governance:
|
52
|
+
# Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
|
53
|
+
# https://app.configcat.com/organization/data-governance
|
54
|
+
# (Only Organization Admins have access)
|
46
55
|
#
|
47
56
|
if sdk_key === nil
|
48
57
|
raise ConfigCatClientException, "SDK Key is required."
|
@@ -63,17 +72,19 @@ module ConfigCat
|
|
63
72
|
proxy_address: proxy_address,
|
64
73
|
proxy_port: proxy_port,
|
65
74
|
proxy_user: proxy_user,
|
66
|
-
proxy_pass: proxy_pass
|
75
|
+
proxy_pass: proxy_pass,
|
76
|
+
data_governance: data_governance)
|
67
77
|
end
|
68
78
|
|
69
79
|
def ConfigCat.create_client_with_lazy_load(sdk_key,
|
70
80
|
cache_time_to_live_seconds: 60,
|
71
81
|
config_cache_class: nil,
|
72
82
|
base_url: nil,
|
73
|
-
proxy_address:nil,
|
74
|
-
proxy_port:nil,
|
75
|
-
proxy_user:nil,
|
76
|
-
proxy_pass:nil
|
83
|
+
proxy_address: nil,
|
84
|
+
proxy_port: nil,
|
85
|
+
proxy_user: nil,
|
86
|
+
proxy_pass: nil,
|
87
|
+
data_governance: DataGovernance::GLOBAL)
|
77
88
|
#
|
78
89
|
# Create an instance of ConfigCatClient and setup Lazy Load mode with custom options
|
79
90
|
#
|
@@ -86,6 +97,10 @@ module ConfigCat
|
|
86
97
|
# :param proxy_port: Proxy port
|
87
98
|
# :param proxy_user: username for proxy authentication
|
88
99
|
# :param proxy_pass: password for proxy authentication
|
100
|
+
# :param data_governance:
|
101
|
+
# Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
|
102
|
+
# https://app.configcat.com/organization/data-governance
|
103
|
+
# (Only Organization Admins have access)
|
89
104
|
#
|
90
105
|
if sdk_key === nil
|
91
106
|
raise ConfigCatClientException, "SDK Key is required."
|
@@ -103,7 +118,8 @@ module ConfigCat
|
|
103
118
|
proxy_address: proxy_address,
|
104
119
|
proxy_port: proxy_port,
|
105
120
|
proxy_user: proxy_user,
|
106
|
-
proxy_pass: proxy_pass
|
121
|
+
proxy_pass: proxy_pass,
|
122
|
+
data_governance: data_governance)
|
107
123
|
end
|
108
124
|
|
109
125
|
def ConfigCat.create_client_with_manual_poll(sdk_key,
|
@@ -112,7 +128,8 @@ module ConfigCat
|
|
112
128
|
proxy_address:nil,
|
113
129
|
proxy_port:nil,
|
114
130
|
proxy_user:nil,
|
115
|
-
proxy_pass:nil
|
131
|
+
proxy_pass:nil,
|
132
|
+
data_governance: DataGovernance::GLOBAL)
|
116
133
|
#
|
117
134
|
# Create an instance of ConfigCatClient and setup Manual Poll mode with custom options
|
118
135
|
#
|
@@ -124,6 +141,10 @@ module ConfigCat
|
|
124
141
|
# :param proxy_port: Proxy port
|
125
142
|
# :param proxy_user: username for proxy authentication
|
126
143
|
# :param proxy_pass: password for proxy authentication
|
144
|
+
# :param data_governance:
|
145
|
+
# Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
|
146
|
+
# https://app.configcat.com/organization/data-governance
|
147
|
+
# (Only Organization Admins have access)
|
127
148
|
#
|
128
149
|
if sdk_key === nil
|
129
150
|
raise ConfigCatClientException, "SDK Key is required."
|
@@ -138,7 +159,8 @@ module ConfigCat
|
|
138
159
|
proxy_address: proxy_address,
|
139
160
|
proxy_port: proxy_port,
|
140
161
|
proxy_user: proxy_user,
|
141
|
-
proxy_pass: proxy_pass
|
162
|
+
proxy_pass: proxy_pass,
|
163
|
+
data_governance: data_governance)
|
142
164
|
end
|
143
165
|
|
144
166
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'configcat/interfaces'
|
2
|
+
require 'configcat/constants'
|
2
3
|
require 'concurrent'
|
3
4
|
|
4
5
|
module ConfigCat
|
5
6
|
class AutoPollingCachePolicy < CachePolicy
|
6
|
-
def initialize(config_fetcher, config_cache, poll_interval_seconds=60, max_init_wait_time_seconds=5, on_configuration_changed_callback=nil)
|
7
|
+
def initialize(config_fetcher, config_cache, cache_key, poll_interval_seconds=60, max_init_wait_time_seconds=5, on_configuration_changed_callback=nil)
|
7
8
|
if poll_interval_seconds < 1
|
8
9
|
poll_interval_seconds = 1
|
9
10
|
end
|
@@ -12,6 +13,7 @@ module ConfigCat
|
|
12
13
|
end
|
13
14
|
@_config_fetcher = config_fetcher
|
14
15
|
@_config_cache = config_cache
|
16
|
+
@_cache_key = cache_key
|
15
17
|
@_poll_interval_seconds = poll_interval_seconds
|
16
18
|
@_max_init_wait_time_seconds = max_init_wait_time_seconds
|
17
19
|
@_on_configuration_changed_callback = on_configuration_changed_callback
|
@@ -40,7 +42,7 @@ module ConfigCat
|
|
40
42
|
end
|
41
43
|
begin
|
42
44
|
@_lock.acquire_read_lock()
|
43
|
-
return @_config_cache.get()
|
45
|
+
return @_config_cache.get(@_cache_key)
|
44
46
|
ensure
|
45
47
|
@_lock.release_read_lock()
|
46
48
|
end
|
@@ -52,7 +54,7 @@ module ConfigCat
|
|
52
54
|
|
53
55
|
begin
|
54
56
|
@_lock.acquire_read_lock()
|
55
|
-
old_configuration = @_config_cache.get()
|
57
|
+
old_configuration = @_config_cache.get(@_cache_key)
|
56
58
|
ensure
|
57
59
|
@_lock.release_read_lock()
|
58
60
|
end
|
@@ -62,7 +64,7 @@ module ConfigCat
|
|
62
64
|
if configuration != old_configuration
|
63
65
|
begin
|
64
66
|
@_lock.acquire_write_lock()
|
65
|
-
@_config_cache.set(configuration)
|
67
|
+
@_config_cache.set(@_cache_key, configuration)
|
66
68
|
@_initialized = true
|
67
69
|
ensure
|
68
70
|
@_lock.release_write_lock()
|
@@ -3,15 +3,15 @@ require 'configcat/interfaces'
|
|
3
3
|
module ConfigCat
|
4
4
|
class InMemoryConfigCache < ConfigCache
|
5
5
|
def initialize()
|
6
|
-
@_value =
|
6
|
+
@_value = {}
|
7
7
|
end
|
8
8
|
|
9
|
-
def get()
|
10
|
-
return @_value
|
9
|
+
def get(key)
|
10
|
+
return @_value.fetch(key, nil)
|
11
11
|
end
|
12
12
|
|
13
|
-
def set(value)
|
14
|
-
@_value = value
|
13
|
+
def set(key, value)
|
14
|
+
@_value[key] = value
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -5,6 +5,7 @@ require 'configcat/autopollingcachepolicy'
|
|
5
5
|
require 'configcat/manualpollingcachepolicy'
|
6
6
|
require 'configcat/lazyloadingcachepolicy'
|
7
7
|
require 'configcat/rolloutevaluator'
|
8
|
+
require 'configcat/datagovernance'
|
8
9
|
|
9
10
|
module ConfigCat
|
10
11
|
KeyValue = Struct.new(:key, :value)
|
@@ -19,7 +20,8 @@ module ConfigCat
|
|
19
20
|
proxy_address:nil,
|
20
21
|
proxy_port:nil,
|
21
22
|
proxy_user:nil,
|
22
|
-
proxy_pass:nil
|
23
|
+
proxy_pass:nil,
|
24
|
+
data_governance: DataGovernance::GLOBAL)
|
23
25
|
if sdk_key === nil
|
24
26
|
raise ConfigCatClientException, "SDK Key is required."
|
25
27
|
end
|
@@ -32,15 +34,15 @@ module ConfigCat
|
|
32
34
|
end
|
33
35
|
|
34
36
|
if poll_interval_seconds > 0
|
35
|
-
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "p", base_url, proxy_address, proxy_port, proxy_user, proxy_pass)
|
36
|
-
@_cache_policy = AutoPollingCachePolicy.new(@_config_fetcher, @_config_cache, poll_interval_seconds, max_init_wait_time_seconds, on_configuration_changed_callback)
|
37
|
+
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "p", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
|
38
|
+
@_cache_policy = AutoPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), poll_interval_seconds, max_init_wait_time_seconds, on_configuration_changed_callback)
|
37
39
|
else
|
38
40
|
if cache_time_to_live_seconds > 0
|
39
|
-
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "l", base_url, proxy_address, proxy_port, proxy_user, proxy_pass)
|
40
|
-
@_cache_policy = LazyLoadingCachePolicy.new(@_config_fetcher, @_config_cache, cache_time_to_live_seconds)
|
41
|
+
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "l", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
|
42
|
+
@_cache_policy = LazyLoadingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), cache_time_to_live_seconds)
|
41
43
|
else
|
42
|
-
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "m", base_url, proxy_address, proxy_port, proxy_user, proxy_pass)
|
43
|
-
@_cache_policy = ManualPollingCachePolicy.new(@_config_fetcher, @_config_cache)
|
44
|
+
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "m", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
|
45
|
+
@_cache_policy = ManualPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key())
|
44
46
|
end
|
45
47
|
end
|
46
48
|
end
|
@@ -59,7 +61,11 @@ module ConfigCat
|
|
59
61
|
if config === nil
|
60
62
|
return []
|
61
63
|
end
|
62
|
-
|
64
|
+
feature_flags = config.fetch(FEATURE_FLAGS, nil)
|
65
|
+
if feature_flags === nil
|
66
|
+
return []
|
67
|
+
end
|
68
|
+
return feature_flags.keys
|
63
69
|
end
|
64
70
|
|
65
71
|
def get_variation_id(key, default_variation_id, user=nil)
|
@@ -92,22 +98,29 @@ module ConfigCat
|
|
92
98
|
ConfigCat.logger.warn("Evaluating get_variation_id('%s') failed. Cache is empty. Returning nil." % variation_id)
|
93
99
|
return nil
|
94
100
|
end
|
95
|
-
|
96
|
-
|
97
|
-
|
101
|
+
|
102
|
+
feature_flags = config.fetch(FEATURE_FLAGS, nil)
|
103
|
+
if feature_flags === nil
|
104
|
+
ConfigCat.logger.warn("Evaluating get_key_and_value('%s') failed. Cache is empty. Returning None." % variation_id)
|
105
|
+
return nil
|
106
|
+
end
|
107
|
+
|
108
|
+
for key, value in feature_flags
|
109
|
+
if variation_id == value.fetch(VARIATION_ID, nil)
|
110
|
+
return KeyValue.new(key, value[VALUE])
|
98
111
|
end
|
99
112
|
|
100
|
-
rollout_rules = value.fetch(
|
113
|
+
rollout_rules = value.fetch(ROLLOUT_RULES, [])
|
101
114
|
for rollout_rule in rollout_rules
|
102
|
-
if variation_id == rollout_rule.fetch(
|
103
|
-
return KeyValue.new(key, rollout_rule[
|
115
|
+
if variation_id == rollout_rule.fetch(VARIATION_ID, nil)
|
116
|
+
return KeyValue.new(key, rollout_rule[VALUE])
|
104
117
|
end
|
105
118
|
end
|
106
119
|
|
107
|
-
rollout_percentage_items = value.fetch(
|
120
|
+
rollout_percentage_items = value.fetch(ROLLOUT_PERCENTAGE_ITEMS, [])
|
108
121
|
for rollout_percentage_item in rollout_percentage_items
|
109
|
-
if variation_id == rollout_percentage_item.fetch(
|
110
|
-
return KeyValue.new(key, rollout_percentage_item[
|
122
|
+
if variation_id == rollout_percentage_item.fetch(VARIATION_ID, nil)
|
123
|
+
return KeyValue.new(key, rollout_percentage_item[VALUE])
|
111
124
|
end
|
112
125
|
end
|
113
126
|
end
|
@@ -122,5 +135,11 @@ module ConfigCat
|
|
122
135
|
@_config_fetcher.close()
|
123
136
|
end
|
124
137
|
|
138
|
+
private
|
139
|
+
|
140
|
+
def _get_cache_key()
|
141
|
+
return Digest::SHA1.hexdigest("ruby_" + CONFIG_FILE_NAME + "_" + @_sdk_key)
|
142
|
+
end
|
143
|
+
|
125
144
|
end
|
126
145
|
end
|
@@ -1,13 +1,22 @@
|
|
1
1
|
require 'configcat/interfaces'
|
2
2
|
require 'configcat/version'
|
3
|
+
require 'configcat/datagovernance'
|
4
|
+
require 'configcat/constants'
|
3
5
|
require 'net/http'
|
4
6
|
require 'uri'
|
5
7
|
require 'json'
|
6
8
|
|
7
9
|
module ConfigCat
|
8
|
-
|
10
|
+
BASE_URL_GLOBAL = "https://cdn-global.configcat.com"
|
11
|
+
BASE_URL_EU_ONLY = "https://cdn-eu.configcat.com"
|
9
12
|
BASE_PATH = "configuration-files/"
|
10
|
-
BASE_EXTENSION = "/
|
13
|
+
BASE_EXTENSION = "/" + CONFIG_FILE_NAME + ".json"
|
14
|
+
|
15
|
+
class RedirectMode
|
16
|
+
NO_REDIRECT = 0
|
17
|
+
SHOULD_REDIRECT = 1
|
18
|
+
FORCE_REDIRECT = 2
|
19
|
+
end
|
11
20
|
|
12
21
|
class FetchResponse
|
13
22
|
def initialize(response)
|
@@ -32,34 +41,89 @@ module ConfigCat
|
|
32
41
|
end
|
33
42
|
|
34
43
|
class CacheControlConfigFetcher < ConfigFetcher
|
35
|
-
def initialize(sdk_key, mode, base_url=nil, proxy_address=nil, proxy_port=nil, proxy_user=nil, proxy_pass=nil
|
44
|
+
def initialize(sdk_key, mode, base_url=nil, proxy_address=nil, proxy_port=nil, proxy_user=nil, proxy_pass=nil,
|
45
|
+
data_governance=DataGovernance::GLOBAL)
|
36
46
|
@_sdk_key = sdk_key
|
47
|
+
@_proxy_address = proxy_address
|
48
|
+
@_proxy_port = proxy_port
|
49
|
+
@_proxy_user = proxy_user
|
50
|
+
@_proxy_pass = proxy_pass
|
37
51
|
@_etag = ""
|
38
52
|
@_headers = {"User-Agent" => ((("ConfigCat-Ruby/") + mode) + ("-")) + VERSION, "X-ConfigCat-UserAgent" => ((("ConfigCat-Ruby/") + mode) + ("-")) + VERSION, "Content-Type" => "application/json"}
|
39
53
|
if !base_url.equal?(nil)
|
54
|
+
@_base_url_overridden = true
|
40
55
|
@_base_url = base_url.chomp("/")
|
41
56
|
else
|
42
|
-
@
|
57
|
+
@_base_url_overridden = false
|
58
|
+
if data_governance == DataGovernance::EU_ONLY
|
59
|
+
@_base_url = BASE_URL_EU_ONLY
|
60
|
+
else
|
61
|
+
@_base_url = BASE_URL_GLOBAL
|
62
|
+
end
|
43
63
|
end
|
44
|
-
uri = URI.parse(@_base_url)
|
45
|
-
@_http = Net::HTTP.new(uri.host, uri.port, proxy_address, proxy_port, proxy_user, proxy_pass)
|
46
|
-
@_http.use_ssl = true if uri.scheme == 'https'
|
47
|
-
@_http.open_timeout = 10 # in seconds
|
48
|
-
@_http.read_timeout = 30 # in seconds
|
49
64
|
end
|
50
65
|
|
51
66
|
# Returns the FetchResponse object contains configuration json Dictionary
|
52
|
-
def get_configuration_json()
|
67
|
+
def get_configuration_json(retries=0)
|
53
68
|
ConfigCat.logger.debug "Fetching configuration from ConfigCat"
|
54
69
|
uri = URI.parse((((@_base_url + ("/")) + BASE_PATH) + @_sdk_key) + BASE_EXTENSION)
|
55
70
|
headers = @_headers
|
56
71
|
headers["If-None-Match"] = @_etag unless @_etag.empty?
|
72
|
+
_create_http()
|
57
73
|
request = Net::HTTP::Get.new(uri.request_uri, headers)
|
58
74
|
response = @_http.request(request)
|
59
75
|
etag = response["ETag"]
|
60
76
|
@_etag = etag unless etag.nil? || etag.empty?
|
61
77
|
ConfigCat.logger.debug "ConfigCat configuration json fetch response code:#{response.code} Cached:#{response['ETag']}"
|
62
|
-
|
78
|
+
fetch_response = FetchResponse.new(response)
|
79
|
+
|
80
|
+
# If there wasn't a config change, we return the response.
|
81
|
+
if !fetch_response.is_fetched()
|
82
|
+
return fetch_response
|
83
|
+
end
|
84
|
+
|
85
|
+
preferences = fetch_response.json().fetch(PREFERENCES, nil)
|
86
|
+
if preferences === nil
|
87
|
+
return fetch_response
|
88
|
+
end
|
89
|
+
|
90
|
+
base_url = preferences.fetch(BASE_URL, nil)
|
91
|
+
|
92
|
+
# If the base_url is the same as the last called one, just return the response.
|
93
|
+
if base_url.equal?(nil) || @_base_url == base_url
|
94
|
+
return fetch_response
|
95
|
+
end
|
96
|
+
|
97
|
+
redirect = preferences.fetch(REDIRECT, nil)
|
98
|
+
# If the base_url is overridden, and the redirect parameter is not 2 (force),
|
99
|
+
# the SDK should not redirect the calls and it just have to return the response.
|
100
|
+
if @_base_url_overridden && redirect != RedirectMode::FORCE_REDIRECT
|
101
|
+
return fetch_response
|
102
|
+
end
|
103
|
+
|
104
|
+
# The next call should use the base_url provided in the config json
|
105
|
+
@_base_url = base_url
|
106
|
+
|
107
|
+
# If the redirect property == 0 (redirect not needed), return the response
|
108
|
+
if redirect == RedirectMode::NO_REDIRECT
|
109
|
+
# Return the response
|
110
|
+
return fetch_response
|
111
|
+
end
|
112
|
+
|
113
|
+
# Try to download again with the new url
|
114
|
+
|
115
|
+
if redirect == RedirectMode::SHOULD_REDIRECT
|
116
|
+
ConfigCat.logger.warn("Your data_governance parameter at ConfigCatClient initialization is not in sync with your preferences on the ConfigCat Dashboard: https://app.configcat.com/organization/data-governance. Only Organization Admins can set this preference.")
|
117
|
+
end
|
118
|
+
|
119
|
+
# To prevent loops we check if we retried at least 3 times with the new base_url
|
120
|
+
if retries >= 2
|
121
|
+
ConfigCat.logger.error("Redirect loop during config.json fetch. Please contact support@configcat.com.")
|
122
|
+
return fetch_response
|
123
|
+
end
|
124
|
+
|
125
|
+
# Retry the config download with the new base_url
|
126
|
+
return get_configuration_json(retries + 1)
|
63
127
|
end
|
64
128
|
|
65
129
|
def close()
|
@@ -67,5 +131,19 @@ module ConfigCat
|
|
67
131
|
@_http = nil
|
68
132
|
end
|
69
133
|
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def _create_http()
|
138
|
+
uri = URI.parse(@_base_url)
|
139
|
+
use_ssl = true if uri.scheme == 'https'
|
140
|
+
if @_http.equal?(nil) || @_http.address != uri.host || @_http.port != uri.port || @_http.use_ssl? != use_ssl
|
141
|
+
close()
|
142
|
+
@_http = Net::HTTP.new(uri.host, uri.port, @_proxy_address, @_proxy_port, @_proxy_user, @_proxy_pass)
|
143
|
+
@_http.use_ssl = use_ssl
|
144
|
+
@_http.open_timeout = 10 # in seconds
|
145
|
+
@_http.read_timeout = 30 # in seconds
|
146
|
+
end
|
147
|
+
end
|
70
148
|
end
|
71
149
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ConfigCat
|
2
|
+
CONFIG_FILE_NAME = "config_v5"
|
3
|
+
|
4
|
+
PREFERENCES = "p"
|
5
|
+
BASE_URL = "u"
|
6
|
+
REDIRECT = "r"
|
7
|
+
|
8
|
+
FEATURE_FLAGS = "f"
|
9
|
+
VALUE = "v"
|
10
|
+
COMPARATOR = "t"
|
11
|
+
COMPARISON_ATTRIBUTE = "a"
|
12
|
+
COMPARISON_VALUE = "c"
|
13
|
+
ROLLOUT_PERCENTAGE_ITEMS = "p"
|
14
|
+
PERCENTAGE = "p"
|
15
|
+
ROLLOUT_RULES = "r"
|
16
|
+
VARIATION_ID = "i"
|
17
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module ConfigCat
|
2
|
+
class DataGovernance
|
3
|
+
# Control the location of the config.json files containing your feature flags
|
4
|
+
# and settings within the ConfigCat CDN.
|
5
|
+
# Global: Select this if your feature flags are published to all global CDN nodes.
|
6
|
+
# EuOnly: Select this if your feature flags are published to CDN nodes only in the EU.
|
7
|
+
GLOBAL = 0
|
8
|
+
EU_ONLY = 1
|
9
|
+
end
|
10
|
+
end
|
data/lib/configcat/interfaces.rb
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
require 'configcat/interfaces'
|
2
|
+
require 'configcat/constants'
|
2
3
|
require 'concurrent'
|
3
4
|
|
5
|
+
|
4
6
|
module ConfigCat
|
5
7
|
class LazyLoadingCachePolicy < CachePolicy
|
6
8
|
|
7
|
-
def initialize(config_fetcher, config_cache, cache_time_to_live_seconds=60)
|
9
|
+
def initialize(config_fetcher, config_cache, cache_key, cache_time_to_live_seconds=60)
|
8
10
|
if cache_time_to_live_seconds < 1
|
9
11
|
cache_time_to_live_seconds = 1
|
10
12
|
end
|
11
13
|
@_config_fetcher = config_fetcher
|
12
14
|
@_config_cache = config_cache
|
15
|
+
@_cache_key = cache_key
|
13
16
|
@_cache_time_to_live = cache_time_to_live_seconds
|
14
17
|
@_lock = Concurrent::ReadWriteLock.new()
|
15
18
|
@_last_updated = nil
|
@@ -20,7 +23,7 @@ module ConfigCat
|
|
20
23
|
@_lock.acquire_read_lock()
|
21
24
|
utc_now = Time.now.utc
|
22
25
|
if !@_last_updated.equal?(nil) && (@_last_updated + @_cache_time_to_live > utc_now)
|
23
|
-
config = @_config_cache.get()
|
26
|
+
config = @_config_cache.get(@_cache_key)
|
24
27
|
if !config.equal?(nil)
|
25
28
|
return config
|
26
29
|
end
|
@@ -31,7 +34,7 @@ module ConfigCat
|
|
31
34
|
force_refresh()
|
32
35
|
begin
|
33
36
|
@_lock.acquire_read_lock()
|
34
|
-
config = @_config_cache.get()
|
37
|
+
config = @_config_cache.get(@_cache_key)
|
35
38
|
return config
|
36
39
|
ensure
|
37
40
|
@_lock.release_read_lock()
|
@@ -45,7 +48,7 @@ module ConfigCat
|
|
45
48
|
configuration = configuration_response.json()
|
46
49
|
begin
|
47
50
|
@_lock.acquire_write_lock()
|
48
|
-
@_config_cache.set(configuration)
|
51
|
+
@_config_cache.set(@_cache_key, configuration)
|
49
52
|
@_last_updated = Time.now.utc
|
50
53
|
ensure
|
51
54
|
@_lock.release_write_lock()
|
@@ -1,18 +1,20 @@
|
|
1
1
|
require 'configcat/interfaces'
|
2
|
+
require 'configcat/constants'
|
2
3
|
require 'concurrent'
|
3
4
|
|
4
5
|
module ConfigCat
|
5
6
|
class ManualPollingCachePolicy < CachePolicy
|
6
|
-
def initialize(config_fetcher, config_cache)
|
7
|
+
def initialize(config_fetcher, config_cache, cache_key)
|
7
8
|
@_config_fetcher = config_fetcher
|
8
9
|
@_config_cache = config_cache
|
10
|
+
@_cache_key = cache_key
|
9
11
|
@_lock = Concurrent::ReadWriteLock.new()
|
10
12
|
end
|
11
13
|
|
12
14
|
def get()
|
13
15
|
begin
|
14
16
|
@_lock.acquire_read_lock()
|
15
|
-
config = @_config_cache.get()
|
17
|
+
config = @_config_cache.get(@_cache_key)
|
16
18
|
return config
|
17
19
|
ensure
|
18
20
|
@_lock.release_read_lock()
|
@@ -26,7 +28,7 @@ module ConfigCat
|
|
26
28
|
configuration = configuration_response.json()
|
27
29
|
begin
|
28
30
|
@_lock.acquire_write_lock()
|
29
|
-
@_config_cache.set(configuration)
|
31
|
+
@_config_cache.set(@_cache_key, configuration)
|
30
32
|
ensure
|
31
33
|
@_lock.release_write_lock()
|
32
34
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'configcat/user'
|
2
|
+
require 'configcat/constants'
|
2
3
|
require 'digest'
|
3
4
|
require 'semantic'
|
4
5
|
|
@@ -6,21 +7,18 @@ module ConfigCat
|
|
6
7
|
class RolloutEvaluator
|
7
8
|
COMPARATOR_TEXTS = ["IS ONE OF", "IS NOT ONE OF", "CONTAINS", "DOES NOT CONTAIN", "IS ONE OF (SemVer)", "IS NOT ONE OF (SemVer)", "< (SemVer)", "<= (SemVer)", "> (SemVer)", ">= (SemVer)", "= (Number)", "<> (Number)", "< (Number)", "<= (Number)", "> (Number)", ">= (Number)"]
|
8
9
|
|
9
|
-
VALUE = "v"
|
10
|
-
COMPARATOR = "t"
|
11
|
-
COMPARISON_ATTRIBUTE = "a"
|
12
|
-
COMPARISON_VALUE = "c"
|
13
|
-
ROLLOUT_PERCENTAGE_ITEMS = "p"
|
14
|
-
PERCENTAGE = "p"
|
15
|
-
ROLLOUT_RULES = "r"
|
16
|
-
VARIATION_ID = "i"
|
17
|
-
|
18
10
|
def self.evaluate(key, user, default_value, default_variation_id, config)
|
19
11
|
ConfigCat.logger.info("Evaluating get_value('%s')." % key)
|
20
12
|
|
21
|
-
|
13
|
+
feature_flags = config.fetch(FEATURE_FLAGS, nil)
|
14
|
+
if feature_flags === nil
|
15
|
+
ConfigCat.logger.error("Evaluating get_value('%s') failed. Value not found for key '%s' Returning default_value: [%s]." % [key, key, default_value.to_s])
|
16
|
+
return default_value, default_variation_id
|
17
|
+
end
|
18
|
+
|
19
|
+
setting_descriptor = feature_flags.fetch(key, nil)
|
22
20
|
if setting_descriptor === nil
|
23
|
-
ConfigCat.logger.error("Evaluating get_value('%s') failed. Value not found for key '%s'. Returning default_value: [%s]. Here are the available keys: %s" % [key, key, default_value.to_s,
|
21
|
+
ConfigCat.logger.error("Evaluating get_value('%s') failed. Value not found for key '%s'. Returning default_value: [%s]. Here are the available keys: %s" % [key, key, default_value.to_s, feature_flags.keys.join(", ")])
|
24
22
|
return default_value, default_variation_id
|
25
23
|
end
|
26
24
|
|
data/lib/configcat/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: configcat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ConfigCat
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -110,6 +110,8 @@ files:
|
|
110
110
|
- lib/configcat/configcache.rb
|
111
111
|
- lib/configcat/configcatclient.rb
|
112
112
|
- lib/configcat/configfetcher.rb
|
113
|
+
- lib/configcat/constants.rb
|
114
|
+
- lib/configcat/datagovernance.rb
|
113
115
|
- lib/configcat/interfaces.rb
|
114
116
|
- lib/configcat/lazyloadingcachepolicy.rb
|
115
117
|
- lib/configcat/manualpollingcachepolicy.rb
|