flipt_client 0.17.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +77 -28
- data/flipt-client-ruby.gemspec +1 -1
- data/lib/ext/darwin_aarch64/libfliptengine.dylib +0 -0
- data/lib/ext/darwin_x86_64/libfliptengine.dylib +0 -0
- data/lib/ext/flipt_engine.h +67 -14
- data/lib/ext/linux_aarch64/libfliptengine.so +0 -0
- data/lib/ext/linux_x86_64/libfliptengine.so +0 -0
- data/lib/ext/windows_x86_64/fliptengine.dll +0 -0
- data/lib/flipt_client/models.rb +62 -0
- data/lib/flipt_client/version.rb +1 -1
- data/lib/flipt_client.rb +120 -48
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8cfa993fb8a7521e64c37cef82bf58088f8961d9779e6c5dc9092696a127c6ff
|
4
|
+
data.tar.gz: 2cddbf45abafabd21660a60ab64378a2b1c4bfdafee4b931805ca8b2a1c2d002
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2cc595e3b40f37c420b920415d65e439a6295ddc1d1b4c22dc0fb2cb98e43e36912842568e1eb47246a088f15eb6bcce530e020daf0c2d34253fec9fa18347d
|
7
|
+
data.tar.gz: 26c75eb569c0e0df06cf287ae7f9cb5beb0466be5e1c1cb8ec49252d38277914afa842f56650d7dd857cb3696d73d17a68ea6082ada6101f3bbfa729142c934f
|
data/README.md
CHANGED
@@ -26,9 +26,9 @@ Upon instantiation, the `flipt-client-ruby` library will fetch the flag state fr
|
|
26
26
|
|
27
27
|
By default, the SDK will poll the Flipt server for new flag state at a regular interval. This interval can be configured using the `update_interval` option when constructing a client. The default interval is 120 seconds.
|
28
28
|
|
29
|
-
### Streaming (Flipt Cloud
|
29
|
+
### Streaming (Flipt Cloud/Flipt v2)
|
30
30
|
|
31
|
-
[Flipt Cloud](https://flipt.io/cloud) users can use the `streaming` fetch method to stream flag state changes from the Flipt server to the SDK.
|
31
|
+
[Flipt Cloud](https://flipt.io/cloud) and [Flipt v2](https://docs.flipt.io/v2) users can use the `streaming` fetch method to stream flag state changes from the Flipt server to the SDK.
|
32
32
|
|
33
33
|
When in streaming mode, the SDK will connect to the Flipt server and open a persistent connection that will remain open until the client is closed. The SDK will then receive flag state changes in real-time.
|
34
34
|
|
@@ -67,6 +67,21 @@ gem install ffi -- --enable-system-libffi # to install the gem manually
|
|
67
67
|
bundle config build.ffi --enable-system-libffi # for bundle install
|
68
68
|
```
|
69
69
|
|
70
|
+
## Migration Notes
|
71
|
+
|
72
|
+
### Pre-1.0.0 -> 1.0.0
|
73
|
+
|
74
|
+
This section is for users who are migrating from a previous (pre-1.0.0) version of the SDK.
|
75
|
+
|
76
|
+
- `Flipt::EvaluationClient` has been renamed to `Flipt::Client`. Update all usages and imports accordingly. A deprecation warning is emitted if you use the old class.
|
77
|
+
- All evaluation methods now use **keyword arguments** (e.g., `flag_key:`, `entity_id:`, `context:`) instead of a single hash argument. Update your method calls to use keyword arguments.
|
78
|
+
- All evaluation methods now return **response model objects** (`VariantEvaluationResponse`, `BooleanEvaluationResponse`, `BatchEvaluationResponse`, `ErrorEvaluationResponse`) instead of raw hashes. Update your code to use attribute readers (e.g., `resp.flag_key`, `resp.enabled`).
|
79
|
+
- Batch evaluation responses now contain an array of model objects, not hashes.
|
80
|
+
- Error handling is now standardized and idiomatic. All errors inherit from `Flipt::Error` (with subclasses like `ValidationError`, `EvaluationError`). Update your rescue blocks accordingly.
|
81
|
+
- The minimum supported Ruby version is now 2.7.0.
|
82
|
+
- The client constructor now accepts keyword arguments for configuration (e.g., `url:`, `namespace:`, `authentication:`). The `environment` option is now supported.
|
83
|
+
- The API and documentation are more idiomatic and Ruby-like throughout.
|
84
|
+
|
70
85
|
## Usage
|
71
86
|
|
72
87
|
In your Ruby code you can import this client and use it as so:
|
@@ -74,41 +89,35 @@ In your Ruby code you can import this client and use it as so:
|
|
74
89
|
```ruby
|
75
90
|
require 'flipt_client'
|
76
91
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
|
84
|
-
|
85
|
-
#
|
86
|
-
#
|
87
|
-
# You can replace the url with where your upstream Flipt instance points to, the update interval for how long you are willing
|
88
|
-
# to wait for updated flag state, and the auth token if your Flipt instance requires it.
|
89
|
-
client = Flipt::EvaluationClient.new()
|
90
|
-
resp = client.evaluate_variant({ flag_key: 'buzz', entity_id: 'someentity', context: { fizz: 'buzz' } })
|
91
|
-
|
92
|
-
puts resp
|
92
|
+
client = Flipt::Client.new(url: 'http://localhost:8080', authentication: Flipt::ClientTokenAuthentication.new('secret'))
|
93
|
+
|
94
|
+
resp = client.evaluate_variant(flag_key: 'buzz', entity_id: 'someentity', context: { fizz: 'buzz' })
|
95
|
+
puts resp.flag_key # => 'buzz'
|
96
|
+
puts resp.match # => true
|
97
|
+
puts resp.reason # => 'MATCH_EVALUATION_REASON'
|
98
|
+
|
99
|
+
resp = client.evaluate_boolean(flag_key: 'my-feature', entity_id: 'someentity')
|
100
|
+
puts resp.enabled # => true
|
93
101
|
```
|
94
102
|
|
95
103
|
### Constructor Arguments
|
96
104
|
|
97
|
-
The `Flipt::
|
105
|
+
The `Flipt::Client` constructor accepts the following keyword arguments:
|
98
106
|
|
107
|
+
- `environment`: The environment (Flipt v2) to fetch flag state from. If not provided, the client will default to the `default` environment.
|
99
108
|
- `namespace`: The namespace to fetch flag state from. If not provided, the client will default to the `default` namespace.
|
100
|
-
- `
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
109
|
+
- `url`: The URL of the upstream Flipt instance. Defaults to `http://localhost:8080`.
|
110
|
+
- `request_timeout`: Timeout (in seconds) for requests. Defaults to no timeout.
|
111
|
+
- `update_interval`: Interval (in seconds) to fetch new flag state. Defaults to 120 seconds.
|
112
|
+
- `authentication`: The authentication strategy to use. Defaults to no authentication. See [Authentication](#authentication).
|
113
|
+
- `reference`: The [reference](https://docs.flipt.io/guides/user/using-references) to use when fetching flag state.
|
114
|
+
- `fetch_mode`: The fetch mode to use. Defaults to polling.
|
115
|
+
- `error_strategy`: The error strategy to use. Defaults to fail. See [Error Strategies](#error-strategies).
|
116
|
+
- `snapshot`: The snapshot to use when initializing the client. Defaults to no snapshot. See [Snapshotting](#snapshotting).
|
108
117
|
|
109
118
|
### Authentication
|
110
119
|
|
111
|
-
The `
|
120
|
+
The `Flipt::Client` supports the following authentication strategies:
|
112
121
|
|
113
122
|
- No Authentication (default)
|
114
123
|
- [Client Token Authentication](https://docs.flipt.io/authentication/using-tokens)
|
@@ -121,6 +130,46 @@ The client supports the following error strategies:
|
|
121
130
|
- `fail`: The client will throw an error if the flag state cannot be fetched. This is the default behavior.
|
122
131
|
- `fallback`: The client will maintain the last known good state and use that state for evaluation in case of an error.
|
123
132
|
|
133
|
+
### Response Models
|
134
|
+
|
135
|
+
All evaluation methods return response model objects:
|
136
|
+
|
137
|
+
- `evaluate_variant` returns a `Flipt::VariantEvaluationResponse`
|
138
|
+
- `evaluate_boolean` returns a `Flipt::BooleanEvaluationResponse`
|
139
|
+
- `evaluate_batch` returns a `Flipt::BatchEvaluationResponse`
|
140
|
+
|
141
|
+
### Error Handling
|
142
|
+
|
143
|
+
All errors inherit from `Flipt::Error`. Common subclasses include:
|
144
|
+
|
145
|
+
- `Flipt::ValidationError`
|
146
|
+
- `Flipt::EvaluationError`
|
147
|
+
|
148
|
+
You can rescue these errors as needed:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
begin
|
152
|
+
client.evaluate_variant(flag_key: 'missing', entity_id: 'user')
|
153
|
+
rescue Flipt::EvaluationError => e
|
154
|
+
puts "Evaluation failed: #{e.message}"
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
### Snapshotting
|
159
|
+
|
160
|
+
The client supports snapshotting of flag state as well as seeding the client with a snapshot for evaluation. This is helpful if you want to use the client in an environment where the Flipt server is not guaranteed to be available or reachable on startup.
|
161
|
+
|
162
|
+
To get the snapshot for the client, you can use the `snapshot` method. This returns a base64 encoded JSON string that represents the flag state for the client.
|
163
|
+
|
164
|
+
You can set the snapshot for the client using the `snapshot` option when constructing a client.
|
165
|
+
|
166
|
+
**Note:** You most likely will want to also set the `error_strategy` to `fallback` when using snapshots. This will ensure that you wont get an error if the Flipt server is not available or reachable even on the initial fetch.
|
167
|
+
|
168
|
+
You also may want to store the snapshot in a local file so that you can use it to seed the client on startup.
|
169
|
+
|
170
|
+
> [!IMPORTANT]
|
171
|
+
> If the Flipt server becomes reachable after the setting the snapshot, the client will replace the snapshot with the new flag state from the Flipt server.
|
172
|
+
|
124
173
|
## Load Test
|
125
174
|
|
126
175
|
1. To run the load test, you'll need to have Flipt running locally. You can do this by running the following command from the root of the repository:
|
data/flipt-client-ruby.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.description = 'Flipt Client Evaluation SDK'
|
12
12
|
spec.homepage = 'https://www.flipt.io'
|
13
13
|
spec.license = 'MIT'
|
14
|
-
spec.required_ruby_version = Gem::Requirement.new('>= 2.
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
|
15
15
|
|
16
16
|
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
17
17
|
|
Binary file
|
Binary file
|
data/lib/ext/flipt_engine.h
CHANGED
@@ -8,7 +8,35 @@
|
|
8
8
|
*
|
9
9
|
* This function will initialize an Engine and return a pointer back to the caller.
|
10
10
|
*/
|
11
|
-
void *
|
11
|
+
void *initialize_engine_ffi(const char *opts);
|
12
|
+
|
13
|
+
/**
|
14
|
+
* # Safety
|
15
|
+
*
|
16
|
+
* This function will initialize an Engine and return a pointer back to the caller.
|
17
|
+
*/
|
18
|
+
void *initialize_engine(const char *opts);
|
19
|
+
|
20
|
+
/**
|
21
|
+
* # Safety
|
22
|
+
*
|
23
|
+
* This function will take in a pointer to the engine and return the current snapshot as a JSON string.
|
24
|
+
*/
|
25
|
+
const char *get_snapshot_ffi(void *engine_ptr);
|
26
|
+
|
27
|
+
/**
|
28
|
+
* # Safety
|
29
|
+
*
|
30
|
+
* This function will take in a pointer to the engine and return the current snapshot as a JSON string.
|
31
|
+
*/
|
32
|
+
const char *get_snapshot(void *engine_ptr);
|
33
|
+
|
34
|
+
/**
|
35
|
+
* # Safety
|
36
|
+
*
|
37
|
+
* This function will take in a pointer to the engine and return a variant evaluation response.
|
38
|
+
*/
|
39
|
+
const char *evaluate_variant_ffi(void *engine_ptr, const char *evaluation_request);
|
12
40
|
|
13
41
|
/**
|
14
42
|
* # Safety
|
@@ -17,6 +45,13 @@ void *initialize_engine(const char *namespace_, const char *opts);
|
|
17
45
|
*/
|
18
46
|
const char *evaluate_variant(void *engine_ptr, const char *evaluation_request);
|
19
47
|
|
48
|
+
/**
|
49
|
+
* # Safety
|
50
|
+
*
|
51
|
+
* This function will take in a pointer to the engine and return a boolean evaluation response.
|
52
|
+
*/
|
53
|
+
const char *evaluate_boolean_ffi(void *engine_ptr, const char *evaluation_request);
|
54
|
+
|
20
55
|
/**
|
21
56
|
* # Safety
|
22
57
|
*
|
@@ -24,6 +59,13 @@ const char *evaluate_variant(void *engine_ptr, const char *evaluation_request);
|
|
24
59
|
*/
|
25
60
|
const char *evaluate_boolean(void *engine_ptr, const char *evaluation_request);
|
26
61
|
|
62
|
+
/**
|
63
|
+
* # Safety
|
64
|
+
*
|
65
|
+
* This function will take in a pointer to the engine and return a batch evaluation response.
|
66
|
+
*/
|
67
|
+
const char *evaluate_batch_ffi(void *engine_ptr, const char *batch_evaluation_request);
|
68
|
+
|
27
69
|
/**
|
28
70
|
* # Safety
|
29
71
|
*
|
@@ -34,30 +76,41 @@ const char *evaluate_batch(void *engine_ptr, const char *batch_evaluation_reques
|
|
34
76
|
/**
|
35
77
|
* # Safety
|
36
78
|
*
|
37
|
-
* This function will take in a pointer to the engine and return a list of flags
|
79
|
+
* This function will take in a pointer to the engine and return a list of flags.
|
80
|
+
*/
|
81
|
+
const char *list_flags_ffi(void *engine_ptr);
|
82
|
+
|
83
|
+
/**
|
84
|
+
* # Safety
|
85
|
+
*
|
86
|
+
* This function will take in a pointer to the engine and return a list of flags.
|
38
87
|
*/
|
39
88
|
const char *list_flags(void *engine_ptr);
|
40
89
|
|
41
90
|
/**
|
42
91
|
* # Safety
|
43
92
|
*
|
44
|
-
* This function will
|
93
|
+
* This function will take in a pointer to the engine and destroy it.
|
94
|
+
*/
|
95
|
+
void destroy_engine_ffi(void *engine_ptr);
|
96
|
+
|
97
|
+
/**
|
98
|
+
* # Safety
|
99
|
+
*
|
100
|
+
* This function will take in a pointer to the engine and destroy it.
|
45
101
|
*/
|
46
102
|
void destroy_engine(void *engine_ptr);
|
47
103
|
|
48
104
|
/**
|
49
105
|
* # Safety
|
50
106
|
*
|
51
|
-
* This function will take in a pointer to
|
52
|
-
* See Rust the safety section in CString::from_raw.
|
107
|
+
* This function will take in a pointer to a string and destroy it.
|
53
108
|
*/
|
54
|
-
void
|
109
|
+
void destroy_string_ffi(char *ptr);
|
55
110
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
extern void destroy_engine_ffi(void* engine);
|
63
|
-
extern void destroy_string_ffi(char* str);
|
111
|
+
/**
|
112
|
+
* # Safety
|
113
|
+
*
|
114
|
+
* This function will take in a pointer to a string and destroy it.
|
115
|
+
*/
|
116
|
+
void destroy_string(char *ptr);
|
Binary file
|
Binary file
|
Binary file
|
data/lib/flipt_client/models.rb
CHANGED
@@ -40,4 +40,66 @@ module Flipt
|
|
40
40
|
}
|
41
41
|
end
|
42
42
|
end
|
43
|
+
|
44
|
+
# VariantEvaluationResponse
|
45
|
+
# @attr_reader [String] flag_key
|
46
|
+
# @attr_reader [Boolean] match
|
47
|
+
# @attr_reader [String] reason
|
48
|
+
# @attr_reader [String] variant_key
|
49
|
+
# @attr_reader [String, nil] variant_attachment
|
50
|
+
# @attr_reader [Array<String>] segment_keys
|
51
|
+
class VariantEvaluationResponse
|
52
|
+
attr_reader :flag_key, :match, :reason, :variant_key, :variant_attachment, :segment_keys
|
53
|
+
|
54
|
+
def initialize(flag_key:, match:, reason:, variant_key:, variant_attachment: nil, segment_keys: [])
|
55
|
+
@flag_key = flag_key
|
56
|
+
@match = match
|
57
|
+
@reason = reason
|
58
|
+
@variant_key = variant_key
|
59
|
+
@variant_attachment = variant_attachment
|
60
|
+
@segment_keys = segment_keys
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# BooleanEvaluationResponse
|
65
|
+
# @attr_reader [String] flag_key
|
66
|
+
# @attr_reader [Boolean] enabled
|
67
|
+
# @attr_reader [String] reason
|
68
|
+
# @attr_reader [Array<String>] segment_keys
|
69
|
+
class BooleanEvaluationResponse
|
70
|
+
attr_reader :flag_key, :enabled, :reason, :segment_keys
|
71
|
+
|
72
|
+
def initialize(flag_key:, enabled:, reason:, segment_keys: [])
|
73
|
+
@flag_key = flag_key
|
74
|
+
@enabled = enabled
|
75
|
+
@reason = reason
|
76
|
+
@segment_keys = segment_keys
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# ErrorEvaluationResponse
|
81
|
+
# @attr_reader [String] flag_key
|
82
|
+
# @attr_reader [String] namespace_key
|
83
|
+
# @attr_reader [String] reason
|
84
|
+
# @attr_reader [String] error_message
|
85
|
+
class ErrorEvaluationResponse
|
86
|
+
attr_reader :flag_key, :namespace_key, :reason, :error_message
|
87
|
+
|
88
|
+
def initialize(flag_key:, namespace_key:, reason:, error_message:)
|
89
|
+
@flag_key = flag_key
|
90
|
+
@namespace_key = namespace_key
|
91
|
+
@reason = reason
|
92
|
+
@error_message = error_message
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# BatchEvaluationResponse
|
97
|
+
# @attr_reader [Array] responses
|
98
|
+
class BatchEvaluationResponse
|
99
|
+
attr_reader :responses
|
100
|
+
|
101
|
+
def initialize(responses: [])
|
102
|
+
@responses = responses
|
103
|
+
end
|
104
|
+
end
|
43
105
|
end
|
data/lib/flipt_client/version.rb
CHANGED
data/lib/flipt_client.rb
CHANGED
@@ -7,9 +7,11 @@ require 'json'
|
|
7
7
|
|
8
8
|
module Flipt
|
9
9
|
class Error < StandardError; end
|
10
|
+
class ValidationError < Error; end
|
11
|
+
class EvaluationError < Error; end
|
10
12
|
|
11
|
-
#
|
12
|
-
class
|
13
|
+
# Client is a Ruby Client Side Evaluation Library for Flipt
|
14
|
+
class Client
|
13
15
|
extend FFI::Library
|
14
16
|
|
15
17
|
FLIPTENGINE = 'fliptengine'
|
@@ -32,8 +34,8 @@ module Flipt
|
|
32
34
|
|
33
35
|
ffi_lib File.expand_path(libfile, __dir__)
|
34
36
|
|
35
|
-
# void *initialize_engine(const char *
|
36
|
-
attach_function :initialize_engine,
|
37
|
+
# void *initialize_engine(const char *opts);
|
38
|
+
attach_function :initialize_engine, [:string], :pointer
|
37
39
|
# void destroy_engine(void *engine_ptr);
|
38
40
|
attach_function :destroy_engine, [:pointer], :void
|
39
41
|
# const char *evaluate_variant(void *engine_ptr, const char *evaluation_request);
|
@@ -46,27 +48,31 @@ module Flipt
|
|
46
48
|
attach_function :list_flags, [:pointer], :strptr
|
47
49
|
# void destroy_string(const char *ptr);
|
48
50
|
attach_function :destroy_string, [:pointer], :void
|
51
|
+
# const char *get_snapshot(void *engine_ptr);
|
52
|
+
attach_function :get_snapshot, [:pointer], :strptr
|
49
53
|
|
50
54
|
# Create a new Flipt client
|
51
55
|
#
|
52
|
-
# @param namespace [String] namespace
|
53
56
|
# @param opts [Hash] options
|
57
|
+
# @option opts [String] :environment Flipt environment (default: 'default')
|
58
|
+
# @option opts [String] :namespace Flipt namespace (default: 'default')
|
54
59
|
# @option opts [String] :url Flipt server url
|
55
60
|
# @option opts [AuthenticationStrategy] :authentication strategy to authenticate with Flipt
|
56
61
|
# @option opts [Integer] :request_timeout timeout in seconds for the request
|
57
62
|
# @option opts [Integer] :update_interval interval in seconds to update the cache
|
58
63
|
# @option opts [String] :reference reference to use for namespace data
|
59
64
|
# @option opts [Symbol] :fetch_mode fetch mode to use for the client (:polling or :streaming).
|
60
|
-
# Note: Streaming is currently only supported when using the SDK with Flipt Cloud
|
65
|
+
# Note: Streaming is currently only supported when using the SDK with Flipt Cloud or Flipt v2.
|
61
66
|
# @option opts [Symbol] :error_strategy error strategy to use for the client (:fail or :fallback).
|
62
|
-
|
63
|
-
|
67
|
+
# @option opts [String] :snapshot snapshot to use when initializing the client
|
68
|
+
def initialize(**opts)
|
69
|
+
@namespace = opts.fetch(:namespace, 'default')
|
64
70
|
|
65
71
|
opts[:authentication] = validate_authentication(opts.fetch(:authentication, NoAuthentication.new))
|
66
72
|
opts[:fetch_mode] = validate_fetch_mode(opts.fetch(:fetch_mode, :polling))
|
67
73
|
opts[:error_strategy] = validate_error_strategy(opts.fetch(:error_strategy, :fail))
|
68
74
|
|
69
|
-
@engine = self.class.initialize_engine(
|
75
|
+
@engine = self.class.initialize_engine(opts.to_json)
|
70
76
|
ObjectSpace.define_finalizer(self, self.class.finalize(@engine))
|
71
77
|
end
|
72
78
|
|
@@ -76,88 +82,154 @@ module Flipt
|
|
76
82
|
|
77
83
|
# Evaluate a variant flag for a given request
|
78
84
|
#
|
79
|
-
# @param
|
80
|
-
# @
|
81
|
-
# @
|
82
|
-
def evaluate_variant(
|
83
|
-
validate_evaluation_request(
|
84
|
-
|
85
|
-
ptr =
|
85
|
+
# @param flag_key [String]
|
86
|
+
# @param entity_id [String]
|
87
|
+
# @param context [Hash]
|
88
|
+
def evaluate_variant(flag_key:, entity_id:, context: {})
|
89
|
+
validate_evaluation_request(flag_key, entity_id, context)
|
90
|
+
req = { flag_key: flag_key, entity_id: entity_id, context: context }
|
91
|
+
resp, ptr = self.class.evaluate_variant(@engine, req.to_json)
|
92
|
+
ptr = FFI::AutoPointer.new(ptr, Client.method(:destroy_string))
|
86
93
|
data = JSON.parse(resp)
|
87
|
-
raise
|
88
|
-
|
89
|
-
data['result']
|
94
|
+
raise EvaluationError, data['error_message'] if data['status'] != 'success'
|
95
|
+
|
96
|
+
r = data['result']
|
97
|
+
VariantEvaluationResponse.new(
|
98
|
+
flag_key: r['flag_key'],
|
99
|
+
match: r['match'],
|
100
|
+
reason: r['reason'],
|
101
|
+
variant_key: r['variant_key'],
|
102
|
+
variant_attachment: r['variant_attachment'],
|
103
|
+
segment_keys: r['segment_keys'] || []
|
104
|
+
)
|
90
105
|
end
|
91
106
|
|
92
107
|
# Evaluate a boolean flag for a given request
|
93
108
|
#
|
94
|
-
# @param
|
95
|
-
# @
|
96
|
-
# @
|
97
|
-
def evaluate_boolean(
|
98
|
-
validate_evaluation_request(
|
99
|
-
|
100
|
-
ptr =
|
109
|
+
# @param flag_key [String]
|
110
|
+
# @param entity_id [String]
|
111
|
+
# @param context [Hash]
|
112
|
+
def evaluate_boolean(flag_key:, entity_id:, context: {})
|
113
|
+
validate_evaluation_request(flag_key, entity_id, context)
|
114
|
+
req = { flag_key: flag_key, entity_id: entity_id, context: context }
|
115
|
+
resp, ptr = self.class.evaluate_boolean(@engine, req.to_json)
|
116
|
+
ptr = FFI::AutoPointer.new(ptr, Client.method(:destroy_string))
|
101
117
|
data = JSON.parse(resp)
|
102
|
-
raise
|
103
|
-
|
104
|
-
data['result']
|
118
|
+
raise EvaluationError, data['error_message'] if data['status'] != 'success'
|
119
|
+
|
120
|
+
r = data['result']
|
121
|
+
BooleanEvaluationResponse.new(
|
122
|
+
flag_key: r['flag_key'],
|
123
|
+
enabled: r['enabled'],
|
124
|
+
reason: r['reason'],
|
125
|
+
segment_keys: r['segment_keys'] || []
|
126
|
+
)
|
105
127
|
end
|
106
128
|
|
107
129
|
# Evaluate a batch of flags for a given request
|
108
130
|
#
|
109
|
-
# @param
|
131
|
+
# @param requests [Array<Hash>] batch evaluation request
|
110
132
|
# - :entity_id [String] entity id
|
111
133
|
# - :flag_key [String] flag key
|
112
|
-
def evaluate_batch(
|
113
|
-
|
114
|
-
|
134
|
+
def evaluate_batch(requests:)
|
135
|
+
unless requests.is_a?(Array)
|
136
|
+
raise ValidationError, 'requests must be an array of evaluation requests'
|
115
137
|
end
|
116
138
|
|
117
|
-
|
118
|
-
|
139
|
+
requests.each do |request|
|
140
|
+
validate_evaluation_request(request[:flag_key], request[:entity_id], request[:context] || {})
|
141
|
+
end
|
142
|
+
resp, ptr = self.class.evaluate_batch(@engine, requests.to_json)
|
143
|
+
ptr = FFI::AutoPointer.new(ptr, Client.method(:destroy_string))
|
119
144
|
data = JSON.parse(resp)
|
120
|
-
raise
|
121
|
-
|
122
|
-
data['result']
|
145
|
+
raise EvaluationError, data['error_message'] if data['status'] != 'success'
|
146
|
+
|
147
|
+
responses = (data['result']['responses'] || []).map do |r|
|
148
|
+
case r['type']
|
149
|
+
when 'VARIANT_EVALUATION_RESPONSE_TYPE'
|
150
|
+
v = r['variant_evaluation_response']
|
151
|
+
VariantEvaluationResponse.new(
|
152
|
+
flag_key: v['flag_key'],
|
153
|
+
match: v['match'],
|
154
|
+
reason: v['reason'],
|
155
|
+
variant_key: v['variant_key'],
|
156
|
+
variant_attachment: v['variant_attachment'],
|
157
|
+
segment_keys: v['segment_keys'] || []
|
158
|
+
)
|
159
|
+
when 'BOOLEAN_EVALUATION_RESPONSE_TYPE'
|
160
|
+
b = r['boolean_evaluation_response']
|
161
|
+
BooleanEvaluationResponse.new(
|
162
|
+
flag_key: b['flag_key'],
|
163
|
+
enabled: b['enabled'],
|
164
|
+
reason: b['reason'],
|
165
|
+
segment_keys: b['segment_keys'] || []
|
166
|
+
)
|
167
|
+
when 'ERROR_EVALUATION_RESPONSE_TYPE'
|
168
|
+
e = r['error_evaluation_response']
|
169
|
+
ErrorEvaluationResponse.new(
|
170
|
+
flag_key: e['flag_key'],
|
171
|
+
namespace_key: e['namespace_key'],
|
172
|
+
reason: e['reason'],
|
173
|
+
error_message: e['error_message']
|
174
|
+
)
|
175
|
+
else
|
176
|
+
raise EvaluationError, "Unknown response type encountered: #{r['type']}"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
BatchEvaluationResponse.new(responses: responses)
|
123
180
|
end
|
124
181
|
|
125
182
|
# List all flags in the namespace
|
126
183
|
def list_flags
|
127
184
|
resp, ptr = self.class.list_flags(@engine)
|
128
|
-
ptr = FFI::AutoPointer.new(ptr,
|
185
|
+
ptr = FFI::AutoPointer.new(ptr, Client.method(:destroy_string))
|
129
186
|
data = JSON.parse(resp)
|
130
187
|
raise Error, data['error_message'] if data['status'] != 'success'
|
131
188
|
|
132
189
|
data['result']
|
133
190
|
end
|
134
191
|
|
192
|
+
# Get the snapshot of the current flag state
|
193
|
+
def snapshot
|
194
|
+
resp, ptr = self.class.get_snapshot(@engine)
|
195
|
+
ptr = FFI::AutoPointer.new(ptr, Client.method(:destroy_string))
|
196
|
+
resp
|
197
|
+
end
|
198
|
+
|
135
199
|
private
|
136
200
|
|
137
|
-
def validate_evaluation_request(
|
138
|
-
if
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
201
|
+
def validate_evaluation_request(flag_key, entity_id, context)
|
202
|
+
raise ValidationError, 'flag_key is required' if flag_key.nil? || flag_key.empty?
|
203
|
+
raise ValidationError, 'entity_id is required' if entity_id.nil? || entity_id.empty?
|
204
|
+
return if context.is_a?(Hash)
|
205
|
+
|
206
|
+
raise ValidationError, 'context must be a Hash<String, String>'
|
143
207
|
end
|
144
208
|
|
145
209
|
def validate_authentication(authentication)
|
146
210
|
return authentication.strategy if authentication.is_a?(AuthenticationStrategy)
|
147
211
|
|
148
|
-
raise
|
212
|
+
raise ValidationError, 'invalid authentication strategy'
|
149
213
|
end
|
150
214
|
|
151
215
|
def validate_fetch_mode(fetch_mode)
|
152
216
|
return fetch_mode if %i[polling streaming].include?(fetch_mode)
|
153
217
|
|
154
|
-
raise
|
218
|
+
raise ValidationError, 'invalid fetch mode'
|
155
219
|
end
|
156
220
|
|
157
221
|
def validate_error_strategy(error_strategy)
|
158
222
|
return error_strategy if %i[fail fallback].include?(error_strategy)
|
159
223
|
|
160
|
-
raise
|
224
|
+
raise ValidationError, 'invalid error strategy'
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Deprecation shim for EvaluationClient
|
229
|
+
class EvaluationClient < Client
|
230
|
+
def initialize(*args, **kwargs)
|
231
|
+
warn '[DEPRECATION] `EvaluationClient` is deprecated. Please use `Client` instead.'
|
232
|
+
super
|
161
233
|
end
|
162
234
|
end
|
163
235
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipt_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Flipt Devs
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-06-09 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Flipt Client Evaluation SDK
|
14
14
|
email:
|
@@ -42,7 +42,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
42
42
|
requirements:
|
43
43
|
- - ">="
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: 2.
|
45
|
+
version: 2.7.0
|
46
46
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
47
|
requirements:
|
48
48
|
- - ">="
|