Class: ToggleCraft::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/togglecraft/client.rb

Overview

Main ToggleCraft client class Provides the primary interface for feature flag evaluation with real-time updates

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sdk_key:, **options) ⇒ Client

Initialize the ToggleCraft client

Parameters:

  • sdk_key (String)

    SDK key for authentication

  • options (Hash)

    Configuration options

Raises:

  • (ArgumentError)


12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/togglecraft/client.rb', line 12

def initialize(sdk_key:, **options)
  raise ArgumentError, 'sdk_key is required' if sdk_key.nil? || sdk_key.empty?

  @config = {
    url: 'https://sse.togglecraft.io',
    enable_cache: true,
    cache_adapter: :memory,
    cache_ttl: 300, # 5 minutes
    reconnect_interval: 1,
    max_reconnect_interval: 30,
    max_reconnect_attempts: 10,
    slow_reconnect_interval: 60,
    share_connection: true,
    debug: false,
    enable_rollout_stage_polling: true,
    rollout_stage_check_interval: 60,
    fetch_jitter: 1500, # milliseconds
    api_domain: 'https://togglecraft.io',
    heartbeat_domain: 'https://togglecraft.io' # Default heartbeat domain
  }.merge(options).merge(sdk_key: sdk_key)

  # Initialize components
  @evaluator = Evaluator.new
  @cache = @config[:enable_cache] ? Cache.new(adapter: @config[:cache_adapter], ttl: @config[:cache_ttl]) : nil

  # State
  @ready = Concurrent::AtomicBoolean.new(false)
  @flags = Concurrent::Map.new
  @current_version = Concurrent::AtomicReference.new(nil)
  @project_key = Concurrent::AtomicReference.new(nil)
  @environment_key = Concurrent::AtomicReference.new(nil)
  @fetch_in_progress = Concurrent::AtomicBoolean.new(false)

  # Event listeners
  @listeners = Concurrent::Map.new
  @listeners[:ready] = []
  @listeners[:flags_updated] = []
  @listeners[:error] = []
  @listeners[:disconnected] = []
  @listeners[:reconnecting] = []
  @listeners[:rollout_stage_changed] = []
  @listeners_mutex = Mutex.new

  # Rollout stage polling
  @rollout_stage_percentages = {}
  @rollout_stage_timer = nil

  # Initialize connection
  initialize_connection

  # Enable debug on connection pool if debug is enabled
  ConnectionPool.set_debug(true) if @config[:debug] && @config[:share_connection]
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



7
8
9
# File 'lib/togglecraft/client.rb', line 7

def config
  @config
end

#readyObject (readonly)

Returns the value of attribute ready.



7
8
9
# File 'lib/togglecraft/client.rb', line 7

def ready
  @ready
end

Instance Method Details

#all_flag_keysArray<String>

Get all flag keys

Returns:

  • (Array<String>)


199
200
201
# File 'lib/togglecraft/client.rb', line 199

def all_flag_keys
  @evaluator.flag_keys
end

#connectvoid

This method returns an undefined value.

Connect to SSE server



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/togglecraft/client.rb', line 68

def connect
  # Try to load from cache first
  if @cache
    cached_flags = @cache.all_flags
    if cached_flags.any?
      @flags.clear
      cached_flags.each { |k, v| @flags[k] = v }
      @evaluator.update_flags(cached_flags)
      log 'Loaded flags from cache'
    end
  end

  # Connect to SSE server
  if @using_shared_connection
    @connection.connect(self)
  else
    @connection.connect
  end

  log 'Connected to ToggleCraft'
rescue StandardError => e
  handle_error(e)
  raise
end

#connected?Boolean

Check if connected to SSE server

Returns:

  • (Boolean)


117
118
119
# File 'lib/togglecraft/client.rb', line 117

def connected?
  @connection&.connected? || false
end

#destroyvoid

This method returns an undefined value.

