configcat 4.0.0 → 5.0.2

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: 118a3db79c8d7d9a0795897380a4dfaf14fecda8a636024abfd9d2433b3af924
4
- data.tar.gz: 4c85c82b81fe08fcf9b6eed0a40bea06369939301aa09bc12e82b33a3b2176eb
3
+ metadata.gz: 967461c3bdc865f2911296ecc35117dac6646c80e82496d74811b0649df689dc
4
+ data.tar.gz: 7dd1b2d93dd82b8d279b9e3ac110e9ba564a14c775dfa132a044e749aa2f686b
5
5
  SHA512:
6
- metadata.gz: afe03eda0affc92755ae0eb91196a15bfe61f68a12244270bb5d19b3870bc023fe9ccf3231d8f11f414c4439b49fd2f9481e9a64295c3ab87697511ebcf57b25
7
- data.tar.gz: 5ac8e3beef89cbc84ef89f2eb5b071fcf5cb348db1c302755ba4fc619c759f9919f80785b2b08a4a583725d35ea6b9ef038d869706956485eec3b4a9d4cadbaa
6
+ metadata.gz: 056f50b2304c5fdbcaaf39fc207d1f145d62892732f987a15fb8ad2e7267e57c92eb3ad6aeb2434424c7b26f4fa013350a26156d26fa2434969193e8f9d98d62
7
+ data.tar.gz: 7ef97dac81e1a79d856880798bdfe897bc6de02bdf4ab4d7196320ef2c00d84ba69b6c4e6e08077de9f65c1191a1cb66220d2ecf4ad1e9e03f0e889cc00d83c1
@@ -82,6 +82,9 @@ module ConfigCat
82
82
  if !@_initialized && !old_configuration.equal?(nil)
83
83
  @_initialized = true
84
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()])
85
88
  rescue Exception => e
86
89
  ConfigCat.logger.error("Double-check your SDK Key at https://app.configcat.com/sdkkey.")
87
90
  ConfigCat.logger.error "threw exception #{e.class}:'#{e}'"
@@ -7,25 +7,41 @@ require 'configcat/lazyloadingcachepolicy'
7
7
  require 'configcat/rolloutevaluator'
8
8
  require 'configcat/datagovernance'
9
9
 
10
+
10
11
  module ConfigCat
11
12
  KeyValue = Struct.new(:key, :value)
12
13
  class ConfigCatClient
14
+ @@sdk_keys = []
15
+
13
16
  def initialize(sdk_key,
14
- poll_interval_seconds:60,
15
- max_init_wait_time_seconds:5,
16
- on_configuration_changed_callback:nil,
17
- cache_time_to_live_seconds:60,
18
- config_cache_class:nil,
19
- base_url:nil,
20
- proxy_address:nil,
21
- proxy_port:nil,
22
- proxy_user:nil,
23
- 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,
24
30
  data_governance: DataGovernance::GLOBAL)
25
31
  if sdk_key === nil
26
32
  raise ConfigCatClientException, "SDK Key is required."
27
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
+
28
43
  @_sdk_key = sdk_key
44
+ @_override_data_source = flag_overrides
29
45
 
30
46
  if config_cache_class
31
47
  @_config_cache = config_cache_class.new()
@@ -33,23 +49,35 @@ module ConfigCat
33
49
  @_config_cache = InMemoryConfigCache.new()
34
50
  end
35
51
 
36
- if poll_interval_seconds > 0
37
- @_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "p", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
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, "a", 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)
38
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)
39
67
  else
40
- if cache_time_to_live_seconds > 0
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)
43
- else
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())
46
- 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())
47
73
  end
48
74
  end
49
75
 
50
76
  def get_value(key, default_value, user=nil)
51
- config = @_cache_policy.get()
77
+ config = _get_settings()
52
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])
53
81
  return default_value
54
82
  end
55
83
  value, variation_id = RolloutEvaluator.evaluate(key, user, default_value, nil, config)
@@ -57,7 +85,7 @@ module ConfigCat
57
85
  end
58
86
 
59
87
  def get_all_keys()
60
- config = @_cache_policy.get()
88
+ config = _get_settings()
61
89
  if config === nil
62
90
  return []
63
91
  end
@@ -69,7 +97,7 @@ module ConfigCat
69
97
  end
70
98
 
71
99
  def get_variation_id(key, default_variation_id, user=nil)
72
- config = @_cache_policy.get()
100
+ config = _get_settings()
73
101
  if config === nil
