eppo-server-sdk 0.3.0 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +22 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/Cargo.lock +2015 -0
- data/Cargo.toml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +22 -0
- data/Rakefile +53 -0
- data/Steepfile +27 -0
- data/ext/eppo_client/Cargo.toml +19 -0
- data/ext/eppo_client/build.rs +5 -0
- data/ext/eppo_client/extconf.rb +6 -0
- data/ext/eppo_client/src/client.rs +178 -0
- data/ext/eppo_client/src/lib.rs +34 -0
- data/lib/eppo_client/assignment_logger.rb +7 -3
- data/lib/eppo_client/client.rb +159 -205
- data/lib/eppo_client/config.rb +4 -4
- data/lib/eppo_client/custom_errors.rb +0 -17
- data/lib/eppo_client/validation.rb +2 -2
- data/lib/eppo_client/version.rb +2 -1
- data/lib/eppo_client.rb +7 -45
- data/sig/eppo_server_sdk.rbs +96 -0
- metadata +26 -172
- data/lib/eppo_client/configuration_requestor.rb +0 -108
- data/lib/eppo_client/configuration_store.rb +0 -35
- data/lib/eppo_client/constants.rb +0 -20
- data/lib/eppo_client/http_client.rb +0 -75
- data/lib/eppo_client/lru_cache.rb +0 -28
- data/lib/eppo_client/poller.rb +0 -48
- data/lib/eppo_client/rules.rb +0 -119
- data/lib/eppo_client/shard.rb +0 -30
- data/lib/eppo_client/variation_type.rb +0 -39
data/lib/eppo_client/client.rb
CHANGED
@@ -1,238 +1,192 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "singleton"
|
4
|
+
require "logger"
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative 'rules'
|
9
|
-
require_relative 'shard'
|
10
|
-
require_relative 'validation'
|
11
|
-
require_relative 'variation_type'
|
6
|
+
require_relative "config"
|
7
|
+
require_relative "eppo_client"
|
12
8
|
|
13
9
|
module EppoClient
|
14
10
|
# The main client singleton
|
15
|
-
# rubocop:disable Metrics/ClassLength
|
16
11
|
class Client
|
17
|
-
extend Gem::Deprecate
|
18
12
|
include Singleton
|
19
|
-
attr_accessor :
|
13
|
+
attr_accessor :assignment_logger
|
20
14
|
|
21
|
-
def
|
22
|
-
|
15
|
+
def init(config)
|
16
|
+
config.validate
|
17
|
+
|
18
|
+
if !@core.nil? then
|
19
|
+
STDERR.puts "Eppo Warning: multiple initialization of the client"
|
20
|
+
@core.shutdown
|
21
|
+
end
|
22
|
+
|
23
|
+
@assignment_logger = config.assignment_logger
|
24
|
+
@core = EppoClient::Core::Client.new(config)
|
23
25
|
end
|
24
26
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
flag_key,
|
43
|
-
|
44
|
-
|
45
|
-
)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
subject_attributes
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
flag_key,
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
)
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
def get_assignment(
|
101
|
-
subject_key,
|
102
|
-
flag_key,
|
103
|
-
subject_attributes = {},
|
104
|
-
log_level = EppoClient::DEFAULT_LOGGER_LEVEL
|
105
|
-
)
|
27
|
+
def shutdown
|
28
|
+
@core.shutdown
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_string_assignment(flag_key, subject_key, subject_attributes, default_value)
|
32
|
+
get_assignment_inner(flag_key, subject_key, subject_attributes, "STRING", default_value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_numeric_assignment(flag_key, subject_key, subject_attributes, default_value)
|
36
|
+
get_assignment_inner(flag_key, subject_key, subject_attributes, "NUMERIC", default_value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_integer_assignment(flag_key, subject_key, subject_attributes, default_value)
|
40
|
+
get_assignment_inner(flag_key, subject_key, subject_attributes, "INTEGER", default_value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_boolean_assignment(flag_key, subject_key, subject_attributes, default_value)
|
44
|
+
get_assignment_inner(flag_key, subject_key, subject_attributes, "BOOLEAN", default_value)
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_json_assignment(flag_key, subject_key, subject_attributes, default_value)
|
48
|
+
get_assignment_inner(flag_key, subject_key, subject_attributes, "JSON", default_value)
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_string_assignment_details(flag_key, subject_key, subject_attributes, default_value)
|
52
|
+
get_assignment_details_inner(flag_key, subject_key, subject_attributes, "STRING", default_value)
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_numeric_assignment_details(flag_key, subject_key, subject_attributes, default_value)
|
56
|
+
get_assignment_details_inner(flag_key, subject_key, subject_attributes, "NUMERIC", default_value)
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_integer_assignment_details(flag_key, subject_key, subject_attributes, default_value)
|
60
|
+
get_assignment_details_inner(flag_key, subject_key, subject_attributes, "INTEGER", default_value)
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_boolean_assignment_details(flag_key, subject_key, subject_attributes, default_value)
|
64
|
+
get_assignment_details_inner(flag_key, subject_key, subject_attributes, "BOOLEAN", default_value)
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_json_assignment_details(flag_key, subject_key, subject_attributes, default_value)
|
68
|
+
get_assignment_details_inner(flag_key, subject_key, subject_attributes, "JSON", default_value)
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_bandit_action(flag_key, subject_key, subject_attributes, actions, default_variation)
|
72
|
+
attributes = coerce_context_attributes(subject_attributes)
|
73
|
+
actions = actions.to_h { |action, attributes| [action, coerce_context_attributes(attributes)] }
|
74
|
+
result = @core.get_bandit_action(flag_key, subject_key, attributes, actions, default_variation)
|
75
|
+
|
76
|
+
log_assignment(result[:assignment_event])
|
77
|
+
log_bandit_action(result[:bandit_event])
|
78
|
+
|
79
|
+
return {:variation => result[:variation], :action => result[:action]}
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_bandit_action_details(flag_key, subject_key, subject_attributes, actions, default_variation)
|
83
|
+
attributes = coerce_context_attributes(subject_attributes)
|
84
|
+
actions = actions.to_h { |action, attributes| [action, coerce_context_attributes(attributes)] }
|
85
|
+
result, details = @core.get_bandit_action_details(flag_key, subject_key, attributes, actions, default_variation)
|
86
|
+
|
87
|
+
log_assignment(result[:assignment_event])
|
88
|
+
log_bandit_action(result[:bandit_event])
|
89
|
+
|
90
|
+
return {
|
91
|
+
:variation => result[:variation],
|
92
|
+
:action => result[:action],
|
93
|
+
:evaluationDetails => details
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
# rubocop:disable Metrics/MethodLength
|
100
|
+
def get_assignment_inner(flag_key, subject_key, subject_attributes, expected_type, default_value)
|
106
101
|
logger = Logger.new($stdout)
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
assigned_variation&.value
|
112
|
-
end
|
113
|
-
deprecate :get_assignment, 'the get_<typed>_assignment methods', 2024, 1
|
114
|
-
|
115
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
116
|
-
def get_assignment_variation(
|
117
|
-
subject_key,
|
118
|
-
flag_key,
|
119
|
-
subject_attributes,
|
120
|
-
expected_variation_type,
|
121
|
-
logger
|
122
|
-
)
|
123
|
-
EppoClient.validate_not_blank('subject_key', subject_key)
|
124
|
-
EppoClient.validate_not_blank('flag_key', flag_key)
|
125
|
-
experiment_config = @config_requestor.get_configuration(flag_key)
|
126
|
-
override = get_subject_variation_override(experiment_config, subject_key)
|
127
|
-
unless override.nil?
|
128
|
-
unless expected_variation_type.nil?
|
129
|
-
variation_is_expected_type =
|
130
|
-
EppoClient::VariationType.expected_type?(
|
131
|
-
override, expected_variation_type
|
132
|
-
)
|
133
|
-
return nil unless variation_is_expected_type
|
102
|
+
begin
|
103
|
+
assignment = @core.get_assignment(flag_key, subject_key, subject_attributes, expected_type)
|
104
|
+
if not assignment then
|
105
|
+
return default_value
|
134
106
|
end
|
135
|
-
return override
|
136
|
-
end
|
137
107
|
|
138
|
-
|
139
|
-
logger.debug(
|
140
|
-
'[Eppo SDK] No assigned variation. No active experiment or flag for '\
|
141
|
-
"key: #{flag_key}"
|
142
|
-
)
|
143
|
-
return nil
|
144
|
-
end
|
108
|
+
log_assignment(assignment[:event])
|
145
109
|
|
146
|
-
|
147
|
-
|
148
|
-
logger.debug(
|
149
|
-
'[Eppo SDK] No assigned variation. Subject attributes do not match '\
|
150
|
-
"targeting rules: #{subject_attributes}"
|
151
|
-
)
|
152
|
-
return nil
|
153
|
-
end
|
110
|
+
return assignment[:value][:value]
|
111
|
+
rescue StandardError => error
|
112
|
+
logger.debug("[Eppo SDK] Failed to get assignment: #{error}")
|
154
113
|
|
155
|
-
|
156
|
-
|
157
|
-
subject_key,
|
158
|
-
flag_key,
|
159
|
-
experiment_config.subject_shards,
|
160
|
-
allocation.percent_exposure
|
161
|
-
)
|
162
|
-
logger.debug(
|
163
|
-
'[Eppo SDK] No assigned variation. Subject is not part of experiment'\
|
164
|
-
' sample population'
|
165
|
-
)
|
166
|
-
return nil
|
114
|
+
# TODO: non-graceful mode?
|
115
|
+
default_value
|
167
116
|
end
|
117
|
+
end
|
118
|
+
# rubocop:enable Metrics/MethodLength
|
168
119
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
)
|
173
|
-
|
174
|
-
|
120
|
+
# rubocop:disable Metrics/MethodLength
|
121
|
+
def get_assignment_details_inner(flag_key, subject_key, subject_attributes, expected_type, default_value)
|
122
|
+
result, event = @core.get_assignment_details(flag_key, subject_key, subject_attributes, expected_type)
|
123
|
+
log_assignment(event)
|
124
|
+
|
125
|
+
if not result[:variation] then
|
126
|
+
result[:variation] = default_value
|
127
|
+
else
|
128
|
+
# unwrap from AssignmentValue to untyped value
|
129
|
+
result[:variation] = result[:variation][:value]
|
175
130
|
end
|
176
131
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
unless expected_variation_type.nil?
|
181
|
-
variation_is_expected_type = EppoClient::VariationType.expected_type?(
|
182
|
-
assigned_variation, expected_variation_type
|
183
|
-
)
|
184
|
-
return nil unless variation_is_expected_type
|
185
|
-
end
|
186
|
-
end
|
132
|
+
return result
|
133
|
+
end
|
134
|
+
# rubocop:enable Metrics/MethodLength
|
187
135
|
|
188
|
-
|
189
|
-
|
190
|
-
"experiment": "#{flag_key}-#{matched_rule.allocation_key}",
|
191
|
-
"featureFlag": flag_key,
|
192
|
-
"variation": assigned_variation_value_to_log,
|
193
|
-
"subject": subject_key,
|
194
|
-
"timestamp": Time.now.utc.iso8601,
|
195
|
-
"subjectAttributes": subject_attributes
|
196
|
-
}
|
136
|
+
def log_assignment(event)
|
137
|
+
if not event then return end
|
197
138
|
|
139
|
+
# Because rust's AssignmentEvent has a #[flatten] extra_logging
|
140
|
+
# field, serde_magnus serializes it as a normal HashMap with
|
141
|
+
# string keys.
|
142
|
+
#
|
143
|
+
# Convert keys to symbols here, so that logger sees symbol-keyed
|
144
|
+
# events for both flag assignment and bandit actions.
|
145
|
+
event = event.to_h { |key, value| [key.to_sym, value]}
|
146
|
+
|
147
|
+
enrich_event_metadata(event)
|
198
148
|
begin
|
199
|
-
@assignment_logger.log_assignment(
|
200
|
-
rescue EppoClient::AssignmentLoggerError
|
201
|
-
|
202
|
-
rescue StandardError =>
|
203
|
-
logger.
|
149
|
+
@assignment_logger.log_assignment(event)
|
150
|
+
rescue EppoClient::AssignmentLoggerError
|
151
|
+
# Error means log_assignment was not set up. This is okay to ignore.
|
152
|
+
rescue StandardError => error
|
153
|
+
logger = Logger.new($stdout)
|
154
|
+
logger.error("[Eppo SDK] Error logging assignment event: #{error}")
|
204
155
|
end
|
205
|
-
|
206
|
-
assigned_variation
|
207
156
|
end
|
208
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
209
157
|
|
210
|
-
def
|
211
|
-
|
212
|
-
end
|
158
|
+
def log_bandit_action(event)
|
159
|
+
if not event then return end
|
213
160
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
experiment_config.overrides[subject_hash],
|
223
|
-
experiment_config.typed_overrides[subject_hash],
|
224
|
-
EppoClient::ShardRange.new(0, 1000)
|
225
|
-
)
|
161
|
+
enrich_event_metadata(event)
|
162
|
+
begin
|
163
|
+
@assignment_logger.log_bandit_action(event)
|
164
|
+
rescue EppoClient::AssignmentLoggerError
|
165
|
+
# Error means log_assignment was not set up. This is okay to ignore.
|
166
|
+
rescue StandardError => error
|
167
|
+
logger = Logger.new($stdout)
|
168
|
+
logger.error("[Eppo SDK] Error logging bandit action event: #{error}")
|
226
169
|
end
|
227
170
|
end
|
228
|
-
# rubocop:enable Metrics/MethodLength
|
229
171
|
|
230
|
-
def
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
172
|
+
def enrich_event_metadata(event)
|
173
|
+
event[:metaData]["sdkName"] = "ruby"
|
174
|
+
event[:metaData]["sdkVersion"] = EppoClient::VERSION
|
175
|
+
end
|
176
|
+
|
177
|
+
def coerce_context_attributes(attributes)
|
178
|
+
numeric_attributes = attributes[:numeric_attributes] || attributes["numericAttributes"]
|
179
|
+
categorical_attributes = attributes[:categorical_attributes] || attributes["categoricalAttributes"]
|
180
|
+
if numeric_attributes || categorical_attributes then
|
181
|
+
{
|
182
|
+
numericAttributes: numeric_attributes.to_h do |key, value|
|
183
|
+
value.is_a?(Numeric) ? [key, value] : [nil, nil]
|
184
|
+
end.compact,
|
185
|
+
categoricalAttributes: categorical_attributes.to_h do |key, value|
|
186
|
+
value.nil? ? [nil, nil] : [key, value.to_s]
|
187
|
+
end.compact,
|
188
|
+
}
|
189
|
+
end
|
235
190
|
end
|
236
191
|
end
|
237
|
-
# rubocop:enable Metrics/ClassLength
|
238
192
|
end
|
data/lib/eppo_client/config.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
3
|
+
require_relative "validation"
|
4
|
+
require_relative "assignment_logger"
|
5
5
|
|
6
6
|
module EppoClient
|
7
7
|
# The class for configuring the Eppo client singleton
|
8
8
|
class Config
|
9
9
|
attr_reader :api_key, :assignment_logger, :base_url
|
10
10
|
|
11
|
-
def initialize(api_key, assignment_logger: AssignmentLogger.new, base_url:
|
11
|
+
def initialize(api_key, assignment_logger: AssignmentLogger.new, base_url: EppoClient::Core::DEFAULT_BASE_URL)
|
12
12
|
@api_key = api_key
|
13
13
|
@assignment_logger = assignment_logger
|
14
14
|
@base_url = base_url
|
15
15
|
end
|
16
16
|
|
17
17
|
def validate
|
18
|
-
EppoClient.validate_not_blank(
|
18
|
+
EppoClient.validate_not_blank("api_key", @api_key)
|
19
19
|
end
|
20
20
|
|
21
21
|
# Hide instance variables (specifically api_key) from logs
|
@@ -8,23 +8,6 @@ module EppoClient
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
# A custom error class for unauthorized requests
|
12
|
-
class UnauthorizedError < StandardError
|
13
|
-
def initialize(message)
|
14
|
-
super("Unauthorized: #{message}")
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# A custom error class for HTTP requests
|
19
|
-
class HttpRequestError < StandardError
|
20
|
-
attr_reader :status_code
|
21
|
-
|
22
|
-
def initialize(message, status_code)
|
23
|
-
@status_code = status_code
|
24
|
-
super("HttpRequestError: #{message}")
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
11
|
# A custom error class for invalid values
|
29
12
|
class InvalidValueError < StandardError
|
30
13
|
def initialize(message)
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "custom_errors"
|
4
4
|
|
5
5
|
# The helper module to validate keys
|
6
6
|
module EppoClient
|
7
7
|
module_function
|
8
8
|
|
9
9
|
def validate_not_blank(field_name, field_value)
|
10
|
-
(field_value.nil? || field_value ==
|
10
|
+
(field_value.nil? || field_value == "") && raise(
|
11
11
|
EppoClient::InvalidValueError, "#{field_name} cannot be blank"
|
12
12
|
)
|
13
13
|
end
|
data/lib/eppo_client/version.rb
CHANGED
data/lib/eppo_client.rb
CHANGED
@@ -1,53 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative 'eppo_client/poller'
|
6
|
-
require_relative 'eppo_client/config'
|
7
|
-
require_relative 'eppo_client/client'
|
8
|
-
require_relative 'eppo_client/constants'
|
9
|
-
require_relative 'eppo_client/configuration_requestor'
|
10
|
-
require_relative 'eppo_client/configuration_store'
|
11
|
-
require_relative 'eppo_client/version'
|
3
|
+
require_relative "eppo_client/client"
|
4
|
+
require_relative "eppo_client/version"
|
12
5
|
|
13
|
-
#
|
6
|
+
# EppoClient is the main module for initializing the Eppo client.
|
7
|
+
# It provides a method to initialize the client with a given configuration.
|
14
8
|
module EppoClient
|
15
|
-
# rubocop:disable Metrics/MethodLength
|
16
|
-
def initialize_client(config_requestor, assignment_logger)
|
17
|
-
client = EppoClient::Client.instance
|
18
|
-
!client.poller.nil? && client.shutdown
|
19
|
-
client.config_requestor = config_requestor
|
20
|
-
client.assignment_logger = assignment_logger
|
21
|
-
client.poller = EppoClient::Poller.new(
|
22
|
-
EppoClient::POLL_INTERVAL_MILLIS,
|
23
|
-
EppoClient::POLL_JITTER_MILLIS,
|
24
|
-
proc { client.config_requestor.fetch_and_store_configurations }
|
25
|
-
)
|
26
|
-
client.poller.start
|
27
|
-
client
|
28
|
-
end
|
29
|
-
# rubocop:enable Metrics/MethodLength
|
30
|
-
|
31
|
-
# rubocop:disable Metrics/MethodLength
|
32
9
|
def init(config)
|
33
|
-
|
34
|
-
|
35
|
-
EppoClient::VERSION)
|
36
|
-
http_client = EppoClient::HttpClient.new(config.base_url,
|
37
|
-
sdk_params.formatted)
|
38
|
-
config_store = EppoClient::ConfigurationStore.new(
|
39
|
-
EppoClient::MAX_CACHE_ENTRIES
|
40
|
-
)
|
41
|
-
config_store.lock.with_write_lock do
|
42
|
-
EppoClient.initialize_client(
|
43
|
-
EppoClient::ExperimentConfigurationRequestor.new(
|
44
|
-
http_client, config_store
|
45
|
-
),
|
46
|
-
config.assignment_logger
|
47
|
-
)
|
48
|
-
end
|
10
|
+
client = EppoClient::Client.instance
|
11
|
+
client.init(config)
|
49
12
|
end
|
50
|
-
# rubocop:enable Metrics/MethodLength
|
51
13
|
|
52
|
-
module_function :init
|
14
|
+
module_function :init
|
53
15
|
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# EppoClient is the main module for initializing the Eppo client.
|
2
|
+
# It provides a method to initialize the client with a given configuration.
|
3
|
+
module EppoClient
|
4
|
+
def self.init: (Config config) -> void
|
5
|
+
|
6
|
+
# The base assignment logger class to override
|
7
|
+
class AssignmentLogger
|
8
|
+
def log_assignment: (untyped assignment_event) -> void
|
9
|
+
|
10
|
+
def log_bandit_action: (untyped assignment_event) -> void
|
11
|
+
end
|
12
|
+
|
13
|
+
# The main client singleton
|
14
|
+
class Client
|
15
|
+
@assignment_logger: AssignmentLogger
|
16
|
+
@core: Core::Client
|
17
|
+
|
18
|
+
include Singleton
|
19
|
+
|
20
|
+
attr_accessor assignment_logger: AssignmentLogger
|
21
|
+
|
22
|
+
def self.instance: () -> Client
|
23
|
+
|
24
|
+
def init: (Config config) -> void
|
25
|
+
|
26
|
+
def shutdown: () -> void
|
27
|
+
|
28
|
+
def get_string_assignment: (String flag_key, String subject_key, Hash[String, untyped] subject_attributes, String default_value) -> String
|
29
|
+
|
30
|
+
def get_numeric_assignment: (String flag_key, String subject_key, Hash[String, untyped] subject_attributes, Numeric default_value) -> Numeric
|
31
|
+
|
32
|
+
def get_integer_assignment: (String flag_key, String subject_key, Hash[String, untyped] subject_attributes, Integer default_value) -> Integer
|
33
|
+
|
34
|
+
def get_boolean_assignment: (String flag_key, String subject_key, Hash[String, untyped] subject_attributes, bool default_value) -> bool
|
35
|
+
|
36
|
+
def get_json_assignment: (String flag_key, String subject_key, Hash[String, untyped] subject_attributes, Object default_value) -> Object
|
37
|
+
|
38
|
+
def get_bandit_action: (String flag_key, String subject_key, Hash[String, untyped] subject_attributes, Hash[String, untyped] actions, String default_variation) -> { variation: untyped, action: untyped }
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# rubocop:disable Metrics/MethodLength
|
43
|
+
def get_assignment_inner: (untyped flag_key, String subject_key, untyped subject_attributes, untyped expected_type, untyped default_value) -> untyped
|
44
|
+
|
45
|
+
def log_assignment: (untyped event) -> void
|
46
|
+
|
47
|
+
def log_bandit_action: (untyped event) -> void
|
48
|
+
|
49
|
+
def enrich_event_metadata: (untyped event) -> void
|
50
|
+
|
51
|
+
def coerce_context_attributes: (untyped attributes) -> untyped
|
52
|
+
end
|
53
|
+
|
54
|
+
# The class for configuring the Eppo client singleton
|
55
|
+
class Config
|
56
|
+
@api_key: String
|
57
|
+
@assignment_logger: AssignmentLogger
|
58
|
+
@base_url: String
|
59
|
+
|
60
|
+
attr_reader api_key: String
|
61
|
+
attr_reader assignment_logger: AssignmentLogger
|
62
|
+
attr_reader base_url: String
|
63
|
+
|
64
|
+
def initialize: (String api_key, ?assignment_logger: AssignmentLogger, ?base_url: String) -> void
|
65
|
+
|
66
|
+
def validate: () -> void
|
67
|
+
|
68
|
+
# Hide instance variables (specifically api_key) from logs
|
69
|
+
def inspect: () -> ::String
|
70
|
+
end
|
71
|
+
|
72
|
+
# A custom error class for AssignmentLogger
|
73
|
+
class AssignmentLoggerError < StandardError
|
74
|
+
def initialize: (String message) -> void
|
75
|
+
end
|
76
|
+
|
77
|
+
# A custom error class for invalid values
|
78
|
+
class InvalidValueError < StandardError
|
79
|
+
def initialize: (String message) -> void
|
80
|
+
end
|
81
|
+
|
82
|
+
def self?.validate_not_blank: (String field_name, String field_value) -> void
|
83
|
+
|
84
|
+
VERSION: String
|
85
|
+
end
|
86
|
+
|
87
|
+
# Exposed from Rust
|
88
|
+
module EppoClient::Core
|
89
|
+
DEFAULT_BASE_URL: String
|
90
|
+
class Client
|
91
|
+
def self.new: (untyped config) -> Client
|
92
|
+
def shutdown: () -> void
|
93
|
+
def get_assignment: (String flag_key, String subject_key, untyped subject_attributes, String expected_type) -> untyped
|
94
|
+
def get_bandit_action: (String flag_key, String subject_key, untyped attributes, untyped actions, String default_variation) -> untyped
|
95
|
+
end
|
96
|
+
end
|