openfeature-go-feature-flag-provider 0.1.6 → 0.1.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88b909669520d990cdd3bab857d26fe0aebd5a6d753a311d88b73fd8026cfd49
4
- data.tar.gz: f5ae9b1d0a474a1f547f1dd9b84b0f9c4cee48f938f79e1b2d96ca67acc5380c
3
+ metadata.gz: ddfe59a26f6cb77f15f337d09960c06d01f35465e388c39a3b06603f36c0f573
4
+ data.tar.gz: 7598fabc63d82fa717b8dd388a1ccd4825db1a71e86aa5d92161eb704751616f
5
5
  SHA512:
6
- metadata.gz: 68053f645f8b2ea7d3c48f71e5c22bf6b64308cf4656a3480611bc82f200d38df9d527134e734b51e017bbf96814eb7b9abbb5b86205860eaafc7ff68df3d37c
7
- data.tar.gz: 1f5125e5d8360b48a12282f227dc69ea9302dd273c4bd728ce5c67ff159f11aaa97753a8dcca25a7d36959400e5d40c4af80b39150cb83cd5a514058f1099248
6
+ metadata.gz: ab45b781c719f2f037677808d3fce03e49dbe683f9c33acdc52065e79ccc0b81a428f642bc55310ffef543f54dbea1e530665954f8a0b714df052f8ba6dbcdc2
7
+ data.tar.gz: 1c831f1f4a7015fd811111fc91d6f1055a9feb032771be4b87c467edba901f3d4aff394c22d9dc9966ad3ec0cd18feeafc087d547534946e86fc424810128374
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.8](https://github.com/open-feature/ruby-sdk-contrib/compare/openfeature-go-feature-flag-provider/v0.1.7...openfeature-go-feature-flag-provider/v0.1.8) (2026-01-13)
4
+
5
+
6
+ ### 🐛 Bug Fixes
7
+
8
+ * Make goff unix socket client thread safe ([#74](https://github.com/open-feature/ruby-sdk-contrib/issues/74)) ([ec25c37](https://github.com/open-feature/ruby-sdk-contrib/commit/ec25c3787b108ed2af8d7f1c9efbd6a258870a21))
9
+
10
+ ## [0.1.7](https://github.com/open-feature/ruby-sdk-contrib/compare/openfeature-go-feature-flag-provider/v0.1.6...openfeature-go-feature-flag-provider/v0.1.7) (2025-11-19)
11
+
12
+
13
+ ### ✨ New Features
14
+
15
+ * **GoFeatureFlag:** unix client ([#66](https://github.com/open-feature/ruby-sdk-contrib/issues/66)) ([3f68ce8](https://github.com/open-feature/ruby-sdk-contrib/commit/3f68ce8691646779755affb2c86edf51ae21b40b))
16
+
3
17
  ## [0.1.6](https://github.com/open-feature/ruby-sdk-contrib/compare/openfeature-go-feature-flag-provider/v0.1.5...openfeature-go-feature-flag-provider/v0.1.6) (2025-11-11)
4
18
 
5
19
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openfeature-go-feature-flag-provider (0.1.6)
4
+ openfeature-go-feature-flag-provider (0.1.8)
5
5
  faraday-net_http_persistent (~> 2.3)
6
6
  openfeature-sdk (~> 0.3.1)
7
7
 
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "json"
5
+ require "open_feature/sdk"
6
+ require_relative "../error/errors"
7
+ require_relative "../model/ofrep_api_response"
8
+
9
+ module OpenFeature
10
+ module GoFeatureFlag
11
+ module Client
12
+ class Common
13
+ def initialize(endpoint: nil, custom_headers: nil)
14
+ raise "This should be overwritten by implementations"
15
+ end
16
+
17
+ def evaluate_ofrep_api(flag_key:, evaluation_context:)
18
+ raise "This should be overwritten by implementations"
19
+ end
20
+
21
+ private
22
+
23
+ def headers
24
+ {"Content-Type" => "application/json"}.merge(@custom_headers || {})
25
+ end
26
+
27
+ def evaluation_request(evaluation_context)
28
+ ctx = evaluation_context || OpenFeature::SDK::EvaluationContext.new
29
+ fields = ctx.fields.dup
30
+ # replace targeting_key by targetingKey without mutating original fields
31
+ fields["targetingKey"] = ctx.targeting_key
32
+ fields.delete("targeting_key")
33
+
34
+ {context: fields}
35
+ end
36
+
37
+ def check_retry_after
38
+ lock = (@retry_lock ||= Mutex.new)
39
+ lock.synchronize do
40
+ return if @retry_after.nil?
41
+ if Time.now < @retry_after
42
+ raise OpenFeature::GoFeatureFlag::RateLimited.new(nil)
43
+ else
44
+ @retry_after = nil
45
+ end
46
+ end
47
+ end
48
+
49
+ def parse_error_response(response)
50
+ required_keys = %w[key error_code]
51
+ parsed = JSON.parse(response.body)
52
+
53
+ missing_keys = required_keys - parsed.keys
54
+ unless missing_keys.empty?
55
+ raise OpenFeature::GoFeatureFlag::ParseError.new(response)
56
+ end
57
+
58
+ OpenFeature::GoFeatureFlag::OfrepApiResponse.new(
59
+ value: nil,
60
+ key: parsed["key"],
61
+ reason: SDK::Provider::Reason::ERROR,
62
+ variant: nil,
63
+ error_code: error_code_mapper(parsed["error_code"]),
64
+ error_details: parsed["error_details"],
65
+ metadata: nil
66
+ )
67
+ end
68
+
69
+ def parse_success_response(response)
70
+ required_keys = %w[key value reason variant]
71
+ parsed = JSON.parse(response.body)
72
+
73
+ missing_keys = required_keys - parsed.keys
74
+ unless missing_keys.empty?
75
+ raise OpenFeature::GoFeatureFlag::ParseError.new(response)
76
+ end
77
+
78
+ OpenFeature::GoFeatureFlag::OfrepApiResponse.new(
79
+ value: parsed["value"],
80
+ key: parsed["key"],
81
+ reason: reason_mapper(parsed["reason"]),
82
+ variant: parsed["variant"],
83
+ error_code: nil,
84
+ error_details: nil,
85
+ metadata: parsed["metadata"]
86
+ )
87
+ end
88
+
89
+ def reason_mapper(reason_str)
90
+ reason_str = reason_str.upcase
91
+ reason_map = {
92
+ "STATIC" => SDK::Provider::Reason::STATIC,
93
+ "DEFAULT" => SDK::Provider::Reason::DEFAULT,
94
+ "TARGETING_MATCH" => SDK::Provider::Reason::TARGETING_MATCH,
95
+ "SPLIT" => SDK::Provider::Reason::SPLIT,
96
+ "CACHED" => SDK::Provider::Reason::CACHED,
97
+ "DISABLED" => SDK::Provider::Reason::DISABLED,
98
+ "UNKNOWN" => SDK::Provider::Reason::UNKNOWN,
99
+ "STALE" => SDK::Provider::Reason::STALE,
100
+ "ERROR" => SDK::Provider::Reason::ERROR
101
+ }
102
+ reason_map[reason_str] || SDK::Provider::Reason::UNKNOWN
103
+ end
104
+
105
+ def error_code_mapper(error_code_str)
106
+ error_code_str = error_code_str.upcase
107
+ error_code_map = {
108
+ "PROVIDER_NOT_READY" => SDK::Provider::ErrorCode::PROVIDER_NOT_READY,
109
+ "FLAG_NOT_FOUND" => SDK::Provider::ErrorCode::FLAG_NOT_FOUND,
110
+ "PARSE_ERROR" => SDK::Provider::ErrorCode::PARSE_ERROR,
111
+ "TYPE_MISMATCH" => SDK::Provider::ErrorCode::TYPE_MISMATCH,
112
+ "TARGETING_KEY_MISSING" => SDK::Provider::ErrorCode::TARGETING_KEY_MISSING,
113
+ "INVALID_CONTEXT" => SDK::Provider::ErrorCode::INVALID_CONTEXT,
114
+ "GENERAL" => SDK::Provider::ErrorCode::GENERAL
115
+ }
116
+ error_code_map[error_code_str] || SDK::Provider::ErrorCode::GENERAL
117
+ end
118
+
119
+ def parse_retry_later_header(response)
120
+ retry_after = response["Retry-After"]
121
+ return nil if retry_after.nil?
122
+
123
+ begin
124
+ next_retry_time =
125
+ if /^\d+$/.match?(retry_after)
126
+ # Retry-After is in seconds
127
+ Time.now + Integer(retry_after)
128
+ else
129
+ # Retry-After is an HTTP-date
130
+ Time.httpdate(retry_after)
131
+ end
132
+ # Protect updates and never shorten an existing backoff window
133
+ lock = (@retry_lock ||= Mutex.new)
134
+ lock.synchronize do
135
+ @retry_after = [@retry_after, next_retry_time].compact.max
136
+ end
137
+ rescue ArgumentError
138
+ # ignore invalid Retry-After header
139
+ nil
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "common"
4
+ require "faraday/net_http_persistent"
5
+
6
+ module OpenFeature
7
+ module GoFeatureFlag
8
+ module Client
9
+ class HttpApi < Common
10
+ def initialize(endpoint: nil, custom_headers: nil, instrumentation: nil)
11
+ @custom_headers = custom_headers
12
+ @faraday_connection = Faraday.new(url: endpoint, headers: headers) do |f|
13
+ f.request :instrumentation, instrumentation if instrumentation
14
+ f.adapter :net_http_persistent do |http|
15
+ http.idle_timeout = 30
16
+ end
17
+ end
18
+ end
19
+
20
+ def evaluate_ofrep_api(flag_key:, evaluation_context:)
21
+ check_retry_after
22
+ request = evaluation_request(evaluation_context)
23
+
24
+ response = @faraday_connection.post("/ofrep/v1/evaluate/flags/#{flag_key}") do |req|
25
+ req.body = request.to_json
26
+ end
27
+
28
+ case response.status
29
+ when 200
30
+ parse_success_response(response)
31
+ when 400
32
+ parse_error_response(response)
33
+ when 401, 403
34
+ raise OpenFeature::GoFeatureFlag::UnauthorizedError.new(response)
35
+ when 404
36
+ raise OpenFeature::GoFeatureFlag::FlagNotFoundError.new(response, flag_key)
37
+ when 429
38
+ parse_retry_later_header(response)
39
+ raise OpenFeature::GoFeatureFlag::RateLimited.new(response)
40
+ else
41
+ raise OpenFeature::GoFeatureFlag::InternalServerError.new(response)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "common"
4
+ require_relative "../internal/http_unix"
5
+
6
+ module OpenFeature
7
+ module GoFeatureFlag
8
+ module Client
9
+ class UnixApi < Common
10
+ def initialize(endpoint: nil, custom_headers: nil, unix_socket_client_factory: nil)
11
+ @custom_headers = custom_headers
12
+ @endpoint = endpoint
13
+ @unix_socket_client_factory = unix_socket_client_factory || ->(ep) { HttpUnix.new(ep) }
14
+ end
15
+
16
+ def evaluate_ofrep_api(flag_key:, evaluation_context:)
17
+ check_retry_after
18
+
19
+ request = evaluation_request(evaluation_context)
20
+ response = thread_local_socket.post("/ofrep/v1/evaluate/flags/#{flag_key}", request, headers)
21
+
22
+ case response.code
23
+ when "200"
24
+ parse_success_response(response)
25
+ when "400"
26
+ parse_error_response(response)
27
+ when "401", "403"
28
+ raise OpenFeature::GoFeatureFlag::UnauthorizedError.new(response)
29
+ when "404"
30
+ raise OpenFeature::GoFeatureFlag::FlagNotFoundError.new(response, flag_key)
31
+ when "429"
32
+ parse_retry_later_header(response)
33
+ raise OpenFeature::GoFeatureFlag::RateLimited.new(response)
34
+ else
35
+ raise OpenFeature::GoFeatureFlag::InternalServerError.new(response)
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def thread_local_socket
42
+ key = "openfeature_goff_unix_socket_#{object_id}"
43
+ Thread.current[key] ||= @unix_socket_client_factory.call(@endpoint)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,16 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "openfeature/go-feature-flag/client/http_api"
4
+ require "openfeature/go-feature-flag/client/unix_api"
5
+
3
6
  module OpenFeature
4
7
  module GoFeatureFlag
5
8
  # This class is the entry point for the GoFeatureFlagProvider
6
9
  class Provider
7
10
  PROVIDER_NAME = "GO Feature Flag Provider"
11
+ Client = OpenFeature::GoFeatureFlag::Client
8
12
  attr_reader :metadata, :options
9
13
 
10
14
  def initialize(options: Options.new)
11
15
  @metadata = SDK::Provider::ProviderMetadata.new(name: PROVIDER_NAME)
12
16
  @options = options
13
- @goff_api = GoFeatureFlagApi.new(endpoint: options.endpoint, custom_headers: options.custom_headers, instrumentation: options.instrumentation)
17
+ @goff_api = build_client(options)
14
18
  end
15
19
 
16
20
  def fetch_boolean_value(flag_key:, default_value:, evaluation_context: nil)
@@ -95,6 +99,17 @@ module OpenFeature
95
99
  raise InvalidOptionError.new(SDK::Provider::ErrorCode::GENERAL, "invalid flag key provided")
96
100
  end
97
101
  end
102
+
103
+ def build_client(options)
104
+ case options.type
105
+ when "http"
106
+ Client::HttpApi.new(endpoint: options.endpoint, custom_headers: options.custom_headers, instrumentation: options.instrumentation)
107
+ when "unix"
108
+ Client::UnixApi.new(endpoint: options.endpoint, custom_headers: options.custom_headers)
109
+ else
110
+ raise InvalidOptionError.new(SDK::Provider::ErrorCode::GENERAL, "Invalid client type: '#{options.type}'. Supported types are: 'http', 'unix'")
111
+ end
112
+ end
98
113
  end
99
114
  end
100
115
  end
@@ -0,0 +1,31 @@
1
+ require "net/http"
2
+
3
+ class HttpUnix < Net::HTTP
4
+ BufferedIO = ::Net::BufferedIO
5
+ UNIX_REGEXP = %r{^unix://}i
6
+
7
+ def initialize(address, port = nil)
8
+ super(address, port)
9
+ @socket_type = "unix"
10
+ @socket_path = address.sub(UNIX_REGEXP, "")
11
+
12
+ @host = "localhost"
13
+ @port = 1031
14
+ end
15
+
16
+ def connect
17
+ s = UNIXSocket.open(@socket_path)
18
+ @socket = BufferedIO.new(s,
19
+ read_timeout: @read_timeout,
20
+ continue_timeout: @continue_timeout,
21
+ debug_output: @debug_output)
22
+ on_connect
23
+ end
24
+
25
+ def post(url, body, headers)
26
+ request = Net::HTTP::Post.new(url, headers)
27
+ request["host"] = "localhost" # required to form correct HTTP request
28
+ request.body = body.to_json
29
+ request(request)
30
+ end
31
+ end
@@ -6,11 +6,12 @@ module OpenFeature
6
6
  module GoFeatureFlag
7
7
  # This class is the configuration class for the GoFeatureFlagProvider
8
8
  class Options
9
- attr_accessor :endpoint, :custom_headers, :exporter_metadata, :instrumentation
9
+ attr_accessor :endpoint, :custom_headers, :exporter_metadata, :instrumentation, :type
10
10
 
11
- def initialize(endpoint: nil, headers: {}, exporter_metadata: {}, instrumentation: nil)
12
- validate_endpoint(endpoint: endpoint)
11
+ def initialize(endpoint: nil, headers: {}, exporter_metadata: {}, instrumentation: nil, type: "http")
12
+ validate_endpoint(endpoint, type)
13
13
  validate_instrumentation(instrumentation: instrumentation)
14
+ @type = type
14
15
  @endpoint = endpoint
15
16
  @custom_headers = headers
16
17
  @exporter_metadata = exporter_metadata
@@ -19,11 +20,18 @@ module OpenFeature
19
20
 
20
21
  private
21
22
 
22
- def validate_endpoint(endpoint: nil)
23
+ def validate_endpoint(endpoint, type)
23
24
  return if endpoint.nil?
24
25
 
25
- uri = URI.parse(endpoint)
26
- raise ArgumentError, "Invalid URL for endpoint: #{endpoint}" unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
26
+ case type
27
+ when "http"
28
+ uri = URI.parse(endpoint)
29
+ raise ArgumentError, "Invalid URL for endpoint: #{endpoint}" unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
30
+ when "unix"
31
+ raise ArgumentError, "File not found: #{endpoint}" unless File.exist?(endpoint)
32
+ else
33
+ raise ArgumentError, "Invalid Type: #{type}"
34
+ end
27
35
  rescue URI::InvalidURIError
28
36
  raise ArgumentError, "Invalid URL for endpoint: #{endpoint}"
29
37
  end
@@ -1,5 +1,5 @@
1
1
  module OpenFeature
2
2
  module GoFeatureFlag
3
- GO_FEATURE_FLAG_PROVIDER_VERSION = "0.1.6"
3
+ GO_FEATURE_FLAG_PROVIDER_VERSION = "0.1.8"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openfeature-go-feature-flag-provider
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Poignant
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-11-11 00:00:00.000000000 Z
11
+ date: 2026-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: openfeature-sdk
@@ -136,9 +136,12 @@ files:
136
136
  - README.md
137
137
  - Rakefile
138
138
  - bin/rake
139
+ - lib/openfeature/go-feature-flag/client/common.rb
140
+ - lib/openfeature/go-feature-flag/client/http_api.rb
141
+ - lib/openfeature/go-feature-flag/client/unix_api.rb
139
142
  - lib/openfeature/go-feature-flag/error/errors.rb
140
143
  - lib/openfeature/go-feature-flag/go_feature_flag_provider.rb
141
- - lib/openfeature/go-feature-flag/goff_api.rb
144
+ - lib/openfeature/go-feature-flag/internal/http_unix.rb
142
145
  - lib/openfeature/go-feature-flag/model/ofrep_api_response.rb
143
146
  - lib/openfeature/go-feature-flag/options.rb
144
147
  - lib/openfeature/go-feature-flag/version.rb
@@ -1,153 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "open_feature/sdk"
4
- require "net/http"
5
- require "json"
6
- require "faraday/net_http_persistent"
7
- require_relative "error/errors"
8
- require_relative "model/ofrep_api_response"
9
-
10
- module OpenFeature
11
- module GoFeatureFlag
12
- # This class is the entry point for the GoFeatureFlagProvider
13
- class GoFeatureFlagApi
14
- def initialize(endpoint: nil, custom_headers: nil, instrumentation: nil)
15
- @faraday_connection = Faraday.new(url: endpoint, headers: headers(custom_headers)) do |f|
16
- f.request :instrumentation, instrumentation if instrumentation
17
- f.adapter :net_http_persistent do |http|
18
- http.idle_timeout = 30
19
- end
20
- end
21
- end
22
-
23
- def evaluate_ofrep_api(flag_key:, evaluation_context:)
24
- unless @retry_after.nil?
25
- if Time.now < @retry_after
26
- raise OpenFeature::GoFeatureFlag::RateLimited.new(nil)
27
- else
28
- @retry_after = nil
29
- end
30
- end
31
-
32
- evaluation_context = OpenFeature::SDK::EvaluationContext.new if evaluation_context.nil?
33
- # replace targeting_key by targetingKey
34
- evaluation_context.fields["targetingKey"] = evaluation_context.targeting_key
35
- evaluation_context.fields.delete("targeting_key")
36
-
37
- response = @faraday_connection.post("/ofrep/v1/evaluate/flags/#{flag_key}") do |req|
38
- req.body = {context: evaluation_context.fields}.to_json
39
- end
40
-
41
- case response.status
42
- when 200
43
- parse_success_response(response)
44
- when 400
45
- parse_error_response(response)
46
- when 401, 403
47
- raise OpenFeature::GoFeatureFlag::UnauthorizedError.new(response)
48
- when 404
49
- raise OpenFeature::GoFeatureFlag::FlagNotFoundError.new(response, flag_key)
50
- when 429
51
- parse_retry_later_header(response)
52
- raise OpenFeature::GoFeatureFlag::RateLimited.new(response)
53
- else
54
- raise OpenFeature::GoFeatureFlag::InternalServerError.new(response)
55
- end
56
- end
57
-
58
- private
59
-
60
- def headers(custom_headers)
61
- {"Content-Type" => "application/json"}.merge(custom_headers || {})
62
- end
63
-
64
- def parse_error_response(response)
65
- required_keys = %w[key error_code]
66
- parsed = JSON.parse(response.body)
67
-
68
- missing_keys = required_keys - parsed.keys
69
- unless missing_keys.empty?
70
- raise OpenFeature::GoFeatureFlag::ParseError.new(response)
71
- end
72
-
73
- OpenFeature::GoFeatureFlag::OfrepApiResponse.new(
74
- value: nil,
75
- key: parsed["key"],
76
- reason: SDK::Provider::Reason::ERROR,
77
- variant: nil,
78
- error_code: error_code_mapper(parsed["error_code"]),
79
- error_details: parsed["error_details"],
80
- metadata: nil
81
- )
82
- end
83
-
84
- def parse_success_response(response)
85
- required_keys = %w[key value reason variant]
86
- parsed = JSON.parse(response.body)
87
-
88
- missing_keys = required_keys - parsed.keys
89
- unless missing_keys.empty?
90
- raise OpenFeature::GoFeatureFlag::ParseError.new(response)
91
- end
92
-
93
- OpenFeature::GoFeatureFlag::OfrepApiResponse.new(
94
- value: parsed["value"],
95
- key: parsed["key"],
96
- reason: reason_mapper(parsed["reason"]),
97
- variant: parsed["variant"],
98
- error_code: nil,
99
- error_details: nil,
100
- metadata: parsed["metadata"]
101
- )
102
- end
103
-
104
- def reason_mapper(reason_str)
105
- reason_str = reason_str.upcase
106
- reason_map = {
107
- "STATIC" => SDK::Provider::Reason::STATIC,
108
- "DEFAULT" => SDK::Provider::Reason::DEFAULT,
109
- "TARGETING_MATCH" => SDK::Provider::Reason::TARGETING_MATCH,
110
- "SPLIT" => SDK::Provider::Reason::SPLIT,
111
- "CACHED" => SDK::Provider::Reason::CACHED,
112
- "DISABLED" => SDK::Provider::Reason::DISABLED,
113
- "UNKNOWN" => SDK::Provider::Reason::UNKNOWN,
114
- "STALE" => SDK::Provider::Reason::STALE,
115
- "ERROR" => SDK::Provider::Reason::ERROR
116
- }
117
- reason_map[reason_str] || SDK::Provider::Reason::UNKNOWN
118
- end
119
-
120
- def error_code_mapper(error_code_str)
121
- error_code_str = error_code_str.upcase
122
- error_code_map = {
123
- "PROVIDER_NOT_READY" => SDK::Provider::ErrorCode::PROVIDER_NOT_READY,
124
- "FLAG_NOT_FOUND" => SDK::Provider::ErrorCode::FLAG_NOT_FOUND,
125
- "PARSE_ERROR" => SDK::Provider::ErrorCode::PARSE_ERROR,
126
- "TYPE_MISMATCH" => SDK::Provider::ErrorCode::TYPE_MISMATCH,
127
- "TARGETING_KEY_MISSING" => SDK::Provider::ErrorCode::TARGETING_KEY_MISSING,
128
- "INVALID_CONTEXT" => SDK::Provider::ErrorCode::INVALID_CONTEXT,
129
- "GENERAL" => SDK::Provider::ErrorCode::GENERAL
130
- }
131
- error_code_map[error_code_str] || SDK::Provider::ErrorCode::GENERAL
132
- end
133
-
134
- def parse_retry_later_header(response)
135
- retry_after = response["Retry-After"]
136
- return nil if retry_after.nil?
137
-
138
- begin
139
- @retry_after = if /^\d+$/.match?(retry_after)
140
- # Retry-After is in seconds
141
- Time.now + Integer(retry_after)
142
- else
143
- # Retry-After is an HTTP-date
144
- Time.httpdate(retry_after)
145
- end
146
- rescue ArgumentError
147
- # ignore invalid Retry-After header
148
- nil
149
- end
150
- end
151
- end
152
- end
153
- end