74
102
  ConfigCat.logger.warn("Evaluating get_variation_id('%s') failed. Cache is empty. "\
75
103
  "Returning default_variation_id in your get_variation_id call: [%s]." %
@@ -93,7 +121,7 @@ module ConfigCat
93
121
  end
94
122
 
95
123
  def get_key_and_value(variation_id)
96
- config = @_cache_policy.get()
124
+ config = _get_settings()
97
125
  if config === nil
98
126
  ConfigCat.logger.warn("Evaluating get_variation_id('%s') failed. Cache is empty. Returning nil." % variation_id)
99
127
  return nil
@@ -126,17 +154,56 @@ module ConfigCat
126
154
  end
127
155
  end
128
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
+
129
169
  def force_refresh()
130
170
  @_cache_policy.force_refresh()
131
171
  end
132
172
 
133
173
  def stop()
134
- @_cache_policy.stop()
135
- @_config_fetcher.close()
174
+ @_cache_policy.stop() if @_cache_policy
175
+ @_config_fetcher.close() if @_config_fetcher
176
+ @@sdk_keys.delete(@_sdk_key)
136
177
  end
137
178
 
138
179
  private
139
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
+
140
207
  def _get_cache_key()
141
208
  return Digest::SHA1.hexdigest("ruby_" + CONFIG_FILE_NAME + "_" + @_sdk_key)
142
209
  end
@@ -41,13 +41,16 @@ module ConfigCat
41
41
  end
42
42
 
43
43
  class CacheControlConfigFetcher < ConfigFetcher
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)
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)
46
47
  @_sdk_key = sdk_key
47
48
  @_proxy_address = proxy_address
48
49
  @_proxy_port = proxy_port
49
50
  @_proxy_user = proxy_user
50
51
  @_proxy_pass = proxy_pass
52
+ @_open_timeout = open_timeout
53
+ @_read_timeout = read_timeout
51
54
  @_etag = ""
52
55
  @_headers = {"User-Agent" => ((("ConfigCat-Ruby/") + mode) + ("-")) + VERSION, "X-ConfigCat-UserAgent" => ((("ConfigCat-Ruby/") + mode) + ("-")) + VERSION, "Content-Type" => "application/json"}
53
56
  if !base_url.equal?(nil)
@@ -63,6 +66,14 @@ module ConfigCat
63
66
  end
64
67
  end
65
68
 
69
+ def get_open_timeout()
70
+ return @_open_timeout
71
+ end
72
+
73
+ def get_read_timeout()
74
+ return @_read_timeout
75
+ end
76
+
66
77
  # Returns the FetchResponse object contains configuration json Dictionary
67
78
  def get_configuration_json(retries=0)
68
79
  ConfigCat.logger.debug "Fetching configuration from ConfigCat"
@@ -141,8 +152,8 @@ module ConfigCat
141
152
  close()
142
153
  @_http = Net::HTTP.new(uri.host, uri.port, @_proxy_address, @_proxy_port, @_proxy_user, @_proxy_pass)
143
154
  @_http.use_ssl = use_ssl
144
- @_http.open_timeout = 10 # in seconds
145
- @_http.read_timeout = 30 # in seconds
155
+ @_http.open_timeout = @_open_timeout
156
+ @_http.read_timeout = @_read_timeout
146
157
  end
147
158
  end
148
159
  end
@@ -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
@@ -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
@@ -39,132 +39,142 @@ module ConfigCat
39
39
  return return_value, return_variation_id
40
40
  end
41
41
 
42
- ConfigCat.logger.info("User object:\n%s" % user.to_s)
43
-
44
- # Evaluate targeting rules
45
- for rollout_rule in rollout_rules
46
- comparison_attribute = rollout_rule.fetch(COMPARISON_ATTRIBUTE)
47
- comparison_value = rollout_rule.fetch(COMPARISON_VALUE, nil)
48
- comparator = rollout_rule.fetch(COMPARATOR, nil)
49
-
50
- user_value = user.get_attribute(comparison_attribute)
51
- if user_value === nil || !user_value
52
- ConfigCat.logger.info(format_no_match_rule(comparison_attribute, user_value, comparator, comparison_value))
53
- next
54
- end
42
+ log_entries = ["Evaluating get_value('%s')." % key, "User object:\n%s" % user.to_s]
43
+
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)
50
+
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
55
56
 
56
- value = rollout_rule.fetch(VALUE, nil)
57
- 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)
58
59
 
