kobako 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +1 -1
  3. data/README.md +95 -60
  4. data/data/kobako.wasm +0 -0
  5. data/ext/kobako/Cargo.toml +1 -1
  6. data/ext/kobako/src/wasm/cache.rs +39 -1
  7. data/ext/kobako/src/wasm/dispatch.rs +20 -20
  8. data/ext/kobako/src/wasm/host_state.rs +261 -34
  9. data/ext/kobako/src/wasm/instance.rs +467 -272
  10. data/ext/kobako/src/wasm.rs +50 -19
  11. data/lib/kobako/capture.rb +46 -0
  12. data/lib/kobako/codec/decoder.rb +66 -0
  13. data/lib/kobako/codec/encoder.rb +37 -0
  14. data/lib/kobako/codec/error.rb +33 -0
  15. data/lib/kobako/codec/factory.rb +155 -0
  16. data/lib/kobako/codec/utils.rb +55 -0
  17. data/lib/kobako/codec.rb +27 -0
  18. data/lib/kobako/errors.rb +24 -1
  19. data/lib/kobako/outcome/panic.rb +42 -0
  20. data/lib/kobako/outcome.rb +133 -0
  21. data/lib/kobako/rpc/dispatcher.rb +169 -0
  22. data/lib/kobako/rpc/envelope.rb +118 -0
  23. data/lib/kobako/{wire/exception.rb → rpc/fault.rb} +6 -4
  24. data/lib/kobako/{wire → rpc}/handle.rb +4 -2
  25. data/lib/kobako/{registry → rpc}/handle_table.rb +9 -9
  26. data/lib/kobako/{registry/service_group.rb → rpc/namespace.rb} +20 -11
  27. data/lib/kobako/rpc/server.rb +156 -0
  28. data/lib/kobako/rpc.rb +11 -0
  29. data/lib/kobako/sandbox.rb +149 -69
  30. data/lib/kobako/version.rb +1 -1
  31. data/lib/kobako/wasm.rb +6 -16
  32. data/lib/kobako.rb +2 -0
  33. data/sig/kobako/capture.rbs +13 -0
  34. data/sig/kobako/codec/decoder.rbs +11 -0
  35. data/sig/kobako/codec/encoder.rbs +7 -0
  36. data/sig/kobako/codec/error.rbs +18 -0
  37. data/sig/kobako/codec/factory.rbs +31 -0
  38. data/sig/kobako/codec/utils.rbs +9 -0
  39. data/sig/kobako/errors.rbs +52 -0
  40. data/sig/kobako/outcome/panic.rbs +34 -0
  41. data/sig/kobako/outcome.rbs +24 -0
  42. data/sig/kobako/rpc/dispatcher.rbs +33 -0
  43. data/sig/kobako/rpc/envelope.rbs +51 -0
  44. data/sig/kobako/rpc/fault.rbs +20 -0
  45. data/sig/kobako/rpc/handle.rbs +19 -0
  46. data/sig/kobako/rpc/handle_table.rbs +25 -0
  47. data/sig/kobako/rpc/namespace.rbs +24 -0
  48. data/sig/kobako/rpc/server.rbs +37 -0
  49. data/sig/kobako/rpc.rbs +4 -0
  50. data/sig/kobako/sandbox.rbs +53 -0
  51. data/sig/kobako/wasm.rbs +37 -0
  52. data/sig/kobako.rbs +0 -1
  53. metadata +37 -17
  54. data/lib/kobako/registry/dispatcher.rb +0 -168
  55. data/lib/kobako/registry.rb +0 -160
  56. data/lib/kobako/sandbox/outcome_decoder.rb +0 -100
  57. data/lib/kobako/sandbox/output_buffer.rb +0 -79
  58. data/lib/kobako/wire/codec/decoder.rb +0 -87
  59. data/lib/kobako/wire/codec/encoder.rb +0 -41
  60. data/lib/kobako/wire/codec/error.rb +0 -35
  61. data/lib/kobako/wire/codec/factory.rb +0 -136
  62. data/lib/kobako/wire/codec.rb +0 -44
  63. data/lib/kobako/wire/envelope/payloads.rb +0 -145
  64. data/lib/kobako/wire/envelope.rb +0 -147
  65. data/lib/kobako/wire.rb +0 -40
