Skip to content

Commit

Permalink
Merge pull request #12 from configcat/sdk-improvements
Browse files Browse the repository at this point in the history
Sdk improvements
  • Loading branch information
kp-cat authored Apr 12, 2022
2 parents c8a6659 + 3795ad7 commit b0a8cc6
Show file tree
Hide file tree
Showing 19 changed files with 667 additions and 171 deletions.
35 changes: 31 additions & 4 deletions lib/configcat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ def ConfigCat.create_client_with_auto_poll(sdk_key,
proxy_port: nil,
proxy_user: nil,
proxy_pass: nil,
open_timeout: 10,
read_timeout: 30,
flag_overrides: nil,
data_governance: DataGovernance::GLOBAL)
#
# Create an instance of ConfigCatClient and setup Auto Poll mode with custom options
Expand All @@ -48,6 +51,9 @@ def ConfigCat.create_client_with_auto_poll(sdk_key,
# :param proxy_port: Proxy port
# :param proxy_user: username for proxy authentication
# :param proxy_pass: password for proxy authentication
# :param open_timeout: The number of seconds to wait for the server to make the initial connection. Default: 10 seconds.
# :param read_timeout: The number of seconds to wait for the server to respond before giving up. Default: 30 seconds.
# :param flag_overrides: An OverrideDataSource implementation used to override feature flags & settings.
# :param data_governance:
# Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
# https://app.configcat.com/organization/data-governance
Expand All @@ -73,6 +79,9 @@ def ConfigCat.create_client_with_auto_poll(sdk_key,
proxy_port: proxy_port,
proxy_user: proxy_user,
proxy_pass: proxy_pass,
open_timeout: open_timeout,
read_timeout: read_timeout,
flag_overrides: flag_overrides,
data_governance: data_governance)
end

Expand All @@ -84,6 +93,9 @@ def ConfigCat.create_client_with_lazy_load(sdk_key,
proxy_port: nil,
proxy_user: nil,
proxy_pass: nil,
open_timeout: 10,
read_timeout: 30,
flag_overrides: nil,
data_governance: DataGovernance::GLOBAL)
#
# Create an instance of ConfigCatClient and setup Lazy Load mode with custom options
Expand All @@ -97,6 +109,9 @@ def ConfigCat.create_client_with_lazy_load(sdk_key,
# :param proxy_port: Proxy port
# :param proxy_user: username for proxy authentication
# :param proxy_pass: password for proxy authentication
# :param open_timeout: The number of seconds to wait for the server to make the initial connection. Default: 10 seconds.
# :param read_timeout: The number of seconds to wait for the server to respond before giving up. Default: 30 seconds.
# :param flag_overrides: An OverrideDataSource implementation used to override feature flags & settings.
# :param data_governance:
# Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
# https://app.configcat.com/organization/data-governance
Expand All @@ -119,16 +134,22 @@ def ConfigCat.create_client_with_lazy_load(sdk_key,
proxy_port: proxy_port,
proxy_user: proxy_user,
proxy_pass: proxy_pass,
open_timeout: open_timeout,
read_timeout: read_timeout,
flag_overrides: flag_overrides,
data_governance: data_governance)
end

def ConfigCat.create_client_with_manual_poll(sdk_key,
config_cache_class: nil,
base_url: nil,
proxy_address:nil,
proxy_port:nil,
proxy_user:nil,
proxy_pass:nil,
proxy_address: nil,
proxy_port: nil,
proxy_user: nil,
proxy_pass: nil,
open_timeout: 10,
read_timeout: 30,
flag_overrides: nil,
data_governance: DataGovernance::GLOBAL)
#
# Create an instance of ConfigCatClient and setup Manual Poll mode with custom options
Expand All @@ -141,6 +162,9 @@ def ConfigCat.create_client_with_manual_poll(sdk_key,
# :param proxy_port: Proxy port
# :param proxy_user: username for proxy authentication
# :param proxy_pass: password for proxy authentication
# :param open_timeout: The number of seconds to wait for the server to make the initial connection. Default: 10 seconds.
# :param read_timeout: The number of seconds to wait for the server to respond before giving up. Default: 30 seconds.
# :param flag_overrides: An OverrideDataSource implementation used to override feature flags & settings.
# :param data_governance:
# Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
# https://app.configcat.com/organization/data-governance
Expand All @@ -160,6 +184,9 @@ def ConfigCat.create_client_with_manual_poll(sdk_key,
proxy_port: proxy_port,
proxy_user: proxy_user,
proxy_pass: proxy_pass,
open_timeout: open_timeout,
read_timeout: read_timeout,
flag_overrides: flag_overrides,
data_governance: data_governance)
end

Expand Down
3 changes: 3 additions & 0 deletions lib/configcat/autopollingcachepolicy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ def force_refresh()
if !@_initialized && !old_configuration.equal?(nil)
@_initialized = true
end
rescue Timeout::Error => e
ConfigCat.logger.error("Request timed out. Timeout values: [open: %ss, read: %ss]" %
[@_config_fetcher.get_open_timeout(), @_config_fetcher.get_read_timeout()])
rescue Exception => e
ConfigCat.logger.error("Double-check your SDK Key at https://app.configcat.com/sdkkey.")
ConfigCat.logger.error "threw exception #{e.class}:'#{e}'"
Expand Down
117 changes: 92 additions & 25 deletions lib/configcat/configcatclient.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,85 @@
require 'configcat/rolloutevaluator'
require 'configcat/datagovernance'


module ConfigCat
KeyValue = Struct.new(:key, :value)
class ConfigCatClient
@@sdk_keys = []

def initialize(sdk_key,
poll_interval_seconds:60,
max_init_wait_time_seconds:5,
on_configuration_changed_callback:nil,
cache_time_to_live_seconds:60,
config_cache_class:nil,
base_url:nil,
proxy_address:nil,
proxy_port:nil,
proxy_user:nil,
proxy_pass:nil,
poll_interval_seconds: 60,
max_init_wait_time_seconds: 5,
on_configuration_changed_callback: nil,
cache_time_to_live_seconds: 60,
config_cache_class: nil,
base_url: nil,
proxy_address: nil,
proxy_port: nil,
proxy_user: nil,
proxy_pass: nil,
open_timeout: 10,
read_timeout: 30,
flag_overrides: nil,
data_governance: DataGovernance::GLOBAL)
if sdk_key === nil
raise ConfigCatClientException, "SDK Key is required."
end

if @@sdk_keys.include?(sdk_key)
ConfigCat.logger.warn("A ConfigCat Client is already initialized with sdk_key %s. "\
"We strongly recommend you to use the ConfigCat Client as "\
"a Singleton object in your application." % sdk_key)
else
@@sdk_keys.push(sdk_key)
end

@_sdk_key = sdk_key
@_override_data_source = flag_overrides

if config_cache_class
@_config_cache = config_cache_class.new()
else
@_config_cache = InMemoryConfigCache.new()
end

if poll_interval_seconds > 0
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "p", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
if !@_override_data_source.equal?(nil) && @_override_data_source.get_behaviour() == OverrideBehaviour::LOCAL_ONLY
@_config_fetcher = nil
@_cache_policy = nil
elsif poll_interval_seconds > 0
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "p", base_url: base_url,
proxy_address: proxy_address, proxy_port: proxy_port, proxy_user: proxy_user, proxy_pass: proxy_pass,
open_timeout: open_timeout, read_timeout: read_timeout,
data_governance: data_governance)
@_cache_policy = AutoPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), poll_interval_seconds, max_init_wait_time_seconds, on_configuration_changed_callback)
elsif cache_time_to_live_seconds > 0
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "l", base_url: base_url,
proxy_address: proxy_address, proxy_port: proxy_port, proxy_user: proxy_user, proxy_pass: proxy_pass,
open_timeout: open_timeout, read_timeout: read_timeout,
data_governance: data_governance)
@_cache_policy = LazyLoadingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), cache_time_to_live_seconds)
else
if cache_time_to_live_seconds > 0
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "l", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
@_cache_policy = LazyLoadingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), cache_time_to_live_seconds)
else
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "m", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
@_cache_policy = ManualPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key())
end
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "m", base_url: base_url,
proxy_address: proxy_address, proxy_port: proxy_port, proxy_user: proxy_user, proxy_pass: proxy_pass,
open_timeout: open_timeout, read_timeout: read_timeout,
data_governance: data_governance)
@_cache_policy = ManualPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key())
end
end

