kobako 0.14.0-aarch64-linux → 0.16.0-aarch64-linux
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.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +67 -0
- data/README.md +104 -29
- data/ROADMAP.md +2 -3
- data/SECURITY.md +1 -1
- data/crates/kobako-runtime/CHANGELOG.md +14 -0
- data/crates/kobako-runtime/README.md +1 -1
- data/crates/kobako-wasmtime/CHANGELOG.md +14 -0
- data/crates/kobako-wasmtime/README.md +1 -1
- data/data/kobako.wasm +0 -0
- data/lib/kobako/3.3/kobako.so +0 -0
- data/lib/kobako/3.4/kobako.so +0 -0
- data/lib/kobako/4.0/kobako.so +0 -0
- data/lib/kobako/catalog/extensions.rb +114 -0
- data/lib/kobako/catalog/handles.rb +1 -1
- data/lib/kobako/catalog/services.rb +135 -0
- data/lib/kobako/catalog/snippets.rb +1 -1
- data/lib/kobako/catalog.rb +7 -5
- data/lib/kobako/codec/decoder.rb +3 -3
- data/lib/kobako/codec/encoder.rb +4 -4
- data/lib/kobako/codec/ext_types.rb +169 -0
- data/lib/kobako/codec/state.rb +98 -0
- data/lib/kobako/codec/utils.rb +2 -2
- data/lib/kobako/codec.rb +23 -6
- data/lib/kobako/extension.rb +47 -0
- data/lib/kobako/fault.rb +1 -1
- data/lib/kobako/handle.rb +1 -1
- data/lib/kobako/outcome.rb +13 -7
- data/lib/kobako/pool.rb +1 -1
- data/lib/kobako/sandbox.rb +47 -27
- data/lib/kobako/transport/dispatcher.rb +25 -18
- data/lib/kobako/transport/request.rb +14 -9
- data/lib/kobako/transport/response.rb +9 -2
- data/lib/kobako/transport/yield.rb +4 -1
- data/lib/kobako/transport/yielder.rb +14 -6
- data/lib/kobako/version.rb +1 -1
- data/lib/kobako.rb +1 -0
- data/sig/kobako/catalog/extensions.rbs +25 -0
- data/sig/kobako/catalog/services.rbs +27 -0
- data/sig/kobako/codec/ext_types.rbs +31 -0
- data/sig/kobako/codec/state.rbs +20 -0
- data/sig/kobako/codec.rbs +3 -0
- data/sig/kobako/extension.rbs +20 -0
- data/sig/kobako/sandbox.rbs +3 -1
- data/sig/kobako/transport/dispatcher.rbs +4 -4
- data/sig/kobako/transport/yielder.rbs +1 -1
- data/sig/kobako/transport.rbs +2 -2
- metadata +12 -8
- data/lib/kobako/catalog/namespaces.rb +0 -115
- data/lib/kobako/codec/factory.rb +0 -187
- data/lib/kobako/namespace.rb +0 -78
- data/sig/kobako/catalog/namespaces.rbs +0 -17
- data/sig/kobako/codec/factory.rbs +0 -34
- data/sig/kobako/namespace.rbs +0 -21
data/lib/kobako/pool.rb
CHANGED
|
@@ -24,7 +24,7 @@ module Kobako
|
|
|
24
24
|
# seconds (+nil+ waits indefinitely); every other keyword is
|
|
25
25
|
# forwarded verbatim to +Kobako::Sandbox.new+. The optional block
|
|
26
26
|
# runs exactly once per constructed Sandbox — it is the setup window
|
|
27
|
-
# for +#
|
|
27
|
+
# for +#bind+ / +#preload+ before that Sandbox's first checkout.
|
|
28
28
|
# No Sandbox is constructed here. Raises +ArgumentError+ for an
|
|
29
29
|
# invalid +slots+ / +checkout_timeout+.
|
|
30
30
|
def initialize(slots:, checkout_timeout: DEFAULT_CHECKOUT_TIMEOUT_SECONDS, **sandbox_options, &setup)
|
data/lib/kobako/sandbox.rb
CHANGED
|
@@ -17,7 +17,7 @@ module Kobako
|
|
|
17
17
|
#
|
|
18
18
|
# The Sandbox owns the +Kobako::Runtime+, the per-Sandbox
|
|
19
19
|
# +Kobako::Catalog::Handles+, the per-instance
|
|
20
|
-
# +Kobako::Catalog::
|
|
20
|
+
# +Kobako::Catalog::Services+ (which receives the +Catalog::Handles+ by
|
|
21
21
|
# injection so guest→host dispatch and host→guest auto-wrap share one
|
|
22
22
|
# allocator), and the dispatch +Proc+ / +yield_to_guest+ lambda installed
|
|
23
23
|
# on the Runtime via +Runtime#on_dispatch=+. The underlying wasmtime Engine
|
|
@@ -48,29 +48,21 @@ module Kobako
|
|
|
48
48
|
# so use +#stdout_truncated?+ to observe overflow. Populated on every
|
|
49
49
|
# outcome — including a rescued +TrapError+, after which it holds the
|
|
50
50
|
# bytes written before the trap fired — mirroring +#usage+.
|
|
51
|
-
def stdout
|
|
52
|
-
@stdout_capture.bytes
|
|
53
|
-
end
|
|
51
|
+
def stdout = @stdout_capture.bytes
|
|
54
52
|
|
|
55
53
|
# Returns the bytes the guest wrote to stderr during the most recent
|
|
56
54
|
# invocation as a UTF-8 String, clipped at +stderr_limit+. Empty before
|
|
57
55
|
# any invocation. Mirror of +#stdout+.
|
|
58
|
-
def stderr
|
|
59
|
-
@stderr_capture.bytes
|
|
60
|
-
end
|
|
56
|
+
def stderr = @stderr_capture.bytes
|
|
61
57
|
|
|
62
58
|
# Returns +true+ iff stdout capture during the most recent invocation
|
|
63
59
|
# exceeded +stdout_limit+. Resets to +false+ at the start of the next
|
|
64
60
|
# invocation.
|
|
65
|
-
def stdout_truncated?
|
|
66
|
-
@stdout_capture.truncated?
|
|
67
|
-
end
|
|
61
|
+
def stdout_truncated? = @stdout_capture.truncated?
|
|
68
62
|
|
|
69
63
|
# Returns +true+ iff stderr capture during the most recent invocation
|
|
70
64
|
# exceeded +stderr_limit+. Mirror of +#stdout_truncated?+.
|
|
71
|
-
def stderr_truncated?
|
|
72
|
-
@stderr_capture.truncated?
|
|
73
|
-
end
|
|
65
|
+
def stderr_truncated? = @stderr_capture.truncated?
|
|
74
66
|
|
|
75
67
|
# Returns the +Kobako::Usage+ value object for the most recent
|
|
76
68
|
# invocation. Carries +wall_time+ (Float seconds the guest export call spent
|
|
@@ -100,21 +92,42 @@ module Kobako
|
|
|
100
92
|
@wasm_path = wasm_path || Kobako::Runtime.default_path
|
|
101
93
|
@options = SandboxOptions.new(**)
|
|
102
94
|
@handler = Catalog::Handles.new
|
|
103
|
-
@services = Kobako::Catalog::
|
|
95
|
+
@services = Kobako::Catalog::Services.new(handler: @handler)
|
|
104
96
|
@snippets = Catalog::Snippets.new
|
|
97
|
+
@extensions = Catalog::Extensions.new
|
|
105
98
|
@runtime = build_runtime!
|
|
106
99
|
install_dispatch_proc!
|
|
107
100
|
reset_invocation_state!
|
|
108
101
|
end
|
|
109
102
|
|
|
110
|
-
#
|
|
111
|
-
#
|
|
112
|
-
# +
|
|
103
|
+
# Bind +object+ as the Service reachable at +path+ — a Symbol or
|
|
104
|
+
# String of one or more +::+-separated constant-form segments
|
|
105
|
+
# (+"MyService::KV"+ or a top-level +"File"+). Returns +self+ for
|
|
106
|
+
# chaining.
|
|
107
|
+
#
|
|
108
|
+
# Raises +ArgumentError+ when a segment is malformed, when +path+
|
|
109
|
+
# collides with an existing binding (a name is a bound Service or a
|
|
110
|
+
# grouping prefix, never both), or when called after the first
|
|
111
|
+
# invocation has sealed Service registration.
|
|
112
|
+
def bind(path, object)
|
|
113
|
+
@services.bind(path, object)
|
|
114
|
+
self
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Install one or more Extensions — each a guest idiom (+source+) paired
|
|
118
|
+
# with an optional host +backend+, composed onto the Sandbox through
|
|
119
|
+
# +#preload+ and +#bind+. An Extension is any object exposing
|
|
120
|
+
# +name+ / +source+ / +backend+ / +depends_on+; +Kobako::Extension+ is
|
|
121
|
+
# the bundled value type. Returns +self+.
|
|
113
122
|
#
|
|
114
|
-
# Raises +ArgumentError+
|
|
115
|
-
#
|
|
116
|
-
|
|
117
|
-
|
|
123
|
+
# Raises +ArgumentError+ for a malformed Extension, a call after the
|
|
124
|
+
# first invocation seals registration, or — at that first invocation —
|
|
125
|
+
# an unmet +depends_on+.
|
|
126
|
+
def install(*extensions)
|
|
127
|
+
raise ArgumentError, "cannot install after first Sandbox invocation" if @services.sealed?
|
|
128
|
+
|
|
129
|
+
extensions.each { |extension| @extensions.install(extension, snippets: @snippets, services: @services) }
|
|
130
|
+
self
|
|
118
131
|
end
|
|
119
132
|
|
|
120
133
|
# Register a snippet on this Sandbox in one of two forms:
|
|
@@ -175,15 +188,15 @@ module Kobako
|
|
|
175
188
|
#
|
|
176
189
|
# Source delivery uses the WASI stdin three-frame protocol
|
|
177
190
|
# ({docs/wire-codec.md Invocation channels}[link:../../docs/wire-codec.md]):
|
|
178
|
-
# Frame 1 carries the msgpack-encoded preamble (
|
|
179
|
-
#
|
|
191
|
+
# Frame 1 carries the msgpack-encoded preamble (Service registry
|
|
192
|
+
# snapshot), Frame 2 carries the user source UTF-8 bytes, and
|
|
180
193
|
# Frame 3 carries the snippet table registered via +#preload+.
|
|
181
194
|
# Each frame is prefixed by a 4-byte big-endian u32 length; Frame 3 is
|
|
182
195
|
# mandatory-presence — an empty snippet table sends an empty msgpack
|
|
183
196
|
# array, never an absent frame.
|
|
184
197
|
#
|
|
185
198
|
# The first invocation seals the Service registry and snippet table;
|
|
186
|
-
# subsequent +#
|
|
199
|
+
# subsequent +#bind+ / +#preload+ calls raise +ArgumentError+.
|
|
187
200
|
#
|
|
188
201
|
# Raises +Kobako::TrapError+ on a Wasm trap or wire-violation fallback;
|
|
189
202
|
# +Kobako::SandboxError+ when the guest ran to completion but failed
|
|
@@ -237,14 +250,18 @@ module Kobako
|
|
|
237
250
|
end
|
|
238
251
|
end
|
|
239
252
|
|
|
240
|
-
# Per-invocation prologue. Seals the Service / snippet
|
|
241
|
-
# first call (idempotent
|
|
253
|
+
# Per-invocation prologue. Seals the Service / snippet / Extension
|
|
254
|
+
# registries on first call (idempotent — asserting Extension
|
|
255
|
+
# dependencies then), refreshes each callable Extension backend to this
|
|
256
|
+
# invocation's fresh object, and zeros the per-invocation capability
|
|
242
257
|
# state — capture buffers, truncation predicates, and the
|
|
243
258
|
# +Catalog::Handles+ counter — before the guest runs. The
|
|
244
259
|
# +Catalog::Handles+ itself is held as +@handler+ and never exposed
|
|
245
260
|
# beyond this class — it is not part of the Host App's surface.
|
|
246
261
|
def begin_invocation!
|
|
247
262
|
@services.seal!
|
|
263
|
+
@extensions.seal!
|
|
264
|
+
@extensions.refresh_backends!(@services)
|
|
248
265
|
@handler.reset!
|
|
249
266
|
reset_invocation_state!
|
|
250
267
|
end
|
|
@@ -318,7 +335,10 @@ module Kobako
|
|
|
318
335
|
# token; restore it to the host object the guest referenced before
|
|
319
336
|
# handing the value to the Host App. @handler still holds this
|
|
320
337
|
# invocation's table — reset only happens at the next #begin_invocation!.
|
|
321
|
-
|
|
338
|
+
# A Handle-free result resolves to itself, so the restoration walk is
|
|
339
|
+
# skipped when the decode carried none.
|
|
340
|
+
value, carried_handle = Codec.track_handles { Outcome.decode(return_bytes) }
|
|
341
|
+
carried_handle ? Codec::HandleWalk.deep_restore(value, @handler) : value
|
|
322
342
|
rescue Kobako::TrapError => e
|
|
323
343
|
raise trap_class_for(e), "Sandbox##{verb} failed: #{e.message}"
|
|
324
344
|
ensure
|
|
@@ -13,7 +13,7 @@ module Kobako
|
|
|
13
13
|
module Transport
|
|
14
14
|
# Pure-function dispatcher for guest-initiated transport calls.
|
|
15
15
|
# Decodes a msgpack-encoded Request envelope, resolves the target
|
|
16
|
-
# object through the Catalog::
|
|
16
|
+
# object through the Catalog::Services (path lookup) or
|
|
17
17
|
# Catalog::Handles (Handle lookup), invokes the method, and returns
|
|
18
18
|
# a msgpack-encoded Response envelope.
|
|
19
19
|
#
|
|
@@ -24,7 +24,7 @@ module Kobako
|
|
|
24
24
|
#
|
|
25
25
|
# Entry point:
|
|
26
26
|
#
|
|
27
|
-
# Kobako::Transport::Dispatcher.dispatch(request_bytes,
|
|
27
|
+
# Kobako::Transport::Dispatcher.dispatch(request_bytes, services, handler, yield_to_guest)
|
|
28
28
|
# # => msgpack-encoded Response bytes (never raises)
|
|
29
29
|
module Dispatcher
|
|
30
30
|
# Throw tag for the Yielder's break unwind back to the
|
|
@@ -67,7 +67,7 @@ module Kobako
|
|
|
67
67
|
|
|
68
68
|
# Dispatch a single transport request and return the encoded
|
|
69
69
|
# Response bytes. Invoked from the +Runtime#on_dispatch+ Proc that
|
|
70
|
-
# +Kobako::Sandbox#initialize+ installs on the ext side; +
|
|
70
|
+
# +Kobako::Sandbox#initialize+ installs on the ext side; +services+,
|
|
71
71
|
# +handler+, and +yield_to_guest+ are captured in that Proc's
|
|
72
72
|
# closure so the Dispatcher stays stateless and the registry doesn't
|
|
73
73
|
# need to publish accessors for the Sandbox-owned +Catalog::Handles+
|
|
@@ -77,24 +77,31 @@ module Kobako
|
|
|
77
77
|
# returns a binary String — every failure path is reified as a
|
|
78
78
|
# Response.error envelope so the guest sees a transport error rather
|
|
79
79
|
# than a wasm trap.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
#
|
|
81
|
+
# The decode runs inside +Codec.track_handles+ so #resolve_call_args
|
|
82
|
+
# can skip the argument walk when no Capability Handle crossed the
|
|
83
|
+
# wire.
|
|
84
|
+
def dispatch(request_bytes, services, handler, yield_to_guest)
|
|
85
|
+
request, carried_handle = Kobako::Codec.track_handles { Kobako::Transport::Request.decode(request_bytes) }
|
|
86
|
+
target = resolve_target(request.target, services, handler)
|
|
87
|
+
args, kwargs = resolve_call_args(request, handler, carried_handle)
|
|
84
88
|
yielder = Yielder.new(yield_to_guest, BREAK_THROW, handler) if request.block_given
|
|
85
|
-
|
|
86
|
-
encode_ok(value, handler)
|
|
89
|
+
encode_ok(catch(BREAK_THROW) { invoke(target, request.method_name, args, kwargs, yielder) }, handler)
|
|
87
90
|
rescue StandardError => e
|
|
88
91
|
encode_caught_error(e)
|
|
89
92
|
ensure
|
|
90
93
|
yielder&.invalidate!
|
|
91
94
|
end
|
|
92
95
|
|
|
93
|
-
# Resolve positional and keyword arguments off +request+ in one
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
|
|
96
|
+
# Resolve positional and keyword arguments off +request+ in one step.
|
|
97
|
+
# +carried_handle+ reports whether the decode carried any Capability
|
|
98
|
+
# Handle; when it did not, every argument resolves to itself, so the
|
|
99
|
+
# decoded values pass straight through and the walk is skipped entirely.
|
|
100
|
+
# Otherwise both go through #resolve_arg so Handles round-trip back to
|
|
101
|
+
# the host-side Ruby object before the call reaches +public_send+.
|
|
102
|
+
def resolve_call_args(request, handler, carried_handle)
|
|
103
|
+
return [request.args, request.kwargs] unless carried_handle
|
|
104
|
+
|
|
98
105
|
[request.args.map { |v| resolve_arg(v, handler) },
|
|
99
106
|
request.kwargs.transform_values { |v| resolve_arg(v, handler) }]
|
|
100
107
|
end
|
|
@@ -187,17 +194,17 @@ module Kobako
|
|
|
187
194
|
# Target type is already validated by +Transport::Request.decode+
|
|
188
195
|
# before this method is reached, so no else-branch is needed here —
|
|
189
196
|
# the wire layer is the system boundary that enforces the invariant.
|
|
190
|
-
def resolve_target(target,
|
|
197
|
+
def resolve_target(target, services, handler)
|
|
191
198
|
case target
|
|
192
199
|
when String
|
|
193
|
-
resolve_path(target,
|
|
200
|
+
resolve_path(target, services)
|
|
194
201
|
when Kobako::Handle
|
|
195
202
|
require_live_object!(target.id, handler)
|
|
196
203
|
end
|
|
197
204
|
end
|
|
198
205
|
|
|
199
|
-
def resolve_path(path,
|
|
200
|
-
|
|
206
|
+
def resolve_path(path, services)
|
|
207
|
+
services.lookup(path)
|
|
201
208
|
rescue KeyError => e
|
|
202
209
|
raise UndefinedTargetError, e.message
|
|
203
210
|
end
|
|
@@ -12,7 +12,7 @@ module Kobako
|
|
|
12
12
|
#
|
|
13
13
|
# 5-element msgpack array:
|
|
14
14
|
# +[target, method_name, args, kwargs, block_given]+. +target+ is
|
|
15
|
-
# either a +String+ (+"
|
|
15
|
+
# either a +String+ (+"MyService::KV"+, e.g. +"MyService::KV"+)
|
|
16
16
|
# or a Handle. SPEC pins +kwargs+ map keys to ext 0x00 Symbol;
|
|
17
17
|
# enforced at construction so the Value Object is the single source of
|
|
18
18
|
# truth. +block_given+ is a Boolean signalling whether the guest call
|
|
@@ -44,16 +44,21 @@ module Kobako
|
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
# Decode +bytes+ into a Request. Raises +Codec::InvalidType+ when the
|
|
47
|
-
# envelope is not the expected 5-element msgpack array,
|
|
48
|
-
#
|
|
47
|
+
# envelope is not the expected 5-element msgpack array, when any
|
|
48
|
+
# position carries an ext 0x02 Fault envelope (a Request is a payload
|
|
49
|
+
# position; the Response fault field is the envelope's only home), or
|
|
50
|
+
# when the Value Object's construction invariants reject the decoded
|
|
51
|
+
# fields.
|
|
49
52
|
def self.decode(bytes)
|
|
50
|
-
Codec
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
Codec.forbid_faults do
|
|
54
|
+
Codec::Decoder.decode(bytes) do |arr|
|
|
55
|
+
unless arr.is_a?(Array) && arr.length == 5
|
|
56
|
+
raise Codec::InvalidType, "Request envelope is malformed (expected a 5-element array)"
|
|
57
|
+
end
|
|
54
58
|
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
target, method_name, args, kwargs, block_given = arr
|
|
60
|
+
new(target: target, method_name: method_name, args: args, kwargs: kwargs, block_given: block_given)
|
|
61
|
+
end
|
|
57
62
|
end
|
|
58
63
|
end
|
|
59
64
|
|
|
@@ -53,9 +53,16 @@ module Kobako
|
|
|
53
53
|
def error? = status == STATUS_ERROR
|
|
54
54
|
|
|
55
55
|
# Encode this Response to msgpack bytes as the 2-element
|
|
56
|
-
# +[status, payload]+ array.
|
|
56
|
+
# +[status, payload]+ array. The ok variant's value is a payload
|
|
57
|
+
# position, so a +Kobako::Fault+ inside it has no wire
|
|
58
|
+
# representation and surfaces as +UnsupportedType+ — the
|
|
59
|
+
# Dispatcher's auto-wrap rescue turns it into a Capability Handle.
|
|
60
|
+
# The error variant carries the Fault envelope in its one legal
|
|
61
|
+
# position and encodes it plainly.
|
|
57
62
|
def encode
|
|
58
|
-
Codec::Encoder.encode([status, payload])
|
|
63
|
+
return Codec::Encoder.encode([status, payload]) if error?
|
|
64
|
+
|
|
65
|
+
Codec.forbid_faults { Codec::Encoder.encode([status, payload]) }
|
|
59
66
|
end
|
|
60
67
|
|
|
61
68
|
# Decode +bytes+ into a Response. Raises +Codec::InvalidType+ when the
|
|
@@ -70,7 +70,10 @@ module Kobako
|
|
|
70
70
|
body = bytes.byteslice(1, bytes.bytesize - 1) # : String
|
|
71
71
|
|
|
72
72
|
reject_dead_tag!(tag)
|
|
73
|
-
|
|
73
|
+
# A YieldResponse is a payload position: an ext 0x02 Fault in its
|
|
74
|
+
# value is a wire violation (the Response fault field is the
|
|
75
|
+
# envelope's only home).
|
|
76
|
+
new(tag: tag, value: Codec.forbid_faults { Codec::Decoder.decode(body) })
|
|
74
77
|
end
|
|
75
78
|
|
|
76
79
|
def self.reject_dead_tag!(tag)
|
|
@@ -52,8 +52,14 @@ module Kobako
|
|
|
52
52
|
def yield(*args)
|
|
53
53
|
raise LocalJumpError, "guest block invoked after host dispatch frame returned" unless @active
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
# Yield arguments are a payload position: a +Kobako::Fault+ among
|
|
56
|
+
# them has no wire representation, so the encode refuses it at
|
|
57
|
+
# this call site. The tracking bracket below opens only around the
|
|
58
|
+
# decode: the guest re-entry may run nested dispatches whose own
|
|
59
|
+
# brackets would otherwise pollute the signal.
|
|
60
|
+
bytes = @yield_to_guest.call(Kobako::Codec.forbid_faults { Kobako::Codec::Encoder.encode(args) })
|
|
61
|
+
response, carried_handle = Kobako::Codec.track_handles { Kobako::Transport::Yield.decode(bytes) }
|
|
62
|
+
return restore(response.value, carried_handle) if response.ok?
|
|
57
63
|
|
|
58
64
|
throw @break_tag, response.value if response.break?
|
|
59
65
|
|
|
@@ -78,10 +84,12 @@ module Kobako
|
|
|
78
84
|
# Restore any Capability Handle in a block's ok value to its host
|
|
79
85
|
# object via the injected +Catalog::Handles+. Only the
|
|
80
86
|
# ok path calls this — host code consumes the ok value, whereas a
|
|
81
|
-
# break value returns to the guest and stays a Handle.
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
def restore(value)
|
|
87
|
+
# break value returns to the guest and stays a Handle. A response
|
|
88
|
+
# whose decode carried no Handle resolves to itself, so the walk is
|
|
89
|
+
# skipped entirely.
|
|
90
|
+
def restore(value, carried_handle)
|
|
91
|
+
return value unless carried_handle
|
|
92
|
+
|
|
85
93
|
Kobako::Codec::HandleWalk.deep_restore(value, @handler)
|
|
86
94
|
end
|
|
87
95
|
|
data/lib/kobako/version.rb
CHANGED
data/lib/kobako.rb
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Kobako
|
|
2
|
+
module Catalog
|
|
3
|
+
class Extensions
|
|
4
|
+
def initialize: () -> void
|
|
5
|
+
|
|
6
|
+
def install: (untyped extension, snippets: Kobako::Catalog::Snippets, services: Kobako::Catalog::Services) -> self
|
|
7
|
+
|
|
8
|
+
def seal!: () -> self
|
|
9
|
+
|
|
10
|
+
def refresh_backends!: (Kobako::Catalog::Services services) -> self
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def refresh_backend: (untyped extension, Kobako::Catalog::Services services, Hash[untyped, untyped] resolved) -> void
|
|
15
|
+
|
|
16
|
+
def validate!: (untyped extension) -> void
|
|
17
|
+
|
|
18
|
+
def assert_dependencies!: () -> void
|
|
19
|
+
|
|
20
|
+
def callable?: (untyped provider) -> bool
|
|
21
|
+
|
|
22
|
+
def initial_object: (untyped provider) -> untyped
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Kobako
|
|
2
|
+
module Catalog
|
|
3
|
+
class Services
|
|
4
|
+
NAME_PATTERN: Regexp
|
|
5
|
+
|
|
6
|
+
def initialize: (?handler: Kobako::Catalog::Handles) -> void
|
|
7
|
+
|
|
8
|
+
def bind: (Symbol | String path, untyped object) -> self
|
|
9
|
+
|
|
10
|
+
def lookup: (Symbol | String target) -> untyped
|
|
11
|
+
|
|
12
|
+
def refresh: (Symbol | String path, untyped object) -> self
|
|
13
|
+
|
|
14
|
+
def encode: () -> String
|
|
15
|
+
|
|
16
|
+
def seal!: () -> self
|
|
17
|
+
|
|
18
|
+
def sealed?: () -> bool
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def validate_path!: (Symbol | String path) -> String
|
|
23
|
+
|
|
24
|
+
def collision?: (String path) -> bool
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Kobako
|
|
2
|
+
module Codec
|
|
3
|
+
module ExtTypes
|
|
4
|
+
EXT_SYMBOL: Integer
|
|
5
|
+
EXT_HANDLE: Integer
|
|
6
|
+
EXT_ERRENV: Integer
|
|
7
|
+
|
|
8
|
+
def self?.build_factory: () -> MessagePack::Factory
|
|
9
|
+
|
|
10
|
+
def self?.pack_symbol: (Symbol symbol) -> String
|
|
11
|
+
|
|
12
|
+
def self?.unpack_symbol: (String payload) -> Symbol
|
|
13
|
+
|
|
14
|
+
def self?.pack_handle: (Kobako::Handle handle) -> String
|
|
15
|
+
|
|
16
|
+
def self?.unpack_handle: (String payload, State state) -> Kobako::Handle
|
|
17
|
+
|
|
18
|
+
def self?.pack_fault: (Kobako::Fault fault, State state) -> String
|
|
19
|
+
|
|
20
|
+
def self?.unpack_fault: (String payload, State state) -> Kobako::Fault
|
|
21
|
+
|
|
22
|
+
def self?.register_symbol: (MessagePack::Factory factory) -> void
|
|
23
|
+
|
|
24
|
+
def self?.register_handle: (MessagePack::Factory factory) -> void
|
|
25
|
+
|
|
26
|
+
def self?.register_fault: (MessagePack::Factory factory) -> void
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
FACTORY: MessagePack::Factory
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Kobako
|
|
2
|
+
module Codec
|
|
3
|
+
class State
|
|
4
|
+
MAX_EXT_DEPTH: Integer
|
|
5
|
+
STATE_KEY: Symbol
|
|
6
|
+
|
|
7
|
+
def self.current: () -> State
|
|
8
|
+
|
|
9
|
+
def track_handles: [T] { () -> T } -> [T, bool]
|
|
10
|
+
def record_handle!: () -> void
|
|
11
|
+
def forbid_faults: [T] { () -> T } -> T
|
|
12
|
+
def faults_forbidden?: () -> bool
|
|
13
|
+
def within_ext_frame: [T] (singleton(Kobako::Codec::Error) over_limit) { () -> T } -> T
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def initialize: () -> void
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/sig/kobako/codec.rbs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
module Kobako
|
|
2
2
|
module Codec
|
|
3
|
+
def self.track_handles: [T] { () -> T } -> [T, bool]
|
|
4
|
+
def self.forbid_faults: [T] { () -> T } -> T
|
|
5
|
+
|
|
3
6
|
# The Handle allocator/resolver a wire walk works against: alloc
|
|
4
7
|
# registers a non-wire-representable object and returns its Handle,
|
|
5
8
|
# fetch resolves a wire Handle id back to the live object. The
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Kobako
|
|
2
|
+
class Extension < Data
|
|
3
|
+
attr_reader name: Symbol
|
|
4
|
+
attr_reader source: String
|
|
5
|
+
attr_reader backend: Kobako::Extension::Backend?
|
|
6
|
+
attr_reader depends_on: Array[Symbol]
|
|
7
|
+
|
|
8
|
+
def self.new: (name: Symbol, source: String, ?backend: Kobako::Extension::Backend?, ?depends_on: Array[Symbol]) -> Kobako::Extension
|
|
9
|
+
|
|
10
|
+
def initialize: (name: Symbol, source: String, ?backend: Kobako::Extension::Backend?, ?depends_on: Array[Symbol]) -> void
|
|
11
|
+
|
|
12
|
+
class Backend < Data
|
|
13
|
+
attr_reader path: String
|
|
14
|
+
attr_reader provider: untyped
|
|
15
|
+
|
|
16
|
+
def self.new: (path: String, provider: untyped) -> Kobako::Extension::Backend
|
|
17
|
+
| (String path, untyped provider) -> Kobako::Extension::Backend
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/sig/kobako/sandbox.rbs
CHANGED
|
@@ -29,7 +29,9 @@ module Kobako
|
|
|
29
29
|
|
|
30
30
|
attr_reader usage: Kobako::Usage
|
|
31
31
|
|
|
32
|
-
def
|
|
32
|
+
def bind: (Symbol | String path, untyped object) -> Kobako::Sandbox
|
|
33
|
+
|
|
34
|
+
def install: (*untyped extensions) -> Kobako::Sandbox
|
|
33
35
|
|
|
34
36
|
def preload: (code: String, name: Symbol | String) -> Kobako::Sandbox
|
|
35
37
|
| (binary: String) -> Kobako::Sandbox
|
|
@@ -12,9 +12,9 @@ module Kobako
|
|
|
12
12
|
|
|
13
13
|
CALLABLE_ALLOW: Array[Symbol]
|
|
14
14
|
|
|
15
|
-
def self?.dispatch: (String request_bytes, Kobako::Transport::
|
|
15
|
+
def self?.dispatch: (String request_bytes, Kobako::Transport::_ServiceRegistry services, Kobako::Codec::_HandleTable handler, Kobako::Transport::_GuestYielder yield_to_guest) -> String
|
|
16
16
|
|
|
17
|
-
def self?.resolve_call_args: (Kobako::Transport::Request request, Kobako::Codec::_HandleTable handler) -> [Array[untyped], Hash[Symbol, untyped]]
|
|
17
|
+
def self?.resolve_call_args: (Kobako::Transport::Request request, Kobako::Codec::_HandleTable handler, bool carried_handle) -> [Array[untyped], Hash[Symbol, untyped]]
|
|
18
18
|
|
|
19
19
|
def self?.encode_caught_error: (StandardError error) -> String
|
|
20
20
|
|
|
@@ -26,9 +26,9 @@ module Kobako
|
|
|
26
26
|
|
|
27
27
|
def self?.resolve_arg: (untyped value, Kobako::Codec::_HandleTable handler) -> untyped
|
|
28
28
|
|
|
29
|
-
def self?.resolve_target: (String | Kobako::Handle target, Kobako::Transport::
|
|
29
|
+
def self?.resolve_target: (String | Kobako::Handle target, Kobako::Transport::_ServiceRegistry services, Kobako::Codec::_HandleTable handler) -> untyped
|
|
30
30
|
|
|
31
|
-
def self?.resolve_path: (String path, Kobako::Transport::
|
|
31
|
+
def self?.resolve_path: (String path, Kobako::Transport::_ServiceRegistry services) -> untyped
|
|
32
32
|
|
|
33
33
|
def self?.require_live_object!: (Integer id, Kobako::Codec::_HandleTable handler) -> untyped
|
|
34
34
|
|
data/sig/kobako/transport.rbs
CHANGED
|
@@ -10,10 +10,10 @@ module Kobako
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
# The Service registry a dispatch resolves constant-path targets
|
|
13
|
-
# against. The Sandbox's Kobako::Catalog::
|
|
13
|
+
# against. The Sandbox's Kobako::Catalog::Services is the
|
|
14
14
|
# production conformer; modelled structurally so the Transport
|
|
15
15
|
# layer needs no upward dependency on Catalog.
|
|
16
|
-
interface
|
|
16
|
+
interface _ServiceRegistry
|
|
17
17
|
def lookup: (String target) -> untyped
|
|
18
18
|
end
|
|
19
19
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kobako
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.16.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Aotokitsuruya
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: msgpack
|
|
@@ -50,20 +50,22 @@ files:
|
|
|
50
50
|
- lib/kobako/4.0/kobako.so
|
|
51
51
|
- lib/kobako/capture.rb
|
|
52
52
|
- lib/kobako/catalog.rb
|
|
53
|
+
- lib/kobako/catalog/extensions.rb
|
|
53
54
|
- lib/kobako/catalog/handles.rb
|
|
54
|
-
- lib/kobako/catalog/
|
|
55
|
+
- lib/kobako/catalog/services.rb
|
|
55
56
|
- lib/kobako/catalog/snippets.rb
|
|
56
57
|
- lib/kobako/codec.rb
|
|
57
58
|
- lib/kobako/codec/decoder.rb
|
|
58
59
|
- lib/kobako/codec/encoder.rb
|
|
59
60
|
- lib/kobako/codec/error.rb
|
|
60
|
-
- lib/kobako/codec/
|
|
61
|
+
- lib/kobako/codec/ext_types.rb
|
|
61
62
|
- lib/kobako/codec/handle_walk.rb
|
|
63
|
+
- lib/kobako/codec/state.rb
|
|
62
64
|
- lib/kobako/codec/utils.rb
|
|
63
65
|
- lib/kobako/errors.rb
|
|
66
|
+
- lib/kobako/extension.rb
|
|
64
67
|
- lib/kobako/fault.rb
|
|
65
68
|
- lib/kobako/handle.rb
|
|
66
|
-
- lib/kobako/namespace.rb
|
|
67
69
|
- lib/kobako/outcome.rb
|
|
68
70
|
- lib/kobako/outcome/panic.rb
|
|
69
71
|
- lib/kobako/pool.rb
|
|
@@ -88,20 +90,22 @@ files:
|
|
|
88
90
|
- sig/kobako.rbs
|
|
89
91
|
- sig/kobako/capture.rbs
|
|
90
92
|
- sig/kobako/catalog.rbs
|
|
93
|
+
- sig/kobako/catalog/extensions.rbs
|
|
91
94
|
- sig/kobako/catalog/handles.rbs
|
|
92
|
-
- sig/kobako/catalog/
|
|
95
|
+
- sig/kobako/catalog/services.rbs
|
|
93
96
|
- sig/kobako/catalog/snippets.rbs
|
|
94
97
|
- sig/kobako/codec.rbs
|
|
95
98
|
- sig/kobako/codec/decoder.rbs
|
|
96
99
|
- sig/kobako/codec/encoder.rbs
|
|
97
100
|
- sig/kobako/codec/error.rbs
|
|
98
|
-
- sig/kobako/codec/
|
|
101
|
+
- sig/kobako/codec/ext_types.rbs
|
|
99
102
|
- sig/kobako/codec/handle_walk.rbs
|
|
103
|
+
- sig/kobako/codec/state.rbs
|
|
100
104
|
- sig/kobako/codec/utils.rbs
|
|
101
105
|
- sig/kobako/errors.rbs
|
|
106
|
+
- sig/kobako/extension.rbs
|
|
102
107
|
- sig/kobako/fault.rbs
|
|
103
108
|
- sig/kobako/handle.rbs
|
|
104
|
-
- sig/kobako/namespace.rbs
|
|
105
109
|
- sig/kobako/outcome.rbs
|
|
106
110
|
- sig/kobako/outcome/panic.rbs
|
|
107
111
|
- sig/kobako/pool.rbs
|