Class: Kobako::Registry
- Inherits:
-
Object
- Object
- Kobako::Registry
- Defined in:
- lib/kobako/registry.rb,
lib/kobako/registry/dispatcher.rb,
lib/kobako/registry/handle_table.rb,
lib/kobako/registry/service_group.rb
Overview
Kobako::Registry — per-Sandbox container of Service Groups and Handle state. Manages capability injection and guest-initiated RPC dispatch (SPEC.md B-07..B-21).
Public API:
registry = Kobako::Registry.new
group = registry.define(:MyService) # => ServiceGroup
group.bind(:KV, kv_object) # => group (chainable)
registry.to_preamble # => array for Frame 1
registry.dispatch(request_bytes) # => msgpack bytes (delegated to Dispatcher)
Service Groups are defined in Kobako::Registry::ServiceGroup (lib/kobako/registry/service_group.rb). The opaque Handle allocator lives in Kobako::Registry::HandleTable (lib/kobako/registry/handle_table.rb). Dispatch helpers live in Kobako::Registry::Dispatcher (lib/kobako/registry/dispatcher.rb).
Defined Under Namespace
Modules: Dispatcher Classes: HandleTable, ServiceGroup
Constant Summary collapse
- NAME_PATTERN =
Ruby constant-name pattern shared by Group and Member names (SPEC.md B-07/B-08 Notes). Referenced by both
#definehere and ServiceGroup#bind — single source of truth so the validation rule cannot drift between the two boundaries. /\A[A-Z]\w*\z/
Instance Attribute Summary collapse
-
#handle_table ⇒ Object
readonly
Expose the
Kobako::Registry::HandleTablefor tests and wire-layer Handle wrapping.
Instance Method Summary collapse
-
#bound?(target) ⇒ Boolean
Returns
truewhentarget(a “GroupName::MemberName” path) resolves to a bound member,falseotherwise. -
#define(name) ⇒ Object
Declare or retrieve the Group named
name(idempotent — SPEC.md B-10). -
#dispatch(request_bytes) ⇒ Object
Dispatch a single RPC request and return the encoded response bytes (SPEC.md B-12).
-
#empty? ⇒ Boolean
Returns
truewhen no groups have been declared,falseotherwise. -
#groups ⇒ Object
Returns all declared
Kobako::Registry::ServiceGroupinstances as anArray. -
#guest_preamble ⇒ Object
Encode the preamble as msgpack bytes for stdin Frame 1 delivery (SPEC.md B-02).
-
#initialize(handle_table: HandleTable.new) ⇒ Registry
constructor
Build a fresh Registry.
-
#lookup(target) ⇒ Object
Resolve a
targetpath of the form “GroupName::MemberName” to the bound Host object. -
#reset_handles! ⇒ Object
Reset the HandleTable for a new
#runboundary. -
#seal! ⇒ Object
Mark the Registry as sealed.
-
#sealed? ⇒ Boolean
Returns
truewhen #seal! has been called,falseotherwise. -
#size ⇒ Object
Returns the number of declared groups as an
Integer. -
#to_preamble ⇒ Object
Structured Frame 1 description.
Constructor Details
#initialize(handle_table: HandleTable.new) ⇒ Registry
Build a fresh Registry. handle_table is an internal seam that injects a pre-configured HandleTable; tests pass one whose next_id is pinned near MAX_ID to exercise the B-21 cap-exhaustion path without 2³¹ allocations. Production callers leave it at the default.
39 40 41 42 43 |
# File 'lib/kobako/registry.rb', line 39 def initialize(handle_table: HandleTable.new) @groups = {} @handle_table = handle_table @sealed = false end |
Instance Attribute Details
#handle_table ⇒ Object (readonly)
Expose the Kobako::Registry::HandleTable for tests and wire-layer Handle wrapping.
147 148 149 |
# File 'lib/kobako/registry.rb', line 147 def handle_table @handle_table end |
Instance Method Details
#bound?(target) ⇒ Boolean
Returns true when target (a “GroupName::MemberName” path) resolves to a bound member, false otherwise.
77 78 79 80 |
# File 'lib/kobako/registry.rb', line 77 def bound?(target) group, member_name, = resolve_pair(target) !group.nil? && !member_name.nil? && !group[member_name].nil? end |
#define(name) ⇒ Object
Declare or retrieve the Group named name (idempotent — SPEC.md B-10). name is a constant-form name as a Symbol or String (must satisfy NAME_PATTERN). Returns the Kobako::Registry::ServiceGroup for that name, creating it if it does not exist. Raises ArgumentError when name is malformed, or when called after the owning Sandbox has been sealed by #run.
51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/kobako/registry.rb', line 51 def define(name) raise ArgumentError, "cannot define after Sandbox#run has been invoked" if @sealed name_str = name.to_s unless NAME_PATTERN.match?(name_str) raise ArgumentError, "GroupName must match #{NAME_PATTERN.inspect} (got #{name.inspect})" end @groups[name_str] ||= ServiceGroup.new(name_str) end |
#dispatch(request_bytes) ⇒ Object
Dispatch a single RPC request and return the encoded response bytes (SPEC.md B-12). request_bytes is a msgpack-encoded Request envelope. Called by the Rust ext from inside __kobako_rpc_call. Always returns a binary String — never raises. Delegates to Dispatcher.dispatch which reifies any failure as a Response.err envelope so the guest sees the failure as a normal RPC error rather than a wasm trap.
141 142 143 |
# File 'lib/kobako/registry.rb', line 141 def dispatch(request_bytes) Dispatcher.dispatch(request_bytes, self) end |
#empty? ⇒ Boolean
Returns true when no groups have been declared, false otherwise.
94 95 96 |
# File 'lib/kobako/registry.rb', line 94 def empty? @groups.empty? end |
#groups ⇒ Object
Returns all declared Kobako::Registry::ServiceGroup instances as an Array.
84 85 86 |
# File 'lib/kobako/registry.rb', line 84 def groups @groups.values end |
#guest_preamble ⇒ Object
Encode the preamble as msgpack bytes for stdin Frame 1 delivery (SPEC.md B-02). Uses plain MessagePack (no kobako ext types) because the preamble contains only strings — no Handles or Exception envelopes. Structure: [[“GroupName”, [“MemberA”, “MemberB”]], …]. Returns a binary String of msgpack bytes.
112 113 114 |
# File 'lib/kobako/registry.rb', line 112 def guest_preamble MessagePack.pack(to_preamble) end |
#lookup(target) ⇒ Object
Resolve a target path of the form “GroupName::MemberName” to the bound Host object. target is a two-level path using the :: separator. Returns the bound Host object. Raises KeyError when the group or the member is not bound.
67 68 69 70 71 72 73 |
# File 'lib/kobako/registry.rb', line 67 def lookup(target) group, member_name, group_name = resolve_pair(target) raise KeyError, "no service group named #{group_name.inspect}" if group.nil? raise KeyError, "no member #{target.inspect} bound in registry" unless member_name group.fetch(member_name) end |
#reset_handles! ⇒ Object
Reset the HandleTable for a new #run boundary. Called by Sandbox#run before each invocation (SPEC.md B-19).
130 131 132 |
# File 'lib/kobako/registry.rb', line 130 def reset_handles! @handle_table.reset! end |
#seal! ⇒ Object
Mark the Registry as sealed. Called by ‘Sandbox#run` on first run. After sealing, #define raises ArgumentError. Idempotent.
118 119 120 121 |
# File 'lib/kobako/registry.rb', line 118 def seal! @sealed = true self end |
#sealed? ⇒ Boolean
Returns true when #seal! has been called, false otherwise.
124 125 126 |
# File 'lib/kobako/registry.rb', line 124 def sealed? @sealed end |
#size ⇒ Object
Returns the number of declared groups as an Integer.
89 90 91 |
# File 'lib/kobako/registry.rb', line 89 def size @groups.size end |
#to_preamble ⇒ Object
Structured Frame 1 description. Called by Sandbox#run when assembling stdin Frame 1 (SPEC.md B-02). Returns an unencoded preamble array — an Array of two-element [name, members] arrays, one per declared group.
102 103 104 |
# File 'lib/kobako/registry.rb', line 102 def to_preamble @groups.values.map(&:to_preamble) end |