configcat 3.1.0 → 5.0.1

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
2
  SHA256:
3
- metadata.gz: b842d2ff2f62e6a6c3dbe2ddab53c561e4b1db93f3928ce805044127cd2d7819
4
- data.tar.gz: 6d64d084c4a732d26d54879d914f4e9ce1722b9e73fee2aa4161cc5503e152d7
3
+ metadata.gz: 980bb5bf4d92b6a479a10727b25ea488461317569f3b60943642db8fa9960898
4
+ data.tar.gz: 9de2dc2d9fe881372f70e862bb72af396a9ea99b81defabf3c82e1b19423078e
5
5
  SHA512:
6
- metadata.gz: 83a7d19dc642e492bb5443a1fc42f0f35db8f5278f02582848e8677133f4450faa41a1a30b158ccdca58bc5396cad109b914fa4851e4db74dcf03df1f5129d00
7
- data.tar.gz: 2e79ed9965f3c9da2f8afd9fed4636b6d349b0bda09fdfb0d8398b6e4334a458713114d23083fc5f611878ea02801c5e8ea1e73fad54f6e580ef1c098e8f9d7c
6
+ metadata.gz: 7d1e19a4729ef760d686a4e47c2efd2d82464adfa652caf2782b4ebcfefc3edc7f27baddfdcdd9e66264ee0cd13d9806a51b8c171d74cdd21b6088073aff0368
7
+ data.tar.gz: 1640d5a7a23f9af9461ee38bfb6a789cbed6d898c582bb325f18c27b20dec7944c60dbbe9dc749800a0325be844a252225dfb769f89acd157f644bb1d1a93ef9
@@ -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()
@@ -80,6 +82,9 @@ module ConfigCat
80
82
  if !@_initialized && !old_configuration.equal?(nil)
81
83
  @_initialized = true
82
84
  end
85
+ rescue Timeout::Error => e
86
+ ConfigCat.logger.error("Request timed out. Timeout values: [open: %ss, read: %ss]" %
87
+ [@_config_fetcher.get_open_timeout(), @_config_fetcher.get_read_timeout()])
83
88
  rescue Exception => e
84
89
  ConfigCat.logger.error("Double-check your SDK Key at https://app.configcat.com/sdkkey.")
85
90
  ConfigCat.logger.error "threw exception #{e.class}:'#{e}'"
@@ -3,15 +3,15 @@ require 'configcat/interfaces'
3
3
  module ConfigCat
4
4
  class InMemoryConfigCache < ConfigCache
5
5
  def initialize()
6
- @_value = nil
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,25 +5,43 @@ require 'configcat/autopollingcachepolicy'
5
5
  require 'configcat/manualpollingcachepolicy'
6
6
  require 'configcat/lazyloadingcachepolicy'
7
7
  require 'configcat/rolloutevaluator'
8
+ require 'configcat/datagovernance'
9
+
8
10
 
9
11
  module ConfigCat
10
12
  KeyValue = Struct.new(:key, :value)
11
13
  class ConfigCatClient
14
+ @@sdk_keys = []
15
+
12
16
  def initialize(sdk_key,
13
- poll_interval_seconds:60,
14
- max_init_wait_time_seconds:5,
15
- on_configuration_changed_callback:nil,
16
- cache_time_to_live_seconds:60,
17
- config_cache_class:nil,
18
- base_url:nil,
19
- proxy_address:nil,
20
- proxy_port:nil,
21
- proxy_user:nil,
22
- proxy_pass:nil)
17
+ poll_interval_seconds: 60,
18
+ max_init_wait_time_seconds: 5,
19
+ on_configuration_changed_callback: nil,
20
+ cache_time_to_live_seconds: 60,
21
+ config_cache_class: nil,
22
+ base_url: nil,
23
+ proxy_address: nil,
24
+ proxy_port: nil,
25
+ proxy_user: nil,
26
+ proxy_pass: nil,
27
+ open_timeout: 10,
28
+ read_timeout: 30,
29
+ flag_overrides: nil,
30
+ data_governance: DataGovernance::GLOBAL)
23
31
  if sdk_key === nil
24
32
  raise ConfigCatClientException, "SDK Key is required."
25
33
  end
34
+
35
+ if @@sdk_keys.include?(sdk_key)
36
+ ConfigCat.logger.warn("A ConfigCat Client is already initialized with sdk_key %s. "\
37
+ "We strongly recommend you to use the ConfigCat Client as "\
38
+ "a Singleton object in your application." % sdk_key)
39
+ else
40
+ @@sdk_keys.push(sdk_key)
41
+ end
42
+
26
43
  @_sdk_key = sdk_key
44
+ @_override_data_source = flag_overrides
27
45
 
28
46
  if config_cache_class
29
47
  @_config_cache = config_cache_class.new()
@@ -31,23 +49,35 @@ module ConfigCat
31
49
  @_config_cache = InMemoryConfigCache.new()
32
50
  end
33
51
 
34
- 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)
52
+ if !@_override_data_source.equal?(nil) && @_override_data_source.get_behaviour() == OverrideBehaviour::LOCAL_ONLY
53
+ @_config_fetcher = nil
54
+ @_cache_policy = nil
55
+ elsif poll_interval_seconds > 0
56
+ @_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "p", base_url: base_url,
57
+ proxy_address: proxy_address, proxy_port: proxy_port, proxy_user: proxy_user, proxy_pass: proxy_pass,
58
+ open_timeout: open_timeout, read_timeout: read_timeout,
59
+ data_governance: data_governance)
60
+ @_cache_policy = AutoPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), poll_interval_seconds, max_init_wait_time_seconds, on_configuration_changed_callback)
61
+ elsif cache_time_to_live_seconds > 0
62
+ @_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "l", base_url: base_url,
63
+ proxy_address: proxy_address, proxy_port: proxy_port, proxy_user: proxy_user, proxy_pass: proxy_pass,
64
+ open_timeout: open_timeout, read_timeout: read_timeout,
65
+ data_governance: data_governance)
66
+ @_cache_policy = LazyLoadingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), cache_time_to_live_seconds)
37
67
  else