def get_value(key, default_value, user=nil)
config = @_cache_policy.get()
config = _get_settings()
if config === nil
ConfigCat.logger.warn("Evaluating get_value('%s') failed. Cache is empty. "\
"Returning default_value in your get_value call: [%s]." % [key, default_value.to_s])
return default_value
end
value, variation_id = RolloutEvaluator.evaluate(key, user, default_value, nil, config)
return value
end

def get_all_keys()
config = @_cache_policy.get()
config = _get_settings()
if config === nil
return []
end
Expand All @@ -69,7 +97,7 @@ def get_all_keys()
end

def get_variation_id(key, default_variation_id, user=nil)
config = @_cache_policy.get()
config = _get_settings()
if config === nil
ConfigCat.logger.warn("Evaluating get_variation_id('%s') failed. Cache is empty. "\
"Returning default_variation_id in your get_variation_id call: [%s]." %
Expand All @@ -93,7 +121,7 @@ def get_all_variation_ids(user: nil)
end

def get_key_and_value(variation_id)
config = @_cache_policy.get()
config = _get_settings()
if config === nil
ConfigCat.logger.warn("Evaluating get_variation_id('%s') failed. Cache is empty. Returning nil." % variation_id)
return nil
Expand Down Expand Up @@ -126,17 +154,56 @@ def get_key_and_value(variation_id)
end
end

def get_all_values(user: nil)
keys = get_all_keys()
all_values = {}
for key in keys
value = get_value(key, nil, user)
if !value.equal?(nil)
all_values[key] = value
end
end
return all_values
end

def force_refresh()
@_cache_policy.force_refresh()
end

def stop()
@_cache_policy.stop()
@_config_fetcher.close()
@_cache_policy.stop() if @_cache_policy
@_config_fetcher.close() if @_config_fetcher
@@sdk_keys.delete(@_sdk_key)
end

private

def _get_settings()
if !@_override_data_source.nil?
behaviour = @_override_data_source.get_behaviour()
if behaviour == OverrideBehaviour::LOCAL_ONLY
return @_override_data_source.get_overrides()
elsif behaviour == OverrideBehaviour::REMOTE_OVER_LOCAL
remote_settings = @_cache_policy.get()
local_settings = @_override_data_source.get_overrides()
result = local_settings.clone()
if remote_settings.key?(FEATURE_FLAGS) && local_settings.key?(FEATURE_FLAGS)
result[FEATURE_FLAGS] = result[FEATURE_FLAGS].merge(remote_settings[FEATURE_FLAGS])
end
return result
elsif behaviour == OverrideBehaviour::LOCAL_OVER_REMOTE
remote_settings = @_cache_policy.get()
local_settings = @_override_data_source.get_overrides()
result = remote_settings.clone()
if remote_settings.key?(FEATURE_FLAGS) && local_settings.key?(FEATURE_FLAGS)
result[FEATURE_FLAGS] = result[FEATURE_FLAGS].merge(local_settings[FEATURE_FLAGS])
end
return result
end
end
return @_cache_policy.get()
end

def _get_cache_key()
return Digest::SHA1.hexdigest("ruby_" + CONFIG_FILE_NAME + "_" + @_sdk_key)
end
Expand Down
19 changes: 15 additions & 4 deletions lib/configcat/configfetcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,16 @@ def is_not_modified()
end

class CacheControlConfigFetcher < ConfigFetcher
def initialize(sdk_key, mode, base_url=nil, proxy_address=nil, proxy_port=nil, proxy_user=nil, proxy_pass=nil,
data_governance=DataGovernance::GLOBAL)
def initialize(sdk_key, mode, base_url:nil, proxy_address:nil, proxy_port:nil, proxy_user:nil, proxy_pass:nil,
open_timeout:10, read_timeout:30,
data_governance:DataGovernance::GLOBAL)
@_sdk_key = sdk_key
@_proxy_address = proxy_address
@_proxy_port = proxy_port
@_proxy_user = proxy_user
@_proxy_pass = proxy_pass
@_open_timeout = open_timeout
@_read_timeout = read_timeout
@_etag = ""
@_headers = {"User-Agent" => ((("ConfigCat-Ruby/") + mode) + ("-")) + VERSION, "X-ConfigCat-UserAgent" => ((("ConfigCat-Ruby/") + mode) + ("-")) + VERSION, "Content-Type" => "application/json"}
if !base_url.equal?(nil)
Expand All @@ -63,6 +66,14 @@ def initialize(sdk_key, mode, base_url=nil, proxy_address=nil, proxy_port=nil, p
end
end

def get_open_timeout()
return @_open_timeout
end

def get_read_timeout()
return @_read_timeout
end

# Returns the FetchResponse object contains configuration json Dictionary
def get_configuration_json(retries=0)
ConfigCat.logger.debug "Fetching configuration from ConfigCat"
Expand Down Expand Up @@ -141,8 +152,8 @@ def _create_http()
close()
@_http = Net::HTTP.new(uri.host, uri.port, @_proxy_address, @_proxy_port, @_proxy_user, @_proxy_pass)
@_http.use_ssl = use_ssl
@_http.open_timeout = 10 # in seconds
@_http.read_timeout = 30 # in seconds
@_http.open_timeout = @_open_timeout
@_http.read_timeout = @_read_timeout
end
end
end
Expand Down
20 changes: 20 additions & 0 deletions lib/configcat/localdictionarydatasource.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'configcat/overridedatasource'
require 'configcat/constants'


module ConfigCat
class LocalDictionaryDataSource < OverrideDataSource
def initialize(source, override_behaviour)
super(override_behaviour)
dictionary = {}
source.each do |key, value|
dictionary[key] = {VALUE => value}
end
@_settings = {FEATURE_FLAGS => dictionary}
end

def get_overrides()
return @_settings
end
end
end
Loading

0 comments on commit b0a8cc6

Please sign in to comment.