Clean up resources



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/togglecraft/client.rb', line 256

def destroy
  log 'Destroying client instance'

  stop_rollout_stage_polling

  # Handle cleanup based on connection type
  if @using_shared_connection && @connection
    @connection.remove_client(self)
  elsif @connection
    disconnect
  end

  @cache&.destroy

  # Clear all listeners
  @listeners_mutex.synchronize do
    @listeners.each_key { |key| @listeners[key] = [] }
  end

  @connection = nil
  @flags.clear
  @ready.make_false
end

#disconnectvoid

This method returns an undefined value.

Disconnect from SSE server



95
96
97
98
99
100
# File 'lib/togglecraft/client.rb', line 95

def disconnect
  log 'Disconnecting from SSE'
  stop_rollout_stage_polling
  @connection.disconnect
  @ready.make_false
end

#enabled?(flag_key, context = {}, default: false) ⇒ Boolean

Evaluate a boolean flag

Parameters:

  • flag_key (String)

    Flag key

  • context (Hash) (defaults to: {})

    Evaluation context

  • default (Boolean) (defaults to: false)

    Default value

Returns:

  • (Boolean)


144
145
146
147
148
149
150
151
# File 'lib/togglecraft/client.rb', line 144

def enabled?(flag_key, context = {}, default: false)
  result = @evaluator.evaluate_boolean(flag_key, context, default)

  # Cache the result
  cache_evaluation(flag_key, context, result) if @cache && context

  result
end

#evaluate(flag_key, context = {}, default: false) ⇒ Object

Evaluate any flag type

Parameters:

  • flag_key (String)

    Flag key

  • context (Hash) (defaults to: {})

    Evaluation context

  • default (Object) (defaults to: false)

    Default value

Returns:

  • (Object)


193
194
195
# File 'lib/togglecraft/client.rb', line 193

def evaluate(flag_key, context = {}, default: false)
  @evaluator.evaluate(flag_key, context, default)
end

#flag_metadata(flag_key) ⇒ Hash?

Get flag metadata

Parameters:

  • flag_key (String)

    Flag key

Returns:

  • (Hash, nil)


206
207
208
# File 'lib/togglecraft/client.rb', line 206

def (flag_key)
  @evaluator.(flag_key)
end

#handle_connectvoid

This method returns an undefined value.

Handle SSE connection event



282
283
284
# File 'lib/togglecraft/client.rb', line 282

def handle_connect
  log 'SSE connected'
end

#handle_disconnectvoid

This method returns an undefined value.

Handle SSE disconnection event



288
289
290
291
# File 'lib/togglecraft/client.rb', line 288

def handle_disconnect
  @ready.make_false
  emit(:disconnected)
end

#handle_error(error) ⇒ void

This method returns an undefined value.

Handle error

Parameters:

  • error (Exception)

    Error that occurred



296
297
298
299
# File 'lib/togglecraft/client.rb', line 296

def handle_error(error)
  log "Error: #{error.message}"
  emit(:error, error)
end

#handle_flags_update(payload) ⇒ void

This method returns an undefined value.

Handle flags update from SSE

Parameters:

  • payload (Hash)

    Message payload



304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/togglecraft/client.rb', line 304

def handle_flags_update(payload)
  log "Received message: #{payload}"

  # Handle version update notification
  if payload[:type] == 'version_update'
    handle_version_update(payload)
    return
  end

  # Handle full flags payload
  process_flags_payload(payload) if payload[:flags]
end

#has_flag?(flag_key) ⇒ Boolean

Check if flag exists

Parameters:

  • flag_key (String)

    Flag key

Returns:

  • (Boolean)


213
214
215
# File 'lib/togglecraft/client.rb', line 213

def has_flag?(flag_key)
  @evaluator.has_flag?(flag_key)
end

#in_percentage?(flag_key, context = {}, default: false) ⇒ Boolean

Check if in percentage rollout