38
- 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
- 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
- end
68
+ @_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "m", base_url: base_url,
69
+ proxy_address: proxy_address, proxy_port: proxy_port, proxy_user: proxy_user, proxy_pass: proxy_pass,
70
+ open_timeout: open_timeout, read_timeout: read_timeout,
71
+ data_governance: data_governance)
72
+ @_cache_policy = ManualPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key())
45
73
  end
46
74
  end
47
75
 
48
76
  def get_value(key, default_value, user=nil)
49
- config = @_cache_policy.get()
77
+ config = _get_settings()
50
78
  if config === nil
79
+ ConfigCat.logger.warn("Evaluating get_value('%s') failed. Cache is empty. "\
80
+ "Returning default_value in your get_value call: [%s]." % [key, default_value.to_s])
51
81
  return default_value
52
82
  end
53
83
  value, variation_id = RolloutEvaluator.evaluate(key, user, default_value, nil, config)
@@ -55,15 +85,19 @@ module ConfigCat
55
85
  end
56
86
 
57
87
  def get_all_keys()
58
- config = @_cache_policy.get()
88
+ config = _get_settings()
59
89
  if config === nil
60
90
  return []
61
91
  end
62
- return config.keys
92
+ feature_flags = config.fetch(FEATURE_FLAGS, nil)
93
+ if feature_flags === nil
94
+ return []
95
+ end
96
+ return feature_flags.keys
63
97
  end
64
98
 
65
99
  def get_variation_id(key, default_variation_id, user=nil)
66
- config = @_cache_policy.get()
100
+ config = _get_settings()
67
101
  if config === nil
68
102
  ConfigCat.logger.warn("Evaluating get_variation_id('%s') failed. Cache is empty. "\
69
103
  "Returning default_variation_id in your get_variation_id call: [%s]." %
@@ -87,39 +121,91 @@ module ConfigCat
87
121
  end
88
122
 
89
123
  def get_key_and_value(variation_id)
90
- config = @_cache_policy.get()
124
+ config = _get_settings()
91
125
  if config === nil
92
126
  ConfigCat.logger.warn("Evaluating get_variation_id('%s') failed. Cache is empty. Returning nil." % variation_id)
93
127
  return nil
94
128
  end
95
- for key, value in config
96
- if variation_id == value.fetch(RolloutEvaluator::VARIATION_ID, nil)
97
- return KeyValue.new(key, value[RolloutEvaluator::VALUE])
129
+
130
+ feature_flags = config.fetch(FEATURE_FLAGS, nil)
131
+ if feature_flags === nil
132
+ ConfigCat.logger.warn("Evaluating get_key_and_value('%s') failed. Cache is empty. Returning None." % variation_id)
133
+ return nil
134
+ end
135
+
136
+ for key, value in feature_flags
137
+ if variation_id == value.fetch(VARIATION_ID, nil)
138
+ return KeyValue.new(key, value[VALUE])
98
139
  end
99
140
 
100
- rollout_rules = value.fetch(RolloutEvaluator::ROLLOUT_RULES, [])
141
+ rollout_rules = value.fetch(ROLLOUT_RULES, [])
101
142
  for rollout_rule in rollout_rules
102
- if variation_id == rollout_rule.fetch(RolloutEvaluator::VARIATION_ID, nil)
103
- return KeyValue.new(key, rollout_rule[RolloutEvaluator::VALUE])
143
+ if variation_id == rollout_rule.fetch(VARIATION_ID, nil)
144
+ return KeyValue.new(key, rollout_rule[VALUE])
104
145
  end
105
146
  end
106
147
 
107
- rollout_percentage_items = value.fetch(RolloutEvaluator::ROLLOUT_PERCENTAGE_ITEMS, [])
148
+ rollout_percentage_items = value.fetch(ROLLOUT_PERCENTAGE_ITEMS, [])
108
149
  for rollout_percentage_item in rollout_percentage_items
109
- if variation_id == rollout_percentage_item.fetch(RolloutEvaluator::VARIATION_ID, nil)
110
- return KeyValue.new(key, rollout_percentage_item[RolloutEvaluator::VALUE])
150
+ if variation_id == rollout_percentage_item.fetch(VARIATION_ID, nil)
151
+ return KeyValue.new(key, rollout_percentage_item[VALUE])
111
152
  end
112
153
  end
113
154
  end
114
155
  end
115
156
 
157
+ def get_all_values(user: nil)
158
+ keys = get_all_keys()
159
+ all_values = {}
160
+ for key in keys
161
+ value = get_value(key, nil, user)
162
+ if !value.equal?(nil)
163
+ all_values[key] = value
164
+ end
165
+ end
166
+ return all_values
167
+ end
168
+
116
169
  def force_refresh()
117
170
  @_cache_policy.force_refresh()
118
171
  end
119
172
 
120
173
  def stop()
121
- @_cache_policy.stop()
122
- @_config_fetcher.close()
174
+ @_cache_policy.stop() if @_cache_policy
175
+ @_config_fetcher.close() if @_config_fetcher
176
+ @@sdk_keys.delete(@_sdk_key)
177
+ end
178
+
179
+ private
180
+
181
+ def _get_settings()
182
+ if !@_override_data_source.nil?
183
+ behaviour = @_override_data_source.get_behaviour()
184
+ if behaviour == OverrideBehaviour::LOCAL_ONLY
185
+ return @_override_data_source.get_overrides()
186
+ elsif behaviour == OverrideBehaviour::REMOTE_OVER_LOCAL
187
+ remote_settings = @_cache_policy.get()
188
+ local_settings = @_override_data_source.get_overrides()
189
+ result = local_settings.clone()
190
+ if remote_settings.key?(FEATURE_FLAGS) && local_settings.key?(FEATURE_FLAGS)
191
+ result[FEATURE_FLAGS] = result[FEATURE_FLAGS].merge(remote_settings[FEATURE_FLAGS])
192
+ end
193
+ return result
194
+ elsif behaviour == OverrideBehaviour::LOCAL_OVER_REMOTE
195
+ remote_settings = @_cache_policy.get()
196
+ local_settings = @_override_data_source.get_overrides()
197
+ result = remote_settings.clone()
198
+ if remote_settings.key?(FEATURE_FLAGS) && local_settings.key?(FEATURE_FLAGS)
199
+ result[FEATURE_FLAGS] = result[FEATURE_FLAGS].merge(local_settings[FEATURE_FLAGS])
200
+ end
201
+ return result
202
+ end
203
+ end
204
+ return @_cache_policy.get()
205
+ end
206
+
207
+ def _get_cache_key()
208
+ return Digest::SHA1.hexdigest("ruby_" + CONFIG_FILE_NAME + "_" + @_sdk_key)
123
209
  end
124
210
 
125
211
  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
- BASE_URL = "https://cdn.configcat.com"
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 = "/config_v4.json"
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,100 @@ 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
+ open_timeout:10, read_timeout:30,
46
+ data_governance:DataGovernance::GLOBAL)
36
47
  @_sdk_key = sdk_key
