kobako 0.13.0 → 0.15.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.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +81 -0
- data/Cargo.lock +3 -3
- data/README.md +107 -32
- data/ROADMAP.md +25 -0
- data/SECURITY.md +1 -1
- data/crates/kobako-runtime/CHANGELOG.md +14 -0
- data/crates/kobako-runtime/Cargo.toml +1 -1
- data/crates/kobako-runtime/README.md +1 -1
- data/crates/kobako-runtime/src/error.rs +8 -0
- data/crates/kobako-runtime/src/snapshot.rs +7 -3
- data/crates/kobako-wasmtime/CHANGELOG.md +14 -0
- data/crates/kobako-wasmtime/Cargo.toml +2 -2
- data/crates/kobako-wasmtime/README.md +1 -1
- data/crates/kobako-wasmtime/src/capture.rs +17 -13
- data/crates/kobako-wasmtime/src/driver.rs +7 -8
- data/crates/kobako-wasmtime/src/frames.rs +3 -10
- data/crates/kobako-wasmtime/src/guest_mem.rs +8 -1
- data/crates/kobako-wasmtime/src/instance_pre.rs +7 -6
- data/crates/kobako-wasmtime/src/invocation.rs +4 -5
- data/crates/kobako-wasmtime/src/trap.rs +65 -71
- data/data/kobako.wasm +0 -0
- data/ext/kobako/Cargo.toml +1 -1
- data/ext/kobako/src/runtime/errors.rs +9 -39
- data/ext/kobako/src/runtime.rs +5 -20
- data/lib/kobako/catalog/handles.rb +3 -3
- data/lib/kobako/catalog/services.rb +123 -0
- data/lib/kobako/catalog/snippets.rb +2 -2
- data/lib/kobako/catalog.rb +2 -2
- data/lib/kobako/codec/decoder.rb +10 -10
- data/lib/kobako/codec/encoder.rb +5 -5
- data/lib/kobako/codec/error.rb +3 -3
- data/lib/kobako/codec/ext_types.rb +169 -0
- data/lib/kobako/codec/handle_walk.rb +17 -21
- data/lib/kobako/codec/state.rb +98 -0
- data/lib/kobako/codec/utils.rb +9 -9
- data/lib/kobako/codec.rb +23 -6
- data/lib/kobako/errors.rb +14 -39
- data/lib/kobako/fault.rb +1 -1
- data/lib/kobako/handle.rb +6 -3
- data/lib/kobako/outcome.rb +14 -7
- data/lib/kobako/pool.rb +1 -1
- data/lib/kobako/sandbox.rb +30 -25
- data/lib/kobako/transport/dispatcher.rb +41 -31
- data/lib/kobako/transport/request.rb +16 -11
- data/lib/kobako/transport/response.rb +11 -4
- data/lib/kobako/transport/run.rb +1 -1
- data/lib/kobako/transport/yield.rb +7 -4
- data/lib/kobako/transport/yielder.rb +20 -12
- data/lib/kobako/version.rb +1 -1
- data/release-please-config.json +37 -7
- data/sig/kobako/catalog/services.rbs +25 -0
- data/sig/kobako/codec/ext_types.rbs +31 -0
- data/sig/kobako/codec/handle_walk.rbs +2 -2
- data/sig/kobako/codec/state.rbs +20 -0
- data/sig/kobako/codec.rbs +14 -0
- data/sig/kobako/handle.rbs +0 -2
- data/sig/kobako/sandbox.rbs +1 -1
- data/sig/kobako/transport/dispatcher.rbs +8 -8
- data/sig/kobako/transport/run.rbs +1 -1
- data/sig/kobako/transport/yielder.rbs +3 -3
- data/sig/kobako/transport.rbs +8 -0
- metadata +8 -7
- 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/transport/run.rb
CHANGED
|
@@ -51,7 +51,7 @@ module Kobako
|
|
|
51
51
|
# Encode this Run to the msgpack bytes the guest's +__kobako_run+
|
|
52
52
|
# entry point consumes as its command-buffer payload
|
|
53
53
|
# ({docs/wire-codec.md Invocation channels}[link:../../../docs/wire-codec.md]).
|
|
54
|
-
# Walks +args+ / +kwargs+ through
|
|
54
|
+
# Walks +args+ / +kwargs+ through Codec::HandleWalk.deep_wrap so
|
|
55
55
|
# any non-wire-representable leaf is allocated into +handler+ and
|
|
56
56
|
# replaced with a +Kobako::Handle+; the
|
|
57
57
|
# +handler+ argument is the Sandbox's table, sharing the same
|
|
@@ -10,9 +10,9 @@ module Kobako
|
|
|
10
10
|
# First byte of the YieldResponse for the success branch — body is
|
|
11
11
|
# the block's return value encoded as a single msgpack value.
|
|
12
12
|
TAG_OK = 0x01
|
|
13
|
-
# First byte for
|
|
13
|
+
# First byte for +break val+ — body is the break value.
|
|
14
14
|
TAG_BREAK = 0x02
|
|
15
|
-
# Reserved for future
|
|
15
|
+
# Reserved for future +return val+ support; both sides reject this
|
|
16
16
|
# tag as a wire violation (YieldResponse envelope contract).
|
|
17
17
|
TAG_RESERVED = 0x03
|
|
18
18
|
# First byte for an error / fault outcome — body is a
|
|
@@ -58,7 +58,7 @@ module Kobako
|
|
|
58
58
|
[tag].pack("C") + Codec::Encoder.encode(value)
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
# Decode +bytes+ into a
|
|
61
|
+
# Decode +bytes+ into a Yield. Rejects empty input, the reserved
|
|
62
62
|
# tag 0x03, and any tag outside +LIVE_TAGS+ by raising
|
|
63
63
|
# +Kobako::Codec::InvalidType+ — these are wire violations per the
|
|
64
64
|
# SPEC's YieldResponse envelope contract.
|
|
@@ -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)
|
|
@@ -13,7 +13,7 @@ module Kobako
|
|
|
13
13
|
# Each guest call that carries +block_given: true+ gets a Yielder
|
|
14
14
|
# that the Dispatcher hands to the Service method as +&block+. The
|
|
15
15
|
# Service method observes it as an ordinary Ruby Proc through
|
|
16
|
-
#
|
|
16
|
+
# #to_proc; +yield val+ / +block.call(val)+ invokes #yield, which
|
|
17
17
|
# serialises the positional args, re-enters the guest via the injected
|
|
18
18
|
# +yield_to_guest+ lambda, and reifies the +YieldResponse+ into Ruby
|
|
19
19
|
# control flow:
|
|
@@ -24,13 +24,13 @@ module Kobako
|
|
|
24
24
|
# * +tag 0x04+ error — raise the +{class, message}+ payload at the
|
|
25
25
|
# Service's yield site
|
|
26
26
|
#
|
|
27
|
-
# The Dispatcher calls
|
|
27
|
+
# The Dispatcher calls #invalidate! from its +ensure+ block once
|
|
28
28
|
# dispatch completes; any later call to a stashed Yielder then raises
|
|
29
29
|
# +LocalJumpError+ — the observable shape of an escaped Yielder.
|
|
30
30
|
class Yielder
|
|
31
31
|
# +yield_to_guest+ is a +String → String+ callable (the ext's
|
|
32
32
|
# per-dispatch +Kobako::Runtime::GuestYielder+) that
|
|
33
|
-
#
|
|
33
|
+
# #yield invokes to re-enter the guest; +break_tag+ is the +catch+
|
|
34
34
|
# throw tag the Dispatcher matches against to unwind the Service on
|
|
35
35
|
# +tag 0x02+. +handler+ is the Sandbox's +Kobako::Catalog::Handles+,
|
|
36
36
|
# used to restore a Capability Handle in the block's ok value back to
|
|
@@ -44,7 +44,7 @@ module Kobako
|
|
|
44
44
|
|
|
45
45
|
# Re-enter the guest with +args+ and reify the YieldResponse into
|
|
46
46
|
# Ruby control flow. Raises +LocalJumpError+ if called after
|
|
47
|
-
#
|
|
47
|
+
# #invalidate!. The ok value is consumed by the host Service
|
|
48
48
|
# method, so a Capability Handle in it is restored to its host object.
|
|
49
49
|
# The break value unwinds past the Service back to the guest
|
|
50
50
|
# Member call, so it passes through verbatim — a Handle stays a
|
|
@@ -52,22 +52,28 @@ 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
|
|
|
60
66
|
raise yield_failure(response.value, default: "yield error")
|
|
61
67
|
end
|
|
62
68
|
|
|
63
|
-
# The Proc the Dispatcher passes as +&block+, binding
|
|
69
|
+
# The Proc the Dispatcher passes as +&block+, binding #yield so a
|
|
64
70
|
# Service method's +yield+ / +block.call+ drives the round-trip.
|
|
65
71
|
def to_proc
|
|
66
72
|
method(:yield).to_proc
|
|
67
73
|
end
|
|
68
74
|
|
|
69
75
|
# Mark this Yielder dead. Called by the Dispatcher's +ensure+ block
|
|
70
|
-
# when the originating dispatch frame returns; any later
|
|
76
|
+
# when the originating dispatch frame returns; any later #yield
|
|
71
77
|
# call then raises +LocalJumpError+.
|
|
72
78
|
def invalidate!
|
|
73
79
|
@active = false
|
|
@@ -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/release-please-config.json
CHANGED
|
@@ -29,28 +29,28 @@
|
|
|
29
29
|
}
|
|
30
30
|
]
|
|
31
31
|
},
|
|
32
|
-
"wasm/kobako": {
|
|
33
|
-
"component": "kobako-
|
|
32
|
+
"wasm/kobako-mruby": {
|
|
33
|
+
"component": "kobako-mruby",
|
|
34
34
|
"release-type": "rust",
|
|
35
35
|
"extra-files": [
|
|
36
36
|
{
|
|
37
37
|
"type": "toml",
|
|
38
38
|
"path": "/wasm/Cargo.lock",
|
|
39
|
-
"jsonpath": "$.package[?(@.name=='kobako')].version"
|
|
39
|
+
"jsonpath": "$.package[?(@.name=='kobako-mruby')].version"
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
42
|
"type": "toml",
|
|
43
|
-
"path": "/wasm/kobako/Cargo.toml",
|
|
43
|
+
"path": "/wasm/kobako-mruby/Cargo.toml",
|
|
44
44
|
"jsonpath": "$.dependencies['kobako-core'].version"
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"type": "toml",
|
|
48
|
-
"path": "/wasm/kobako/Cargo.toml",
|
|
48
|
+
"path": "/wasm/kobako-mruby/Cargo.toml",
|
|
49
49
|
"jsonpath": "$.dependencies['kobako-codec'].version"
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
"type": "generic",
|
|
53
|
-
"path": "/wasm/kobako/README.md"
|
|
53
|
+
"path": "/wasm/kobako-mruby/README.md"
|
|
54
54
|
}
|
|
55
55
|
]
|
|
56
56
|
},
|
|
@@ -178,13 +178,43 @@
|
|
|
178
178
|
"path": "/crates/kobako-wasmtime/README.md"
|
|
179
179
|
}
|
|
180
180
|
]
|
|
181
|
+
},
|
|
182
|
+
"crates/kobako": {
|
|
183
|
+
"component": "kobako-sdk",
|
|
184
|
+
"release-type": "rust",
|
|
185
|
+
"extra-files": [
|
|
186
|
+
{
|
|
187
|
+
"type": "toml",
|
|
188
|
+
"path": "/crates/Cargo.lock",
|
|
189
|
+
"jsonpath": "$.package[?(@.name=='kobako')].version"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"type": "toml",
|
|
193
|
+
"path": "/crates/kobako/Cargo.toml",
|
|
194
|
+
"jsonpath": "$.dependencies['kobako-codec'].version"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"type": "toml",
|
|
198
|
+
"path": "/crates/kobako/Cargo.toml",
|
|
199
|
+
"jsonpath": "$.dependencies['kobako-runtime'].version"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"type": "toml",
|
|
203
|
+
"path": "/crates/kobako/Cargo.toml",
|
|
204
|
+
"jsonpath": "$.dependencies['kobako-wasmtime'].version"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"type": "generic",
|
|
208
|
+
"path": "/crates/kobako/README.md"
|
|
209
|
+
}
|
|
210
|
+
]
|
|
181
211
|
}
|
|
182
212
|
},
|
|
183
213
|
"plugins": [
|
|
184
214
|
{
|
|
185
215
|
"type": "linked-versions",
|
|
186
216
|
"groupName": "kobako crates",
|
|
187
|
-
"components": ["kobako-codec", "kobako-core", "kobako-
|
|
217
|
+
"components": ["kobako-codec", "kobako-core", "kobako-mruby", "kobako-io", "kobako-json", "kobako-regexp", "kobako-baker", "kobako-runtime", "kobako-wasmtime", "kobako-sdk"]
|
|
188
218
|
}
|
|
189
219
|
],
|
|
190
220
|
"extra-files": [
|
|
@@ -0,0 +1,25 @@
|
|
|
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 encode: () -> String
|
|
13
|
+
|
|
14
|
+
def seal!: () -> self
|
|
15
|
+
|
|
16
|
+
def sealed?: () -> bool
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def validate_path!: (Symbol | String path) -> String
|
|
21
|
+
|
|
22
|
+
def collision?: (String path) -> bool
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
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
|
|
@@ -5,9 +5,9 @@ module Kobako
|
|
|
5
5
|
|
|
6
6
|
def self?.representable?: (untyped value) -> bool
|
|
7
7
|
|
|
8
|
-
def self?.deep_wrap: (untyped value, Kobako::
|
|
8
|
+
def self?.deep_wrap: (untyped value, Kobako::Codec::_HandleTable handler) -> untyped
|
|
9
9
|
|
|
10
|
-
def self?.deep_restore: (untyped value, Kobako::
|
|
10
|
+
def self?.deep_restore: (untyped value, Kobako::Codec::_HandleTable handler) -> untyped
|
|
11
11
|
|
|
12
12
|
def self?.primitive_type?: (untyped value) -> bool
|
|
13
13
|
|
|
@@ -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,4 +1,18 @@
|
|
|
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
|
+
|
|
6
|
+
# The Handle allocator/resolver a wire walk works against: alloc
|
|
7
|
+
# registers a non-wire-representable object and returns its Handle,
|
|
8
|
+
# fetch resolves a wire Handle id back to the live object. The
|
|
9
|
+
# Sandbox's Kobako::Catalog::Handles is the production conformer;
|
|
10
|
+
# modelled structurally so the Codec and Transport tiers need no
|
|
11
|
+
# upward dependency on Catalog.
|
|
12
|
+
interface _HandleTable
|
|
13
|
+
def alloc: (untyped object) -> Kobako::Handle
|
|
14
|
+
|
|
15
|
+
def fetch: (Integer id) -> untyped
|
|
16
|
+
end
|
|
3
17
|
end
|
|
4
18
|
end
|
data/sig/kobako/handle.rbs
CHANGED
data/sig/kobako/sandbox.rbs
CHANGED
|
@@ -29,7 +29,7 @@ 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
33
|
|
|
34
34
|
def preload: (code: String, name: Symbol | String) -> Kobako::Sandbox
|
|
35
35
|
| (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::
|
|
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::
|
|
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
|
|
|
@@ -24,17 +24,17 @@ module Kobako
|
|
|
24
24
|
|
|
25
25
|
def self?.reject_unexposed!: (untyped target, Symbol name) -> void
|
|
26
26
|
|
|
27
|
-
def self?.resolve_arg: (untyped value, Kobako::
|
|
27
|
+
def self?.resolve_arg: (untyped value, Kobako::Codec::_HandleTable handler) -> untyped
|
|
28
28
|
|
|
29
|
-
def self?.resolve_target: (String | Kobako::Handle target, Kobako::
|
|
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::
|
|
31
|
+
def self?.resolve_path: (String path, Kobako::Transport::_ServiceRegistry services) -> untyped
|
|
32
32
|
|
|
33
|
-
def self?.require_live_object!: (Integer id, Kobako::
|
|
33
|
+
def self?.require_live_object!: (Integer id, Kobako::Codec::_HandleTable handler) -> untyped
|
|
34
34
|
|
|
35
|
-
def self?.encode_ok: (untyped value, Kobako::
|
|
35
|
+
def self?.encode_ok: (untyped value, Kobako::Codec::_HandleTable handler) -> String
|
|
36
36
|
|
|
37
|
-
def self?.wrap_as_handle: (untyped value, Kobako::
|
|
37
|
+
def self?.wrap_as_handle: (untyped value, Kobako::Codec::_HandleTable handler) -> Kobako::Handle
|
|
38
38
|
|
|
39
39
|
def self?.encode_error: (String type, String message) -> String
|
|
40
40
|
end
|
|
@@ -11,7 +11,7 @@ module Kobako
|
|
|
11
11
|
|
|
12
12
|
def initialize: (entrypoint: Symbol | String, ?args: Array[untyped], ?kwargs: Hash[untyped, untyped]) -> void
|
|
13
13
|
|
|
14
|
-
def encode: (Kobako::
|
|
14
|
+
def encode: (Kobako::Codec::_HandleTable handler) -> String
|
|
15
15
|
|
|
16
16
|
private
|
|
17
17
|
|
|
@@ -3,10 +3,10 @@ module Kobako
|
|
|
3
3
|
class Yielder
|
|
4
4
|
@yield_to_guest: Kobako::Transport::_GuestYielder
|
|
5
5
|
@break_tag: Symbol
|
|
6
|
-
@handler: Kobako::
|
|
6
|
+
@handler: Kobako::Codec::_HandleTable
|
|
7
7
|
@active: bool
|
|
8
8
|
|
|
9
|
-
def initialize: (Kobako::Transport::_GuestYielder yield_to_guest, Symbol break_tag, Kobako::
|
|
9
|
+
def initialize: (Kobako::Transport::_GuestYielder yield_to_guest, Symbol break_tag, Kobako::Codec::_HandleTable handler) -> void
|
|
10
10
|
|
|
11
11
|
def yield: (*untyped args) -> untyped
|
|
12
12
|
|
|
@@ -16,7 +16,7 @@ module Kobako
|
|
|
16
16
|
|
|
17
17
|
private
|
|
18
18
|
|
|
19
|
-
def restore: (untyped value) -> untyped
|
|
19
|
+
def restore: (untyped value, bool carried_handle) -> untyped
|
|
20
20
|
|
|
21
21
|
def yield_failure: (untyped payload, default: String) -> RuntimeError
|
|
22
22
|
end
|
data/sig/kobako/transport.rbs
CHANGED
|
@@ -8,5 +8,13 @@ module Kobako
|
|
|
8
8
|
interface _GuestYielder
|
|
9
9
|
def call: (String) -> String
|
|
10
10
|
end
|
|
11
|
+
|
|
12
|
+
# The Service registry a dispatch resolves constant-path targets
|
|
13
|
+
# against. The Sandbox's Kobako::Catalog::Services is the
|
|
14
|
+
# production conformer; modelled structurally so the Transport
|
|
15
|
+
# layer needs no upward dependency on Catalog.
|
|
16
|
+
interface _ServiceRegistry
|
|
17
|
+
def lookup: (String target) -> untyped
|
|
18
|
+
end
|
|
11
19
|
end
|
|
12
20
|
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.
|
|
4
|
+
version: 0.15.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Aotokitsuruya
|
|
@@ -53,6 +53,7 @@ files:
|
|
|
53
53
|
- Cargo.toml
|
|
54
54
|
- LICENSE
|
|
55
55
|
- README.md
|
|
56
|
+
- ROADMAP.md
|
|
56
57
|
- SECURITY.md
|
|
57
58
|
- crates/kobako-runtime/CHANGELOG.md
|
|
58
59
|
- crates/kobako-runtime/Cargo.toml
|
|
@@ -91,19 +92,19 @@ files:
|
|
|
91
92
|
- lib/kobako/capture.rb
|
|
92
93
|
- lib/kobako/catalog.rb
|
|
93
94
|
- lib/kobako/catalog/handles.rb
|
|
94
|
-
- lib/kobako/catalog/
|
|
95
|
+
- lib/kobako/catalog/services.rb
|
|
95
96
|
- lib/kobako/catalog/snippets.rb
|
|
96
97
|
- lib/kobako/codec.rb
|
|
97
98
|
- lib/kobako/codec/decoder.rb
|
|
98
99
|
- lib/kobako/codec/encoder.rb
|
|
99
100
|
- lib/kobako/codec/error.rb
|
|
100
|
-
- lib/kobako/codec/
|
|
101
|
+
- lib/kobako/codec/ext_types.rb
|
|
101
102
|
- lib/kobako/codec/handle_walk.rb
|
|
103
|
+
- lib/kobako/codec/state.rb
|
|
102
104
|
- lib/kobako/codec/utils.rb
|
|
103
105
|
- lib/kobako/errors.rb
|
|
104
106
|
- lib/kobako/fault.rb
|
|
105
107
|
- lib/kobako/handle.rb
|
|
106
|
-
- lib/kobako/namespace.rb
|
|
107
108
|
- lib/kobako/outcome.rb
|
|
108
109
|
- lib/kobako/outcome/panic.rb
|
|
109
110
|
- lib/kobako/pool.rb
|
|
@@ -129,19 +130,19 @@ files:
|
|
|
129
130
|
- sig/kobako/capture.rbs
|
|
130
131
|
- sig/kobako/catalog.rbs
|
|
131
132
|
- sig/kobako/catalog/handles.rbs
|
|
132
|
-
- sig/kobako/catalog/
|
|
133
|
+
- sig/kobako/catalog/services.rbs
|
|
133
134
|
- sig/kobako/catalog/snippets.rbs
|
|
134
135
|
- sig/kobako/codec.rbs
|
|
135
136
|
- sig/kobako/codec/decoder.rbs
|
|
136
137
|
- sig/kobako/codec/encoder.rbs
|
|
137
138
|
- sig/kobako/codec/error.rbs
|
|
138
|
-
- sig/kobako/codec/
|
|
139
|
+
- sig/kobako/codec/ext_types.rbs
|
|
139
140
|
- sig/kobako/codec/handle_walk.rbs
|
|
141
|
+
- sig/kobako/codec/state.rbs
|
|
140
142
|
- sig/kobako/codec/utils.rbs
|
|
141
143
|
- sig/kobako/errors.rbs
|
|
142
144
|
- sig/kobako/fault.rbs
|
|
143
145
|
- sig/kobako/handle.rbs
|
|
144
|
-
- sig/kobako/namespace.rbs
|
|
145
146
|
- sig/kobako/outcome.rbs
|
|
146
147
|
- sig/kobako/outcome/panic.rbs
|
|
147
148
|
- sig/kobako/pool.rbs
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "handles"
|
|
4
|
-
require_relative "../codec"
|
|
5
|
-
require_relative "../errors"
|
|
6
|
-
require_relative "../namespace"
|
|
7
|
-
|
|
8
|
-
module Kobako
|
|
9
|
-
module Catalog
|
|
10
|
-
# Kobako::Catalog::Namespaces — per-Sandbox registry of
|
|
11
|
-
# +Kobako::Namespace+ entities. Holds the Namespace / Member bindings
|
|
12
|
-
# and the preamble emitted on Frame 1.
|
|
13
|
-
#
|
|
14
|
-
# Public API:
|
|
15
|
-
#
|
|
16
|
-
# namespaces = Kobako::Catalog::Namespaces.new
|
|
17
|
-
# namespace = namespaces.define(:MyService) # => Kobako::Namespace
|
|
18
|
-
# namespace.bind(:KV, kv_object) # => namespace (chainable)
|
|
19
|
-
# namespaces.encode # => msgpack bytes for Frame 1
|
|
20
|
-
# namespaces.lookup("MyService::KV") # => kv_object
|
|
21
|
-
#
|
|
22
|
-
# Namespaces live at +Kobako::Namespace+. Per-dispatch routing is
|
|
23
|
-
# +Kobako::Transport::Dispatcher+'s responsibility — the Dispatcher
|
|
24
|
-
# receives this registry and the +Catalog::Handles+ as arguments from
|
|
25
|
-
# the +Runtime#on_dispatch+ Proc that +Kobako::Sandbox#initialize+
|
|
26
|
-
# installs. The registry holds an injected +Catalog::Handles+ reference so
|
|
27
|
-
# dispatch target resolution and host→guest auto-wrap share the same
|
|
28
|
-
# Sandbox-owned allocator.
|
|
29
|
-
class Namespaces
|
|
30
|
-
# Build a fresh registry. +handler+ is an internal seam that injects
|
|
31
|
-
# a pre-configured +Catalog::Handles+; tests pass one whose +next_id+
|
|
32
|
-
# is pinned near +MAX_ID+ to exercise the cap-exhaustion path
|
|
33
|
-
# without 2³¹ allocations. Production callers leave it at the default.
|
|
34
|
-
def initialize(handler: Catalog::Handles.new)
|
|
35
|
-
@namespaces = {} # : Hash[String, Kobako::Namespace]
|
|
36
|
-
@handler = handler
|
|
37
|
-
@sealed = false
|
|
38
|
-
@encoded = nil # : String?
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# Declare or retrieve the Namespace named +name+ (idempotent).
|
|
42
|
-
# +name+ is a constant-form name as a +Symbol+ or +String+ (must satisfy
|
|
43
|
-
# +Namespace::NAME_PATTERN+). Returns the +Kobako::Namespace+ for that
|
|
44
|
-
# name, creating it if it does not exist. Raises +ArgumentError+ when
|
|
45
|
-
# +name+ is malformed, or when called after the owning Sandbox has been
|
|
46
|
-
# sealed by its first invocation.
|
|
47
|
-
def define(name)
|
|
48
|
-
raise ArgumentError, "cannot define after first Sandbox invocation" if @sealed
|
|
49
|
-
|
|
50
|
-
name_str = name.to_s
|
|
51
|
-
unless Namespace::NAME_PATTERN.match?(name_str)
|
|
52
|
-
raise ArgumentError,
|
|
53
|
-
"Namespace name must match #{Namespace::NAME_PATTERN.inspect} (got #{name.inspect})"
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
@namespaces[name_str] ||= Namespace.new(name_str)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# Resolve a +target+ path of the form +"<Namespace>::<Member>"+
|
|
60
|
-
# (e.g. +"MyService::KV"+) to the bound Host object. +target+ is a
|
|
61
|
-
# two-level path using the +::+ separator. Returns the bound Host
|
|
62
|
-
# object. Raises +KeyError+ when the namespace or the member is not
|
|
63
|
-
# bound.
|
|
64
|
-
def lookup(target)
|
|
65
|
-
namespace_name, member_name = target.to_s.split("::", 2)
|
|
66
|
-
namespace = @namespaces[namespace_name]
|
|
67
|
-
raise KeyError, "no namespace named #{namespace_name.inspect}" if namespace.nil?
|
|
68
|
-
raise KeyError, "no member in target #{target.inspect}" unless member_name
|
|
69
|
-
|
|
70
|
-
namespace.fetch(member_name)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Encode the preamble as msgpack bytes for stdin Frame 1 delivery.
|
|
74
|
-
# Routes through {Kobako::Codec::Encoder} like every other host-side
|
|
75
|
-
# wire encode so there is a single codec path; the preamble carries
|
|
76
|
-
# only Strings and Arrays, so none of the kobako ext types actually
|
|
77
|
-
# fire. Structure: +[["Namespace", ["MemberA", "MemberB"]], ...]+.
|
|
78
|
-
# Returns a binary +String+ of msgpack bytes.
|
|
79
|
-
#
|
|
80
|
-
# Once sealed, the bytes are computed once and reused for every
|
|
81
|
-
# subsequent invocation: sealing freezes Service registration at the
|
|
82
|
-
# first invocation, so the preamble is exactly the bindings that
|
|
83
|
-
# existed at that moment — a bind reaching a +Kobako::Namespace+
|
|
84
|
-
# after the seal raises +ArgumentError+ and never alters Frame 1.
|
|
85
|
-
# The memo is gated on the seal rather than dropped per mutation (the
|
|
86
|
-
# +Catalog::Snippets#encode+ approach) because a +Member+ bind lands
|
|
87
|
-
# on a child +Kobako::Namespace+, invisible to this collection; only
|
|
88
|
-
# the seal guarantees nothing further can change.
|
|
89
|
-
def encode
|
|
90
|
-
return @encoded if @encoded
|
|
91
|
-
|
|
92
|
-
bytes = Codec::Encoder.encode(@namespaces.values.map(&:to_preamble)).freeze
|
|
93
|
-
@encoded = bytes if @sealed
|
|
94
|
-
bytes
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# Mark the registry as sealed and propagate the seal to every
|
|
98
|
-
# declared +Kobako::Namespace+. Called by +Sandbox+ on the first
|
|
99
|
-
# invocation. After sealing, both #define and +Namespace#bind+
|
|
100
|
-
# raise ArgumentError. Idempotent.
|
|
101
|
-
def seal!
|
|
102
|
-
return self if @sealed
|
|
103
|
-
|
|
104
|
-
@sealed = true
|
|
105
|
-
@namespaces.each_value(&:seal!)
|
|
106
|
-
self
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# Returns +true+ when {#seal!} has been called, +false+ otherwise.
|
|
110
|
-
def sealed?
|
|
111
|
-
@sealed
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|