Class: Kobako::RPC::Server
- Inherits:
-
Object
- Object
- Kobako::RPC::Server
- Defined in:
- lib/kobako/rpc/server.rb
Overview
Kobako::RPC::Server — per-Sandbox host-side RPC coordinator. Maintains the Namespace / Member registry, owns the HandleTable, and routes incoming Requests to the resolved Service object (docs/behavior.md B-07..B-21).
Public API:
server = Kobako::RPC::Server.new
namespace = server.define(:MyService) # => Kobako::RPC::Namespace
namespace.bind(:KV, kv_object) # => namespace (chainable)
server.to_preamble # => array for Frame 1
server.dispatch(request_bytes) # => msgpack bytes (delegated to Dispatcher)
Namespaces live at Kobako::RPC::Namespace (lib/kobako/rpc/namespace.rb). The opaque Handle allocator lives at Kobako::RPC::HandleTable (lib/kobako/rpc/handle_table.rb). Dispatch helpers live at Kobako::RPC::Dispatcher (lib/kobako/rpc/dispatcher.rb).
Instance Attribute Summary collapse
-
#handle_table ⇒ Object
readonly
Expose the
HandleTablefor tests and wire-layer Handle wrapping.
Instance Method Summary collapse
-
#bound?(target) ⇒ Boolean
Returns
truewhentarget(a “Namespace::Member” path) resolves to a bound member,falseotherwise. -
#define(name) ⇒ Object
Declare or retrieve the Namespace named
name(idempotent — docs/behavior.md B-10). -
#dispatch(request_bytes) ⇒ Object
Dispatch a single RPC request and return the encoded response bytes (docs/behavior.md B-12).
-
#empty? ⇒ Boolean
Returns
truewhen no namespaces have been declared,falseotherwise. -
#encoded_preamble ⇒ Object
Encode the preamble as msgpack bytes for stdin Frame 1 delivery (docs/behavior.md B-02).
-
#initialize(handle_table: HandleTable.new) ⇒ Server
constructor
Build a fresh Server.
-
#lookup(target) ⇒ Object
Resolve a
targetpath of the form “Namespace::Member” to the bound Host object. -
#namespaces ⇒ Object
Returns all declared
Kobako::RPC::Namespaceinstances as anArray. -
#reset_handles! ⇒ Object
Reset the HandleTable for a new invocation boundary.
-
#seal! ⇒ Object
Mark the Server as sealed.
-
#sealed? ⇒ Boolean
Returns
truewhen #seal! has been called,falseotherwise. -
#size ⇒ Object
Returns the number of declared namespaces as an
Integer. -
#to_preamble ⇒ Object
Structured Frame 1 description.
Constructor Details
#initialize(handle_table: HandleTable.new) ⇒ Server
Build a fresh Server. 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.
36 37 38 39 40 |
# File 'lib/kobako/rpc/server.rb', line 36 def initialize(handle_table: HandleTable.new) @namespaces = {} # : Hash[String, Kobako::RPC::Namespace] @handle_table = handle_table @sealed = false end |
Instance Attribute Details
#handle_table ⇒ Object (readonly)
Expose the HandleTable for tests and wire-layer Handle wrapping.
144 145 146 |
# File 'lib/kobako/rpc/server.rb', line 144 def handle_table @handle_table end |
Instance Method Details
#bound?(target) ⇒ Boolean
Returns true when target (a “Namespace::Member” path) resolves to a bound member, false otherwise.
74 75 76 77 |
# File 'lib/kobako/rpc/server.rb', line 74 def bound?(target) namespace, member_name, = parse_target(target) !namespace.nil? && !member_name.nil? && !namespace[member_name].nil? end |
#define(name) ⇒ Object
Declare or retrieve the Namespace named name (idempotent — docs/behavior.md B-10). name is a constant-form name as a Symbol or String (must satisfy Namespace::NAME_PATTERN). Returns the Kobako::RPC::Namespace 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 its first invocation (docs/behavior.md B-07).
48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/kobako/rpc/server.rb', line 48 def define(name) raise ArgumentError, "cannot define after first Sandbox invocation" if @sealed name_str = name.to_s unless Namespace::NAME_PATTERN.match?(name_str) raise ArgumentError, "Namespace name must match #{Namespace::NAME_PATTERN.inspect} (got #{name.inspect})" end @namespaces[name_str] ||= Namespace.new(name_str) end |
#dispatch(request_bytes) ⇒ Object
Dispatch a single RPC request and return the encoded response bytes (docs/behavior.md B-12). request_bytes is a msgpack-encoded Request envelope. Called by the Rust ext from inside __kobako_dispatch. Always returns a binary String — never raises. Delegates to Dispatcher.dispatch which reifies any failure as a Response.error envelope so the guest sees the failure as a normal RPC error rather than a wasm trap.
139 140 141 |
# File 'lib/kobako/rpc/server.rb', line 139 def dispatch(request_bytes) Dispatcher.dispatch(request_bytes, self) end |
#empty? ⇒ Boolean
Returns true when no namespaces have been declared, false otherwise.
90 91 92 |
# File 'lib/kobako/rpc/server.rb', line 90 def empty? @namespaces.empty? end |
#encoded_preamble ⇒ Object
Encode the preamble as msgpack bytes for stdin Frame 1 delivery (docs/behavior.md B-02). Uses plain MessagePack (no kobako ext types) because the preamble contains only strings — no Handles or Fault envelopes. Structure: [[“Namespace”, [“MemberA”, “MemberB”]], …]. Returns a binary String of msgpack bytes.
109 110 111 |
# File 'lib/kobako/rpc/server.rb', line 109 def encoded_preamble MessagePack.pack(to_preamble) end |
#lookup(target) ⇒ Object
Resolve a target path of the form “Namespace::Member” to the bound Host object. target is a two-level path using the :: separator. Returns the bound Host object. Raises KeyError when the namespace or the member is not bound.
64 65 66 67 68 69 70 |
# File 'lib/kobako/rpc/server.rb', line 64 def lookup(target) namespace, member_name, namespace_name = parse_target(target) raise KeyError, "no namespace named #{namespace_name.inspect}" if namespace.nil? raise KeyError, "no member #{target.inspect} bound on server" unless member_name namespace.fetch(member_name) end |
#namespaces ⇒ Object
Returns all declared Kobako::RPC::Namespace instances as an Array.
80 81 82 |
# File 'lib/kobako/rpc/server.rb', line 80 def namespaces @namespaces.values end |
#reset_handles! ⇒ Object
Reset the HandleTable for a new invocation boundary. Called by Sandbox before each invocation (docs/behavior.md B-19).
128 129 130 |
# File 'lib/kobako/rpc/server.rb', line 128 def reset_handles! @handle_table.reset! end |
#seal! ⇒ Object
Mark the Server as sealed. Called by Sandbox on the first invocation. After sealing, #define raises ArgumentError. Idempotent.
115 116 117 118 |
# File 'lib/kobako/rpc/server.rb', line 115 def seal! @sealed = true self end |
#sealed? ⇒ Boolean
Returns true when #seal! has been called, false otherwise.
121 122 123 |
# File 'lib/kobako/rpc/server.rb', line 121 def sealed? @sealed end |
#size ⇒ Object
Returns the number of declared namespaces as an Integer.
85 86 87 |
# File 'lib/kobako/rpc/server.rb', line 85 def size @namespaces.size end |
#to_preamble ⇒ Object
Structured Frame 1 description. Called by Sandbox#eval when assembling stdin Frame 1 (docs/behavior.md B-02). Returns an unencoded preamble array — an Array of two-element [name, members] arrays, one per declared namespace.
99 100 101 |
# File 'lib/kobako/rpc/server.rb', line 99 def to_preamble @namespaces.values.map(&:to_preamble) end |