@@ -0,0 +1,34 @@
1
+ module Kobako
2
+ module Outcome
3
+ class Panic
4
+ ORIGIN_SANDBOX: String
5
+ ORIGIN_SERVICE: String
6
+
7
+ attr_reader origin: String
8
+ attr_reader klass: String
9
+ attr_reader message: String
10
+ attr_reader backtrace: Array[String]
11
+ attr_reader details: untyped
12
+
13
+ def initialize: (
14
+ origin: String,
15
+ klass: String,
16
+ message: String,
17
+ ?backtrace: Array[String],
18
+ ?details: untyped
19
+ ) -> void
20
+
21
+ def with: (
22
+ ?origin: String,
23
+ ?klass: String,
24
+ ?message: String,
25
+ ?backtrace: Array[String],
26
+ ?details: untyped
27
+ ) -> Panic
28
+
29
+ def ==: (untyped other) -> bool
30
+
31
+ def hash: () -> Integer
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ module Kobako
2
+ module Outcome
3
+ TYPE_VALUE: Integer
4
+ TYPE_PANIC: Integer
5
+
6
+ def self?.decode: (String bytes) -> untyped
7
+
8
+ def self?.build_trap_error: (Integer? tag) -> TrapError
9
+
10
+ def self?.split_tag: (String bytes) -> [Integer?, String]
11
+
12
+ def self?.decode_value: (String body) -> untyped
13
+
14
+ def self?.decode_panic: (String body) -> void
15
+
16
+ def self?.parse_panic: (String body) -> Panic
17
+
18
+ def self?.build_panic_error: (Panic panic) -> (SandboxError | ServiceError)
19
+
20
+ def self?.panic_target_class: (Panic panic) -> (singleton(SandboxError) | singleton(ServiceError))
21
+
22
+ def self?.build_wire_violation_error: (String message) -> SandboxError
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ module Kobako
2
+ module RPC
3
+ module Dispatcher
4
+ class UndefinedTargetError < StandardError
5
+ end
6
+
7
+ class DisconnectedTargetError < StandardError
8
+ end
9
+
10
+ def self?.dispatch: (String request_bytes, Server server) -> String
11
+
12
+ def self?.encode_caught_error: (StandardError error) -> String
13
+
14
+ def self?.invoke: (untyped target, String method, Array[untyped] args, Hash[Symbol, untyped] kwargs) -> untyped
15
+
16
+ def self?.resolve_arg: (untyped value, HandleTable handle_table) -> untyped
17
+
18
+ def self?.resolve_target: (String | Kobako::RPC::Handle target, Server server, HandleTable handle_table) -> untyped
19
+
20
+ def self?.resolve_path: (String path, Server server) -> untyped
21
+
22
+ def self?.resolve_handle: (Kobako::RPC::Handle handle, HandleTable handle_table) -> untyped
23
+
24
+ def self?.require_live_object!: (Integer id, HandleTable handle_table) -> untyped
25
+
26
+ def self?.encode_ok: (untyped value, Server server) -> String
27
+
28
+ def self?.wrap_as_handle: (untyped value, Server server) -> Kobako::RPC::Handle
29
+
30
+ def self?.encode_error: (String type, String message) -> String
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,51 @@
1
+ module Kobako
2
+ module RPC
3
+ STATUS_OK: Integer
4
+ STATUS_ERROR: Integer
5
+
6
+ class Request
7
+ attr_reader target: String | Kobako::RPC::Handle
8
+ attr_reader method_name: String
9
+ attr_reader args: Array[untyped]
10
+ attr_reader kwargs: Hash[Symbol, untyped]
11
+
12
+ def initialize: (target: String | Kobako::RPC::Handle, method: String, ?args: Array[untyped], ?kwargs: Hash[Symbol, untyped]) -> void
13
+
14
+ def with: (?target: String | Kobako::RPC::Handle, ?method: String, ?args: Array[untyped], ?kwargs: Hash[Symbol, untyped]) -> Request
15
+
16
+ def ==: (untyped other) -> bool
17
+
18
+ def hash: () -> Integer
19
+ end
20
+
21
+ def self.encode_request: (Request request) -> String
22
+
23
+ def self.decode_request: (String bytes) -> Request
24
+
25
+ class Response
26
+ attr_reader status: Integer
27
+ attr_reader payload: untyped
28
+
29
+ def self.ok: (untyped value) -> Response
30
+
31
+ def self.error: (Kobako::RPC::Fault fault) -> Response
32
+
33
+ def initialize: (Integer status, untyped payload) -> void
34
+ | (status: Integer, payload: untyped) -> void
35
+
36
+ def with: (?status: Integer, ?payload: untyped) -> Response
37
+
38
+ def ok?: () -> bool
39
+
40
+ def error?: () -> bool
41
+
42
+ def ==: (untyped other) -> bool
43
+
44
+ def hash: () -> Integer
45
+ end
46
+
47
+ def self.encode_response: (Response response) -> String
48
+
49
+ def self.decode_response: (String bytes) -> Response
50
+ end
51
+ end
@@ -0,0 +1,20 @@
1
+ module Kobako
2
+ module RPC
3
+ class Fault
4
+ VALID_TYPES: Array[String]
5
+
6
+ attr_reader type: String
7
+ attr_reader message: String
8
+ attr_reader details: untyped
9
+
10
+ def initialize: (String type, String message, untyped details) -> void
11
+ | (type: String, message: String, ?details: untyped) -> void
12
+
13
+ def with: (?type: String, ?message: String, ?details: untyped) -> Fault
14
+
15
+ def ==: (untyped other) -> bool
16
+
17
+ def hash: () -> Integer
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module Kobako
2
+ module RPC
3
+ class Handle
4
+ MIN_ID: Integer
5
+ MAX_ID: Integer
6
+
7
+ attr_reader id: Integer
8
+
9
+ def initialize: (Integer id) -> void
10
+ | (id: Integer) -> void
11
+
12
+ def with: (?id: Integer) -> Handle
13
+
14
+ def ==: (untyped other) -> bool
15
+
16
+ def hash: () -> Integer
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ module Kobako
2
+ module RPC
3
+ class HandleTable
4
+ def initialize: (?next_id: Integer) -> void
5
+
6
+ def alloc: (untyped object) -> Integer
7
+
8
+ def fetch: (Integer id) -> untyped
9
+
10
+ def release: (Integer id) -> untyped
11
+
12
+ def reset!: () -> self
13
+
14
+ def mark_disconnected: (Integer id) -> self
15
+
16
+ def size: () -> Integer
17
+
18
+ def include?: (Integer id) -> bool
19
+
20
+ private
21
+
22
+ def require_bound!: (Integer id) -> void
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ module Kobako
2
+ module RPC
3
+ class Namespace
4
+ NAME_PATTERN: Regexp
5
+
6
+ attr_reader name: String
7
+ attr_reader members: Hash[String, untyped]
8
+
9
+ def initialize: (String name) -> void
10
+
11
+ def bind: (Symbol | String member, untyped object) -> self
12
+
13
+ def []: (Symbol | String member) -> untyped
14
+
15
+ def fetch: (Symbol | String member) -> untyped
16
+
17
+ def to_preamble: () -> [String, Array[String]]
18
+
19
+ private
20
+
21
+ def validate_member_name!: (Symbol | String member) -> String
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,37 @@
1
+ module Kobako
2
+ module RPC
3
+ class Server
4
+ attr_reader handle_table: HandleTable
5
+
6
+ def initialize: (?handle_table: HandleTable) -> void
7
+
8
+ def define: (Symbol | String name) -> Kobako::RPC::Namespace
9
+
10
+ def lookup: (String target) -> untyped
11
+
12
+ def bound?: (String target) -> bool
13
+
14
+ def namespaces: () -> Array[Kobako::RPC::Namespace]
15
+
16
+ def size: () -> Integer
17
+
18
+ def empty?: () -> bool
19
+
20
+ def to_preamble: () -> Array[[String, Array[String]]]
21
+
22
+ def encoded_preamble: () -> String
23
+
24
+ def seal!: () -> self
25
+
26
+ def sealed?: () -> bool
27
+
28
+ def reset_handles!: () -> HandleTable
29
+
30
+ def dispatch: (String request_bytes) -> String
31
+
32
+ private
33
+
34
+ def parse_target: (String target) -> [Kobako::RPC::Namespace?, String?, String?]
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,4 @@
1
+ module Kobako
2
+ module RPC
3
+ end
4
+ end
@@ -0,0 +1,53 @@
1
+ module Kobako
2
+ class Sandbox
3
+ DEFAULT_OUTPUT_LIMIT: Integer
4
+
5
+ DEFAULT_TIMEOUT_SECONDS: Float
6
+
7
+ DEFAULT_MEMORY_LIMIT: Integer
8
+
9
+ attr_reader wasm_path: String
10
+ attr_reader instance: Kobako::Wasm::Instance
11
+ attr_reader stdout_limit: Integer
12
+ attr_reader stderr_limit: Integer
13
+ attr_reader timeout: Float?
14
+ attr_reader memory_limit: Integer?
15
+ attr_reader services: Kobako::RPC::Server
16
+
17
+ def initialize: (
18
+ ?wasm_path: String?,
19
+ ?stdout_limit: Integer?,
20
+ ?stderr_limit: Integer?,
21
+ ?timeout: (Float | Integer)?,
22
+ ?memory_limit: Integer?
23
+ ) -> void
24
+
25
+ def stdout: () -> String
26
+
27
+ def stderr: () -> String
28
+
29
+ def stdout_truncated?: () -> bool
30
+
31
+ def stderr_truncated?: () -> bool
32
+
33
+ def define: (Symbol | String name) -> Kobako::RPC::Namespace
34
+
35
+ def run: (String source) -> untyped
36
+
37
+ private
38
+
39
+ def clear_captures!: () -> void
40
+
41
+ def normalize_timeout: ((Float | Integer)? timeout) -> Float?
42
+
43
+ def normalize_memory_limit: (Integer? memory_limit) -> Integer?
44
+
45
+ def reset_run_state!: () -> void
46
+
47
+ def read_captures!: () -> void
48
+
49
+ def run_guest: (String preamble, String source) -> void
50
+
51
+ def take_result!: () -> untyped
52
+ end
53
+ end
@@ -0,0 +1,37 @@
1
+ module Kobako
2
+ module Wasm
3
+ class Error < StandardError
4
+ end
5
+
6
+ class ModuleNotBuiltError < Error
7
+ end
8
+
9
+ def self.default_path: () -> String
10
+
11
+ class TimeoutError < Error
12
+ end
13
+
14
+ class MemoryLimitError < Error
15
+ end
16
+
17
+ class Instance
18
+ def self.from_path: (
19
+ String path,
20
+ (Float | Integer)? timeout_seconds,
21
+ Integer? memory_limit,
22
+ Integer? stdout_limit_bytes,
23
+ Integer? stderr_limit_bytes
24
+ ) -> Instance
25
+
26
+ def server=: (Kobako::RPC::Server server) -> void
27
+
28
+ def run: (String preamble, String source) -> void
29
+
30
+ def stdout: () -> [String, bool]
31
+
32
+ def stderr: () -> [String, bool]
33
+
34
+ def outcome!: () -> String
35
+ end
36
+ end
37
+ end
data/sig/kobako.rbs CHANGED
@@ -1,4 +1,3 @@
1
1
  module Kobako
