flagsmith 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/.rubocop.yml +4 -1
- data/.rubocop_todo.yml +0 -1
- data/.ruby-version +1 -0
- data/Gemfile.lock +35 -6
- data/LICENCE +4 -5
- data/README.md +8 -64
- data/Rakefile +5 -1
- data/example/.env.development +5 -0
- data/example/.env.test +4 -0
- data/example/.gitignore +5 -0
- data/example/.hanamirc +3 -0
- data/example/.rspec +2 -0
- data/example/Gemfile +25 -0
- data/example/Gemfile.lock +269 -0
- data/example/README.md +29 -0
- data/example/Rakefile +9 -0
- data/example/apps/web/application.rb +162 -0
- data/example/apps/web/config/routes.rb +1 -0
- data/example/apps/web/controllers/.gitkeep +0 -0
- data/example/apps/web/controllers/home/index.rb +32 -0
- data/example/apps/web/templates/application.html.slim +7 -0
- data/example/apps/web/templates/home/index.html.slim +10 -0
- data/example/apps/web/views/application_layout.rb +7 -0
- data/example/apps/web/views/home/index.rb +29 -0
- data/example/config/boot.rb +2 -0
- data/example/config/environment.rb +17 -0
- data/example/config/initializers/.gitkeep +0 -0
- data/example/config/initializers/flagsmith.rb +9 -0
- data/example/config/puma.rb +15 -0
- data/example/config.ru +3 -0
- data/example/spec/example/entities/.gitkeep +0 -0
- data/example/spec/example/mailers/.gitkeep +0 -0
- data/example/spec/example/repositories/.gitkeep +0 -0
- data/example/spec/features_helper.rb +12 -0
- data/example/spec/spec_helper.rb +103 -0
- data/example/spec/support/.gitkeep +0 -0
- data/example/spec/support/capybara.rb +8 -0
- data/example/spec/web/controllers/.gitkeep +0 -0
- data/example/spec/web/controllers/home/index_spec.rb +9 -0
- data/example/spec/web/features/.gitkeep +0 -0
- data/example/spec/web/views/application_layout_spec.rb +10 -0
- data/example/spec/web/views/home/index_spec.rb +10 -0
- data/lib/flagsmith/engine/core.rb +88 -0
- data/lib/flagsmith/engine/environments/models.rb +61 -0
- data/lib/flagsmith/engine/features/models.rb +173 -0
- data/lib/flagsmith/engine/identities/models.rb +115 -0
- data/lib/flagsmith/engine/organisations/models.rb +28 -0
- data/lib/flagsmith/engine/projects/models.rb +31 -0
- data/lib/flagsmith/engine/segments/constants.rb +41 -0
- data/lib/flagsmith/engine/segments/evaluator.rb +68 -0
- data/lib/flagsmith/engine/segments/models.rb +121 -0
- data/lib/flagsmith/engine/utils/hash_func.rb +34 -0
- data/lib/flagsmith/hash_slice.rb +12 -0
- data/lib/flagsmith/sdk/analytics_processor.rb +39 -0
- data/lib/flagsmith/sdk/api_client.rb +47 -0
- data/lib/flagsmith/sdk/config.rb +91 -0
- data/lib/flagsmith/sdk/errors.rb +9 -0
- data/lib/flagsmith/sdk/instance_methods.rb +137 -0
- data/lib/flagsmith/sdk/intervals.rb +24 -0
- data/lib/flagsmith/sdk/models/flag.rb +62 -0
- data/lib/flagsmith/sdk/models/flags/collection.rb +105 -0
- data/lib/flagsmith/sdk/pooling_manager.rb +31 -0
- data/lib/flagsmith/version.rb +5 -0
- data/lib/flagsmith.rb +79 -101
- metadata +104 -6
- data/.gitignore +0 -57
- data/flagsmith.gemspec +0 -22
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module Flagsmith
|
6
|
+
# Ruby client for flagsmith.com
|
7
|
+
class ApiClient
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
HTTP_METHODS_ALLOW_LIST = %i[get post].freeze
|
11
|
+
|
12
|
+
delegate HTTP_METHODS_ALLOW_LIST => :@conn
|
13
|
+
|
14
|
+
def initialize(config)
|
15
|
+
@conn = Faraday.new(url: config.api_url) do |f|
|
16
|
+
build_headers(f, config)
|
17
|
+
f.response :json, parser_options: { symbolize_names: true }
|
18
|
+
f.adapter Faraday.default_adapter
|
19
|
+
|
20
|
+
f.options.timeout = config.request_timeout_seconds
|
21
|
+
configure_logger(f, config)
|
22
|
+
configure_retries(f, config)
|
23
|
+
end
|
24
|
+
|
25
|
+
freeze
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def build_headers(faraday, config)
|
31
|
+
faraday.headers['Accept'] = 'application/json'
|
32
|
+
faraday.headers['Content-Type'] = 'application/json'
|
33
|
+
faraday.headers['X-Environment-Key'] = config.environment_key
|
34
|
+
faraday.headers.merge(config.custom_headers)
|
35
|
+
end
|
36
|
+
|
37
|
+
def configure_logger(faraday, config)
|
38
|
+
faraday.response :logger, config.logger
|
39
|
+
end
|
40
|
+
|
41
|
+
def configure_retries(faraday, config)
|
42
|
+
return unless config.retries
|
43
|
+
|
44
|
+
faraday.request :retry, { max: config.retries }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Flagsmith
|
4
|
+
# Config options shared around Engine
|
5
|
+
class Config
|
6
|
+
DEFAULT_API_URL = 'https://edge.api.flagsmith.com/api/v1/'
|
7
|
+
OPTIONS = %i[
|
8
|
+
environment_key api_url custom_headers request_timeout_seconds enable_local_evaluation
|
9
|
+
environment_refresh_interval_seconds retries enable_analytics default_flag_handler logger
|
10
|
+
].freeze
|
11
|
+
|
12
|
+
# Available Configs
|
13
|
+
#
|
14
|
+
# == Options:
|
15
|
+
#
|
16
|
+
# +environment_key+ - The environment key obtained from Flagsmith
|
17
|
+
# interface
|
18
|
+
# +api_url+ - Override the URL of the Flagsmith API to communicate with
|
19
|
+
# +customer_headers+ - Additional headers to add to requests made
|
20
|
+
# to the Flagsmith API
|
21
|
+
# +request_timeout_seconds+ - Number of seconds to wait for a request to
|
22
|
+
# complete before terminating the request
|
23
|
+
# Defaults to 10 seconds
|
24
|
+
# +enable_local_evaluation+ - Enables local evaluation of flags
|
25
|
+
# +environment_refresh_interval_seconds+ - If using local evaluation,
|
26
|
+
# specify the interval period between
|
27
|
+
# refreshes of local environment data
|
28
|
+
# +retries+ - a faraday retry option to use
|
29
|
+
# on all http requests to the Flagsmith API
|
30
|
+
# +enable_analytics+ - if enabled, sends additional requests to the Flagsmith
|
31
|
+
# API to power flag analytics charts
|
32
|
+
# +default_flag_handler+ - ruby block which will be used in the case where
|
33
|
+
# flags cannot be retrieved from the API or
|
34
|
+
# a non existent feature is requested.
|
35
|
+
# The searched feature#name will be passed to the block as an argument.
|
36
|
+
# +logger+ - Pass your logger, default is Logger.new($stdout)
|
37
|
+
#
|
38
|
+
attr_reader(*OPTIONS)
|
39
|
+
|
40
|
+
def initialize(options)
|
41
|
+
build_config(options)
|
42
|
+
|
43
|
+
freeze
|
44
|
+
end
|
45
|
+
|
46
|
+
def local_evaluation?
|
47
|
+
@enable_local_evaluation
|
48
|
+
end
|
49
|
+
|
50
|
+
def enable_analytics?
|
51
|
+
@enable_analytics
|
52
|
+
end
|
53
|
+
|
54
|
+
def environment_flags_url
|
55
|
+
'flags/'
|
56
|
+
end
|
57
|
+
|
58
|
+
def identities_url
|
59
|
+
'identities/'
|
60
|
+
end
|
61
|
+
|
62
|
+
def environment_url
|
63
|
+
'environment-document/'
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
69
|
+
def build_config(options)
|
70
|
+
opts = options.is_a?(String) ? { environment_key: options } : options
|
71
|
+
|
72
|
+
@environment_key = opts.fetch(:environment_key, Flagsmith::Config.environment_key)
|
73
|
+
@api_url = opts.fetch(:api_url, Flagsmith::Config::DEFAULT_API_URL)
|
74
|
+
@custom_headers = opts.fetch(:custom_headers, {})
|
75
|
+
@request_timeout_seconds = opts.fetch(:request_timeout_seconds, 10)
|
76
|
+
@retries = opts[:retries]
|
77
|
+
@enable_local_evaluation = opts.fetch(:enable_local_evaluation, false)
|
78
|
+
@environment_refresh_interval_seconds = opts.fetch(:environment_refresh_interval_seconds, 60)
|
79
|
+
@enable_analytics = opts.fetch(:enable_analytics, false)
|
80
|
+
@default_flag_handler = opts[:default_flag_handler]
|
81
|
+
@logger = options.fetch(:logger, Logger.new($stdout).tap { |l| l.level = :debug })
|
82
|
+
end
|
83
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
84
|
+
|
85
|
+
class << self
|
86
|
+
def environment_key
|
87
|
+
ENV['FLAGSMITH_ENVIRONMENT_KEY']
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Flagsmith
|
4
|
+
module SDK
|
5
|
+
# Available Flagsmith Functions
|
6
|
+
module InstanceMethods
|
7
|
+
# Get all the default for flags for the current environment.
|
8
|
+
# @returns Flags object holding all the flags for the current environment.
|
9
|
+
def get_environment_flags # rubocop:disable Naming/AccessorMethodName
|
10
|
+
return environment_flags_from_document if @config.local_evaluation?
|
11
|
+
|
12
|
+
environment_flags_from_api
|
13
|
+
end
|
14
|
+
|
15
|
+
# Get all the flags for the current environment for a given identity. Will also
|
16
|
+
# upsert all traits to the Flagsmith API for future evaluations. Providing a
|
17
|
+
# trait with a value of None will remove the trait from the identity if it exists.
|
18
|
+
#
|
19
|
+
# identifier a unique identifier for the identity in the current
|
20
|
+
# environment, e.g. email address, username, uuid
|
21
|
+
# traits { key => value } is a dictionary of traits to add / update on the identity in
|
22
|
+
# Flagsmith, e.g. { "num_orders": 10 }
|
23
|
+
# returns Flags object holding all the flags for the given identity.
|
24
|
+
def get_identity_flags(identifier, **traits)
|
25
|
+
return get_identity_flags_from_document(identifier, traits) if environment
|
26
|
+
|
27
|
+
get_identity_flags_from_api(identifier, traits)
|
28
|
+
end
|
29
|
+
|
30
|
+
def feature_enabled?(feature_name, default: false)
|
31
|
+
flag = get_environment_flags[feature_name]
|
32
|
+
return default if flag.nil?
|
33
|
+
|
34
|
+
flag.enabled?
|
35
|
+
end
|
36
|
+
|
37
|
+
def feature_enabled_for_identity?(feature_name, user_id, default: false)
|
38
|
+
flag = get_identity_flags(user_id)[feature_name]
|
39
|
+
return default if flag.nil?
|
40
|
+
|
41
|
+
flag.enabled?
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_value(feature_name, default: nil)
|
45
|
+
flag = get_environment_flags[feature_name]
|
46
|
+
return default if flag.nil?
|
47
|
+
|
48
|
+
flag.value
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_value_for_identity(feature_name, user_id = nil, default: nil)
|
52
|
+
flag = get_identity_flags(user_id)[feature_name]
|
53
|
+
return default if flag.nil?
|
54
|
+
|
55
|
+
flag.value
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def environment_flags_from_document
|
61
|
+
Flagsmith::Flags::Collection.from_feature_state_models(
|
62
|
+
get_environment_feature_states(environment),
|
63
|
+
analytics_processor: analytics_processor,
|
64
|
+
default_flag_handler: default_flag_handler
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_identity_flags_from_document(identifier, traits = {})
|
69
|
+
identity_model = build_identity_model(identifier, traits)
|
70
|
+
|
71
|
+
Flagsmith::Flags::Collection.from_feature_state_models(
|
72
|
+
get_identity_feature_states(environment, identity_model),
|
73
|
+
analytics_processor: analytics_processor,
|
74
|
+
default_flag_handler: default_flag_handler
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def environment_flags_from_api
|
79
|
+
rescue_with_default_handler do
|
80
|
+
api_flags = api_client.get(@config.environment_flags_url).body
|
81
|
+
api_flags = api_flags.select { |flag| flag[:feature_segment].nil? }
|
82
|
+
Flagsmith::Flags::Collection.from_api(
|
83
|
+
api_flags,
|
84
|
+
analytics_processor: analytics_processor,
|
85
|
+
default_flag_handler: default_flag_handler
|
86
|
+
)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def get_identity_flags_from_api(identifier, traits = {})
|
91
|
+
rescue_with_default_handler do
|
92
|
+
data = generate_identities_data(identifier, traits)
|
93
|
+
json_response = api_client.post(@config.identities_url, data.to_json).body
|
94
|
+
|
95
|
+
Flagsmith::Flags::Collection.from_api(
|
96
|
+
json_response[:flags],
|
97
|
+
analytics_processor: analytics_processor,
|
98
|
+
default_flag_handler: default_flag_handler
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def rescue_with_default_handler
|
104
|
+
yield
|
105
|
+
rescue StandardError
|
106
|
+
if default_flag_handler
|
107
|
+
return Flagsmith::Flags::Collection.new(
|
108
|
+
{},
|
109
|
+
default_flag_handler: default_flag_handler
|
110
|
+
)
|
111
|
+
end
|
112
|
+
raise
|
113
|
+
end
|
114
|
+
|
115
|
+
def build_identity_model(identifier, traits = {})
|
116
|
+
unless environment
|
117
|
+
raise Flagsmith::ClientError,
|
118
|
+
'Unable to build identity model when no local environment present.'
|
119
|
+
end
|
120
|
+
|
121
|
+
trait_models = traits.map do |key, value|
|
122
|
+
Flagsmith::Engine::Identities::Trait.new(trait_key: key, trait_value: value)
|
123
|
+
end
|
124
|
+
Flagsmith::Engine::Identity.new(
|
125
|
+
identity_traits: trait_models, environment_api_key: environment_key, identifier: identifier
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
def generate_identities_data(identifier, traits = {})
|
130
|
+
{
|
131
|
+
identifier: identifier,
|
132
|
+
traits: traits.map { |key, value| { trait_key: key, trait_value: value } }
|
133
|
+
}
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Flagsmith
|
4
|
+
module SDK
|
5
|
+
# Util functions
|
6
|
+
module Intervals
|
7
|
+
# @return [Thread] return loop thread reference
|
8
|
+
# rubocop:disable Naming/AccessorMethodName
|
9
|
+
def set_interval(delay)
|
10
|
+
Thread.new do
|
11
|
+
loop do
|
12
|
+
sleep delay
|
13
|
+
yield if block_given?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
# rubocop:enable Naming/AccessorMethodName
|
18
|
+
|
19
|
+
def clear_interval(thread)
|
20
|
+
thread.kill
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Flagsmith
|
4
|
+
# Flag object
|
5
|
+
class Flag
|
6
|
+
include Comparable
|
7
|
+
|
8
|
+
attr_reader :enabled, :value, :default, :feature_name, :feature_id
|
9
|
+
|
10
|
+
def initialize(feature_name:, enabled:, value:, feature_id:, default: false)
|
11
|
+
@feature_name = feature_name
|
12
|
+
@feature_id = feature_id
|
13
|
+
@enabled = enabled
|
14
|
+
@value = value
|
15
|
+
@default = default
|
16
|
+
end
|
17
|
+
|
18
|
+
def enabled?
|
19
|
+
@enabled
|
20
|
+
end
|
21
|
+
|
22
|
+
alias is_default default
|
23
|
+
|
24
|
+
def <=>(other)
|
25
|
+
feature_name <=> other.feature_name
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](key)
|
29
|
+
to_h[key]
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_h
|
33
|
+
{
|
34
|
+
feature_id: feature_id,
|
35
|
+
feature_name: feature_name,
|
36
|
+
value: value,
|
37
|
+
enabled: enabled,
|
38
|
+
default: default
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
class << self
|
43
|
+
def from_feature_state_model(feature_state_model, identity_id)
|
44
|
+
new(
|
45
|
+
enabled: feature_state_model.enabled,
|
46
|
+
value: feature_state_model.get_value(identity_id),
|
47
|
+
feature_name: feature_state_model.feature.name,
|
48
|
+
feature_id: feature_state_model.feature.id
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def from_api(json_flag_data)
|
53
|
+
new(
|
54
|
+
enabled: json_flag_data[:enabled],
|
55
|
+
value: json_flag_data[:feature_state_value] || json_flag_data[:value],
|
56
|
+
feature_name: json_flag_data.dig(:feature, :name),
|
57
|
+
feature_id: json_flag_data.dig(:feature, :id)
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Flagsmith
|
4
|
+
module Flags
|
5
|
+
class NotFound < StandardError; end
|
6
|
+
|
7
|
+
# Flag Collection
|
8
|
+
class Collection
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
attr_reader :flags, :default_flag_handler, :analytics_processor
|
12
|
+
|
13
|
+
def initialize(flags = {}, analytics_processor: nil, default_flag_handler: nil)
|
14
|
+
@flags = flags
|
15
|
+
@default_flag_handler = default_flag_handler
|
16
|
+
@analytics_processor = analytics_processor
|
17
|
+
end
|
18
|
+
|
19
|
+
def each(&block)
|
20
|
+
flags.each { |item| block&.call(item) || item }
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_a
|
24
|
+
@flags.values || []
|
25
|
+
end
|
26
|
+
alias all_flags to_a
|
27
|
+
|
28
|
+
# Check whether a given feature is enabled.
|
29
|
+
# :param feature_name: the name of the feature to check if enabled.
|
30
|
+
# :return: Boolean representing the enabled state of a given feature.
|
31
|
+
# :raises FlagsmithClientError: if feature doesn't exist
|
32
|
+
def feature_enabled?(feature_name)
|
33
|
+
get_flag(feature_name).enabled?
|
34
|
+
end
|
35
|
+
alias is_feature_enabled feature_enabled?
|
36
|
+
|
37
|
+
# Get the value of a particular feature.
|
38
|
+
# :param feature_name: the name of the feature to retrieve the value of.
|
39
|
+
# :return: the value of the given feature.
|
40
|
+
# :raises FlagsmithClientError: if feature doesn't exist
|
41
|
+
def feature_value(feature_name)
|
42
|
+
get_flag(feature_name).value
|
43
|
+
end
|
44
|
+
alias get_feature_value feature_value
|
45
|
+
|
46
|
+
# Get a specific flag given the feature name.
|
47
|
+
# :param feature_name: the name of the feature to retrieve the flag for.
|
48
|
+
# :return: BaseFlag object.
|
49
|
+
# :raises FlagsmithClientError: if feature doesn't exist
|
50
|
+
def get_flag(feature_name)
|
51
|
+
key = Flagsmith::Flags::Collection.normalize_key(feature_name)
|
52
|
+
flag = flags.fetch(key)
|
53
|
+
@analytics_processor.track_feature(flag.feature_id) if @analytics_processor && flag.feature_id
|
54
|
+
flag
|
55
|
+
rescue KeyError
|
56
|
+
return @default_flag_handler.call(feature_name) if @default_flag_handler
|
57
|
+
|
58
|
+
raise Flagsmith::Flags::NotFound,
|
59
|
+
"Feature does not exist: #{key}, implement default_flag_handler to handle this case."
|
60
|
+
end
|
61
|
+
|
62
|
+
def [](key)
|
63
|
+
key.is_a?(Integer) ? to_a[key] : get_flag(key)
|
64
|
+
end
|
65
|
+
|
66
|
+
def length
|
67
|
+
to_a.length
|
68
|
+
end
|
69
|
+
|
70
|
+
def inspect
|
71
|
+
"<##{self.class}:#{object_id.to_s(8)} flags=#{@flags}>"
|
72
|
+
end
|
73
|
+
|
74
|
+
class << self
|
75
|
+
def from_api(json_data, **args)
|
76
|
+
to_flag_object = lambda { |json_flag, acc|
|
77
|
+
acc[normalize_key(json_flag.dig(:feature, :name))] =
|
78
|
+
Flagsmith::Flag.from_api(json_flag)
|
79
|
+
}
|
80
|
+
|
81
|
+
new(
|
82
|
+
json_data.each_with_object({}, &to_flag_object),
|
83
|
+
**args
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
def from_feature_state_models(feature_states, identity_id: nil, **args)
|
88
|
+
to_flag_object = lambda { |feature_state, acc|
|
89
|
+
acc[normalize_key(feature_state.feature.name)] =
|
90
|
+
Flagsmith::Flag.from_feature_state_model(feature_state, identity_id)
|
91
|
+
}
|
92
|
+
|
93
|
+
new(
|
94
|
+
feature_states.each_with_object({}, &to_flag_object),
|
95
|
+
**args
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
def normalize_key(key)
|
100
|
+
key.to_s.downcase
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'intervals'
|
4
|
+
|
5
|
+
module Flagsmith
|
6
|
+
# Manager to asynchronously fetch the environment
|
7
|
+
class EnvironmentDataPollingManager
|
8
|
+
include Flagsmith::SDK::Intervals
|
9
|
+
|
10
|
+
def initialize(main, refresh_interval_seconds)
|
11
|
+
@main = main
|
12
|
+
@refresh_interval_seconds = refresh_interval_seconds
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
update_environment = lambda {
|
17
|
+
stop
|
18
|
+
@interval = set_interval(@refresh_interval_seconds) { @main.update_environment }
|
19
|
+
}
|
20
|
+
|
21
|
+
# TODO: this call should be awaited for getIdentityFlags/getEnvironmentFlags when enableLocalEvaluation is true
|
22
|
+
update_environment.call
|
23
|
+
end
|
24
|
+
|
25
|
+
def stop
|
26
|
+
return unless @interval
|
27
|
+
|
28
|
+
clear_interval(@interval)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|