48
+ @_proxy_address = proxy_address
49
+ @_proxy_port = proxy_port
50
+ @_proxy_user = proxy_user
51
+ @_proxy_pass = proxy_pass
52
+ @_open_timeout = open_timeout
53
+ @_read_timeout = read_timeout
37
54
  @_etag = ""
38
55
  @_headers = {"User-Agent" => ((("ConfigCat-Ruby/") + mode) + ("-")) + VERSION, "X-ConfigCat-UserAgent" => ((("ConfigCat-Ruby/") + mode) + ("-")) + VERSION, "Content-Type" => "application/json"}
39
56
  if !base_url.equal?(nil)
57
+ @_base_url_overridden = true
40
58
  @_base_url = base_url.chomp("/")
41
59
  else
42
- @_base_url = BASE_URL
60
+ @_base_url_overridden = false
61
+ if data_governance == DataGovernance::EU_ONLY
62
+ @_base_url = BASE_URL_EU_ONLY
63
+ else
64
+ @_base_url = BASE_URL_GLOBAL
65
+ end
43
66
  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
67
+ end
68
+
69
+ def get_open_timeout()
70
+ return @_open_timeout
71
+ end
72
+
73
+ def get_read_timeout()
74
+ return @_read_timeout
49
75
  end
50
76
 
51
77
  # Returns the FetchResponse object contains configuration json Dictionary
52
- def get_configuration_json()
78
+ def get_configuration_json(retries=0)
53
79
  ConfigCat.logger.debug "Fetching configuration from ConfigCat"
54
80
  uri = URI.parse((((@_base_url + ("/")) + BASE_PATH) + @_sdk_key) + BASE_EXTENSION)
55
81
  headers = @_headers
56
82
  headers["If-None-Match"] = @_etag unless @_etag.empty?
83
+ _create_http()
57
84
  request = Net::HTTP::Get.new(uri.request_uri, headers)
58
85
  response = @_http.request(request)
59
86
  etag = response["ETag"]
60
87
  @_etag = etag unless etag.nil? || etag.empty?
61
88
  ConfigCat.logger.debug "ConfigCat configuration json fetch response code:#{response.code} Cached:#{response['ETag']}"
62
- return FetchResponse.new(response)
89
+ fetch_response = FetchResponse.new(response)
90
+
91
+ # If there wasn't a config change, we return the response.
92
+ if !fetch_response.is_fetched()
93
+ return fetch_response
94
+ end
95
+
96
+ preferences = fetch_response.json().fetch(PREFERENCES, nil)
97
+ if preferences === nil
98
+ return fetch_response
99
+ end
100
+
101
+ base_url = preferences.fetch(BASE_URL, nil)
102
+
103
+ # If the base_url is the same as the last called one, just return the response.
104
+ if base_url.equal?(nil) || @_base_url == base_url
105
+ return fetch_response
106
+ end
107
+
108
+ redirect = preferences.fetch(REDIRECT, nil)
109
+ # If the base_url is overridden, and the redirect parameter is not 2 (force),
110
+ # the SDK should not redirect the calls and it just have to return the response.
111
+ if @_base_url_overridden && redirect != RedirectMode::FORCE_REDIRECT
112
+ return fetch_response
113
+ end
114
+
115
+ # The next call should use the base_url provided in the config json
116
+ @_base_url = base_url
117
+
118
+ # If the redirect property == 0 (redirect not needed), return the response
119
+ if redirect == RedirectMode::NO_REDIRECT
120
+ # Return the response
121
+ return fetch_response
122
+ end
123
+
124
+ # Try to download again with the new url
125
+
126
+ if redirect == RedirectMode::SHOULD_REDIRECT
127
+ 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.")
128
+ end
129
+
130
+ # To prevent loops we check if we retried at least 3 times with the new base_url
131
+ if retries >= 2
132
+ ConfigCat.logger.error("Redirect loop during config.json fetch. Please contact support@configcat.com.")
133
+ return fetch_response
134
+ end
135
+
136
+ # Retry the config download with the new base_url
137
+ return get_configuration_json(retries + 1)
63
138
  end
