Class: Flipt::Client

Inherits:
Object
  • Object
show all
Extended by:
FFI::Library
Defined in:
lib/flipt_client.rb

Overview

Client is a Ruby Client Side Evaluation Library for Flipt

Direct Known Subclasses

EvaluationClient

Constant Summary collapse

FLIPTENGINE =
'fliptengine'
LIB_FILES =
{
  /arm64-darwin/ => "ext/darwin_aarch64/lib#{FLIPTENGINE}.dylib",
  /x86_64-darwin/ => "ext/darwin_x86_64/lib#{FLIPTENGINE}.dylib",
  /arm64-linux|aarch64-linux/ => "ext/linux_aarch64/lib#{FLIPTENGINE}.so",
  /x86_64-linux/ => "ext/linux_x86_64/lib#{FLIPTENGINE}.so",
  /x86_64-mingw32/ => "ext/windows_x86_64/#{FLIPTENGINE}.dll"
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**opts) ⇒ Client

Create a new Flipt client

Parameters:

  • opts (Hash)

    options

Options Hash (**opts):

  • :environment (String)

    Flipt environment (default: ‘default’)

  • :namespace (String)

    Flipt namespace (default: ‘default’)

  • :url (String)

    Flipt server url

  • :authentication (AuthenticationStrategy)

    strategy to authenticate with Flipt

  • :request_timeout (Integer)

    timeout in seconds for the request

  • :update_interval (Integer)

    interval in seconds to update the cache

  • :reference (String)

    reference to use for namespace data

  • :fetch_mode (Symbol)

    fetch mode to use for the client (:polling or :streaming). Note: Streaming is currently only supported when using the SDK with Flipt Cloud or Flipt v2.

  • :error_strategy (Symbol)

    error strategy to use for the client (:fail or :fallback).

  • :snapshot (String)

    snapshot to use when initializing the client

  • :tls_config (TlsConfig)

    TLS configuration for connecting to servers with custom certificates



69
70
71
72
73
74
75
76
77
78
79
# File 'lib/flipt_client.rb', line 69

def initialize(**opts)
  @namespace = opts.fetch(:namespace, 'default')

  opts[:authentication] = validate_authentication(opts.fetch(:authentication, NoAuthentication.new))
  opts[:fetch_mode] = validate_fetch_mode(opts.fetch(:fetch_mode, :polling))
  opts[:error_strategy] = validate_error_strategy(opts.fetch(:error_strategy, :fail))
  opts[:tls_config] = validate_tls_config(opts.fetch(:tls_config, nil))

  @engine = self.class.initialize_engine(opts.to_json)
  ObjectSpace.define_finalizer(self, self.class.finalize(@engine))
end

Class Method Details

.finalize(engine) ⇒ Object



81
82
83
# File 'lib/flipt_client.rb', line 81

def self.finalize(engine)
  proc { destroy_engine(engine) }
end

.libfileObject



27
28
29
30
31
32
33
# File 'lib/flipt_client.rb', line 27

def self.libfile
  arch = RbConfig::CONFIG['arch']
  LIB_FILES.each do |pattern, path|
    return path if arch.match?(pattern)
  end
  raise "unsupported platform #{arch}"
end

Instance Method Details

#evaluate_batch(requests:) ⇒ Object

Evaluate a batch of flags for a given request

Parameters:

  • requests (Array<Hash>)

    batch evaluation request

    • :entity_id [String] entity id

    • :flag_key [String] flag key

Raises:



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/flipt_client.rb', line 136

