openfeature-flagd-provider 0.1.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +4 -0
- data/.rubocop.yml +10 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +30 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +92 -0
- data/README.md +83 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/docker/docker-compose.yml +10 -0
- data/docker/flags.json +92 -0
- data/lib/openfeature/flagd/provider/client.rb +142 -0
- data/lib/openfeature/flagd/provider/configuration.rb +42 -0
- data/lib/openfeature/flagd/provider/flagd/evaluation/v1/evaluation_pb.rb +61 -0
- data/lib/openfeature/flagd/provider/flagd/evaluation/v1/evaluation_services_pb.rb +44 -0
- data/lib/openfeature/flagd/provider/flagd/sync/v1/sync_pb.rb +52 -0
- data/lib/openfeature/flagd/provider/flagd/sync/v1/sync_services_pb.rb +39 -0
- data/lib/openfeature/flagd/provider/version.rb +7 -0
- data/lib/openfeature/flagd/provider.rb +83 -0
- data/openfeature-flagd-provider.gemspec +39 -0
- metadata +154 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: '080ce76815c057f001cd65068841a1d73287a0f31a68e45e078b09846ebaf926'
|
|
4
|
+
data.tar.gz: 1bbde9f180b72331cfb50541e3d1572c3ed2092ca76f9093969d0bb2329acdc2
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 11ecdbebda3241daf7ed79a117ccbf0f90f6e13d8197aebca07f91cf949c4afc26b434b5ebf2a3d36037d4be543580c17250e0584c7ed7efae9e2581a90281a1
|
|
7
|
+
data.tar.gz: fb31f4675243aea5d23deef97270336ec53a9f7a9c2d8ca717f4f18c8de8f11ee23c71ef9cd30ebab06c4b2bf6349b0a8568a900393c65f491c2b0a49a02aa82
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.1.4
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0](https://github.com/open-feature/ruby-sdk-contrib/compare/openfeature-flagd-provider-v0.0.1...openfeature-flagd-provider/v0.1.0) (2024-05-16)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* update flagd name and grpc schema ([#30](https://github.com/open-feature/ruby-sdk-contrib/issues/30))
|
|
9
|
+
|
|
10
|
+
### ✨ New Features
|
|
11
|
+
|
|
12
|
+
* Add flagd provider ([#2](https://github.com/open-feature/ruby-sdk-contrib/issues/2)) ([98b695b](https://github.com/open-feature/ruby-sdk-contrib/commit/98b695b05eb1525cb796479be8b36c2751297b98))
|
|
13
|
+
* Add support for unix socket path and secure connection ([#8](https://github.com/open-feature/ruby-sdk-contrib/issues/8)) ([88436c7](https://github.com/open-feature/ruby-sdk-contrib/commit/88436c7175373552bc7cad236297028bb655e12d))
|
|
14
|
+
* Flagd provider uses structs from sdk ([#24](https://github.com/open-feature/ruby-sdk-contrib/issues/24)) ([d437e7f](https://github.com/open-feature/ruby-sdk-contrib/commit/d437e7f72f3790d6c82ce1d006efdd528da7402e))
|
|
15
|
+
* integrate flagd provider with OpenFeature SDK ([#18](https://github.com/open-feature/ruby-sdk-contrib/issues/18)) ([80d6d02](https://github.com/open-feature/ruby-sdk-contrib/commit/80d6d028fbe762fae243d687bba7f9642bb2c116))
|
|
16
|
+
* Return default value on error ([#25](https://github.com/open-feature/ruby-sdk-contrib/issues/25)) ([f365c6d](https://github.com/open-feature/ruby-sdk-contrib/commit/f365c6db6ab8465c39d55764c7715f81d6d7f922))
|
|
17
|
+
* update flagd name and grpc schema ([#30](https://github.com/open-feature/ruby-sdk-contrib/issues/30)) ([ddd438a](https://github.com/open-feature/ruby-sdk-contrib/commit/ddd438abc3c7b6d586c36ea94060c75448e99f27))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### 🧹 Chore
|
|
21
|
+
|
|
22
|
+
* Format with standard ([#20](https://github.com/open-feature/ruby-sdk-contrib/issues/20)) ([bf25043](https://github.com/open-feature/ruby-sdk-contrib/commit/bf25043f87bdd9cd2bc8527fead8f4a0c3b95eff))
|
|
23
|
+
* Make things work ([#13](https://github.com/open-feature/ruby-sdk-contrib/issues/13)) ([5968037](https://github.com/open-feature/ruby-sdk-contrib/commit/5968037b7290f7f84ca96e621bf136f7c7a42e8a))
|
|
24
|
+
* update link to use new doc domain ([#12](https://github.com/open-feature/ruby-sdk-contrib/issues/12)) ([9baff65](https://github.com/open-feature/ruby-sdk-contrib/commit/9baff65051522705606e336ba1fe614115907418))
|
|
25
|
+
* upgrade grpc client ([#16](https://github.com/open-feature/ruby-sdk-contrib/issues/16)) ([23ed78a](https://github.com/open-feature/ruby-sdk-contrib/commit/23ed78a830c81030e1fb40d0aef04ea5458d2d6d))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### 🔄 Refactoring
|
|
29
|
+
|
|
30
|
+
* OpenFeature::FlagD::Provider::Configuration ([#14](https://github.com/open-feature/ruby-sdk-contrib/issues/14)) ([3686eb5](https://github.com/open-feature/ruby-sdk-contrib/commit/3686eb5c31ec0e6af97bc74ff58ffb815b78e114))
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
openfeature-flagd-provider (0.1.0)
|
|
5
|
+
grpc (~> 1.50)
|
|
6
|
+
openfeature-sdk (~> 0.3)
|
|
7
|
+
|
|
8
|
+
GEM
|
|
9
|
+
remote: https://rubygems.org/
|
|
10
|
+
specs:
|
|
11
|
+
ast (2.4.2)
|
|
12
|
+
diff-lcs (1.5.1)
|
|
13
|
+
google-protobuf (3.25.3-arm64-darwin)
|
|
14
|
+
google-protobuf (3.25.3-x86_64-linux)
|
|
15
|
+
googleapis-common-protos-types (1.14.0)
|
|
16
|
+
google-protobuf (~> 3.18)
|
|
17
|
+
grpc (1.62.0-arm64-darwin)
|
|
18
|
+
google-protobuf (~> 3.25)
|
|
19
|
+
googleapis-common-protos-types (~> 1.0)
|
|
20
|
+
grpc (1.62.0-x86_64-linux)
|
|
21
|
+
google-protobuf (~> 3.25)
|
|
22
|
+
googleapis-common-protos-types (~> 1.0)
|
|
23
|
+
json (2.7.2)
|
|
24
|
+
language_server-protocol (3.17.0.3)
|
|
25
|
+
lint_roller (1.1.0)
|
|
26
|
+
openfeature-sdk (0.3.1)
|
|
27
|
+
parallel (1.24.0)
|
|
28
|
+
parser (3.3.0.5)
|
|
29
|
+
ast (~> 2.4.1)
|
|
30
|
+
racc
|
|
31
|
+
racc (1.7.3)
|
|
32
|
+
rainbow (3.1.1)
|
|
33
|
+
rake (13.2.1)
|
|
34
|
+
regexp_parser (2.9.0)
|
|
35
|
+
rexml (3.2.6)
|
|
36
|
+
rspec (3.12.0)
|
|
37
|
+
rspec-core (~> 3.12.0)
|
|
38
|
+
rspec-expectations (~> 3.12.0)
|
|
39
|
+
rspec-mocks (~> 3.12.0)
|
|
40
|
+
rspec-core (3.12.3)
|
|
41
|
+
rspec-support (~> 3.12.0)
|
|
42
|
+
rspec-expectations (3.12.4)
|
|
43
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
44
|
+
rspec-support (~> 3.12.0)
|
|
45
|
+
rspec-mocks (3.12.7)
|
|
46
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
47
|
+
rspec-support (~> 3.12.0)
|
|
48
|
+
rspec-support (3.12.2)
|
|
49
|
+
rubocop (1.62.1)
|
|
50
|
+
json (~> 2.3)
|
|
51
|
+
language_server-protocol (>= 3.17.0)
|
|
52
|
+
parallel (~> 1.10)
|
|
53
|
+
parser (>= 3.3.0.2)
|
|
54
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
55
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
56
|
+
rexml (>= 3.2.5, < 4.0)
|
|
57
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
|
58
|
+
ruby-progressbar (~> 1.7)
|
|
59
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
|
60
|
+
rubocop-ast (1.31.2)
|
|
61
|
+
parser (>= 3.3.0.4)
|
|
62
|
+
rubocop-performance (1.20.2)
|
|
63
|
+
rubocop (>= 1.48.1, < 2.0)
|
|
64
|
+
rubocop-ast (>= 1.30.0, < 2.0)
|
|
65
|
+
ruby-progressbar (1.13.0)
|
|
66
|
+
standard (1.35.1)
|
|
67
|
+
language_server-protocol (~> 3.17.0.2)
|
|
68
|
+
lint_roller (~> 1.0)
|
|
69
|
+
rubocop (~> 1.62.0)
|
|
70
|
+
standard-custom (~> 1.0.0)
|
|
71
|
+
standard-performance (~> 1.3)
|
|
72
|
+
standard-custom (1.0.2)
|
|
73
|
+
lint_roller (~> 1.0)
|
|
74
|
+
rubocop (~> 1.50)
|
|
75
|
+
standard-performance (1.3.1)
|
|
76
|
+
lint_roller (~> 1.1)
|
|
77
|
+
rubocop-performance (~> 1.20.2)
|
|
78
|
+
unicode-display_width (2.5.0)
|
|
79
|
+
|
|
80
|
+
PLATFORMS
|
|
81
|
+
arm64-darwin-21
|
|
82
|
+
x86_64-linux
|
|
83
|
+
|
|
84
|
+
DEPENDENCIES
|
|
85
|
+
openfeature-flagd-provider!
|
|
86
|
+
rake (~> 13.0)
|
|
87
|
+
rspec (~> 3.12.0)
|
|
88
|
+
rubocop
|
|
89
|
+
standard
|
|
90
|
+
|
|
91
|
+
BUNDLED WITH
|
|
92
|
+
2.3.25
|
data/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# OpenFeature flagd Provider for Ruby
|
|
2
|
+
|
|
3
|
+
This is the Ruby [provider](https://openfeature.dev/docs/specification/sections/providers) implementation of the [flagd](https://flagd.dev/)
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'openfeature-flagd-provider'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
bundle install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or install it yourself as:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
gem install openfeature-flagd-provider
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
The `OpenFeature::Flagd` supports multiple configuration options that dictate how the SDK communicates with flagd.
|
|
28
|
+
Options can be defined in the constructor or as environment variables, with constructor options having the highest precedence.
|
|
29
|
+
|
|
30
|
+
### Available options
|
|
31
|
+
|
|
32
|
+
| Option name | Environment variable name | Type | Default |
|
|
33
|
+
| ----------- | ------------------------- | ------- | --------- |
|
|
34
|
+
| host | FLAGD_HOST | string | localhost |
|
|
35
|
+
| port | FLAGD_PORT | number | 8013 |
|
|
36
|
+
| tls | FLAGD_TLS | boolean | false |
|
|
37
|
+
| unix_socket_path | FLAGD_SOCKET_PATH | string | nil |
|
|
38
|
+
| root_cert_path | FLAGD_SERVER_CERT_PATH | string | nil |
|
|
39
|
+
|
|
40
|
+
### Example using TCP
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
OpenFeature::SDK.configure do |config|
|
|
44
|
+
# your provider of choice
|
|
45
|
+
config.provider = OpenFeature::Flagd::Provider.configure do |provider_config|
|
|
46
|
+
provider_config.host = "localhost"
|
|
47
|
+
provider_config.port = 8013
|
|
48
|
+
provider_config.tls = false
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Example using a Unix socket
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
OpenFeature::SDK.configure do |config|
|
|
57
|
+
# your provider of choice
|
|
58
|
+
config.provider = OpenFeature::Flagd::Provider.configure do |provider_config|
|
|
59
|
+
provider_config.unix_socket_path = "tmp/flagd.sock"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
### Example using a secure connection
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
OpenFeature::SDK.configure do |config|
|
|
69
|
+
# your provider of choice
|
|
70
|
+
config.provider = OpenFeature::Flagd::Provider.configure do |provider_config|
|
|
71
|
+
provider_config.host = "localhost"
|
|
72
|
+
provider_config.port = 8013
|
|
73
|
+
provider_config.tls = true
|
|
74
|
+
provider_config.root_cert_path = './ca.pem'
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
If no environment variables are set the [default configuration](./lib/openfeature/flagd/provider/configuration.rb) is set
|
|
80
|
+
|
|
81
|
+
## Contributing
|
|
82
|
+
|
|
83
|
+
https://github.com/open-feature/ruby-sdk-contrib
|
data/Rakefile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "bundler/setup"
|
|
5
|
+
require "openfeature/flagd/provider"
|
|
6
|
+
|
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
+
|
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
11
|
+
# require "pry"
|
|
12
|
+
# Pry.start
|
|
13
|
+
|
|
14
|
+
require "irb"
|
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/docker/flags.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://flagd.dev/schema/v0/flags.json",
|
|
3
|
+
"flags": {
|
|
4
|
+
"boolean-flag": {
|
|
5
|
+
"state": "ENABLED",
|
|
6
|
+
"variants": {
|
|
7
|
+
"on": true,
|
|
8
|
+
"off": false
|
|
9
|
+
},
|
|
10
|
+
"defaultVariant": "off"
|
|
11
|
+
},
|
|
12
|
+
"integer-flag": {
|
|
13
|
+
"state": "ENABLED",
|
|
14
|
+
"variants": {
|
|
15
|
+
"fourty-two": 42
|
|
16
|
+
},
|
|
17
|
+
"defaultVariant": "fourty-two"
|
|
18
|
+
},
|
|
19
|
+
"float-flag": {
|
|
20
|
+
"state": "ENABLED",
|
|
21
|
+
"variants": {
|
|
22
|
+
"four-point-two": 4.2
|
|
23
|
+
},
|
|
24
|
+
"defaultVariant": "four-point-two"
|
|
25
|
+
},
|
|
26
|
+
"string-flag": {
|
|
27
|
+
"state": "ENABLED",
|
|
28
|
+
"variants": {
|
|
29
|
+
"lilili": "lalala"
|
|
30
|
+
},
|
|
31
|
+
"defaultVariant": "lilili"
|
|
32
|
+
},
|
|
33
|
+
"object-flag": {
|
|
34
|
+
"state": "ENABLED",
|
|
35
|
+
"variants": {
|
|
36
|
+
"real-object": { "real": "value" }
|
|
37
|
+
},
|
|
38
|
+
"defaultVariant": "real-object"
|
|
39
|
+
},
|
|
40
|
+
"boolean-flag-targeting": {
|
|
41
|
+
"state": "ENABLED",
|
|
42
|
+
"variants": {
|
|
43
|
+
"on": true,
|
|
44
|
+
"off": false
|
|
45
|
+
},
|
|
46
|
+
"defaultVariant": "off",
|
|
47
|
+
"targeting": {
|
|
48
|
+
"if": [
|
|
49
|
+
{
|
|
50
|
+
"==": [
|
|
51
|
+
{
|
|
52
|
+
"var": "be_true"
|
|
53
|
+
},
|
|
54
|
+
true
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
"on"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"color-palette-experiment": {
|
|
62
|
+
"state": "ENABLED",
|
|
63
|
+
"defaultVariant": "grey",
|
|
64
|
+
"variants": {
|
|
65
|
+
"red": "#b91c1c",
|
|
66
|
+
"blue": "#0284c7",
|
|
67
|
+
"green": "#16a34a",
|
|
68
|
+
"grey": "#4b5563"
|
|
69
|
+
},
|
|
70
|
+
"targeting": {
|
|
71
|
+
"fractional": [
|
|
72
|
+
[
|
|
73
|
+
"red",
|
|
74
|
+
25
|
|
75
|
+
],
|
|
76
|
+
[
|
|
77
|
+
"blue",
|
|
78
|
+
25
|
|
79
|
+
],
|
|
80
|
+
[
|
|
81
|
+
"green",
|
|
82
|
+
25
|
|
83
|
+
],
|
|
84
|
+
[
|
|
85
|
+
"grey",
|
|
86
|
+
25
|
|
87
|
+
]
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "grpc"
|
|
4
|
+
require "google/protobuf/well_known_types"
|
|
5
|
+
|
|
6
|
+
require_relative "flagd/evaluation/v1/evaluation_services_pb"
|
|
7
|
+
require_relative "configuration"
|
|
8
|
+
|
|
9
|
+
module OpenFeature
|
|
10
|
+
module Flagd
|
|
11
|
+
module Provider
|
|
12
|
+
# Client represents a wrapper for the GRPC stub that allows for resolution of boolean, string, number, and object
|
|
13
|
+
# values. The implementation follows the details specified in https://openfeature.dev/docs/specification/sections/providers
|
|
14
|
+
#
|
|
15
|
+
#
|
|
16
|
+
# The Client provides the following methods and attributes:
|
|
17
|
+
#
|
|
18
|
+
# * <tt>metadata</tt> - Returns the associated provider metadata with the name
|
|
19
|
+
#
|
|
20
|
+
# * <tt>fetch_boolean_value(flag_key:, default_value:, evaluation_context: nil)</tt>
|
|
21
|
+
# manner; <tt>client.fetch_boolean(flag_key: 'boolean-flag', default_value: false)</tt>
|
|
22
|
+
#
|
|
23
|
+
# * <tt>fetch_integer_value(flag_key:, default_value:, evaluation_context: nil)</tt>
|
|
24
|
+
# manner; <tt>client.fetch_integer_value(flag_key: 'integer-flag', default_value: 2)</tt>
|
|
25
|
+
#
|
|
26
|
+
# * <tt>fetch_float_value(flag_key:, default_value:, evaluation_context: nil)</tt>
|
|
27
|
+
# manner; <tt>client.fetch_float_value(flag_key: 'float-flag', default_value: 2.0)</tt>
|
|
28
|
+
#
|
|
29
|
+
# * <tt>fetch_string_value(flag_key:, default_value:, evaluation_context: nil)</tt>
|
|
30
|
+
# manner; <tt>client.fetch_string_value(flag_key: 'string-flag', default_value: 'some-default-value')</tt>
|
|
31
|
+
#
|
|
32
|
+
# * <tt>fetch_object_value(flag_key:, default_value:, evaluation_context: nil)</tt>
|
|
33
|
+
# manner; <tt>client.fetch_object_value(flag_key: 'flag', default_value: { default_value: 'value'})</tt>
|
|
34
|
+
class Client
|
|
35
|
+
PROVIDER_NAME = "flagd Provider"
|
|
36
|
+
|
|
37
|
+
attr_reader :metadata
|
|
38
|
+
|
|
39
|
+
def initialize(configuration: nil)
|
|
40
|
+
@metadata = OpenFeature::SDK::Provider::ProviderMetadata.new(name: PROVIDER_NAME)
|
|
41
|
+
@grpc_client = grpc_client(configuration)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def fetch_boolean_value(flag_key:, default_value:, evaluation_context: nil)
|
|
45
|
+
request = Grpc::Evaluation::ResolveBooleanRequest.new(flag_key: flag_key, context: prepare_evaluation_context(evaluation_context))
|
|
46
|
+
process_request(default_value) { @grpc_client.resolve_boolean(request) }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def fetch_number_value(flag_key:, default_value:, evaluation_context: nil)
|
|
50
|
+
case default_value
|
|
51
|
+
when Integer
|
|
52
|
+
fetch_integer_value(flag_key: flag_key, default_value: default_value, evaluation_context: evaluation_context)
|
|
53
|
+
when Float
|
|
54
|
+
fetch_float_value(flag_key: flag_key, default_value: default_value, evaluation_context: evaluation_context)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def fetch_integer_value(flag_key:, default_value:, evaluation_context: nil)
|
|
59
|
+
request = Grpc::Evaluation::ResolveIntRequest.new(flag_key: flag_key, context: prepare_evaluation_context(evaluation_context))
|
|
60
|
+
process_request(default_value) { @grpc_client.resolve_int(request) }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def fetch_float_value(flag_key:, default_value:, evaluation_context: nil)
|
|
64
|
+
request = Grpc::Evaluation::ResolveFloatRequest.new(flag_key: flag_key, context: prepare_evaluation_context(evaluation_context))
|
|
65
|
+
process_request(default_value) { @grpc_client.resolve_float(request) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def fetch_string_value(flag_key:, default_value:, evaluation_context: nil)
|
|
69
|
+
request = Grpc::Evaluation::ResolveStringRequest.new(flag_key: flag_key, context: prepare_evaluation_context(evaluation_context))
|
|
70
|
+
process_request(default_value) { @grpc_client.resolve_string(request) }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def fetch_object_value(flag_key:, default_value:, evaluation_context: nil)
|
|
74
|
+
request = Grpc::Evaluation::ResolveObjectRequest.new(flag_key: flag_key, context: prepare_evaluation_context(evaluation_context))
|
|
75
|
+
process_request(default_value) { @grpc_client.resolve_object(request) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def process_request(default_value, &block)
|
|
81
|
+
response = block.call
|
|
82
|
+
OpenFeature::SDK::Provider::ResolutionDetails.new(
|
|
83
|
+
value: response.value,
|
|
84
|
+
reason: response.reason,
|
|
85
|
+
variant: response.variant,
|
|
86
|
+
error_code: nil,
|
|
87
|
+
error_message: nil,
|
|
88
|
+
flag_metadata: nil
|
|
89
|
+
)
|
|
90
|
+
rescue GRPC::NotFound => e
|
|
91
|
+
error_response(default_value, "FLAG_NOT_FOUND", e.message)
|
|
92
|
+
rescue GRPC::InvalidArgument => e
|
|
93
|
+
error_response(default_value, "TYPE_MISMATCH", e.message)
|
|
94
|
+
rescue GRPC::Unavailable => e
|
|
95
|
+
error_response(default_value, "FLAG_NOT_FOUND", e.message)
|
|
96
|
+
rescue GRPC::DataLoss => e
|
|
97
|
+
error_response(default_value, "PARSE_ERROR", e.message)
|
|
98
|
+
rescue => e
|
|
99
|
+
error_response(default_value, "GENERAL", e.message)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def prepare_evaluation_context(evaluation_context)
|
|
103
|
+
return nil unless evaluation_context
|
|
104
|
+
|
|
105
|
+
fields = evaluation_context.fields
|
|
106
|
+
fields["targetingKey"] = fields.delete(:targeting_key)
|
|
107
|
+
Google::Protobuf::Struct.from_hash(fields)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def error_response(default_value, error_code, error_message)
|
|
111
|
+
OpenFeature::SDK::Provider::ResolutionDetails.new(
|
|
112
|
+
value: default_value,
|
|
113
|
+
reason: "ERROR",
|
|
114
|
+
variant: nil,
|
|
115
|
+
error_code: error_code,
|
|
116
|
+
error_message: error_message,
|
|
117
|
+
flag_metadata: nil
|
|
118
|
+
)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def grpc_client(configuration)
|
|
122
|
+
options = :this_channel_is_insecure
|
|
123
|
+
if configuration.tls
|
|
124
|
+
options = GRPC::Core::ChannelCredentials.new(
|
|
125
|
+
configuration.root_cert_path
|
|
126
|
+
)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
Grpc::Evaluation::Service::Stub.new(server_address(configuration), options).freeze
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def server_address(configuration)
|
|
133
|
+
if configuration.unix_socket_path
|
|
134
|
+
"unix://#{configuration.unix_socket_path}"
|
|
135
|
+
else
|
|
136
|
+
"#{configuration.host}:#{configuration.port}"
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OpenFeature
|
|
4
|
+
module Flagd
|
|
5
|
+
module Provider
|
|
6
|
+
# Represents the configuration object for the Flagd provider,
|
|
7
|
+
# This class is not meant to be interacted with directly but instead through the
|
|
8
|
+
# <tt>OpenFeature::Flagd::Provider.configure</tt> method
|
|
9
|
+
class Configuration < Struct.new(:host, :port, :tls, :unix_socket_path, :root_cert_path, keyword_init: true)
|
|
10
|
+
ENVIRONMENT_CONFIG_NAME = {
|
|
11
|
+
host: "FLAGD_HOST",
|
|
12
|
+
port: "FLAGD_PORT",
|
|
13
|
+
tls: "FLAGD_TLS",
|
|
14
|
+
unix_socket_path: "FLAGD_SOCKET_PATH",
|
|
15
|
+
root_cert_path: "FLAGD_SERVER_CERT_PATH"
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def default_config
|
|
20
|
+
new(host: "localhost", port: 8013, tls: false, unix_socket_path: nil, root_cert_path: nil)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def environment_variables_config
|
|
24
|
+
new(
|
|
25
|
+
host: ENV.fetch(ENVIRONMENT_CONFIG_NAME[:host], nil),
|
|
26
|
+
port: ENV[ENVIRONMENT_CONFIG_NAME[:port]].nil? ? nil : Integer(ENV[ENVIRONMENT_CONFIG_NAME[:port]]),
|
|
27
|
+
tls: ENV[ENVIRONMENT_CONFIG_NAME[:tls]].nil? ? nil : ENV.fetch(ENVIRONMENT_CONFIG_NAME[:tls], nil) == "true",
|
|
28
|
+
unix_socket_path: ENV.fetch(ENVIRONMENT_CONFIG_NAME[:unix_socket_path], nil),
|
|
29
|
+
root_cert_path: ENV.fetch(ENVIRONMENT_CONFIG_NAME[:root_cert_path], nil)
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def merge(other_configuration)
|
|
35
|
+
return self if other_configuration.nil?
|
|
36
|
+
|
|
37
|
+
self.class.new(**to_h.compact.merge(other_configuration.to_h.compact))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# source: flagd/evaluation/v1/evaluation.proto
|
|
4
|
+
|
|
5
|
+
require 'google/protobuf'
|
|
6
|
+
|
|
7
|
+
require 'google/protobuf/struct_pb'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
descriptor_data = "\n$flagd/evaluation/v1/evaluation.proto\x12\x13\x66lagd.evaluation.v1\x1a\x1cgoogle/protobuf/struct.proto\"F\n\x11ResolveAllRequest\x12\x31\n\x07\x63ontext\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\"\xb6\x01\n\x12ResolveAllResponse\x12H\n\x05\x66lags\x18\x01 \x03(\x0b\x32\x32.flagd.evaluation.v1.ResolveAllResponse.FlagsEntryR\x05\x66lags\x1aV\n\nFlagsEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x32\n\x05value\x18\x02 \x01(\x0b\x32\x1c.flagd.evaluation.v1.AnyFlagR\x05value:\x02\x38\x01\"\xed\x01\n\x07\x41nyFlag\x12\x16\n\x06reason\x18\x01 \x01(\tR\x06reason\x12\x18\n\x07variant\x18\x02 \x01(\tR\x07variant\x12\x1f\n\nbool_value\x18\x03 \x01(\x08H\x00R\tboolValue\x12#\n\x0cstring_value\x18\x04 \x01(\tH\x00R\x0bstringValue\x12#\n\x0c\x64ouble_value\x18\x05 \x01(\x01H\x00R\x0b\x64oubleValue\x12<\n\x0cobject_value\x18\x06 \x01(\x0b\x32\x17.google.protobuf.StructH\x00R\x0bobjectValueB\x07\n\x05value\"e\n\x15ResolveBooleanRequest\x12\x19\n\x08\x66lag_key\x18\x01 \x01(\tR\x07\x66lagKey\x12\x31\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\"\x95\x01\n\x16ResolveBooleanResponse\x12\x14\n\x05value\x18\x01 \x01(\x08R\x05value\x12\x16\n\x06reason\x18\x02 \x01(\tR\x06reason\x12\x18\n\x07variant\x18\x03 \x01(\tR\x07variant\x12\x33\n\x08metadata\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\"d\n\x14ResolveStringRequest\x12\x19\n\x08\x66lag_key\x18\x01 \x01(\tR\x07\x66lagKey\x12\x31\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\"\x94\x01\n\x15ResolveStringResponse\x12\x14\n\x05value\x18\x01 \x01(\tR\x05value\x12\x16\n\x06reason\x18\x02 \x01(\tR\x06reason\x12\x18\n\x07variant\x18\x03 \x01(\tR\x07variant\x12\x33\n\x08metadata\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\"c\n\x13ResolveFloatRequest\x12\x19\n\x08\x66lag_key\x18\x01 \x01(\tR\x07\x66lagKey\x12\x31\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\"\x93\x01\n\x14ResolveFloatResponse\x12\x14\n\x05value\x18\x01 \x01(\x01R\x05value\x12\x16\n\x06reason\x18\x02 \x01(\tR\x06reason\x12\x18\n\x07variant\x18\x03 \x01(\tR\x07variant\x12\x33\n\x08metadata\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\"a\n\x11ResolveIntRequest\x12\x19\n\x08\x66lag_key\x18\x01 \x01(\tR\x07\x66lagKey\x12\x31\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\"\x91\x01\n\x12ResolveIntResponse\x12\x14\n\x05value\x18\x01 \x01(\x03R\x05value\x12\x16\n\x06reason\x18\x02 \x01(\tR\x06reason\x12\x18\n\x07variant\x18\x03 \x01(\tR\x07variant\x12\x33\n\x08metadata\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\"d\n\x14ResolveObjectRequest\x12\x19\n\x08\x66lag_key\x18\x01 \x01(\tR\x07\x66lagKey\x12\x31\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\"\xad\x01\n\x15ResolveObjectResponse\x12-\n\x05value\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructR\x05value\x12\x16\n\x06reason\x18\x02 \x01(\tR\x06reason\x12\x18\n\x07variant\x18\x03 \x01(\tR\x07variant\x12\x33\n\x08metadata\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\"V\n\x13\x45ventStreamResponse\x12\x12\n\x04type\x18\x01 \x01(\tR\x04type\x12+\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x04\x64\x61ta\"\x14\n\x12\x45ventStreamRequest2\xd9\x05\n\x07Service\x12_\n\nResolveAll\x12&.flagd.evaluation.v1.ResolveAllRequest\x1a\'.flagd.evaluation.v1.ResolveAllResponse\"\x00\x12k\n\x0eResolveBoolean\x12*.flagd.evaluation.v1.ResolveBooleanRequest\x1a+.flagd.evaluation.v1.ResolveBooleanResponse\"\x00\x12h\n\rResolveString\x12).flagd.evaluation.v1.ResolveStringRequest\x1a*.flagd.evaluation.v1.ResolveStringResponse\"\x00\x12\x65\n\x0cResolveFloat\x12(.flagd.evaluation.v1.ResolveFloatRequest\x1a).flagd.evaluation.v1.ResolveFloatResponse\"\x00\x12_\n\nResolveInt\x12&.flagd.evaluation.v1.ResolveIntRequest\x1a\'.flagd.evaluation.v1.ResolveIntResponse\"\x00\x12h\n\rResolveObject\x12).flagd.evaluation.v1.ResolveObjectRequest\x1a*.flagd.evaluation.v1.ResolveObjectResponse\"\x00\x12\x64\n\x0b\x45ventStream\x12\'.flagd.evaluation.v1.EventStreamRequest\x1a(.flagd.evaluation.v1.EventStreamResponse\"\x00\x30\x01\x42\xc6\x01\n%dev.openfeature.flagd.grpc.evaluationZ\x13\x66lagd/evaluation/v1\xaa\x02!OpenFeature.Flagd.Grpc.Evaluation\xca\x02\x32OpenFeature\\Providers\\Flagd\\Schema\\Grpc\\Evaluation\xea\x02.OpenFeature::Flagd::Provider::Grpc::Evaluationb\x06proto3"
|
|
11
|
+
|
|
12
|
+
pool = Google::Protobuf::DescriptorPool.generated_pool
|
|
13
|
+
|
|
14
|
+
begin
|
|
15
|
+
pool.add_serialized_file(descriptor_data)
|
|
16
|
+
rescue TypeError => e
|
|
17
|
+
# Compatibility code: will be removed in the next major version.
|
|
18
|
+
require 'google/protobuf/descriptor_pb'
|
|
19
|
+
parsed = Google::Protobuf::FileDescriptorProto.decode(descriptor_data)
|
|
20
|
+
parsed.clear_dependency
|
|
21
|
+
serialized = parsed.class.encode(parsed)
|
|
22
|
+
file = pool.add_serialized_file(serialized)
|
|
23
|
+
warn "Warning: Protobuf detected an import path issue while loading generated file #{__FILE__}"
|
|
24
|
+
imports = [
|
|
25
|
+
["google.protobuf.Struct", "google/protobuf/struct.proto"],
|
|
26
|
+
]
|
|
27
|
+
imports.each do |type_name, expected_filename|
|
|
28
|
+
import_file = pool.lookup(type_name).file_descriptor
|
|
29
|
+
if import_file.name != expected_filename
|
|
30
|
+
warn "- #{file.name} imports #{expected_filename}, but that import was loaded as #{import_file.name}"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
warn "Each proto file must use a consistent fully-qualified name."
|
|
34
|
+
warn "This will become an error in the next major version."
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module OpenFeature
|
|
38
|
+
module Flagd
|
|
39
|
+
module Provider
|
|
40
|
+
module Grpc
|
|
41
|
+
module Evaluation
|
|
42
|
+
ResolveAllRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveAllRequest").msgclass
|
|
43
|
+
ResolveAllResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveAllResponse").msgclass
|
|
44
|
+
AnyFlag = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.AnyFlag").msgclass
|
|
45
|
+
ResolveBooleanRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveBooleanRequest").msgclass
|
|
46
|
+
ResolveBooleanResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveBooleanResponse").msgclass
|
|
47
|
+
ResolveStringRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveStringRequest").msgclass
|
|
48
|
+
ResolveStringResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveStringResponse").msgclass
|
|
49
|
+
ResolveFloatRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveFloatRequest").msgclass
|
|
50
|
+
ResolveFloatResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveFloatResponse").msgclass
|
|
51
|
+
ResolveIntRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveIntRequest").msgclass
|
|
52
|
+
ResolveIntResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveIntResponse").msgclass
|
|
53
|
+
ResolveObjectRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveObjectRequest").msgclass
|
|
54
|
+
ResolveObjectResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.ResolveObjectResponse").msgclass
|
|
55
|
+
EventStreamResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.EventStreamResponse").msgclass
|
|
56
|
+
EventStreamRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.evaluation.v1.EventStreamRequest").msgclass
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
2
|
+
# Source: flagd/evaluation/v1/evaluation.proto for package 'OpenFeature.Flagd.Provider.Grpc.Evaluation'
|
|
3
|
+
# Original file comments:
|
|
4
|
+
# *
|
|
5
|
+
# Flag evaluation API
|
|
6
|
+
#
|
|
7
|
+
# This proto forms the basis of a flag-evaluation API.
|
|
8
|
+
# It supports single and bulk evaluation RPCs, and flags of various types, as well as establishing a stream for getting notifications about changes in a flag definition.
|
|
9
|
+
# It supports the inclusion of a "context" with each evaluation, which may contain arbitrary attributes relevant to flag evaluation.
|
|
10
|
+
|
|
11
|
+
require 'grpc'
|
|
12
|
+
require_relative 'evaluation_pb'
|
|
13
|
+
|
|
14
|
+
module OpenFeature
|
|
15
|
+
module Flagd
|
|
16
|
+
module Provider
|
|
17
|
+
module Grpc
|
|
18
|
+
module Evaluation
|
|
19
|
+
module Service
|
|
20
|
+
# Service defines the exposed rpcs of flagd
|
|
21
|
+
class Service
|
|
22
|
+
|
|
23
|
+
include ::GRPC::GenericService
|
|
24
|
+
|
|
25
|
+
self.marshal_class_method = :encode
|
|
26
|
+
self.unmarshal_class_method = :decode
|
|
27
|
+
self.service_name = 'flagd.evaluation.v1.Service'
|
|
28
|
+
|
|
29
|
+
rpc :ResolveAll, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveAllRequest, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveAllResponse
|
|
30
|
+
rpc :ResolveBoolean, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveBooleanRequest, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveBooleanResponse
|
|
31
|
+
rpc :ResolveString, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveStringRequest, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveStringResponse
|
|
32
|
+
rpc :ResolveFloat, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveFloatRequest, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveFloatResponse
|
|
33
|
+
rpc :ResolveInt, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveIntRequest, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveIntResponse
|
|
34
|
+
rpc :ResolveObject, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveObjectRequest, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::ResolveObjectResponse
|
|
35
|
+
rpc :EventStream, ::OpenFeature::Flagd::Provider::Grpc::Evaluation::EventStreamRequest, stream(::OpenFeature::Flagd::Provider::Grpc::Evaluation::EventStreamResponse)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
Stub = Service.rpc_stub_class
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# source: flagd/sync/v1/sync.proto
|
|
4
|
+
|
|
5
|
+
require 'google/protobuf'
|
|
6
|
+
|
|
7
|
+
require 'google/protobuf/struct_pb'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
descriptor_data = "\n\x18\x66lagd/sync/v1/sync.proto\x12\rflagd.sync.v1\x1a\x1cgoogle/protobuf/struct.proto\"O\n\x10SyncFlagsRequest\x12\x1f\n\x0bprovider_id\x18\x01 \x01(\tR\nproviderId\x12\x1a\n\x08selector\x18\x02 \x01(\tR\x08selector\"B\n\x11SyncFlagsResponse\x12-\n\x12\x66lag_configuration\x18\x01 \x01(\tR\x11\x66lagConfiguration\"S\n\x14\x46\x65tchAllFlagsRequest\x12\x1f\n\x0bprovider_id\x18\x01 \x01(\tR\nproviderId\x12\x1a\n\x08selector\x18\x02 \x01(\tR\x08selector\"F\n\x15\x46\x65tchAllFlagsResponse\x12-\n\x12\x66lag_configuration\x18\x01 \x01(\tR\x11\x66lagConfiguration\"\x14\n\x12GetMetadataRequest\"P\n\x13GetMetadataResponse\x12\x33\n\x08metadata\x18\x02 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadataJ\x04\x08\x01\x10\x02\x32\x9b\x02\n\x0f\x46lagSyncService\x12R\n\tSyncFlags\x12\x1f.flagd.sync.v1.SyncFlagsRequest\x1a .flagd.sync.v1.SyncFlagsResponse\"\x00\x30\x01\x12\\\n\rFetchAllFlags\x12#.flagd.sync.v1.FetchAllFlagsRequest\x1a$.flagd.sync.v1.FetchAllFlagsResponse\"\x00\x12V\n\x0bGetMetadata\x12!.flagd.sync.v1.GetMetadataRequest\x1a\".flagd.sync.v1.GetMetadataResponse\"\x00\x42\xa8\x01\n\x1f\x64\x65v.openfeature.flagd.grpc.syncZ\rflagd/sync/v1\xaa\x02\x1bOpenFeature.Flagd.Grpc.Sync\xca\x02,OpenFeature\\Providers\\Flagd\\Schema\\Grpc\\Sync\xea\x02(OpenFeature::Flagd::Provider::Grpc::Syncb\x06proto3"
|
|
11
|
+
|
|
12
|
+
pool = Google::Protobuf::DescriptorPool.generated_pool
|
|
13
|
+
|
|
14
|
+
begin
|
|
15
|
+
pool.add_serialized_file(descriptor_data)
|
|
16
|
+
rescue TypeError => e
|
|
17
|
+
# Compatibility code: will be removed in the next major version.
|
|
18
|
+
require 'google/protobuf/descriptor_pb'
|
|
19
|
+
parsed = Google::Protobuf::FileDescriptorProto.decode(descriptor_data)
|
|
20
|
+
parsed.clear_dependency
|
|
21
|
+
serialized = parsed.class.encode(parsed)
|
|
22
|
+
file = pool.add_serialized_file(serialized)
|
|
23
|
+
warn "Warning: Protobuf detected an import path issue while loading generated file #{__FILE__}"
|
|
24
|
+
imports = [
|
|
25
|
+
["google.protobuf.Struct", "google/protobuf/struct.proto"],
|
|
26
|
+
]
|
|
27
|
+
imports.each do |type_name, expected_filename|
|
|
28
|
+
import_file = pool.lookup(type_name).file_descriptor
|
|
29
|
+
if import_file.name != expected_filename
|
|
30
|
+
warn "- #{file.name} imports #{expected_filename}, but that import was loaded as #{import_file.name}"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
warn "Each proto file must use a consistent fully-qualified name."
|
|
34
|
+
warn "This will become an error in the next major version."
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module OpenFeature
|
|
38
|
+
module Flagd
|
|
39
|
+
module Provider
|
|
40
|
+
module Grpc
|
|
41
|
+
module Sync
|
|
42
|
+
SyncFlagsRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.sync.v1.SyncFlagsRequest").msgclass
|
|
43
|
+
SyncFlagsResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.sync.v1.SyncFlagsResponse").msgclass
|
|
44
|
+
FetchAllFlagsRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.sync.v1.FetchAllFlagsRequest").msgclass
|
|
45
|
+
FetchAllFlagsResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.sync.v1.FetchAllFlagsResponse").msgclass
|
|
46
|
+
GetMetadataRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.sync.v1.GetMetadataRequest").msgclass
|
|
47
|
+
GetMetadataResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("flagd.sync.v1.GetMetadataResponse").msgclass
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
2
|
+
# Source: flagd/sync/v1/sync.proto for package 'OpenFeature.Flagd.Provider.Grpc.Sync'
|
|
3
|
+
# Original file comments:
|
|
4
|
+
# *
|
|
5
|
+
# Flag definition sync API
|
|
6
|
+
#
|
|
7
|
+
# This proto defines a simple API to synchronize a feature flag definition.
|
|
8
|
+
# It supports establishing a stream for getting notifications about changes in a flag definition.
|
|
9
|
+
|
|
10
|
+
require 'grpc'
|
|
11
|
+
require 'flagd/sync/v1/sync_pb'
|
|
12
|
+
|
|
13
|
+
module OpenFeature
|
|
14
|
+
module Flagd
|
|
15
|
+
module Provider
|
|
16
|
+
module Grpc
|
|
17
|
+
module Sync
|
|
18
|
+
module FlagSyncService
|
|
19
|
+
# FlagService implements a server streaming to provide realtime flag configurations
|
|
20
|
+
class Service
|
|
21
|
+
|
|
22
|
+
include ::GRPC::GenericService
|
|
23
|
+
|
|
24
|
+
self.marshal_class_method = :encode
|
|
25
|
+
self.unmarshal_class_method = :decode
|
|
26
|
+
self.service_name = 'flagd.sync.v1.FlagSyncService'
|
|
27
|
+
|
|
28
|
+
rpc :SyncFlags, ::OpenFeature::Flagd::Provider::Grpc::Sync::SyncFlagsRequest, stream(::OpenFeature::Flagd::Provider::Grpc::Sync::SyncFlagsResponse)
|
|
29
|
+
rpc :FetchAllFlags, ::OpenFeature::Flagd::Provider::Grpc::Sync::FetchAllFlagsRequest, ::OpenFeature::Flagd::Provider::Grpc::Sync::FetchAllFlagsResponse
|
|
30
|
+
rpc :GetMetadata, ::OpenFeature::Flagd::Provider::Grpc::Sync::GetMetadataRequest, ::OpenFeature::Flagd::Provider::Grpc::Sync::GetMetadataResponse
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Stub = Service.rpc_stub_class
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "grpc"
|
|
4
|
+
|
|
5
|
+
require_relative "provider/configuration"
|
|
6
|
+
require_relative "provider/client"
|
|
7
|
+
require_relative "provider/version"
|
|
8
|
+
|
|
9
|
+
module OpenFeature
|
|
10
|
+
module Flagd
|
|
11
|
+
# Provider represents the entry point for interacting with the Flagd provider
|
|
12
|
+
# values. The implementation follows the details specified in https://openfeature.dev/docs/specification/sections/providers
|
|
13
|
+
#
|
|
14
|
+
# Provider contains functionality to configure the GRPC connection via
|
|
15
|
+
# flagd_client = OpenFeature::Flagd::Provider.get_client
|
|
16
|
+
# flagd_client.configure do |config|
|
|
17
|
+
# config.host = 'localhost'
|
|
18
|
+
# config.port = 8379
|
|
19
|
+
# config.tls = false
|
|
20
|
+
# end
|
|
21
|
+
# The Provider provides the following methods and attributes:
|
|
22
|
+
#
|
|
23
|
+
# * <tt>metadata</tt> - Returns the associated provider metadata with the name
|
|
24
|
+
#
|
|
25
|
+
# * <tt>resolve_boolean_value(flag_key:, default_value:, context: nil)</tt>
|
|
26
|
+
# manner; <tt>client.resolve_boolean(flag_key: 'boolean-flag', default_value: false)</tt>
|
|
27
|
+
#
|
|
28
|
+
# * <tt>resolve_integer_value(flag_key:, default_value:, context: nil)</tt>
|
|
29
|
+
# manner; <tt>client.resolve_integer_value(flag_key: 'integer-flag', default_value: 2)</tt>
|
|
30
|
+
#
|
|
31
|
+
# * <tt>resolve_float_value(flag_key:, default_value:, context: nil)</tt>
|
|
32
|
+
# manner; <tt>client.resolve_float_value(flag_key: 'float-flag', default_value: 2.0)</tt>
|
|
33
|
+
#
|
|
34
|
+
# * <tt>resolve_string_value(flag_key:, default_value:, context: nil)</tt>
|
|
35
|
+
# manner; <tt>client.resolve_string_value(flag_key: 'string-flag', default_value: 'some-default-value')</tt>
|
|
36
|
+
#
|
|
37
|
+
# * <tt>resolve_object_value(flag_key:, default_value:, context: nil)</tt>
|
|
38
|
+
# manner; <tt>client.resolve_object_value(flag_key: 'object-flag', default_value: { default_value: 'value'})</tt>
|
|
39
|
+
module Provider
|
|
40
|
+
class << self
|
|
41
|
+
def build_client
|
|
42
|
+
ConfiguredClient.new
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class ConfiguredClient
|
|
47
|
+
def method_missing(method_name, ...)
|
|
48
|
+
if client.respond_to?(method_name)
|
|
49
|
+
client.send(method_name, ...)
|
|
50
|
+
else
|
|
51
|
+
super
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
56
|
+
client.respond_to?(method_name, include_private) || super
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def configuration
|
|
60
|
+
@configuration ||= Configuration.default_config
|
|
61
|
+
.merge(Configuration.environment_variables_config)
|
|
62
|
+
.merge(explicit_configuration)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def configure(&block)
|
|
66
|
+
return unless block
|
|
67
|
+
|
|
68
|
+
block.call(explicit_configuration)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def explicit_configuration
|
|
74
|
+
@explicit_configuration ||= Configuration.new
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def client
|
|
78
|
+
@client ||= Client.new(configuration: configuration)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/openfeature/flagd/provider/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "openfeature-flagd-provider"
|
|
7
|
+
spec.version = OpenFeature::Flagd::VERSION
|
|
8
|
+
spec.authors = ["OpenFeature Authors"]
|
|
9
|
+
spec.email = ["cncf-openfeature-contributors@lists.cncf.io"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "The flagd provider for the OpenFeature Ruby SDK"
|
|
12
|
+
spec.description = "The flagd provider for the OpenFeature Ruby SDK"
|
|
13
|
+
spec.homepage = "https://github.com/open-feature/ruby-sdk-contrib/providers/openfeature-flagd-provider"
|
|
14
|
+
spec.license = "Apache-2.0"
|
|
15
|
+
spec.required_ruby_version = ">= 3.1"
|
|
16
|
+
|
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/open-feature/ruby-sdk-contrib/providers/openfeature-flagd-provider"
|
|
19
|
+
spec.metadata["changelog_uri"] = "https://github.com/open-feature/ruby-sdk-contrib/blob/main/providers/openfeature-flagd-provider/CHANGELOG.md"
|
|
20
|
+
spec.metadata["bug_tracker_uri"] = "https://github.com/open-feature/ruby-sdk-contrib/issues"
|
|
21
|
+
spec.metadata["documentation_uri"] = "https://github.com/open-feature/ruby-sdk-contrib/README.md"
|
|
22
|
+
|
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
26
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
27
|
+
end
|
|
28
|
+
spec.bindir = "exe"
|
|
29
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
30
|
+
spec.require_paths = ["lib"]
|
|
31
|
+
|
|
32
|
+
spec.add_runtime_dependency "grpc", "~> 1.50"
|
|
33
|
+
spec.add_runtime_dependency "openfeature-sdk", "~> 0.3"
|
|
34
|
+
|
|
35
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
36
|
+
spec.add_development_dependency "rspec", "~> 3.12.0"
|
|
37
|
+
spec.add_development_dependency "standard"
|
|
38
|
+
spec.add_development_dependency "rubocop"
|
|
39
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: openfeature-flagd-provider
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- OpenFeature Authors
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2024-05-16 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: grpc
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.50'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.50'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: openfeature-sdk
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0.3'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0.3'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '13.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '13.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rspec
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 3.12.0
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: 3.12.0
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: standard
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rubocop
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
description: The flagd provider for the OpenFeature Ruby SDK
|
|
98
|
+
email:
|
|
99
|
+
- cncf-openfeature-contributors@lists.cncf.io
|
|
100
|
+
executables: []
|
|
101
|
+
extensions: []
|
|
102
|
+
extra_rdoc_files: []
|
|
103
|
+
files:
|
|
104
|
+
- ".gitignore"
|
|
105
|
+
- ".rspec"
|
|
106
|
+
- ".rubocop.yml"
|
|
107
|
+
- ".ruby-version"
|
|
108
|
+
- CHANGELOG.md
|
|
109
|
+
- Gemfile
|
|
110
|
+
- Gemfile.lock
|
|
111
|
+
- README.md
|
|
112
|
+
- Rakefile
|
|
113
|
+
- bin/console
|
|
114
|
+
- bin/setup
|
|
115
|
+
- docker/docker-compose.yml
|
|
116
|
+
- docker/flags.json
|
|
117
|
+
- lib/openfeature/flagd/provider.rb
|
|
118
|
+
- lib/openfeature/flagd/provider/client.rb
|
|
119
|
+
- lib/openfeature/flagd/provider/configuration.rb
|
|
120
|
+
- lib/openfeature/flagd/provider/flagd/evaluation/v1/evaluation_pb.rb
|
|
121
|
+
- lib/openfeature/flagd/provider/flagd/evaluation/v1/evaluation_services_pb.rb
|
|
122
|
+
- lib/openfeature/flagd/provider/flagd/sync/v1/sync_pb.rb
|
|
123
|
+
- lib/openfeature/flagd/provider/flagd/sync/v1/sync_services_pb.rb
|
|
124
|
+
- lib/openfeature/flagd/provider/version.rb
|
|
125
|
+
- openfeature-flagd-provider.gemspec
|
|
126
|
+
homepage: https://github.com/open-feature/ruby-sdk-contrib/providers/openfeature-flagd-provider
|
|
127
|
+
licenses:
|
|
128
|
+
- Apache-2.0
|
|
129
|
+
metadata:
|
|
130
|
+
homepage_uri: https://github.com/open-feature/ruby-sdk-contrib/providers/openfeature-flagd-provider
|
|
131
|
+
source_code_uri: https://github.com/open-feature/ruby-sdk-contrib/providers/openfeature-flagd-provider
|
|
132
|
+
changelog_uri: https://github.com/open-feature/ruby-sdk-contrib/blob/main/providers/openfeature-flagd-provider/CHANGELOG.md
|
|
133
|
+
bug_tracker_uri: https://github.com/open-feature/ruby-sdk-contrib/issues
|
|
134
|
+
documentation_uri: https://github.com/open-feature/ruby-sdk-contrib/README.md
|
|
135
|
+
post_install_message:
|
|
136
|
+
rdoc_options: []
|
|
137
|
+
require_paths:
|
|
138
|
+
- lib
|
|
139
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
140
|
+
requirements:
|
|
141
|
+
- - ">="
|
|
142
|
+
- !ruby/object:Gem::Version
|
|
143
|
+
version: '3.1'
|
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
|
+
requirements:
|
|
146
|
+
- - ">="
|
|
147
|
+
- !ruby/object:Gem::Version
|
|
148
|
+
version: '0'
|
|
149
|
+
requirements: []
|
|
150
|
+
rubygems_version: 3.5.9
|
|
151
|
+
signing_key:
|
|
152
|
+
specification_version: 4
|
|
153
|
+
summary: The flagd provider for the OpenFeature Ruby SDK
|
|
154
|
+
test_files: []
|