59
- # IS ONE OF
60
- if comparator == 0
61
- if comparison_value.to_s.split(",").map { |x| x.strip() }.include?(user_value.to_s)
62
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
63
- return value, variation_id
64
- end
65
- # IS NOT ONE OF
66
- elsif comparator == 1
67
- if !comparison_value.to_s.split(",").map { |x| x.strip() }.include?(user_value.to_s)
68
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
69
- return value, variation_id
70
- end
71
- # CONTAINS
72
- elsif comparator == 2
73
- if user_value.to_s.include?(comparison_value.to_s)
74
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
75
- return value, variation_id
76
- end
77
- # DOES NOT CONTAIN
78
- elsif comparator == 3
79
- if !user_value.to_s.include?(comparison_value.to_s)
80
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
81
- return value, variation_id
82
- end
83
- # IS ONE OF, IS NOT ONE OF (Semantic version)
84
- elsif (4 <= comparator) && (comparator <= 5)
85
- begin
86
- match = false
87
- user_value_version = Semantic::Version.new(user_value.to_s.strip())
88
- ((comparison_value.to_s.split(",").map { |x| x.strip() }).reject { |c| c.empty? }).each { |x|
89
- version = Semantic::Version.new(x)
90
- match = (user_value_version == version) || match
91
- }
92
- if match && comparator == 4 || !match && comparator == 5
93
- 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))
94
64
  return value, variation_id
95
65
  end
96
- rescue ArgumentError => e
97
- ConfigCat.logger.warn(format_validation_error_rule(comparison_attribute, user_value, comparator, comparison_value, e.to_s))
98
- next
99
- end
100
- # LESS THAN, LESS THAN OR EQUALS TO, GREATER THAN, GREATER THAN OR EQUALS TO (Semantic version)
101
- elsif (6 <= comparator) && (comparator <= 9)
102
- begin
103
- user_value_version = Semantic::Version.new(user_value.to_s.strip())
104
- comparison_value_version = Semantic::Version.new(comparison_value.to_s.strip())
105
- if (comparator == 6 && user_value_version < comparison_value_version) ||
106
- (comparator == 7 && user_value_version <= comparison_value_version) ||
107
- (comparator == 8 && user_value_version > comparison_value_version) ||
108
- (comparator == 9 && user_value_version >= comparison_value_version)
109
- 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))
110
70
  return value, variation_id
111
71
  end
112
- rescue ArgumentError => e
113
- ConfigCat.logger.warn(format_validation_error_rule(comparison_attribute, user_value, comparator, comparison_value, e.to_s))
114
- next
115
- end
116
- elsif (10 <= comparator) && (comparator <= 15)
117
- begin
118
- user_value_float = Float(user_value.to_s.gsub(",", "."))
119
- comparison_value_float = Float(comparison_value.to_s.gsub(",", "."))
120
- if (comparator == 10 && user_value_float == comparison_value_float) ||
121
- (comparator == 11 && user_value_float != comparison_value_float) ||
122
- (comparator == 12 && user_value_float < comparison_value_float) ||
123
- (comparator == 13 && user_value_float <= comparison_value_float) ||
124
- (comparator == 14 && user_value_float > comparison_value_float) ||
125
- (comparator == 15 && user_value_float >= comparison_value_float)
126
- 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))
127
150
  return value, variation_id
128
151
  end
129
- rescue Exception => e
130
- ConfigCat.logger.warn(format_validation_error_rule(comparison_attribute, user_value, comparator, comparison_value, e.to_s))
131
- next
132
- end
133
- # IS ONE OF (Sensitive)
134
- elsif comparator == 16
135
- if comparison_value.to_s.split(",").map { |x| x.strip() }.include?(Digest::SHA1.hexdigest(user_value).to_s)
136
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
137
- return value, variation_id
138
- end
139
- # IS NOT ONE OF (Sensitive)
140
- elsif comparator == 17
141
- if !comparison_value.to_s.split(",").map { |x| x.strip() }.include?(Digest::SHA1.hexdigest(user_value).to_s)
142
- ConfigCat.logger.info(format_match_rule(comparison_attribute, user_value, comparator, comparison_value, value))
143
- return value, variation_id
144
152
  end
153
+ log_entries.push(format_no_match_rule(comparison_attribute, user_value, comparator, comparison_value))
145
154
  end
146
- ConfigCat.logger.info(format_no_match_rule(comparison_attribute, user_value, comparator, comparison_value))
147
- end
148
155
 
149
- if rollout_percentage_items.size > 0
150
- user_key = user.get_identifier()
151
- hash_candidate = ("%s%s" % [key, user_key]).encode("utf-8")
152
- hash_val = Digest::SHA1.hexdigest(hash_candidate)[0...7].to_i(base=16) % 100
153
- bucket = 0
154
- for rollout_percentage_item in rollout_percentage_items || []
155
- bucket += rollout_percentage_item.fetch(PERCENTAGE, 0)
156
- if hash_val < bucket
157
- percentage_value = rollout_percentage_item.fetch(VALUE, nil)
158
- variation_id = rollout_percentage_item.fetch(VARIATION_ID, default_variation_id)
159
- ConfigCat.logger.info("Evaluating %% options. Returning %s" % percentage_value)
160
- 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
161
169
  end
162
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"))
163
177
  end
164
- return_value = setting_descriptor.fetch(VALUE, default_value)
165
- return_variation_id = setting_descriptor.fetch(VARIATION_ID, default_variation_id)
166
- ConfigCat.logger.info("Returning %s" % return_value)
167
- return return_value, return_variation_id
168
178
  end
