Module: Kobako::Outcome
- Defined in:
- lib/kobako/outcome.rb,
lib/kobako/outcome/panic.rb
Overview
Host-facing boundary for the OUTCOME_BUFFER produced by __kobako_run. Takes raw outcome bytes — a one-byte tag followed by the msgpack-encoded body — and maps them to either the unwrapped mruby return value or a raised three-layer (SPEC.md “Error Scenarios”) exception.
Self-contained: this module owns the wire framing (tag bytes, body decoding), and the Panic wire record lives at Kobako::Outcome::Panic. The byte-level msgpack codec at Kobako::Codec is invoked for the body itself; otherwise nothing in RPC participates.
* tag 0x01, decode OK → return decoded value
* tag 0x01, decode fails → SandboxError (E-09)
* tag 0x02, origin="service" → ServiceError (E-13)
* tag 0x02, origin="sandbox"/missing → SandboxError (E-04..E-07)
* tag 0x02, decode fails → SandboxError (E-08)
* unknown tag → TrapError (E-03)
Defined Under Namespace
Classes: Panic
Constant Summary collapse
- TYPE_VALUE =
First byte of the OUTCOME_BUFFER for the success branch — body is the bare msgpack encoding of the returned value (SPEC.md Outcome Envelope).
0x01- TYPE_PANIC =
First byte of the OUTCOME_BUFFER for the failure branch — body is the msgpack Panic map.
0x02
Class Method Summary collapse
-
.build_panic_error(panic) ⇒ Object
Map a decoded Panic record into the corresponding three-layer Ruby exception.
-
.build_trap_error(tag) ⇒ Object
TrapError for unknown or absent tag (SPEC.md ABI Signatures: len=0 and unknown-tag both walk the trap path).
- .build_wire_violation_error(message) ⇒ Object
- .decode(bytes) ⇒ Object
-
.decode_panic(body) ⇒ Object
Decode failure on the panic tag is a SandboxError (E-08).
-
.decode_value(body) ⇒ Object
Decode failure on the success tag is a SandboxError (E-09): the framing was fine, but the carried value is unrepresentable.
-
.panic_target_class(panic) ⇒ Object
SPEC “Error Classes”: when origin=“service” and the panic
classfield namesServiceError::Disconnected, surface that subclass so callers can rescue the disconnected path specifically (E-14). -
.parse_panic(body) ⇒ Object
Build a
Panicvalue object from the msgpack-decoded body. - .split_tag(bytes) ⇒ Object
Class Method Details
.build_panic_error(panic) ⇒ Object
Map a decoded Panic record into the corresponding three-layer Ruby exception. origin == “service” → ServiceError (with the ::Disconnected subclass selected when the panic carries the disconnected sentinel —SPEC “Error Classes”); everything else → SandboxError.
105 106 107 108 109 110 111 112 113 |
# File 'lib/kobako/outcome.rb', line 105 def build_panic_error(panic) panic_target_class(panic).new( panic., origin: panic.origin, klass: panic.klass, backtrace_lines: panic.backtrace, details: panic.details ) end |
.build_trap_error(tag) ⇒ Object
TrapError for unknown or absent tag (SPEC.md ABI Signatures: len=0 and unknown-tag both walk the trap path).
50 51 52 53 54 |
# File 'lib/kobako/outcome.rb', line 50 def build_trap_error(tag) return TrapError.new("guest exited without writing an outcome (len=0)") if tag.nil? TrapError.new(format("unknown outcome tag 0x%<tag>02x", tag: tag)) end |
.build_wire_violation_error(message) ⇒ Object
125 126 127 128 129 130 131 |
# File 'lib/kobako/outcome.rb', line 125 def build_wire_violation_error() SandboxError.new( , origin: Panic::ORIGIN_SANDBOX, klass: "Kobako::RPC::WireError" ) end |
.decode(bytes) ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/kobako/outcome.rb', line 35 def decode(bytes) tag, body = split_tag(bytes) case tag when TYPE_VALUE decode_value(body) when TYPE_PANIC decode_panic(body) else raise build_trap_error(tag) end end |
.decode_panic(body) ⇒ Object
Decode failure on the panic tag is a SandboxError (E-08). Either path raises — on success the decoded Panic is mapped to its three- layer exception via build_panic_error and raised; on wire-decode failure the rescue path raises the wire-violation SandboxError.
77 78 79 80 81 |
# File 'lib/kobako/outcome.rb', line 77 def decode_panic(body) raise build_panic_error(parse_panic(body)) rescue Kobako::Codec::Error => e raise build_wire_violation_error("panic envelope decode failed: #{e.}") end |
.decode_value(body) ⇒ Object
Decode failure on the success tag is a SandboxError (E-09): the framing was fine, but the carried value is unrepresentable.
67 68 69 70 71 |
# File 'lib/kobako/outcome.rb', line 67 def decode_value(body) Kobako::Codec::Decoder.decode(body) rescue Kobako::Codec::Error => e raise build_wire_violation_error("result envelope decode failed: #{e.}") end |
.panic_target_class(panic) ⇒ Object
SPEC “Error Classes”: when origin=“service” and the panic class field names ServiceError::Disconnected, surface that subclass so callers can rescue the disconnected path specifically (E-14).
119 120 121 122 123 |
# File 'lib/kobako/outcome.rb', line 119 def panic_target_class(panic) return SandboxError unless panic.origin == Panic::ORIGIN_SERVICE panic.klass == "Kobako::ServiceError::Disconnected" ? ServiceError::Disconnected : ServiceError end |
.parse_panic(body) ⇒ Object
Build a Panic value object from the msgpack-decoded body. Raises Kobako::Codec::InvalidType when the body is not a map or when required keys are missing — both routed by decode_panic to build_wire_violation_error.
87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/kobako/outcome.rb', line 87 def parse_panic(body) map = Kobako::Codec::Decoder.decode(body) raise Kobako::Codec::InvalidType, "Panic envelope must be a map, got #{map.class}" unless map.is_a?(Hash) Kobako::Codec::Utils.wire_boundary do Panic.new( origin: map["origin"], klass: map["class"], message: map["message"], backtrace: map["backtrace"] || [], details: map["details"] ) end end |
.split_tag(bytes) ⇒ Object
56 57 58 59 60 61 62 63 |
# File 'lib/kobako/outcome.rb', line 56 def split_tag(bytes) bytes = bytes.b return [nil, "".b] if bytes.empty? tag = bytes.getbyte(0) # : Integer body = bytes.byteslice(1, bytes.bytesize - 1) # : String [tag, body] end |