64
139
 
65
140
  def close()
@@ -67,5 +142,19 @@ module ConfigCat
67
142
  @_http = nil
68
143
  end
69
144
  end
145
+
146
+ private
147
+
148
+ def _create_http()
149
+ uri = URI.parse(@_base_url)
150
+ use_ssl = true if uri.scheme == 'https'
151
+ if @_http.equal?(nil) || @_http.address != uri.host || @_http.port != uri.port || @_http.use_ssl? != use_ssl
152
+ close()
153
+ @_http = Net::HTTP.new(uri.host, uri.port, @_proxy_address, @_proxy_port, @_proxy_user, @_proxy_pass)
154
+ @_http.use_ssl = use_ssl
155
+ @_http.open_timeout = @_open_timeout
156
+ @_http.read_timeout = @_read_timeout
157
+ end
158
+ end
70
159
  end
71
160
  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
@@ -23,13 +23,13 @@ module ConfigCat
23
23
  # Config cache interface
24
24
  #
25
25
 
26
- def get()
26
+ def get(key)
27
27
  #
28
28
  # :returns the config json object from the cache
29
29
  #
30
30
  end
31
31
 
32
- def set(value)
32
+ def set(key, value)
33
33
  #
34
34
  # Sets the config json cache.
35
35
  #
@@ -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()
@@ -0,0 +1,20 @@
1
+ require 'configcat/overridedatasource'
2
+ require 'configcat/constants'
3
+
4
+
5
+ module ConfigCat
6
+ class LocalDictionaryDataSource < OverrideDataSource
7
+ def initialize(source, override_behaviour)
8
+ super(override_behaviour)
9
+ dictionary = {}
10
+ source.each do |key, value|
11
+ dictionary[key] = {VALUE => value}
12
+ end
13
+ @_settings = {FEATURE_FLAGS => dictionary}
14
+ end
15
+
16
+ def get_overrides()
17
+ return @_settings
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,49 @@
1
+ require 'configcat/overridedatasource'
2
+ require 'configcat/constants'
3
+
4
+
5
+ module ConfigCat
6
+ class LocalFileDataSource < OverrideDataSource
7
+ def initialize(file_path, override_behaviour)
8
+ super(override_behaviour)
9
+ if File.exists?(file_path)
10
+ ConfigCat.logger.error("The file '%s' does not exists." % file_path)
11
+ end
12
+ @_file_path = file_path
13
+ @_settings = nil
14
+ @_cached_file_stamp = 0
15
+ end
16
+
17
+ def get_overrides()
18
+ reload_file_content()
19
+ return @_settings
20
+ end
21
+
22
+ private
23
+
24
+ def reload_file_content()
25
+ begin
26
+ stamp = File.mtime(@_file_path)
27
+ if stamp != @_cached_file_stamp
28
+ @_cached_file_stamp = stamp
29
+ file = File.read(@_file_path)
30
+ data = JSON.parse(file)
31
+ if data.key?("flags")
32
+ dictionary = {}
33
+ source = data["flags"]
34
+ source.each do |key, value|
35
+ dictionary[key] = {VALUE => value}
36
+ end
37
+ @_settings = {FEATURE_FLAGS => dictionary}
38
+ else
39
+ @_settings = data
40
+ end
41
+ end
42
+ rescue JSON::ParserError => e
43
+ ConfigCat.logger.error("Could not decode json from file %s. %s" % [@_file_path, e.to_s])
44
+ rescue Exception => e
45
+ ConfigCat.logger.error("Could not read the content of the file %s. %s" % [@_file_path, e.to_s])
46
+ end
47
+ end
48
+ end
49
+ end
@@ -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
@@ -0,0 +1,32 @@
1
+ module ConfigCat
2
+ class OverrideBehaviour
3
+ # When evaluating values, the SDK will not use feature flags & settings from the ConfigCat CDN, but it will use
4
+ # all feature flags & settings that are loaded from local-override sources.
5
+ LOCAL_ONLY = 0
6
+
7
+ # When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN,
8
+ # plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is
9
+ # defined both in the fetched and the local-override source then the local-override version will take precedence.
10
+ LOCAL_OVER_REMOTE = 1
11
+
12
+ # When evaluating values, the SDK will use all feature flags & settings that are downloaded from the ConfigCat CDN,
13
+ # plus all feature flags & settings that are loaded from local-override sources. If a feature flag or a setting is
14
+ # defined both in the fetched and the local-override source then the fetched version will take precedence.
15
+ REMOTE_OVER_LOCAL = 2
16
+ end
17
+
18
+ class OverrideDataSource
19
+ def initialize(override_behaviour)
20
+ @_override_behaviour = override_behaviour
21
+ end
22
+
23
+ def get_behaviour()
24
+ return @_override_behaviour
25
+ end
26
+
27
+ def get_overrides()
28
+ # :returns the override dictionary
29
+ return {}
30
+ end
31
+ end
32
+ 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
- setting_descriptor = config.fetch(key, nil)
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, config.keys.join(", ")])
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
 
@@ -41,132 +39,142 @@ module ConfigCat
41
39
  return return_value, return_variation_id
42
40
  end
43
41
 