def evaluate_batch(requests:)
  unless requests.is_a?(Array)
    raise ValidationError, 'requests must be an array of evaluation requests'
  end

  requests.each do |request|
    validate_evaluation_request(request[:flag_key], request[:entity_id], request[:context] || {})
  end
  resp, ptr = self.class.evaluate_batch(@engine, requests.to_json)
  ptr = FFI::AutoPointer.new(ptr, Client.method(:destroy_string))
  data = JSON.parse(resp)
  raise EvaluationError, data['error_message'] if data['status'] != 'success'

  responses = (data['result']['responses'] || []).map do |r|
    case r['type']
    when 'VARIANT_EVALUATION_RESPONSE_TYPE'
      v = r['variant_evaluation_response']
      VariantEvaluationResponse.new(
        flag_key: v['flag_key'],
        match: v['match'],
        reason: v['reason'],
        variant_key: v['variant_key'],
        variant_attachment: v['variant_attachment'],
        segment_keys: v['segment_keys'] || []
      )
    when 'BOOLEAN_EVALUATION_RESPONSE_TYPE'
      b = r['boolean_evaluation_response']
      BooleanEvaluationResponse.new(
        flag_key: b['flag_key'],
        enabled: b['enabled'],
        reason: b['reason'],
        segment_keys: b['segment_keys'] || []
      )
    when 'ERROR_EVALUATION_RESPONSE_TYPE'
      e = r['error_evaluation_response']
      ErrorEvaluationResponse.new(
        flag_key: e['flag_key'],
        namespace_key: e['namespace_key'],
        reason: e['reason'],
        error_message: e['error_message']
      )
    else
      raise EvaluationError, "Unknown response type encountered: #{r['type']}"
    end
  end
  BatchEvaluationResponse.new(responses: responses)
end

#evaluate_boolean(flag_key:, entity_id:, context: {}) ⇒ Object

Evaluate a boolean flag for a given request

Parameters:

  • flag_key (String)
  • entity_id (String)
  • context (Hash) (defaults to: {})

Raises:



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/flipt_client.rb', line 114

def evaluate_boolean(flag_key:, entity_id:, context: {})
  validate_evaluation_request(flag_key, entity_id, context)
  req = { flag_key: flag_key, entity_id: entity_id, context: context }
  resp, ptr = self.class.evaluate_boolean(@engine, req.to_json)
  ptr = FFI::AutoPointer.new(ptr, Client.method(:destroy_string))
  data = JSON.parse(resp)
  raise EvaluationError, data['error_message'] if data['status'] != 'success'

  r = data['result']
  BooleanEvaluationResponse.new(
    flag_key: r['flag_key'],
    enabled: r['enabled'],
    reason: r['reason'],
    segment_keys: r['segment_keys'] || []
  )
end

#evaluate_variant(flag_key:, entity_id:, context: {}) ⇒ Object

Evaluate a variant flag for a given request

Parameters:

  • flag_key (String)
  • entity_id (String)
  • context (Hash) (defaults to: {})

Raises:



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/flipt_client.rb', line 90

def evaluate_variant(flag_key:, entity_id:, context: {})
  validate_evaluation_request(flag_key, entity_id, context)
  req = { flag_key: flag_key, entity_id: entity_id, context: context }
  resp, ptr = self.class.evaluate_variant(@engine, req.to_json)
  ptr = FFI::AutoPointer.new(ptr, Client.method(:destroy_string))
  data = JSON.parse(resp)
  raise EvaluationError, data['error_message'] if data['status'] != 'success'

  r = data['result']
  VariantEvaluationResponse.new(
    flag_key: r['flag_key'],
    match: r['match'],
    reason: r['reason'],
    variant_key: r['variant_key'],
    variant_attachment: r['variant_attachment'],
    segment_keys: r['segment_keys'] || []
  )
end

#list_flagsObject

List all flags in the namespace

Raises:



185
186
187
188
189
190
191
192
# File 'lib/flipt_client.rb', line 185

def list_flags
  resp, ptr = self.class.list_flags(@engine)
  ptr = FFI::AutoPointer.new(ptr, Client.method(:destroy_string))
  data = JSON.parse(resp)
  raise Error, data['error_message'] if data['status'] != 'success'

  data['result']
end

#snapshotObject

Get the snapshot of the current flag state



195
196
197
198
199
# File 'lib/flipt_client.rb', line 195

def snapshot
  resp, ptr = self.class.get_snapshot(@engine)
  ptr = FFI::AutoPointer.new(ptr, Client.method(:destroy_string))
  resp
end