2
2
  VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kobako
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aotokitsuruya
@@ -61,27 +61,47 @@ files:
61
61
  - ext/kobako/src/wasm/host_state.rs
62
62
  - ext/kobako/src/wasm/instance.rs
63
63
  - lib/kobako.rb
64
+ - lib/kobako/capture.rb
65
+ - lib/kobako/codec.rb
66
+ - lib/kobako/codec/decoder.rb
67
+ - lib/kobako/codec/encoder.rb
68
+ - lib/kobako/codec/error.rb
69
+ - lib/kobako/codec/factory.rb
70
+ - lib/kobako/codec/utils.rb
64
71
  - lib/kobako/errors.rb
65
- - lib/kobako/registry.rb
66
- - lib/kobako/registry/dispatcher.rb
67
- - lib/kobako/registry/handle_table.rb
68
- - lib/kobako/registry/service_group.rb
72
+ - lib/kobako/outcome.rb
73
+ - lib/kobako/outcome/panic.rb
74
+ - lib/kobako/rpc.rb
75
+ - lib/kobako/rpc/dispatcher.rb
76
+ - lib/kobako/rpc/envelope.rb
77
+ - lib/kobako/rpc/fault.rb
78
+ - lib/kobako/rpc/handle.rb
79
+ - lib/kobako/rpc/handle_table.rb
80
+ - lib/kobako/rpc/namespace.rb
81
+ - lib/kobako/rpc/server.rb
69
82
  - lib/kobako/sandbox.rb