Parameters:

  • flag_key (String)

    Flag key

  • context (Hash) (defaults to: {})

    Evaluation context

  • default (Boolean) (defaults to: false)

    Default value

Returns:

  • (Boolean)


172
173
174
175
176
177
178
179
# File 'lib/togglecraft/client.rb', line 172

def in_percentage?(flag_key, context = {}, default: false)
  result = @evaluator.evaluate_percentage(flag_key, context, default)

  # Cache the result
  cache_evaluation(flag_key, context, result) if @cache && context

  result
end

#off(event, callable = nil) ⇒ void

This method returns an undefined value.

Remove event listener

Parameters:

  • event (Symbol)

    Event type

  • callable (Proc, nil) (defaults to: nil)

    Specific handler to remove



244
245
246
247
248
249
250
251
252
# File 'lib/togglecraft/client.rb', line 244

def off(event, callable = nil)
  @listeners_mutex.synchronize do
    if callable
      @listeners[event]&.delete(callable)
    else
      @listeners[event] = []
    end
  end
end

#on(event, &block) ⇒ void

This method returns an undefined value.

Add event listener

Parameters:

  • event (Symbol)

    Event type

  • block (Proc)

    Event handler



221
222
223
224
225
226
# File 'lib/togglecraft/client.rb', line 221

def on(event, &block)
  @listeners_mutex.synchronize do
    @listeners[event] ||= []
    @listeners[event] << block
  end
end

#once(event, &block) ⇒ void

This method returns an undefined value.

Add one-time event listener

Parameters:

  • event (Symbol)

    Event type

  • block (Proc)

    Event handler



232
233
234
235
236
237
238
# File 'lib/togglecraft/client.rb', line 232

def once(event, &block)
  wrapper = lambda do |*args|
    block.call(*args)
    off(event, wrapper)
  end
  on(event, &wrapper)
end

#percentage(flag_key) ⇒ Integer?

Get current percentage for a flag

Parameters:

  • flag_key (String)

    Flag key

Returns:

  • (Integer, nil)


184
185
186
# File 'lib/togglecraft/client.rb', line 184

def percentage(flag_key)
  @evaluator.percentage(flag_key)
end

#ready?Boolean

Check if client is ready

Returns:

  • (Boolean)


111
112
113
# File 'lib/togglecraft/client.rb', line 111

def ready?
  @ready.value
end

#reconnectvoid

This method returns an undefined value.

Reconnect to SSE server



104
105
106
107
# File 'lib/togglecraft/client.rb', line 104

def reconnect
  emit(:reconnecting)
  @connection.reconnect
end

#variant(flag_key, context = {}, default: nil) ⇒ String?

Get variant for multivariate flag

Parameters:

  • flag_key (String)

    Flag key

  • context (Hash) (defaults to: {})

    Evaluation context

  • default (String, nil) (defaults to: nil)

    Default variant

Returns:

  • (String, nil)


158
159
160
161
162
163
164
165
# File 'lib/togglecraft/client.rb', line 158

def variant(flag_key, context = {}, default: nil)
  result = @evaluator.evaluate_multivariate(flag_key, context, default)

  # Cache the result
  cache_evaluation(flag_key, context, result) if @cache && context

  result
end

#wait_for_ready(timeout: 5) ⇒ void

This method returns an undefined value.

Wait for client to be ready

Parameters:

  • timeout (Integer) (defaults to: 5)

    Timeout in seconds

Raises:

  • (Timeout::Error)

    if timeout is reached



125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/togglecraft/client.rb', line 125

def wait_for_ready(timeout: 5)
  return if ready?

  ready_latch = Concurrent::CountDownLatch.new(1)
  ready_handler = -> { ready_latch.count_down }

  once(:ready, &ready_handler)

  return if ready_latch.wait(timeout)

  off(:ready, ready_handler)
  raise Timeout::Error, 'Timeout waiting for client to be ready'
end