169
179
 
170
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 = "4.0.0"
2
+ VERSION = "5.0.2"
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'
@@ -33,6 +35,9 @@ module ConfigCat
33
35
  proxy_port: nil,
34
36
  proxy_user: nil,
35
37
  proxy_pass: nil,
38
+ open_timeout: 10,
39
+ read_timeout: 30,
40
+ flag_overrides: nil,
36
41
  data_governance: DataGovernance::GLOBAL)
37
42
  #
38
43
  # Create an instance of ConfigCatClient and setup Auto Poll mode with custom options
@@ -48,6 +53,9 @@ module ConfigCat
48
53
  # :param proxy_port: Proxy port
49
54
  # :param proxy_user: username for proxy authentication
50
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.
51
59
  # :param data_governance:
52
60
  # Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
53
61
  # https://app.configcat.com/organization/data-governance
@@ -73,6 +81,9 @@ module ConfigCat
73
81
  proxy_port: proxy_port,
74
82
  proxy_user: proxy_user,
75
83
  proxy_pass: proxy_pass,
84
+ open_timeout: open_timeout,
85
+ read_timeout: read_timeout,
86
+ flag_overrides: flag_overrides,
76
87
  data_governance: data_governance)
77
88
  end
78
89
 
@@ -84,6 +95,9 @@ module ConfigCat
84
95
  proxy_port: nil,
85
96
  proxy_user: nil,
86
97
  proxy_pass: nil,
98
+ open_timeout: 10,
99
+ read_timeout: 30,
100
+ flag_overrides: nil,
87
101
  data_governance: DataGovernance::GLOBAL)
88
102
  #
89
103
  # Create an instance of ConfigCatClient and setup Lazy Load mode with custom options
@@ -97,6 +111,9 @@ module ConfigCat
97
111
  # :param proxy_port: Proxy port
98
112
  # :param proxy_user: username for proxy authentication
99
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.
100
117
  # :param data_governance:
101
118
  # Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
102
119
  # https://app.configcat.com/organization/data-governance
@@ -119,16 +136,22 @@ module ConfigCat
119
136
  proxy_port: proxy_port,
120
137
  proxy_user: proxy_user,
121
138
  proxy_pass: proxy_pass,
139
+ open_timeout: open_timeout,
140
+ read_timeout: read_timeout,
141
+ flag_overrides: flag_overrides,
122
142
  data_governance: data_governance)
123
143
  end
124
144
 
125
145
  def ConfigCat.create_client_with_manual_poll(sdk_key,
126
146
  config_cache_class: nil,
127
147
  base_url: nil,
128
- proxy_address:nil,
129
- proxy_port:nil,
130
- proxy_user:nil,
131
- 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,
132
155
  data_governance: DataGovernance::GLOBAL)
133
156
  #
134
157
  # Create an instance of ConfigCatClient and setup Manual Poll mode with custom options
@@ -141,6 +164,9 @@ module ConfigCat
141
164
  # :param proxy_port: Proxy port
142
165
  # :param proxy_user: username for proxy authentication
143
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.
144
170
  # :param data_governance:
145
171
  # Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
146
172
  # https://app.configcat.com/organization/data-governance
@@ -160,6 +186,9 @@ module ConfigCat
160
186
  proxy_port: proxy_port,
161
187
  proxy_user: proxy_user,
162
188
  proxy_pass: proxy_pass,
189
+ open_timeout: open_timeout,
190
+ read_timeout: read_timeout,
191
+ flag_overrides: flag_overrides,
163
192
  data_governance: data_governance)
164
193
  end
165
194
 
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.0.0
4
+ version: 5.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - ConfigCat
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-12 00:00:00.000000000 Z
11
+ date: 2022-06-27 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
@@ -114,7 +114,10 @@ files:
114
114
  - lib/configcat/datagovernance.rb
115
115
  - lib/configcat/interfaces.rb
116
116
  - lib/configcat/lazyloadingcachepolicy.rb
117
+ - lib/configcat/localdictionarydatasource.rb
118
+ - lib/configcat/localfiledatasource.rb
117
119
  - lib/configcat/manualpollingcachepolicy.rb
120
+ - lib/configcat/overridedatasource.rb
118
121
  - lib/configcat/rolloutevaluator.rb
119
122
  - lib/configcat/user.rb
120
123
  - lib/configcat/version.rb
@@ -137,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
140
  - !ruby/object:Gem::Version
138
141
  version: '0'
139
142
  requirements: []
140
- rubygems_version: 3.0.8
143
+ rubygems_version: 3.0.3.1
141
144
  signing_key:
142
145
  specification_version: 4
143
146
  summary: ConfigCat SDK for Ruby.