70
- - lib/kobako/sandbox/outcome_decoder.rb
71
- - lib/kobako/sandbox/output_buffer.rb
72
83
  - lib/kobako/version.rb
73
84
  - lib/kobako/wasm.rb
74
- - lib/kobako/wire.rb
75
- - lib/kobako/wire/codec.rb
76
- - lib/kobako/wire/codec/decoder.rb
77
- - lib/kobako/wire/codec/encoder.rb
78
- - lib/kobako/wire/codec/error.rb
79
- - lib/kobako/wire/codec/factory.rb
80
- - lib/kobako/wire/envelope.rb
81
- - lib/kobako/wire/envelope/payloads.rb
82
- - lib/kobako/wire/exception.rb
83
- - lib/kobako/wire/handle.rb
84
85
  - sig/kobako.rbs
86
+ - sig/kobako/capture.rbs
87
+ - sig/kobako/codec/decoder.rbs
88
+ - sig/kobako/codec/encoder.rbs
89
+ - sig/kobako/codec/error.rbs
90
+ - sig/kobako/codec/factory.rbs
91
+ - sig/kobako/codec/utils.rbs
92
+ - sig/kobako/errors.rbs
93
+ - sig/kobako/outcome.rbs
94
+ - sig/kobako/outcome/panic.rbs
95
+ - sig/kobako/rpc.rbs
96
+ - sig/kobako/rpc/dispatcher.rbs
97
+ - sig/kobako/rpc/envelope.rbs
98
+ - sig/kobako/rpc/fault.rbs
99
+ - sig/kobako/rpc/handle.rbs
100
+ - sig/kobako/rpc/handle_table.rbs
101
+ - sig/kobako/rpc/namespace.rbs
102
+ - sig/kobako/rpc/server.rbs
103
+ - sig/kobako/sandbox.rbs
104
+ - sig/kobako/wasm.rbs
85
105
  homepage: https://github.com/elct9620/kobako
