Class: Beachcomber::Client

Inherits:
Object
  • Object
show all
Includes:
ResponseParsing
Defined in:
lib/beachcomber/client.rb

Overview

Client sends individual requests through the shared library, which owns socket handling, framing and JSON mapping. For workloads that issue many queries per invocation, use #session to reuse a persistent connection.

Examples:

client = Beachcomber::Client.new
result = client.get('git.branch', path: '/repo')
puts result.data if result.hit?

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(socket_path: nil, timeout: DEFAULT_TIMEOUT, autostart: nil) ⇒ Client

Returns a new instance of Client.

Parameters:

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

    explicit socket path; library default discovery applies when nil.

  • timeout (Numeric, nil) (defaults to: DEFAULT_TIMEOUT)

    socket read/write timeout in seconds (default 0.1 / 100ms, matching the library's own default).

  • autostart (Boolean, nil) (defaults to: nil)

    attempt to start the daemon if it isn't running. When nil (the default) the shared library's default applies (autostart on); pass false to disable. The library only autostarts when the socket path is auto-discovered — never for an explicit socket_path.



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

def initialize(socket_path: nil, timeout: DEFAULT_TIMEOUT, autostart: nil)
  options = {}
  options[:autostart] = autostart unless autostart.nil?
  options[:socket_path] = socket_path if socket_path
  options[:timeout_ms] = (timeout * 1000).round if timeout

  @handle = Beachcomber::FFI.new_client(JSON.generate(options))
  ObjectSpace.define_finalizer(self, self.class.finalizer(@handle))
end

Class Method Details

.finalizer(handle) ⇒ Object



242
243
244
# File 'lib/beachcomber/client.rb', line 242

def self.finalizer(handle)
  proc { Beachcomber::FFI.free_client(handle) }
end

Instance Method Details

#eval_expression(template, cwd:, env: nil, overrides: nil) ⇒ String

Evaluates an arbitrary expression string against env.*/cache.* refs, using the same evaluator #resolve uses for a declared field.

Parameters:

  • template (String)
  • cwd (String)

    required, matching #resolve

  • env (Hash, nil) (defaults to: nil)
  • overrides (Hash, nil) (defaults to: nil)

Returns:

  • (String)


344
345
346
# File 'lib/beachcomber/client.rb', line 344

def eval_expression(template, cwd:, env: nil, overrides: nil)
  Beachcomber::FFI.call!(:bc_eval, @handle, template, cwd, json_or_nil(env), json_or_nil(overrides))
end

#get(key, path: nil) ⇒ Result

Reads a cached value.

Parameters:

  • key (String)

    e.g. "git.branch" or "git"

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

    optional working-directory context

Returns:

Raises:



253
254
255
# File 'lib/beachcomber/client.rb', line 253

def get(key, path: nil)
  build_result(Beachcomber::FFI.call!(:bc_get, @handle, key, path, 0))
end

#get_with_flags(key, path: nil, force: false, wait: false) ⇒ Result

Reads a cached value with protocol flags.

Parameters:

  • key (String)
  • path (String, nil) (defaults to: nil)
  • force (Boolean) (defaults to: false)

    bypass cache and recompute

  • wait (Boolean) (defaults to: false)

    block until a fresh value is available

Returns:



264
265
266
267
# File 'lib/beachcomber/client.rb', line 264

def get_with_flags(key, path: nil, force: false, wait: false)
  flags = (force ? Beachcomber::FFI::GET_FORCE : 0) | (wait ? Beachcomber::FFI::GET_WAIT : 0)
  build_result(Beachcomber::FFI.call!(:bc_get, @handle, key, path, flags))
end

#helloHelloInfo

Sends a hello handshake and returns server info.

Returns:



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

def hello
  parse_hello(Beachcomber::FFI.call!(:bc_hello, @handle))
end

#introspect(subject, duration_secs: nil) ⇒ IntrospectResponse

Introspects a daemon subsystem.

Parameters:

  • subject (String)

    one of the IntrospectSubject constants

  • duration_secs (Numeric, nil) (defaults to: nil)

Returns:



314
315
316
317
318
# File 'lib/beachcomber/client.rb', line 314

def introspect(subject, duration_secs: nil)
  options_json = duration_secs ? JSON.generate(duration_secs: duration_secs) : nil
  data = Beachcomber::FFI.call!(:bc_introspect, @handle, subject.to_s, options_json)
  parse_introspect(subject.to_s, data)
end

#put(key, data = nil, ttl: nil, path: nil) ⇒ nil

Writes a value into the daemon cache. data = nil clears the entry without dropping the registry entry.

Parameters:

  • key (String)
  • data (Object, nil) (defaults to: nil)
  • ttl (Numeric, String, nil) (defaults to: nil)

    time-to-live (e.g. "60s")

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

Returns:

  • (nil)


300
301
302
303
304
305
306
307
# File 'lib/beachcomber/client.rb', line 300

def put(key, data = nil, ttl: nil, path: nil)
  if data.nil?
    Beachcomber::FFI.call!(:bc_put_null, @handle, key, path)
  else
    Beachcomber::FFI.call!(:bc_put, @handle, key, JSON.generate(data), ttl&.to_s, path)
  end
  nil
end

#refresh(key, path: nil) ⇒ Object

Forces the daemon to recompute a provider/key.

Parameters:

  • key (String)
  • path (String, nil) (defaults to: nil)


273
274
275
276
# File 'lib/beachcomber/client.rb', line 273

def refresh(key, path: nil)
  Beachcomber::FFI.call!(:bc_refresh, @handle, key, path)
  nil
end

#resolve(key, cwd:, env: nil, overrides: nil) ⇒ Object?

Resolves a virtual field ("provider.field") or a provider's path expression ("provider") client-side, exactly as comb get's resolution layer does. cache.* refs the expression makes are fetched live through this client.

Parameters:

  • key (String)

    "provider.field" or a bare provider name

  • cwd (String)

    required — path-expression evaluation has no ambient fallback; the library never reads the process's own cwd.

  • env (Hash, nil) (defaults to: nil)

    env var values env.* refs resolve against

  • overrides (Hash, nil) (defaults to: nil)

    expression overrides, keyed "provider.field" or a bare provider name

Returns:

  • (Object, nil)

    the resolved value, or nil on a path-expression miss



332
333
334
# File 'lib/beachcomber/client.rb', line 332

def resolve(key, cwd:, env: nil, overrides: nil)
  Beachcomber::FFI.call!(:bc_resolve, @handle, key, cwd, json_or_nil(env), json_or_nil(overrides))
end

#session {|Session| ... } ⇒ Object

Opens a persistent session and yields it to the block. The connection is closed automatically when the block returns (even on exception).

Yields:

Returns:

  • the block's return value



366
367
368
369
370
371
372
# File 'lib/beachcomber/client.rb', line 366

def session
  handle = Beachcomber::FFI.new_session(@handle)
  sess = Session.new(handle, @handle)
  yield sess
ensure
  sess&.close
end

#statusArray<CacheRow>

Returns cache rows from the daemon.

Returns:



281
282
283
# File 'lib/beachcomber/client.rb', line 281

def status
  parse_cache_rows(Beachcomber::FFI.call!(:bc_status, @handle))
end

#watch(key, path: nil) ⇒ WatchStream

Opens a persistent watch subscription. Returns a WatchStream (Enumerable). The caller is responsible for closing the stream.

Parameters:

  • key (String)
  • path (String, nil) (defaults to: nil)

Returns:

Raises:



354
355
356
357
358
359
# File 'lib/beachcomber/client.rb', line 354

def watch(key, path: nil)
  handle = Beachcomber::FFI.new_watch(@handle, key, path)
  raise Beachcomber::Error, 'bc_watch_open returned NULL (allocation failure)' if handle.nil? || handle.null?

  WatchStream.new(handle)
end