44
- ConfigCat.logger.info("User object:\n%s" % user.to_s)
42
+ log_entries = ["Evaluating get_value('%s')." % key, "User object:\n%s" % user.to_s]
45
43
 
46
- # Evaluate targeting rules
47
- for rollout_rule in rollout_rules
48
- comparison_attribute = rollout_rule.fetch(COMPARISON_ATTRIBUTE)
49
- comparison_value = rollout_rule.fetch(COMPARISON_VALUE, nil)
50
- comparator = rollout_rule.fetch(COMPARATOR, nil)
44
+ begin
45
+ # Evaluate targeting rules
46
+ for rollout_rule in rollout_rules
47
+ comparison_attribute = rollout_rule.fetch(COMPARISON_ATTRIBUTE)
48
+ comparison_value = rollout_rule.fetch(COMPARISON_VALUE, nil)
49
+ comparator = rollout_rule.fetch(COMPARATOR, nil)
51
50
 
52
- user_value = user.get_attribute(comparison_attribute)
53
- if user_value === nil || !user_value
54
- ConfigCat.logger.info(format_no_match_rule(comparison_attribute, user_value, comparator, comparison_value))
55
- next
56
- end
51
+ user_value = user.get_attribute(comparison_attribute)
52
+ if user_value === nil || !user_value
53
+ log_entries.push(format_no_match_rule(comparison_attribute, user_value, comparator, comparison_value))
54
+ next
55
+ end
57
56
 
58
- value = rollout_rule.fetch(VALUE, nil)
59
- variation_id = rollout_rule.fetch(VARIATION_ID, default_variation_id)
57
+ value = rollout_rule.fetch(VALUE, nil)
58
+ variation_id = rollout_rule.fetch(VARIATION_ID, default_variation_id)
60
59
 