86
106
  licenses:
87
107
  - Apache-2.0
@@ -1,168 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kobako
4
- class Registry
5
- # Pure-function dispatcher for guest-initiated RPC calls. Decodes a
6
- # msgpack-encoded Request envelope, resolves the target object through the
7
- # Registry (path lookup or HandleTable lookup), invokes the method, and
8
- # returns a msgpack-encoded Response envelope.
9
- #
10
- # The module is stateless — all mutable state is threaded through the
11
- # +registry+ argument so Dispatcher has no instance variables and no side
12
- # effects beyond mutating the HandleTable via +alloc+ when a non-wire-
13
- # representable return value must be wrapped ({SPEC.md B-14}[link:../../../SPEC.md]).
14
- #
15
- # Entry point:
16
- #
17
- # Kobako::Registry::Dispatcher.dispatch(request_bytes, registry)
18
- # # => msgpack-encoded Response bytes (never raises)
19
- module Dispatcher
20
- module_function
21
-
22
- # Internal sentinel raised when target resolution fails. Mapped to
23
- # Response.err with type="undefined". Contained at the wire boundary —
24
- # not part of the public Kobako error taxonomy
25
- # ({SPEC.md E-xx}[link:../../../SPEC.md]).
26
- class UndefinedTargetError < StandardError; end
27
-
28
- # Internal sentinel raised when a Handle target resolves to the
29
- # +:disconnected+ sentinel in the HandleTable (ABA protection,
30
- # {SPEC.md E-14}[link:../../../SPEC.md]). Mapped to Response.err with
31
- # type="disconnected". Contained at the wire boundary.
32
- class DisconnectedTargetError < StandardError; end
33
-
34
- # Dispatch a single RPC request and return the encoded response bytes.
35
- # Called by +Kobako::Registry#dispatch+ which is invoked from the Rust
36
- # ext inside +__kobako_rpc_call+. +request_bytes+ is the msgpack-encoded
37
- # Request envelope. +registry+ is the live registry for this run, used
38
- # to resolve path-based targets via +#lookup+ and to access the
39
- # +#handle_table+ for Handle-based targets and return-value wrapping.
40
- # Always returns a binary String — never raises. Any failure during
41
- # decode, lookup, or method invocation is reified as a Response.err
42
- # envelope so the guest sees the failure as a normal RPC error rather
43
- # than a wasm trap
44
- # ({SPEC.md B-12}[link:../../../SPEC.md]).
45
- def dispatch(request_bytes, registry)
46
- value = perform_dispatch(request_bytes, registry)
47
- encode_ok_or_wrap(value, registry)
48
- rescue StandardError => e
49
- encode_dispatch_error(e)
50
- end
51
-
52
- # Map an error raised during dispatch to a Response.err envelope.
53
- # +error+ is the +StandardError+ caught at the dispatch boundary. Returns
54
- # a msgpack-encoded Response envelope (binary). Four error buckets
55
- # ({SPEC.md B-12}[link:../../../SPEC.md]): +Wire::Codec::Error+ →
56
- # type="runtime" (wire decode failed); +DisconnectedTargetError+ →
57
- # type="disconnected" (E-14); +UndefinedTargetError+ → type="undefined"
58
- # (E-13); +ArgumentError+ → type="argument" (B-12 arity mismatch);
59
- # everything else → type="runtime".
60
- def encode_dispatch_error(error)
61
- case error
62
- when Kobako::Wire::Codec::Error then encode_err("runtime", "wire decode failed: #{error.message}")
63
- when DisconnectedTargetError then encode_err("disconnected", error.message)
64
- when UndefinedTargetError then encode_err("undefined", error.message)
65
- when ArgumentError then encode_err("argument", error.message)
66
- else encode_err("runtime", "#{error.class}: #{error.message}")
67
- end
68
- end
69
-
70
- def perform_dispatch(request_bytes, registry)
71
- request = Kobako::Wire::Envelope.decode_request(request_bytes)
72
- handle_table = registry.handle_table
73
- target_object = resolve_target(request.target, registry, handle_table)
74
- args = request.args.map { |v| resolve_arg(v, handle_table) }
75
- kwargs = request.kwargs.transform_values { |v| resolve_arg(v, handle_table) }
76
- invoke(target_object, request.method_name, args, kwargs)
77
- end
78
-
79
- # Dispatch +method+ on +target+. +kwargs+ is already Symbol-keyed
80
- # (the +Envelope::Request+ invariant pins it). The empty-kwargs
81
- # branch omits the +**+ splat so Ruby 3.x's strict kwargs
82
- # separation does not reject calls to no-kwarg methods when the
83
- # wire carries the uniform empty-map shape.
84
- def invoke(target, method, args, kwargs)
85
- if kwargs.empty?
86
- target.public_send(method.to_sym, *args)
87
- else
88
- target.public_send(method.to_sym, *args, **kwargs)
89
- end
90
- end
91
-
92
- # {SPEC.md B-16}[link:../../../SPEC.md] — A Wire::Handle arriving as a positional or keyword
93
- # argument identifies a host-side object previously allocated by a prior
94
- # RPC's Handle wrap (B-14). Resolve it back to the Ruby object before
95
- # the dispatch reaches +public_send+. A Handle whose entry is the
96
- # +:disconnected+ sentinel (E-14) raises DisconnectedTargetError so
97
- # the dispatcher emits a Response.err with type="disconnected".
98
- def resolve_arg(value, handle_table)
99
- case value
100
- when Kobako::Wire::Handle
101
- fetch_live_object(value.id, handle_table)
102
- else
103
- value
104
- end
105
- end
106
-
107
- # Resolve a Request target to the Ruby object the Registry (or
108
- # HandleTable) holds. String targets go through the Registry;
109
- # Handle targets (ext 0x01) go through the HandleTable.
110
- #
111
- # Target type is already validated by +Wire::Envelope.decode_request+
112
- # before this method is reached, so no else-branch is needed here —
113
- # the wire layer is the system boundary that enforces the invariant.
114
- def resolve_target(target, registry, handle_table)
115
- case target
116
- when String
117
- resolve_path(target, registry)
118
- when Kobako::Wire::Handle
119
- resolve_handle(target, handle_table)
120
- end
121
- end
122
-
123
- def resolve_path(path, registry)
124
- registry.lookup(path)
125
- rescue KeyError => e
126
- raise UndefinedTargetError, e.message
127
- end
128
-
129
- def resolve_handle(handle, handle_table)
130
- fetch_live_object(handle.id, handle_table)
131
- end
132
-
133
- # Resolve +id+ through the HandleTable, distinguishing the
134
- # +:disconnected+ sentinel (E-14) from an unknown id (E-13).
135
- def fetch_live_object(id, handle_table)
136
- object = handle_table.fetch(id)
137
- raise DisconnectedTargetError, "Handle id #{id} is disconnected" if object == :disconnected
138
-
139
- object
140
- rescue Kobako::HandleTableError => e
141
- raise UndefinedTargetError, e.message
142
- end
143
-
144
- # Encode +value+ as a +Response.ok+ envelope. When the value is not
145
- # wire-representable per {SPEC.md B-13}[link:../../../SPEC.md]'s type
146
- # mapping, the +UnsupportedType+ rescue routes it through the
147
- # HandleTable and re-encodes with the Capability Handle in place
148
- # ({SPEC.md B-14}[link:../../../SPEC.md]). The happy path encodes
149
- # exactly once.
150
- def encode_ok_or_wrap(value, registry)
151
- encode_ok(value)
152
- rescue Kobako::Wire::Codec::UnsupportedType
153
- encode_ok(Kobako::Wire::Handle.new(registry.handle_table.alloc(value)))
154
- end
155
-
156
- def encode_ok(value)
157
- response = Kobako::Wire::Envelope::Response.ok(value)
158
- Kobako::Wire::Envelope.encode_response(response)
159
- end
160
-
161
- def encode_err(type, message)
162
- exception = Kobako::Wire::Exception.new(type: type, message: message)
163
- response = Kobako::Wire::Envelope::Response.err(exception)
164
- Kobako::Wire::Envelope.encode_response(response)
165
- end
166
- end
167
- end
168
- end