61
- # IS ONE OF
62
- if comparator == 0
63
- if comparison_value.to_s.split(",").map { |x| x.strip() }.include?(user_value.to_s)
64
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
65
- return value, variation_id
66
- end
67
- # IS NOT ONE OF
68
- elsif comparator == 1
69
- if !comparison_value.to_s.split(",").map { |x| x.strip() }.include?(user_value.to_s)
70
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
71
- return value, variation_id
72
- end
73
- # CONTAINS
74
- elsif comparator == 2
75
- if user_value.to_s.include?(comparison_value.to_s)
76
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
77
- return value, variation_id
78
- end
79
- # DOES NOT CONTAIN
80
- elsif comparator == 3
81
- if !user_value.to_s.include?(comparison_value.to_s)
82
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
83
- return value, variation_id
84
- end
85
- # IS ONE OF, IS NOT ONE OF (Semantic version)
86
- elsif (4 <= comparator) && (comparator <= 5)
87
- begin
88
- match = false
89
- user_value_version = Semantic::Version.new(user_value.to_s.strip())
90
- ((comparison_value.to_s.split(",").map { |x| x.strip() }).reject { |c| c.empty? }).each { |x|
91
- version = Semantic::Version.new(x)
92
- match = (user_value_version == version) || match
93
- }
94
- if match && comparator == 4 || !match && comparator == 5
95
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
60
+ # IS ONE OF
61
+ if comparator == 0
62
+ if comparison_value.to_s.split(",").map { |x| x.strip() }.include?(user_value.to_s)
63
+ log_entries.push(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
96
64
  return value, variation_id
97
65
  end
98
- rescue ArgumentError => e
99
- ConfigCat.logger.warn(format_validation_error_rule(comparison_attribute, user_value, comparator, comparison_value, e.to_s))
100
- next
101
- end
102
- # LESS THAN, LESS THAN OR EQUALS TO, GREATER THAN, GREATER THAN OR EQUALS TO (Semantic version)
103
- elsif (6 <= comparator) && (comparator <= 9)
104
- begin
105
- user_value_version = Semantic::Version.new(user_value.to_s.strip())
106
- comparison_value_version = Semantic::Version.new(comparison_value.to_s.strip())
107
- if (comparator == 6 && user_value_version < comparison_value_version) ||
108
- (comparator == 7 && user_value_version <= comparison_value_version) ||
109
- (comparator == 8 && user_value_version > comparison_value_version) ||
110
- (comparator == 9 && user_value_version >= comparison_value_version)
111
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
66
+ # IS NOT ONE OF
67
+ elsif comparator == 1
68
+ if !comparison_value.to_s.split(",").map { |x| x.strip() }.include?(user_value.to_s)
69
+ log_entries.push(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
112
70
  return value, variation_id
113
71
  end
114
- rescue ArgumentError => e
115
- ConfigCat.logger.warn(format_validation_error_rule(comparison_attribute, user_value, comparator, comparison_value, e.to_s))
116
- next
117
- end
118
- elsif (10 <= comparator) && (comparator <= 15)
119
- begin
120
- user_value_float = Float(user_value.to_s.gsub(",", "."))
121
- comparison_value_float = Float(comparison_value.to_s.gsub(",", "."))
122
- if (comparator == 10 && user_value_float == comparison_value_float) ||
123
- (comparator == 11 && user_value_float != comparison_value_float) ||
124
- (comparator == 12 && user_value_float < comparison_value_float) ||
125
- (comparator == 13 && user_value_float <= comparison_value_float) ||
126
- (comparator == 14 && user_value_float > comparison_value_float) ||
127
- (comparator == 15 && user_value_float >= comparison_value_float)
128
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
72
+ # CONTAINS
73
+ elsif comparator == 2
74
+ if user_value.to_s.include?(comparison_value.to_s)
75
+ log_entries.push(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
76
+ return value, variation_id
77
+ end
78
+ # DOES NOT CONTAIN
79
+ elsif comparator == 3
80
+ if !user_value.to_s.include?(comparison_value.to_s)
81
+ log_entries.push(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
82
+ return value, variation_id
83
+ end
84
+ # IS ONE OF, IS NOT ONE OF (Semantic version)
85
+ elsif (4 <= comparator) && (comparator <= 5)
86
+ begin
87
+ match = false
88
+ user_value_version = Semantic::Version.new(user_value.to_s.strip())
89
+ ((comparison_value.to_s.split(",").map { |x| x.strip() }).reject { |c| c.empty? }).each { |x|
90
+ version = Semantic::Version.new(x)
91
+ match = (user_value_version == version) || match
92
+ }
93
+ if match && comparator == 4 || !match && comparator == 5
94
+ log_entries.push(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
95
+ return value, variation_id
96
+ end
97
+ rescue ArgumentError => e
98
+ message = format_validation_error_rule(comparison_attribute, user_value, comparator, comparison_value, e.to_s)
99
+ ConfigCat.logger.warn(message)
100
+ log_entries.push(message)
101
+ next
102
+ end
103
+ # LESS THAN, LESS THAN OR EQUALS TO, GREATER THAN, GREATER THAN OR EQUALS TO (Semantic version)
104
+ elsif (6 <= comparator) && (comparator <= 9)
105
+ begin
106
+ user_value_version = Semantic::Version.new(user_value.to_s.strip())
107
+ comparison_value_version = Semantic::Version.new(comparison_value.to_s.strip())
108
+ if (comparator == 6 && user_value_version < comparison_value_version) ||
109
+ (comparator == 7 && user_value_version <= comparison_value_version) ||
110
+ (comparator == 8 && user_value_version > comparison_value_version) ||
111
+ (comparator == 9 && user_value_version >= comparison_value_version)
112
+ log_entries.push(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
113
+ return value, variation_id
114
+ end
115
+ rescue ArgumentError => e
116
+ message = format_validation_error_rule(comparison_attribute, user_value, comparator, comparison_value, e.to_s)
117
+ ConfigCat.logger.warn(message)
118
+ log_entries.push(message)
119
+ next
120
+ end
121
+ elsif (10 <= comparator) && (comparator <= 15)
122
+ begin
123
+ user_value_float = Float(user_value.to_s.gsub(",", "."))
124
+ comparison_value_float = Float(comparison_value.to_s.gsub(",", "."))
125
+ if (comparator == 10 && user_value_float == comparison_value_float) ||
126
+ (comparator == 11 && user_value_float != comparison_value_float) ||
127
+ (comparator == 12 && user_value_float < comparison_value_float) ||
128
+ (comparator == 13 && user_value_float <= comparison_value_float) ||
129
+ (comparator == 14 && user_value_float > comparison_value_float) ||
130
+ (comparator == 15 && user_value_float >= comparison_value_float)
131
+ log_entries.push(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
132
+ return value, variation_id
133
+ end
134
+ rescue Exception => e
135
+ message = format_validation_error_rule(comparison_attribute, user_value, comparator, comparison_value, e.to_s)
136
+ ConfigCat.logger.warn(message)
137
+ log_entries.push(message)
138
+ next
139
+ end
140
+ # IS ONE OF (Sensitive)
141
+ elsif comparator == 16
142
+ if comparison_value.to_s.split(",").map { |x| x.strip() }.include?(Digest::SHA1.hexdigest(user_value).to_s)
143
+ log_entries.push(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
144
+ return value, variation_id
145
+ end
146
+ # IS NOT ONE OF (Sensitive)
147
+ elsif comparator == 17
148
+ if !comparison_value.to_s.split(",").map { |x| x.strip() }.include?(Digest::SHA1.hexdigest(user_value).to_s)
149
+ log_entries.push(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
129
150
  return value, variation_id
130
151
  end
131
- rescue Exception => e
132
- ConfigCat.logger.warn(format_validation_error_rule(comparison_attribute, user_value, comparator, comparison_value, e.to_s))
133
- next
134
- end
135
- # IS ONE OF (Sensitive)
136
- elsif comparator == 16
137
- if comparison_value.to_s.split(",").map { |x| x.strip() }.include?(Digest::SHA1.hexdigest(user_value).to_s)
138
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
139
- return value, variation_id
140
- end
141
- # IS NOT ONE OF (Sensitive)
142
- elsif comparator == 17
143
- if !comparison_value.to_s.split(",").map { |x| x.strip() }.include?(Digest::SHA1.hexdigest(user_value).to_s)
144
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
145
- return value, variation_id
146
152
  end
153
+ log_entries.push(format_no_match_rule(comparison_attribute, user_value, comparator, comparison_value))
147
154
  end
148
- ConfigCat.logger.info(format_no_match_rule(comparison_attribute, user_value, comparator, comparison_value))
149
- end
150
155
 
151
- if rollout_percentage_items.size > 0
152
- user_key = user.get_identifier()
153
- hash_candidate = ("%s%s" % [key, user_key]).encode("utf-8")
154
- hash_val = Digest::SHA1.hexdigest(hash_candidate)[0...7].to_i(base=16) % 100
155
- bucket = 0
156
- for rollout_percentage_item in rollout_percentage_items || []
157
- bucket += rollout_percentage_item.fetch(PERCENTAGE, 0)
158
- if hash_val < bucket
159
- percentage_value = rollout_percentage_item.fetch(VALUE, nil)
160
- variation_id = rollout_percentage_item.fetch(VARIATION_ID, default_variation_id)
161
- ConfigCat.logger.info("Evaluating %% options. Returning %s" % percentage_value)
162
- return percentage_value, variation_id
156
+ if rollout_percentage_items.size > 0
157
+ user_key = user.get_identifier()
158
+ hash_candidate = ("%s%s" % [key, user_key]).encode("utf-8")
159
+ hash_val = Digest::SHA1.hexdigest(hash_candidate)[0...7].to_i(base=16) % 100
160
+ bucket = 0
161
+ for rollout_percentage_item in rollout_percentage_items || []
162
+ bucket += rollout_percentage_item.fetch(PERCENTAGE, 0)
163
+ if hash_val < bucket
164
+ percentage_value = rollout_percentage_item.fetch(VALUE, nil)
165
+ variation_id = rollout_percentage_item.fetch(VARIATION_ID, default_variation_id)
166
+ log_entries.push("Evaluating %% options. Returning %s" % percentage_value)
167
+ return percentage_value, variation_id
168
+ end
163
169
  end
164
170
  end
171
+ return_value = setting_descriptor.fetch(VALUE, default_value)
172
+ return_variation_id = setting_descriptor.fetch(VARIATION_ID, default_variation_id)
173
+ log_entries.push("Returning %s" % return_value)
174
+ return return_value, return_variation_id
175
+ ensure
176
+ ConfigCat.logger.info(log_entries.join("\n"))
165
177
  end
166
- return_value = setting_descriptor.fetch(VALUE, default_value)
167
- return_variation_id = setting_descriptor.fetch(VARIATION_ID, default_variation_id)
168
- ConfigCat.logger.info("Returning %s" % return_value)
169
- return return_value, return_variation_id
170
178
  end
171
179
 
172
180
  private
@@ -32,6 +32,25 @@ module ConfigCat
32
32
  end
33
33
  return nil
34
34
  end
35
+
36
+ def to_s()
37
+ r = %Q({\n "Identifier": "#{@__identifier}")
38
+ if !@__data["Email"].equal?(nil)
39
+ r += %Q(,\n "Email": "#{@__data["Email"]}")
40
+ end
41
+ if !@__data["Country"].equal?(nil)
42
+ r += %Q(,\n "Country": "#{@__data["Country"]}")
43
+ end
44
+ if !@__custom.equal?(nil)
45
+ r += %Q(,\n "Custom": {)
46
+ for customField in @__custom
47
+ r += %Q(\n "#{customField}": "#{@__custom[customField]}",)
48
+ end
49
+ r += "\n }"
50
+ end
51
+ r += "\n}"
52
+ return r
53
+ end
35
54
  end
36
55
 
37
56
  end
@@ -1,3 +1,3 @@
1
1
  module ConfigCat
2
- VERSION = "3.1.0"
2
+ VERSION = "5.0.1"
3
3
  end
data/lib/configcat.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'configcat/interfaces'
2
+ require 'configcat/localdictionarydatasource'
3
+ require 'configcat/localfiledatasource'
2
4
  require 'configcat/configcatclient'
3
5
  require 'configcat/user'
4
6
  require 'logger'
@@ -10,13 +12,17 @@ module ConfigCat
10
12
  attr_accessor :logger
11
13
  end
12
14
 
13
- def ConfigCat.create_client(sdk_key)
15
+ def ConfigCat.create_client(sdk_key, data_governance: DataGovernance::GLOBAL)
14
16
  #
15
17
  # Create an instance of ConfigCatClient and setup Auto Poll mode with default options
16
18
  #
17
19
  # :param sdk_key: ConfigCat SDK Key to access your configuration.
20
+ # :param data_governance:
21
+ # Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
22
+ # https://app.configcat.com/organization/data-governance
23
+ # (Only Organization Admins have access)
18
24
  #
19
- return create_client_with_auto_poll(sdk_key)
25
+ return create_client_with_auto_poll(sdk_key, data_governance: data_governance)
20
26
  end
21
27
 
22
28
  def ConfigCat.create_client_with_auto_poll(sdk_key,
@@ -25,10 +31,14 @@ module ConfigCat
25
31
  on_configuration_changed_callback: nil,
26
32
  config_cache_class: nil,
27
33
  base_url: nil,
28
- proxy_address:nil,
29
- proxy_port:nil,
30
- proxy_user:nil,
31
- proxy_pass:nil)
34
+ proxy_address: nil,
35
+ proxy_port: nil,
36
+ proxy_user: nil,
37
+ proxy_pass: nil,
38
+ open_timeout: 10,
39
+ read_timeout: 30,
40
+ flag_overrides: nil,
41
+ data_governance: DataGovernance::GLOBAL)
32
42
  #
33
43
  # Create an instance of ConfigCatClient and setup Auto Poll mode with custom options
34
44
  #
@@ -43,6 +53,13 @@ module ConfigCat
43
53
  # :param proxy_port: Proxy port
44
54
  # :param proxy_user: username for proxy authentication
45
55
  # :param proxy_pass: password for proxy authentication
56
+ # :param open_timeout: The number of seconds to wait for the server to make the initial connection. Default: 10 seconds.
57
+ # :param read_timeout: The number of seconds to wait for the server to respond before giving up. Default: 30 seconds.
58
+ # :param flag_overrides: An OverrideDataSource implementation used to override feature flags & settings.
59
+ # :param data_governance:
60
+ # Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
61
+ # https://app.configcat.com/organization/data-governance
62
+ # (Only Organization Admins have access)
46
63
  #
47
64
  if sdk_key === nil
48
65
  raise ConfigCatClientException, "SDK Key is required."
@@ -63,17 +80,25 @@ module ConfigCat
63
80
  proxy_address: proxy_address,
64
81
  proxy_port: proxy_port,
65
82
  proxy_user: proxy_user,
66
- proxy_pass: proxy_pass)
83
+ proxy_pass: proxy_pass,
84
+ open_timeout: open_timeout,
85
+ read_timeout: read_timeout,
86
+ flag_overrides: flag_overrides,
87
+ data_governance: data_governance)
67
88
  end
68
89
 
69
90
  def ConfigCat.create_client_with_lazy_load(sdk_key,
70
91
  cache_time_to_live_seconds: 60,
71
92
  config_cache_class: nil,
72
93
  base_url: nil,
73
- proxy_address:nil,
74
- proxy_port:nil,
75
- proxy_user:nil,
76
- proxy_pass:nil)
94
+ proxy_address: nil,
95
+ proxy_port: nil,
96
+ proxy_user: nil,
97
+ proxy_pass: nil,
98
+ open_timeout: 10,
99
+ read_timeout: 30,
100
+ flag_overrides: nil,
101
+ data_governance: DataGovernance::GLOBAL)
77
102
  #
78
103
  # Create an instance of ConfigCatClient and setup Lazy Load mode with custom options
79
104
  #
@@ -86,6 +111,13 @@ module ConfigCat
86
111
  # :param proxy_port: Proxy port
87
112
  # :param proxy_user: username for proxy authentication
88
113
  # :param proxy_pass: password for proxy authentication
114
+ # :param open_timeout: The number of seconds to wait for the server to make the initial connection. Default: 10 seconds.
115
+ # :param read_timeout: The number of seconds to wait for the server to respond before giving up. Default: 30 seconds.
116
+ # :param flag_overrides: An OverrideDataSource implementation used to override feature flags & settings.
117
+ # :param data_governance:
118
+ # Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
119
+ # https://app.configcat.com/organization/data-governance
120
+ # (Only Organization Admins have access)
89
121
  #
90
122
  if sdk_key === nil
91
123
  raise ConfigCatClientException, "SDK Key is required."
@@ -103,16 +135,24 @@ module ConfigCat
103
135
  proxy_address: proxy_address,
104
136
  proxy_port: proxy_port,
105
137
  proxy_user: proxy_user,
106
- proxy_pass: proxy_pass)
138
+ proxy_pass: proxy_pass,
139
+ open_timeout: open_timeout,
140
+ read_timeout: read_timeout,
141
+ flag_overrides: flag_overrides,
142
+ data_governance: data_governance)
107
143
  end
108
144
 
109
145
  def ConfigCat.create_client_with_manual_poll(sdk_key,
110
146
  config_cache_class: nil,
111
147
  base_url: nil,
112
- proxy_address:nil,
113
- proxy_port:nil,
114
- proxy_user:nil,
115
- proxy_pass:nil)
148
+ proxy_address: nil,
149
+ proxy_port: nil,
150
+ proxy_user: nil,
151
+ proxy_pass: nil,
152
+ open_timeout: 10,
153
+ read_timeout: 30,
154
+ flag_overrides: nil,
155
+ data_governance: DataGovernance::GLOBAL)
116
156
  #
117
157
  # Create an instance of ConfigCatClient and setup Manual Poll mode with custom options
118
158
  #
@@ -124,6 +164,13 @@ module ConfigCat
124
164
  # :param proxy_port: Proxy port
125
165
  # :param proxy_user: username for proxy authentication
126
166
  # :param proxy_pass: password for proxy authentication
167
+ # :param open_timeout: The number of seconds to wait for the server to make the initial connection. Default: 10 seconds.
168
+ # :param read_timeout: The number of seconds to wait for the server to respond before giving up. Default: 30 seconds.
169
+ # :param flag_overrides: An OverrideDataSource implementation used to override feature flags & settings.
170
+ # :param data_governance:
171
+ # Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
172
+ # https://app.configcat.com/organization/data-governance
173
+ # (Only Organization Admins have access)
127
174
  #
128
175
  if sdk_key === nil
129
176
  raise ConfigCatClientException, "SDK Key is required."
@@ -138,7 +185,11 @@ module ConfigCat
138
185
  proxy_address: proxy_address,
139
186
  proxy_port: proxy_port,
140
187
  proxy_user: proxy_user,
141
- proxy_pass: proxy_pass)
188
+ proxy_pass: proxy_pass,
189
+ open_timeout: open_timeout,
190
+ read_timeout: read_timeout,
191
+ flag_overrides: flag_overrides,
192
+ data_governance: data_governance)
142
193
  end
143
194
 
144
195
  end
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: 3.1.0
4
+ version: 5.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ConfigCat
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-14 00:00:00.000000000 Z
11
+ date: 2022-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -67,19 +67,19 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '12.3'
69
69
  - !ruby/object:Gem::Dependency
70
- name: coveralls
70
+ name: codecov
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0.8'
75
+ version: '0.5'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0.8'
82
+ version: '0.5'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: webmock
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -110,9 +110,14 @@ 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
117
+ - lib/configcat/localdictionarydatasource.rb
118
+ - lib/configcat/localfiledatasource.rb
115
119
  - lib/configcat/manualpollingcachepolicy.rb
120
+ - lib/configcat/overridedatasource.rb
116
121
  - lib/configcat/rolloutevaluator.rb
117
122
  - lib/configcat/user.rb
118
123
  - lib/configcat/version.rb
@@ -135,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
140
  - !ruby/object:Gem::Version
136
141
  version: '0'
137
142
  requirements: []
138
- rubygems_version: 3.0.8
143
+ rubygems_version: 3.0.3.1
139
144
  signing_key:
140
145
  specification_version: 4
141
146
  summary: ConfigCat SDK for Ruby.