tigrbl-kernel 0.4.4.dev1__py3-none-any.whl → 0.4.4.dev7__py3-none-any.whl
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.
- tigrbl_kernel/_compile.py +123 -18
- tigrbl_kernel/contract_classification.py +4 -0
- tigrbl_kernel/core.py +0 -4
- tigrbl_kernel/cross_transport.py +3 -3
- tigrbl_kernel/protocol_anchors.py +0 -12
- tigrbl_kernel/protocol_bindings.py +281 -109
- tigrbl_kernel/types.py +4 -0
- tigrbl_kernel/utils.py +2 -2
- tigrbl_kernel/webtransport_events.py +6 -3
- {tigrbl_kernel-0.4.4.dev1.dist-info → tigrbl_kernel-0.4.4.dev7.dist-info}/METADATA +3 -4
- {tigrbl_kernel-0.4.4.dev1.dist-info → tigrbl_kernel-0.4.4.dev7.dist-info}/RECORD +14 -17
- tigrbl_kernel/rust_compile.py +0 -24
- tigrbl_kernel/rust_plan.py +0 -20
- tigrbl_kernel/rust_spec.py +0 -36
- {tigrbl_kernel-0.4.4.dev1.dist-info → tigrbl_kernel-0.4.4.dev7.dist-info}/WHEEL +0 -0
- {tigrbl_kernel-0.4.4.dev1.dist-info → tigrbl_kernel-0.4.4.dev7.dist-info}/licenses/LICENSE +0 -0
- {tigrbl_kernel-0.4.4.dev1.dist-info → tigrbl_kernel-0.4.4.dev7.dist-info}/licenses/NOTICE +0 -0
tigrbl_kernel/_compile.py
CHANGED
|
@@ -5,7 +5,17 @@ from types import SimpleNamespace
|
|
|
5
5
|
from typing import Any, Mapping
|
|
6
6
|
|
|
7
7
|
from tigrbl_atoms import StepFn
|
|
8
|
-
from tigrbl_core._spec.binding_spec import
|
|
8
|
+
from tigrbl_core._spec.binding_spec import (
|
|
9
|
+
HttpJsonRpcProtocolBindingSpec,
|
|
10
|
+
HttpRestBindingSpec,
|
|
11
|
+
HttpRestProtocolBindingSpec,
|
|
12
|
+
WebSocketProtocolBindingSpec,
|
|
13
|
+
WebTransportProtocolBindingSpec,
|
|
14
|
+
derive_websocket_subprotocol_for_framing,
|
|
15
|
+
derive_session_metadata_for_framing,
|
|
16
|
+
framing_kind,
|
|
17
|
+
framing_spec_name,
|
|
18
|
+
)
|
|
9
19
|
from tigrbl_core.config.constants import __JSONRPC_DEFAULT_ENDPOINT__
|
|
10
20
|
from tigrbl_core._spec.op_spec import OpSpec
|
|
11
21
|
from tigrbl_core._spec.well_known_spec import well_known_op_alias
|
|
@@ -28,6 +38,69 @@ from .utils import (
|
|
|
28
38
|
DEFAULT_PHASE_ORDER = tuple(getattr(_ev, "PHASES", ())) or _DEFAULT_PHASE_ORDER
|
|
29
39
|
|
|
30
40
|
|
|
41
|
+
def _route_metadata_for_binding(binding: Any) -> dict[str, Any]:
|
|
42
|
+
framing_obj = getattr(binding, "framing", None)
|
|
43
|
+
framing = framing_kind(framing_obj)
|
|
44
|
+
metadata: dict[str, Any] = {
|
|
45
|
+
"framing": framing,
|
|
46
|
+
"framing_kind": framing,
|
|
47
|
+
"framing_spec": framing_spec_name(framing_obj),
|
|
48
|
+
}
|
|
49
|
+
proto = str(getattr(binding, "proto", "") or "")
|
|
50
|
+
if isinstance(binding, WebSocketProtocolBindingSpec):
|
|
51
|
+
derived_subprotocol = derive_websocket_subprotocol_for_framing(framing_obj)
|
|
52
|
+
if derived_subprotocol is not None:
|
|
53
|
+
metadata["websocket_subprotocol"] = derived_subprotocol
|
|
54
|
+
elif proto in {"ws", "wss"}:
|
|
55
|
+
metadata.update(
|
|
56
|
+
derive_session_metadata_for_framing(
|
|
57
|
+
binding_kind=proto,
|
|
58
|
+
framing=framing_obj,
|
|
59
|
+
subprotocols=tuple(getattr(binding, "subprotocols", ()) or ()),
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
if isinstance(binding, WebTransportProtocolBindingSpec):
|
|
63
|
+
if binding.control_stream is not None:
|
|
64
|
+
control = binding.control_stream
|
|
65
|
+
metadata["control_stream"] = {
|
|
66
|
+
"name": control.name,
|
|
67
|
+
"kind": control.kind,
|
|
68
|
+
"opens": control.opens,
|
|
69
|
+
"purpose": control.purpose,
|
|
70
|
+
"framing": framing_kind(control.framing),
|
|
71
|
+
"framing_spec": framing_spec_name(control.framing),
|
|
72
|
+
}
|
|
73
|
+
metadata["streams"] = tuple(
|
|
74
|
+
{
|
|
75
|
+
"name": stream.name,
|
|
76
|
+
"kind": stream.kind,
|
|
77
|
+
"purpose": stream.purpose,
|
|
78
|
+
"framing": framing_kind(stream.framing),
|
|
79
|
+
"framing_spec": framing_spec_name(stream.framing),
|
|
80
|
+
}
|
|
81
|
+
for stream in binding.streams
|
|
82
|
+
)
|
|
83
|
+
metadata["datagrams"] = tuple(
|
|
84
|
+
{
|
|
85
|
+
"name": datagram.name,
|
|
86
|
+
"purpose": datagram.purpose,
|
|
87
|
+
"framing": framing_kind(datagram.framing),
|
|
88
|
+
"framing_spec": framing_spec_name(datagram.framing),
|
|
89
|
+
}
|
|
90
|
+
for datagram in binding.datagrams
|
|
91
|
+
)
|
|
92
|
+
elif proto == "webtransport":
|
|
93
|
+
lane = getattr(binding, "lane", None) or getattr(binding, "profile", None)
|
|
94
|
+
inner_framing = getattr(binding, "inner_framing", None)
|
|
95
|
+
metadata["lane"] = lane
|
|
96
|
+
metadata["inner_framing"] = framing_kind(inner_framing)
|
|
97
|
+
metadata["inner_framing_spec"] = framing_spec_name(inner_framing)
|
|
98
|
+
if inner_framing is not None:
|
|
99
|
+
metadata["inner_framing_kind"] = str(inner_framing)
|
|
100
|
+
metadata["inner_framing_spec"] = framing_spec_name(inner_framing)
|
|
101
|
+
return metadata
|
|
102
|
+
|
|
103
|
+
|
|
31
104
|
def _pathspec_iter(app: Any) -> tuple[Any, ...]:
|
|
32
105
|
collected: list[Any] = []
|
|
33
106
|
collected.extend(tuple(getattr(app, "_tigrbl_path_specs", ()) or ()))
|
|
@@ -133,9 +206,13 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
|
|
|
133
206
|
from tigrbl_core._spec.binding_spec import (
|
|
134
207
|
HttpJsonRpcBindingSpec,
|
|
135
208
|
HttpRestBindingSpec,
|
|
209
|
+
HttpJsonRpcProtocolBindingSpec,
|
|
210
|
+
HttpRestProtocolBindingSpec,
|
|
136
211
|
HttpStreamBindingSpec,
|
|
137
212
|
SseBindingSpec,
|
|
213
|
+
WebSocketProtocolBindingSpec,
|
|
138
214
|
WebTransportBindingSpec,
|
|
215
|
+
WebTransportProtocolBindingSpec,
|
|
139
216
|
WsBindingSpec,
|
|
140
217
|
)
|
|
141
218
|
|
|
@@ -169,7 +246,12 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
|
|
|
169
246
|
for binding in getattr(sp, "bindings", ()) or ():
|
|
170
247
|
if isinstance(
|
|
171
248
|
binding,
|
|
172
|
-
(
|
|
249
|
+
(
|
|
250
|
+
HttpRestBindingSpec,
|
|
251
|
+
HttpRestProtocolBindingSpec,
|
|
252
|
+
HttpStreamBindingSpec,
|
|
253
|
+
SseBindingSpec,
|
|
254
|
+
),
|
|
173
255
|
):
|
|
174
256
|
bucket = route_data.setdefault(
|
|
175
257
|
binding.proto, {"exact": {}, "templated": []}
|
|
@@ -199,34 +281,53 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
|
|
|
199
281
|
meta_index
|
|
200
282
|
)
|
|
201
283
|
|
|
202
|
-
elif isinstance(binding, HttpJsonRpcBindingSpec):
|
|
203
|
-
|
|
204
|
-
getattr(
|
|
284
|
+
elif isinstance(binding, (HttpJsonRpcBindingSpec, HttpJsonRpcProtocolBindingSpec)):
|
|
285
|
+
rpc_path = str(
|
|
286
|
+
getattr(
|
|
287
|
+
binding,
|
|
288
|
+
"path",
|
|
289
|
+
getattr(binding, "endpoint", __JSONRPC_DEFAULT_ENDPOINT__),
|
|
290
|
+
)
|
|
205
291
|
or __JSONRPC_DEFAULT_ENDPOINT__
|
|
206
292
|
)
|
|
207
|
-
|
|
293
|
+
rpc_method = getattr(
|
|
294
|
+
binding,
|
|
295
|
+
"method",
|
|
296
|
+
getattr(binding, "rpc_method", None),
|
|
297
|
+
)
|
|
298
|
+
selector = f"{rpc_path}:{rpc_method}"
|
|
208
299
|
opkey_to_meta[OpKey(proto=binding.proto, selector=selector)] = (
|
|
209
300
|
meta_index
|
|
210
301
|
)
|
|
211
302
|
proto_bucket = route_data.setdefault(
|
|
212
|
-
binding.proto, {"endpoints": {}}
|
|
213
|
-
)
|
|
214
|
-
endpoint_bucket = proto_bucket.setdefault("endpoints", {}).setdefault(
|
|
215
|
-
endpoint, {}
|
|
303
|
+
binding.proto, {"paths": {}, "endpoints": {}}
|
|
216
304
|
)
|
|
217
|
-
proto_bucket
|
|
218
|
-
endpoint_bucket
|
|
305
|
+
path_bucket = proto_bucket.setdefault("paths", {}).setdefault(rpc_path, {})
|
|
306
|
+
endpoint_bucket = proto_bucket.setdefault("endpoints", {}).setdefault(rpc_path, {})
|
|
307
|
+
proto_bucket[rpc_method] = meta_index
|
|
308
|
+
row = {
|
|
219
309
|
"meta_index": meta_index,
|
|
220
310
|
"selector": selector,
|
|
221
|
-
"
|
|
222
|
-
"
|
|
311
|
+
"method": rpc_method,
|
|
312
|
+
"path": rpc_path,
|
|
223
313
|
}
|
|
314
|
+
path_bucket[rpc_method] = row
|
|
315
|
+
endpoint_bucket[rpc_method] = row
|
|
224
316
|
|
|
225
|
-
elif isinstance(
|
|
317
|
+
elif isinstance(
|
|
318
|
+
binding,
|
|
319
|
+
(
|
|
320
|
+
WsBindingSpec,
|
|
321
|
+
WebSocketProtocolBindingSpec,
|
|
322
|
+
WebTransportBindingSpec,
|
|
323
|
+
WebTransportProtocolBindingSpec,
|
|
324
|
+
),
|
|
325
|
+
):
|
|
226
326
|
bucket = route_data.setdefault(
|
|
227
327
|
binding.proto, {"exact": {}, "templated": []}
|
|
228
328
|
)
|
|
229
329
|
selector = binding.path
|
|
330
|
+
route_metadata = _route_metadata_for_binding(binding)
|
|
230
331
|
opkey_to_meta[OpKey(proto=binding.proto, selector=selector)] = (
|
|
231
332
|
meta_index
|
|
232
333
|
)
|
|
@@ -240,13 +341,17 @@ def _compile_plan(self: Any, app: Any) -> KernelPlan:
|
|
|
240
341
|
"names": names,
|
|
241
342
|
"meta_index": meta_index,
|
|
242
343
|
"selector": selector,
|
|
243
|
-
|
|
244
|
-
getattr(binding, "subprotocols", ()) or ()
|
|
245
|
-
),
|
|
344
|
+
**route_metadata,
|
|
246
345
|
}
|
|
247
346
|
)
|
|
248
347
|
else:
|
|
249
348
|
bucket["exact"][selector] = meta_index
|
|
349
|
+
bucket.setdefault("exact_metadata", {})[selector] = {
|
|
350
|
+
"path": binding.path,
|
|
351
|
+
"meta_index": meta_index,
|
|
352
|
+
"selector": selector,
|
|
353
|
+
**route_metadata,
|
|
354
|
+
}
|
|
250
355
|
|
|
251
356
|
semantic = KernelPlan(
|
|
252
357
|
proto_indices=route_data,
|
|
@@ -61,6 +61,9 @@ CANONICAL_CONTRACT_EVENTS: tuple[str, ...] = (
|
|
|
61
61
|
"webtransport.stream.stop_sending",
|
|
62
62
|
"webtransport.datagram.receive",
|
|
63
63
|
"webtransport.datagram.send",
|
|
64
|
+
"stream.resume.request",
|
|
65
|
+
"stream.resume.accept",
|
|
66
|
+
"stream.resume.reject",
|
|
64
67
|
"webtransport.disconnect",
|
|
65
68
|
"webtransport.close",
|
|
66
69
|
"transport.emit.complete",
|
|
@@ -71,6 +74,7 @@ _EVENT_SCOPE_PREFIXES: dict[str, str] = {
|
|
|
71
74
|
"http.": "http",
|
|
72
75
|
"websocket.": "websocket",
|
|
73
76
|
"webtransport.": "webtransport",
|
|
77
|
+
"stream.resume.": "webtransport",
|
|
74
78
|
"transport.emit.": "webtransport",
|
|
75
79
|
}
|
|
76
80
|
|
tigrbl_kernel/core.py
CHANGED
|
@@ -24,7 +24,6 @@ from .cache import _SpecsOnceCache, _WeakMaybeDict
|
|
|
24
24
|
from .models import KernelPlan, OpView
|
|
25
25
|
from .opview_compiler import compile_opview_from_specs
|
|
26
26
|
from .types import DEFAULT_PHASE_ORDER as _DEFAULT_PHASE_ORDER
|
|
27
|
-
from .rust_compile import build_rust_kernel as _build_rust_kernel
|
|
28
27
|
from .utils import (
|
|
29
28
|
_opspecs,
|
|
30
29
|
_table_iter,
|
|
@@ -155,9 +154,6 @@ class Kernel:
|
|
|
155
154
|
return payload
|
|
156
155
|
return {}
|
|
157
156
|
|
|
158
|
-
def compile_rust_plan(self, app: Any):
|
|
159
|
-
return _build_rust_kernel(app)
|
|
160
|
-
|
|
161
157
|
def invalidate_kernelz_payload(self, app: Optional[Any] = None) -> None:
|
|
162
158
|
with self._lock:
|
|
163
159
|
if app is None:
|
tigrbl_kernel/cross_transport.py
CHANGED
|
@@ -27,7 +27,7 @@ TRANSPORT_ENVELOPE_KEYS = frozenset(
|
|
|
27
27
|
class EquivalenceCase:
|
|
28
28
|
op_id: str
|
|
29
29
|
category: str
|
|
30
|
-
bindings: tuple[
|
|
30
|
+
bindings: tuple[Any, ...]
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def canonical_operation_id(op_id: str) -> str:
|
|
@@ -42,7 +42,7 @@ def canonical_operation_id(op_id: str) -> str:
|
|
|
42
42
|
|
|
43
43
|
def compile_equivalence_manifest(
|
|
44
44
|
op_id: str,
|
|
45
|
-
bindings: Iterable[
|
|
45
|
+
bindings: Iterable[Any],
|
|
46
46
|
*,
|
|
47
47
|
schema_identity: str = "schema:v1",
|
|
48
48
|
runtime_plan_identity: str = "runtime-plan:v1",
|
|
@@ -80,7 +80,7 @@ def equivalent_transport_results(*results: Mapping[str, Any]) -> bool:
|
|
|
80
80
|
return all(normalized_transport_result(result) == first for result in results[1:])
|
|
81
81
|
|
|
82
82
|
|
|
83
|
-
def equivalent_binding_group(op_id: str, bindings: Iterable[
|
|
83
|
+
def equivalent_binding_group(op_id: str, bindings: Iterable[Any]) -> bool:
|
|
84
84
|
manifest = compile_equivalence_manifest(op_id, bindings)
|
|
85
85
|
families = {binding["family"] for binding in manifest["bindings"]}
|
|
86
86
|
return bool(families) and len({manifest["op_id"]}) == 1
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from typing import Any
|
|
4
|
-
import warnings
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
def canonical_protocol_anchor_order(
|
|
@@ -32,18 +31,7 @@ def python_protocol_anchor_trace(case: dict[str, Any]) -> tuple[str, ...]:
|
|
|
32
31
|
)
|
|
33
32
|
|
|
34
33
|
|
|
35
|
-
def rust_protocol_anchor_trace(case: dict[str, Any]) -> tuple[str, ...]:
|
|
36
|
-
del case
|
|
37
|
-
warnings.warn(
|
|
38
|
-
"rust_protocol_anchor_trace is deprecated; protocol anchors are Python-only.",
|
|
39
|
-
DeprecationWarning,
|
|
40
|
-
stacklevel=2,
|
|
41
|
-
)
|
|
42
|
-
raise RuntimeError("rust_protocol_anchor_trace is unavailable.")
|
|
43
|
-
|
|
44
|
-
|
|
45
34
|
__all__ = [
|
|
46
35
|
"canonical_protocol_anchor_order",
|
|
47
36
|
"python_protocol_anchor_trace",
|
|
48
|
-
"rust_protocol_anchor_trace",
|
|
49
37
|
]
|
|
@@ -4,6 +4,16 @@ from collections.abc import Mapping
|
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
6
|
from tigrbl_core._spec.binding_spec import (
|
|
7
|
+
BytesFramingSpec,
|
|
8
|
+
derive_websocket_subprotocol_for_framing,
|
|
9
|
+
framing_spec_name,
|
|
10
|
+
framing_kind as framing_spec_kind,
|
|
11
|
+
framing_spec_from_kind,
|
|
12
|
+
JsonFramingSpec,
|
|
13
|
+
JsonRpcFramingSpec,
|
|
14
|
+
normalize_framing_spec,
|
|
15
|
+
SseFramingSpec,
|
|
16
|
+
TextFramingSpec,
|
|
7
17
|
validate_app_framing_for_binding,
|
|
8
18
|
validate_binding_profile_exchange,
|
|
9
19
|
validate_webtransport_inner_framing,
|
|
@@ -18,30 +28,61 @@ def _unsupported(message: str) -> ValueError:
|
|
|
18
28
|
return ValueError(f"binding protocol unsupported before runtime: {message}")
|
|
19
29
|
|
|
20
30
|
|
|
21
|
-
def
|
|
22
|
-
|
|
31
|
+
def _binding_get(binding: Any, key: str, default: Any = None) -> Any:
|
|
32
|
+
if isinstance(binding, Mapping):
|
|
33
|
+
return binding.get(key, default)
|
|
34
|
+
return getattr(binding, key, default)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _lane_mapping(value: Any, *, lane_kind: str | None = None) -> dict[str, Any]:
|
|
38
|
+
if isinstance(value, Mapping):
|
|
39
|
+
return dict(value)
|
|
40
|
+
row: dict[str, Any] = {}
|
|
41
|
+
for key in ("name", "kind", "opens", "purpose", "framing"):
|
|
42
|
+
item = getattr(value, key, None)
|
|
43
|
+
if item is not None:
|
|
44
|
+
row[key] = item
|
|
45
|
+
if lane_kind is not None:
|
|
46
|
+
row.setdefault("kind", lane_kind)
|
|
47
|
+
return row
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def compile_binding_protocol_plan(op_id: str, binding: Any) -> dict[str, object]:
|
|
51
|
+
kind = _binding_get(binding, "kind") or _binding_get(binding, "proto")
|
|
23
52
|
if not kind:
|
|
24
53
|
raise ValueError(
|
|
25
54
|
"BindingSpec binding source is required; transport guessing is ambiguous"
|
|
26
55
|
)
|
|
27
56
|
|
|
28
57
|
kind = str(kind)
|
|
29
|
-
profile = binding
|
|
58
|
+
profile = _binding_get(binding, "profile")
|
|
30
59
|
if kind in {"http", "https"} and profile:
|
|
31
60
|
kind = f"{kind}.{profile}"
|
|
32
61
|
elif kind == "websocket":
|
|
33
|
-
kind = str(binding
|
|
34
|
-
framing = binding
|
|
62
|
+
kind = str(_binding_get(binding, "proto") or "ws")
|
|
63
|
+
framing = _binding_get(binding, "framing")
|
|
64
|
+
framing_kind = ""
|
|
65
|
+
framing_spec = ""
|
|
66
|
+
subprotocols: tuple[str, ...] = ()
|
|
67
|
+
inner_framing: str | None = None
|
|
35
68
|
rows: tuple[dict[str, str], ...]
|
|
69
|
+
rpc_path: str | None = None
|
|
70
|
+
rpc_method: str | None = None
|
|
36
71
|
|
|
37
72
|
if kind in {"http.rest", "https.rest"}:
|
|
38
73
|
validate_binding_profile_exchange(
|
|
39
74
|
binding_kind=kind,
|
|
40
|
-
exchange=str(binding
|
|
75
|
+
exchange=str(_binding_get(binding, "exchange") or "request_response"),
|
|
41
76
|
)
|
|
42
|
-
|
|
77
|
+
framing_spec_obj = normalize_framing_spec(
|
|
78
|
+
framing_spec_from_kind(framing),
|
|
79
|
+
default=JsonFramingSpec(),
|
|
80
|
+
)
|
|
81
|
+
validate_app_framing_for_binding(binding_kind=kind, framing=framing_spec_obj)
|
|
43
82
|
family = "request"
|
|
44
|
-
framing =
|
|
83
|
+
framing = framing_spec_obj.kind
|
|
84
|
+
framing_kind = framing
|
|
85
|
+
framing_spec = framing_spec_obj.__class__.__name__
|
|
45
86
|
anchors = (
|
|
46
87
|
"ingress.receive",
|
|
47
88
|
"dispatch.subevent.derive",
|
|
@@ -53,15 +94,27 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
|
|
|
53
94
|
{"family": "request", "subevent": "response.emit"},
|
|
54
95
|
)
|
|
55
96
|
elif kind in {"http.jsonrpc", "https.jsonrpc"}:
|
|
56
|
-
|
|
57
|
-
|
|
97
|
+
rpc_method = _binding_get(binding, "method") or _binding_get(binding, "rpc_method")
|
|
98
|
+
if not rpc_method:
|
|
99
|
+
raise _unsupported("http.jsonrpc requires method")
|
|
100
|
+
rpc_method = str(rpc_method)
|
|
101
|
+
rpc_path = str(
|
|
102
|
+
_binding_get(binding, "path", _binding_get(binding, "endpoint", "/rpc"))
|
|
103
|
+
or "/rpc"
|
|
104
|
+
)
|
|
58
105
|
validate_binding_profile_exchange(
|
|
59
106
|
binding_kind=kind,
|
|
60
|
-
exchange=str(binding
|
|
107
|
+
exchange=str(_binding_get(binding, "exchange") or "request_response"),
|
|
108
|
+
)
|
|
109
|
+
framing_spec_obj = normalize_framing_spec(
|
|
110
|
+
framing_spec_from_kind(framing),
|
|
111
|
+
default=JsonRpcFramingSpec(),
|
|
61
112
|
)
|
|
62
|
-
validate_app_framing_for_binding(binding_kind=kind, framing=
|
|
113
|
+
validate_app_framing_for_binding(binding_kind=kind, framing=framing_spec_obj)
|
|
63
114
|
family = "request"
|
|
64
|
-
framing =
|
|
115
|
+
framing = framing_spec_obj.kind
|
|
116
|
+
framing_kind = framing
|
|
117
|
+
framing_spec = framing_spec_obj.__class__.__name__
|
|
65
118
|
anchors = (
|
|
66
119
|
"framing.decode",
|
|
67
120
|
"dispatch.subevent.derive",
|
|
@@ -75,11 +128,17 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
|
|
|
75
128
|
elif kind in {"http.stream", "https.stream"}:
|
|
76
129
|
exchange = validate_binding_profile_exchange(
|
|
77
130
|
binding_kind=kind,
|
|
78
|
-
exchange=str(binding
|
|
131
|
+
exchange=str(_binding_get(binding, "exchange") or "server_stream"),
|
|
79
132
|
)
|
|
80
|
-
|
|
133
|
+
framing_spec_obj = normalize_framing_spec(
|
|
134
|
+
framing_spec_from_kind(framing),
|
|
135
|
+
default=BytesFramingSpec(),
|
|
136
|
+
)
|
|
137
|
+
validate_app_framing_for_binding(binding_kind=kind, framing=framing_spec_obj)
|
|
81
138
|
family = "stream"
|
|
82
|
-
framing =
|
|
139
|
+
framing = framing_spec_obj.kind
|
|
140
|
+
framing_kind = framing
|
|
141
|
+
framing_spec = framing_spec_obj.__class__.__name__
|
|
83
142
|
if exchange == "client_stream":
|
|
84
143
|
anchors = (
|
|
85
144
|
"transport.receive",
|
|
@@ -100,11 +159,17 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
|
|
|
100
159
|
elif kind in {"http.sse", "https.sse"}:
|
|
101
160
|
validate_binding_profile_exchange(
|
|
102
161
|
binding_kind=kind,
|
|
103
|
-
exchange=str(binding
|
|
162
|
+
exchange=str(_binding_get(binding, "exchange") or "server_stream"),
|
|
163
|
+
)
|
|
164
|
+
framing_spec_obj = normalize_framing_spec(
|
|
165
|
+
framing_spec_from_kind(framing),
|
|
166
|
+
default=SseFramingSpec(),
|
|
104
167
|
)
|
|
105
|
-
validate_app_framing_for_binding(binding_kind=kind, framing=
|
|
168
|
+
validate_app_framing_for_binding(binding_kind=kind, framing=framing_spec_obj)
|
|
106
169
|
family = "stream"
|
|
107
|
-
framing =
|
|
170
|
+
framing = framing_spec_obj.kind
|
|
171
|
+
framing_kind = framing
|
|
172
|
+
framing_spec = framing_spec_obj.__class__.__name__
|
|
108
173
|
anchors = (
|
|
109
174
|
"framing.encode",
|
|
110
175
|
"handler.invoke",
|
|
@@ -117,18 +182,25 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
|
|
|
117
182
|
{"family": "stream", "subevent": "stream.close"},
|
|
118
183
|
)
|
|
119
184
|
elif kind in {"ws", "wss", "websocket"}:
|
|
120
|
-
if binding
|
|
185
|
+
if _binding_get(binding, "methods"):
|
|
121
186
|
raise _unsupported("websocket bindings do not accept HTTP methods")
|
|
122
187
|
family = "message"
|
|
123
|
-
|
|
124
|
-
|
|
188
|
+
framing_spec_obj = normalize_framing_spec(
|
|
189
|
+
framing_spec_from_kind(framing),
|
|
190
|
+
default=TextFramingSpec(),
|
|
191
|
+
)
|
|
192
|
+
framing = framing_spec_obj.kind
|
|
193
|
+
framing_kind = framing
|
|
194
|
+
framing_spec = framing_spec_obj.__class__.__name__
|
|
195
|
+
subprotocols = tuple(str(item).lower() for item in (_binding_get(binding, "subprotocols", ()) or ()))
|
|
196
|
+
websocket_subprotocol = derive_websocket_subprotocol_for_framing(framing_spec_obj)
|
|
125
197
|
validate_binding_profile_exchange(
|
|
126
198
|
binding_kind="wss" if kind == "wss" else "ws",
|
|
127
|
-
exchange=str(binding
|
|
199
|
+
exchange=str(_binding_get(binding, "exchange") or "bidirectional_stream"),
|
|
128
200
|
)
|
|
129
201
|
validate_app_framing_for_binding(
|
|
130
202
|
binding_kind="wss" if kind == "wss" else "ws",
|
|
131
|
-
framing=
|
|
203
|
+
framing=framing_spec_obj,
|
|
132
204
|
subprotocols=subprotocols,
|
|
133
205
|
)
|
|
134
206
|
anchors = (
|
|
@@ -144,31 +216,65 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
|
|
|
144
216
|
{"family": "session", "subevent": "session.close"},
|
|
145
217
|
)
|
|
146
218
|
elif kind == "webtransport":
|
|
147
|
-
if binding
|
|
219
|
+
if _binding_get(binding, "exchange") == "request_response":
|
|
148
220
|
raise _unsupported("webtransport request_response exchange")
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
"bidi_stream"
|
|
160
|
-
"
|
|
161
|
-
|
|
162
|
-
"
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
221
|
+
if framing is not None:
|
|
222
|
+
raise _unsupported("webtransport bindings do not accept top-level app framing")
|
|
223
|
+
framing_kind = ""
|
|
224
|
+
framing_spec = ""
|
|
225
|
+
control_stream = _binding_get(binding, "control_stream")
|
|
226
|
+
streams = tuple(_binding_get(binding, "streams", ()) or ())
|
|
227
|
+
datagrams = tuple(_binding_get(binding, "datagrams", ()) or ())
|
|
228
|
+
if control_stream is not None or streams or datagrams:
|
|
229
|
+
control = None
|
|
230
|
+
if control_stream is not None:
|
|
231
|
+
control = _lane_mapping(control_stream, lane_kind="bidi_stream")
|
|
232
|
+
if control.get("kind") != "bidi_stream":
|
|
233
|
+
raise _unsupported("webtransport control_stream must use bidi_stream")
|
|
234
|
+
if control.get("opens") != "first":
|
|
235
|
+
raise _unsupported("webtransport control_stream must open first")
|
|
236
|
+
control_framing = validate_webtransport_inner_framing(
|
|
237
|
+
lane="bidi_stream",
|
|
238
|
+
inner_framing=framing_spec_from_kind(control.get("framing")),
|
|
239
|
+
)
|
|
240
|
+
control["framing"] = framing_spec_kind(control_framing)
|
|
241
|
+
control["framing_spec"] = framing_spec_name(control_framing)
|
|
242
|
+
stream_rows = []
|
|
243
|
+
datagram_rows = []
|
|
244
|
+
names: list[str] = []
|
|
245
|
+
for stream in streams:
|
|
246
|
+
row = _lane_mapping(stream)
|
|
247
|
+
name = str(row.get("name") or "")
|
|
248
|
+
if not name:
|
|
249
|
+
raise _unsupported("webtransport streams require name")
|
|
250
|
+
names.append(name)
|
|
251
|
+
lane_kind = str(row.get("kind") or "")
|
|
252
|
+
stream_framing = validate_webtransport_inner_framing(
|
|
253
|
+
lane=lane_kind,
|
|
254
|
+
inner_framing=framing_spec_from_kind(row.get("framing")),
|
|
255
|
+
)
|
|
256
|
+
row["framing"] = framing_spec_kind(stream_framing)
|
|
257
|
+
row["framing_spec"] = framing_spec_name(stream_framing)
|
|
258
|
+
stream_rows.append(row)
|
|
259
|
+
for datagram in datagrams:
|
|
260
|
+
row = _lane_mapping(datagram)
|
|
261
|
+
name = str(row.get("name") or "")
|
|
262
|
+
if not name:
|
|
263
|
+
raise _unsupported("webtransport datagrams require name")
|
|
264
|
+
names.append(name)
|
|
265
|
+
datagram_framing = validate_webtransport_inner_framing(
|
|
266
|
+
lane="datagram",
|
|
267
|
+
inner_framing=framing_spec_from_kind(row.get("framing")),
|
|
268
|
+
)
|
|
269
|
+
row["framing"] = framing_spec_kind(datagram_framing)
|
|
270
|
+
row["framing_spec"] = framing_spec_name(datagram_framing)
|
|
271
|
+
datagram_rows.append(row)
|
|
272
|
+
if len(set(names)) != len(names):
|
|
273
|
+
raise _unsupported("webtransport lane names must be unique")
|
|
274
|
+
family = "session"
|
|
275
|
+
lane = "session"
|
|
276
|
+
inner_framing = None
|
|
277
|
+
framing = ""
|
|
172
278
|
anchors = (
|
|
173
279
|
"transport.accept",
|
|
174
280
|
"dispatch.subevent.derive",
|
|
@@ -179,68 +285,107 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
|
|
|
179
285
|
{"family": "session", "subevent": "session.open"},
|
|
180
286
|
{"family": "session", "subevent": "session.close"},
|
|
181
287
|
)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
"
|
|
185
|
-
"
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
"
|
|
191
|
-
"transport.close",
|
|
192
|
-
)
|
|
193
|
-
rows = (
|
|
194
|
-
{"family": "stream", "subevent": "stream.open"},
|
|
195
|
-
{"family": "stream", "subevent": "stream.chunk.received"},
|
|
196
|
-
{"family": "stream", "subevent": "stream.chunk.emit"},
|
|
197
|
-
{"family": "stream", "subevent": "stream.close"},
|
|
198
|
-
)
|
|
199
|
-
elif lane == "unidi_client_stream":
|
|
200
|
-
anchors = (
|
|
201
|
-
"transport.accept",
|
|
202
|
-
"transport.receive",
|
|
203
|
-
"framing.decode",
|
|
204
|
-
"dispatch.subevent.derive",
|
|
205
|
-
"handler.invoke",
|
|
206
|
-
"transport.close",
|
|
207
|
-
)
|
|
208
|
-
rows = (
|
|
209
|
-
{"family": "stream", "subevent": "stream.open"},
|
|
210
|
-
{"family": "stream", "subevent": "stream.chunk.received"},
|
|
211
|
-
{"family": "stream", "subevent": "stream.close"},
|
|
212
|
-
)
|
|
213
|
-
elif lane == "unidi_server_stream":
|
|
214
|
-
anchors = (
|
|
215
|
-
"transport.accept",
|
|
216
|
-
"handler.invoke",
|
|
217
|
-
"framing.encode",
|
|
218
|
-
"transport.emit",
|
|
219
|
-
"transport.close",
|
|
220
|
-
)
|
|
221
|
-
rows = (
|
|
222
|
-
{"family": "stream", "subevent": "stream.open"},
|
|
223
|
-
{"family": "stream", "subevent": "stream.chunk.emit"},
|
|
224
|
-
{"family": "stream", "subevent": "stream.emit_complete"},
|
|
225
|
-
{"family": "stream", "subevent": "stream.close"},
|
|
288
|
+
lane_catalog = {
|
|
289
|
+
"control_stream": control,
|
|
290
|
+
"streams": tuple(stream_rows),
|
|
291
|
+
"datagrams": tuple(datagram_rows),
|
|
292
|
+
}
|
|
293
|
+
else:
|
|
294
|
+
lane_catalog = None
|
|
295
|
+
lane = webtransport_lane_for_profile(
|
|
296
|
+
_binding_get(binding, "lane") or _binding_get(binding, "profile") or "webtransport"
|
|
226
297
|
)
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
"
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
298
|
+
validate_webtransport_lane_exchange(
|
|
299
|
+
lane=lane,
|
|
300
|
+
exchange=str(_binding_get(binding, "exchange") or {
|
|
301
|
+
"session": "bidirectional_stream",
|
|
302
|
+
"bidi_stream": "bidirectional_stream",
|
|
303
|
+
"unidi_client_stream": "client_stream",
|
|
304
|
+
"unidi_server_stream": "server_stream",
|
|
305
|
+
"datagram": "bidirectional_stream",
|
|
306
|
+
}[lane]),
|
|
236
307
|
)
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
{"family": "datagram", "subevent": "datagram.emit_complete"},
|
|
308
|
+
inner_framing = validate_webtransport_inner_framing(
|
|
309
|
+
lane=lane,
|
|
310
|
+
inner_framing=framing_spec_from_kind(_binding_get(binding, "inner_framing")),
|
|
241
311
|
)
|
|
242
|
-
|
|
243
|
-
|
|
312
|
+
family = webtransport_runtime_family(lane)
|
|
313
|
+
framing = framing_spec_kind(inner_framing)
|
|
314
|
+
framing_kind = framing
|
|
315
|
+
framing_spec = framing_spec_name(inner_framing)
|
|
316
|
+
if lane == "session":
|
|
317
|
+
anchors = (
|
|
318
|
+
"transport.accept",
|
|
319
|
+
"dispatch.subevent.derive",
|
|
320
|
+
"handler.invoke",
|
|
321
|
+
"transport.close",
|
|
322
|
+
)
|
|
323
|
+
rows = (
|
|
324
|
+
{"family": "session", "subevent": "session.open"},
|
|
325
|
+
{"family": "session", "subevent": "session.close"},
|
|
326
|
+
)
|
|
327
|
+
elif lane == "bidi_stream":
|
|
328
|
+
anchors = (
|
|
329
|
+
"transport.accept",
|
|
330
|
+
"transport.receive",
|
|
331
|
+
"framing.decode",
|
|
332
|
+
"dispatch.subevent.derive",
|
|
333
|
+
"handler.invoke",
|
|
334
|
+
"framing.encode",
|
|
335
|
+
"transport.emit",
|
|
336
|
+
"transport.close",
|
|
337
|
+
)
|
|
338
|
+
rows = (
|
|
339
|
+
{"family": "stream", "subevent": "stream.open"},
|
|
340
|
+
{"family": "stream", "subevent": "stream.chunk.received"},
|
|
341
|
+
{"family": "stream", "subevent": "stream.chunk.emit"},
|
|
342
|
+
{"family": "stream", "subevent": "stream.close"},
|
|
343
|
+
)
|
|
344
|
+
elif lane == "unidi_client_stream":
|
|
345
|
+
anchors = (
|
|
346
|
+
"transport.accept",
|
|
347
|
+
"transport.receive",
|
|
348
|
+
"framing.decode",
|
|
349
|
+
"dispatch.subevent.derive",
|
|
350
|
+
"handler.invoke",
|
|
351
|
+
"transport.close",
|
|
352
|
+
)
|
|
353
|
+
rows = (
|
|
354
|
+
{"family": "stream", "subevent": "stream.open"},
|
|
355
|
+
{"family": "stream", "subevent": "stream.chunk.received"},
|
|
356
|
+
{"family": "stream", "subevent": "stream.close"},
|
|
357
|
+
)
|
|
358
|
+
elif lane == "unidi_server_stream":
|
|
359
|
+
anchors = (
|
|
360
|
+
"transport.accept",
|
|
361
|
+
"handler.invoke",
|
|
362
|
+
"framing.encode",
|
|
363
|
+
"transport.emit",
|
|
364
|
+
"transport.close",
|
|
365
|
+
)
|
|
366
|
+
rows = (
|
|
367
|
+
{"family": "stream", "subevent": "stream.open"},
|
|
368
|
+
{"family": "stream", "subevent": "stream.chunk.emit"},
|
|
369
|
+
{"family": "stream", "subevent": "stream.emit_complete"},
|
|
370
|
+
{"family": "stream", "subevent": "stream.close"},
|
|
371
|
+
)
|
|
372
|
+
elif lane == "datagram":
|
|
373
|
+
anchors = (
|
|
374
|
+
"transport.accept",
|
|
375
|
+
"transport.receive",
|
|
376
|
+
"framing.decode",
|
|
377
|
+
"dispatch.subevent.derive",
|
|
378
|
+
"handler.invoke",
|
|
379
|
+
"framing.encode",
|
|
380
|
+
"transport.emit",
|
|
381
|
+
)
|
|
382
|
+
rows = (
|
|
383
|
+
{"family": "datagram", "subevent": "datagram.received"},
|
|
384
|
+
{"family": "datagram", "subevent": "datagram.emit"},
|
|
385
|
+
{"family": "datagram", "subevent": "datagram.emit_complete"},
|
|
386
|
+
)
|
|
387
|
+
else: # pragma: no cover - guarded by webtransport_lane_for_profile
|
|
388
|
+
raise _unsupported(f"webtransport lane {lane}")
|
|
244
389
|
else:
|
|
245
390
|
raise _unsupported(kind)
|
|
246
391
|
|
|
@@ -249,10 +394,21 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
|
|
|
249
394
|
"binding": kind,
|
|
250
395
|
"framing": framing,
|
|
251
396
|
}
|
|
397
|
+
if subprotocols:
|
|
398
|
+
event_key_inputs["subprotocols"] = subprotocols
|
|
399
|
+
if kind in {"http.jsonrpc", "https.jsonrpc"}:
|
|
400
|
+
event_key_inputs["path"] = rpc_path
|
|
401
|
+
event_key_inputs["method"] = rpc_method
|
|
402
|
+
if kind in {"ws", "wss", "websocket"} and websocket_subprotocol is not None:
|
|
403
|
+
event_key_inputs["websocket_subprotocol"] = websocket_subprotocol
|
|
252
404
|
if kind == "webtransport":
|
|
253
405
|
event_key_inputs["lane"] = lane
|
|
254
|
-
|
|
255
|
-
|
|
406
|
+
if lane_catalog is not None:
|
|
407
|
+
event_key_inputs["lane_catalog"] = lane_catalog
|
|
408
|
+
else:
|
|
409
|
+
event_key_inputs["inner_framing"] = framing_spec_kind(inner_framing)
|
|
410
|
+
event_key_inputs["inner_framing_spec"] = framing_spec_name(inner_framing)
|
|
411
|
+
resume_policy = compile_resume_policy(kind, binding if isinstance(binding, Mapping) else {})
|
|
256
412
|
if resume_policy.enabled:
|
|
257
413
|
event_key_inputs["resume_mode"] = resume_policy.mode
|
|
258
414
|
|
|
@@ -261,6 +417,8 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
|
|
|
261
417
|
"binding_kind": kind,
|
|
262
418
|
"family": family,
|
|
263
419
|
"framing": framing,
|
|
420
|
+
"framing_kind": framing_kind or str(framing),
|
|
421
|
+
"framing_spec": framing_spec,
|
|
264
422
|
"atom_anchors": anchors,
|
|
265
423
|
"event_key_inputs": event_key_inputs,
|
|
266
424
|
"capability_requirements": {
|
|
@@ -268,6 +426,20 @@ def compile_binding_protocol_plan(op_id: str, binding: Mapping[str, Any]) -> dic
|
|
|
268
426
|
},
|
|
269
427
|
"lifecycle_rows": rows,
|
|
270
428
|
}
|
|
429
|
+
if subprotocols:
|
|
430
|
+
plan["subprotocols"] = subprotocols
|
|
431
|
+
if kind in {"http.jsonrpc", "https.jsonrpc"}:
|
|
432
|
+
plan["path"] = rpc_path
|
|
433
|
+
plan["method"] = rpc_method
|
|
434
|
+
if kind in {"ws", "wss", "websocket"} and websocket_subprotocol is not None:
|
|
435
|
+
plan["websocket_subprotocol"] = websocket_subprotocol
|
|
436
|
+
if kind == "webtransport":
|
|
437
|
+
if lane_catalog is not None:
|
|
438
|
+
plan["lane_catalog"] = lane_catalog
|
|
439
|
+
else:
|
|
440
|
+
plan["inner_framing"] = framing_spec_kind(inner_framing)
|
|
441
|
+
plan["inner_framing_kind"] = framing_spec_kind(inner_framing)
|
|
442
|
+
plan["inner_framing_spec"] = framing_spec_name(inner_framing)
|
|
271
443
|
if resume_policy.enabled:
|
|
272
444
|
plan["resume_policy"] = resume_policy.as_dict()
|
|
273
445
|
return plan
|
tigrbl_kernel/types.py
CHANGED
|
@@ -41,6 +41,10 @@ EFFECT_BY_ATOM_NAME = {
|
|
|
41
41
|
"sys.handler_append_chunk": EFFECT_WIRE,
|
|
42
42
|
"sys.handler_send_datagram": EFFECT_WIRE,
|
|
43
43
|
"sys.handler_checkpoint": EFFECT_WIRE,
|
|
44
|
+
"sys.handler_open_bidi_stream": EFFECT_WIRE,
|
|
45
|
+
"sys.handler_open_unidi_stream": EFFECT_WIRE,
|
|
46
|
+
"sys.handler_close_stream": EFFECT_WIRE,
|
|
47
|
+
"sys.handler_close_session": EFFECT_WIRE,
|
|
44
48
|
"egress.to_transport_response": EFFECT_WIRE,
|
|
45
49
|
"egress.asgi_send": EFFECT_WIRE,
|
|
46
50
|
}
|
tigrbl_kernel/utils.py
CHANGED
|
@@ -161,8 +161,8 @@ def _route_payload_template() -> dict[str, Any]:
|
|
|
161
161
|
return {
|
|
162
162
|
"http.rest": {"exact": {}, "templated": []},
|
|
163
163
|
"https.rest": {"exact": {}, "templated": []},
|
|
164
|
-
"http.jsonrpc": {"endpoints": {}},
|
|
165
|
-
"https.jsonrpc": {"endpoints": {}},
|
|
164
|
+
"http.jsonrpc": {"paths": {}, "endpoints": {}},
|
|
165
|
+
"https.jsonrpc": {"paths": {}, "endpoints": {}},
|
|
166
166
|
"ws": {"exact": {}, "templated": []},
|
|
167
167
|
"wss": {"exact": {}, "templated": []},
|
|
168
168
|
}
|
|
@@ -3,7 +3,10 @@ from __future__ import annotations
|
|
|
3
3
|
from collections.abc import Sequence
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
-
from tigrbl_core._spec.binding_spec import
|
|
6
|
+
from tigrbl_core._spec.binding_spec import (
|
|
7
|
+
framing_spec_from_kind,
|
|
8
|
+
validate_webtransport_inner_framing,
|
|
9
|
+
)
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
def _event(subevent: str, atom: str, family: str) -> dict[str, str]:
|
|
@@ -194,7 +197,7 @@ def _validate_stream_payload(
|
|
|
194
197
|
raise ValueError("client_to_server unidirectional streams cannot be send events")
|
|
195
198
|
validate_webtransport_inner_framing(
|
|
196
199
|
lane=lane,
|
|
197
|
-
inner_framing=payload.get("framing"),
|
|
200
|
+
inner_framing=framing_spec_from_kind(payload.get("framing")),
|
|
198
201
|
)
|
|
199
202
|
projection = {
|
|
200
203
|
"family": "stream",
|
|
@@ -228,7 +231,7 @@ def _validate_datagram_payload(
|
|
|
228
231
|
_forbid(payload, "stream_id", "stream_direction", "stream_initiator", "lane_id")
|
|
229
232
|
validate_webtransport_inner_framing(
|
|
230
233
|
lane="datagram",
|
|
231
|
-
inner_framing=payload.get("framing"),
|
|
234
|
+
inner_framing=framing_spec_from_kind(payload.get("framing")),
|
|
232
235
|
)
|
|
233
236
|
return {"family": "datagram", "lane": "datagram", "exchange": "bidirectional_stream"}
|
|
234
237
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tigrbl-kernel
|
|
3
|
-
Version: 0.4.4.
|
|
3
|
+
Version: 0.4.4.dev7
|
|
4
4
|
Summary: Kernel orchestration for composing Tigrbl runtime plans, bindings, operation dispatch, and optimized ASGI execution.
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -318,7 +318,6 @@ Package catalog:
|
|
|
318
318
|
- `tigrbl_kernel/protocol_bindings.py`, `tigrbl_kernel/protocol_phase_tree.py`, `tigrbl_kernel/protocol_chains/`, `tigrbl_kernel/protocol_completion.py`, `tigrbl_kernel/protocol_fusion.py`, and `tigrbl_kernel/protocol_legality_matrix.py`: transport-specific plan compilation, phase tree construction, chain definitions, completion semantics, fusion, and legality checks.
|
|
319
319
|
- `tigrbl_kernel/eventkey.py`, `tigrbl_kernel/events.py`, `tigrbl_kernel/transport_events.py`, `tigrbl_kernel/webtransport_events.py`, `tigrbl_kernel/subevent_taxonomy.py`, and `tigrbl_kernel/subevent_handlers.py`: event-key construction, subevent taxonomy, and protocol subevent handler mapping.
|
|
320
320
|
- `tigrbl_kernel/opchannel_capabilities.py`, `tigrbl_kernel/loop_modes.py`, `tigrbl_kernel/loop_regions.py`, `tigrbl_kernel/segment_fusion.py`, and `tigrbl_kernel/contract_classification.py`: channel capability checks, loop planning, segment grouping, and contract classification.
|
|
321
|
-
- `tigrbl_kernel/rust_plan.py`, `tigrbl_kernel/rust_compile.py`, and `tigrbl_kernel/rust_spec.py`: deprecated compatibility shims; kernel planning is Python-only.
|
|
322
321
|
|
|
323
322
|
## Public API and Import Surface
|
|
324
323
|
|
|
@@ -354,9 +353,9 @@ Protocol planning keeps binding kind, family, framing, exchange, lane, subevent
|
|
|
354
353
|
| `http.stream` / `https.stream` | stream | stream | handler invoke, transport emit, stream close. |
|
|
355
354
|
| `http.sse` / `https.sse` | stream | SSE | encode event, emit event, close stream. |
|
|
356
355
|
| `ws` / `wss` / `websocket` | message | text or negotiated JSON-RPC | accept, decode, dispatch, handler, emit/close. |
|
|
357
|
-
| `webtransport` | session, stream, or datagram |
|
|
356
|
+
| `webtransport` | session, stream, or datagram | no top-level app framing | lane-specific session, stream, or datagram rows with lane-local framing validation. |
|
|
358
357
|
|
|
359
|
-
Unsupported or ambiguous bindings raise planning errors. For example, WebSocket bindings do not accept HTTP methods, HTTP JSON-RPC requires an RPC method, WebTransport request/response exchange is unsupported, and WebTransport
|
|
358
|
+
Unsupported or ambiguous bindings raise planning errors. For example, WebSocket bindings do not accept HTTP methods, HTTP JSON-RPC requires an RPC method, WebTransport request/response exchange is unsupported, and WebTransport app framing must be declared on the relevant control stream, stream, or datagram lane.
|
|
360
359
|
|
|
361
360
|
## Hook Ordering and Labels
|
|
362
361
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
tigrbl_kernel/__init__.py,sha256=fE63Iyq2XrWqFTsvSC28iomE5nW6HsDUOEoQQtPNZ0I,2233
|
|
2
2
|
tigrbl_kernel/_build.py,sha256=kHaS9k4cD5hg1eRj8aQnbPbUkTbOM8npE_yeOsiwUK8,50397
|
|
3
|
-
tigrbl_kernel/_compile.py,sha256=
|
|
3
|
+
tigrbl_kernel/_compile.py,sha256=g1_TP-wMp-O2qLjWkBupXHJ_cAFjeoldXl9L2hDF_gw,15248
|
|
4
4
|
tigrbl_kernel/atoms.py,sha256=ZNGj2PBUMu1BvPjNYlz4_vu4vhx4gD20C7zNE_GKfe8,12253
|
|
5
5
|
tigrbl_kernel/cache.py,sha256=NxuqvH03xYwcQoY86ie1hmtDeA36XdiLmNyx2ImLQ6k,2596
|
|
6
6
|
tigrbl_kernel/callbacks.py,sha256=r_ZI19nbAoDM-uf-FMUmWWAF9WaEKJK3Fpg-58ui8a4,772
|
|
7
7
|
tigrbl_kernel/channel_taxonomy.py,sha256=x_cZHXz_Bw6NGaTK3YdZGUrzH1nBVAMlzViGKiv2K6s,4330
|
|
8
|
-
tigrbl_kernel/contract_classification.py,sha256=
|
|
9
|
-
tigrbl_kernel/core.py,sha256=
|
|
10
|
-
tigrbl_kernel/cross_transport.py,sha256=
|
|
8
|
+
tigrbl_kernel/contract_classification.py,sha256=Qfrn_aDPlCKvJGmAgdu0CuL-bZINW553TqD411rew4E,6132
|
|
9
|
+
tigrbl_kernel/core.py,sha256=7xa4zhMxth7MGzgXnxxnHumchVKcyYHBf5mWNfMk4_M,6518
|
|
10
|
+
tigrbl_kernel/cross_transport.py,sha256=24A4Hm-E6czX7o09EgwqL3WzGQtvifwnXMPB-ztZZzs,5354
|
|
11
11
|
tigrbl_kernel/dispatch_taxonomy.py,sha256=lj-_4hVKzrlPkavAlNqu7eImhjJn-7QoyccquQylCn0,1658
|
|
12
12
|
tigrbl_kernel/eventkey.py,sha256=aTwzBkAjeC-kaEUItL1Mcfcq_Ur1fUbZDY6XxKdwWdg,1980
|
|
13
13
|
tigrbl_kernel/eventkey_hooks.py,sha256=Cbkev0GXgSH27dlFoVeaKC7XuQ9yJq4bI1Mlc3qB4Qs,2480
|
|
@@ -26,8 +26,8 @@ tigrbl_kernel/ordering.py,sha256=C6fHkAwQA_1AY7sEAUy_FC5U3eFmsyqcls1li1qG5MA,135
|
|
|
26
26
|
tigrbl_kernel/packed_access.py,sha256=KhvAt-X4_bsowYVQ47tWEIfQhpcvTmPG7BqzuEWF87U,3587
|
|
27
27
|
tigrbl_kernel/packed_selectors.py,sha256=ZgPvOTUsTSF_ZIpQHM3acQhdIbM0-c6lBW7WjdAROI4,8609
|
|
28
28
|
tigrbl_kernel/payload.py,sha256=eyHo-cAUXLWQQ9-xZVOl_rjFudA-djMZji9hoK-v9IE,2167
|
|
29
|
-
tigrbl_kernel/protocol_anchors.py,sha256=
|
|
30
|
-
tigrbl_kernel/protocol_bindings.py,sha256=
|
|
29
|
+
tigrbl_kernel/protocol_anchors.py,sha256=0jAXmSQ-OD3AGv7MM-2vF7hQmZtHG2bXwFM1ooi0Geg,863
|
|
30
|
+
tigrbl_kernel/protocol_bindings.py,sha256=oE50T0YIEDAPXqxpXnmSAmJWX_SbSPdXBL8FtFF7OgI,18760
|
|
31
31
|
tigrbl_kernel/protocol_chains/__init__.py,sha256=iSnOw5R4ahGypm59bQgPpsBwFXbPcnKPozjSfc9N6GQ,151
|
|
32
32
|
tigrbl_kernel/protocol_chains/http_stream.py,sha256=nop3qMn-zpS5yK9QjqrFA68e1lO-uOb0dWAZf5fPrBg,2427
|
|
33
33
|
tigrbl_kernel/protocol_chains/http_unary.py,sha256=7EABv0bUAJ5UI3TWP-S-8LtgwZJLj5pw-ZnZ_8qiD4g,1776
|
|
@@ -42,9 +42,6 @@ tigrbl_kernel/protocol_phase_tree.py,sha256=LhJdoKfQivKHSDu75KYoq1VoYYkbXaekuN32
|
|
|
42
42
|
tigrbl_kernel/protocol_streams.py,sha256=UUCNn3L5n9PkgSydI4LGzJXFAKT1D9GPPnq6-xbMnBI,17141
|
|
43
43
|
tigrbl_kernel/resume_policy.py,sha256=rHBySvRJKfJ4J2NCb1D49FAXUsSp9rpzg4ev7ewXrSk,2931
|
|
44
44
|
tigrbl_kernel/runtime_contracts.py,sha256=I13L8mWQyYeojll9U2IbPFqZlvcv3MpCU376iNO4RbA,8243
|
|
45
|
-
tigrbl_kernel/rust_compile.py,sha256=dB36g6w1PCh1sOubd7XKUaJlGyrFC4hr__4PfJfnZiE,608
|
|
46
|
-
tigrbl_kernel/rust_plan.py,sha256=N-YZ6oGRtIJKuxS5f7HwhTldrTnozLXWgfpOD2XDGjI,502
|
|
47
|
-
tigrbl_kernel/rust_spec.py,sha256=cMzlYsUwVcJLcIJAbX5gcCnRzhqrJZyeYb5whn_gIBU,853
|
|
48
45
|
tigrbl_kernel/segment_fusion.py,sha256=zbPNGd1eFJGFZHJxrfanaNMyrJjJw1aPRsl_jJfN4sM,1607
|
|
49
46
|
tigrbl_kernel/subevent_handlers.py,sha256=4j4780QjQiqY4qpRsyxrPh_znRK3SkLAFDN_x6eidwU,1779
|
|
50
47
|
tigrbl_kernel/subevent_taxonomy.py,sha256=67RJ7ZkfJMLfa7evzVfTlFqtdWSnhp65zwA4qhNwSG8,2274
|
|
@@ -52,11 +49,11 @@ tigrbl_kernel/trace.py,sha256=dWILtq9seOj-WwCx__Pk_VZAbFIN1tqTbs0gIndYkU8,9816
|
|
|
52
49
|
tigrbl_kernel/transaction_units.py,sha256=_NeQHycjjDoLG1kmD74o10wDQpdA5qjs-Sd_fxPb0_E,863
|
|
53
50
|
tigrbl_kernel/transport_atoms.py,sha256=enfNCMuLgLMKi8zraMm-QOk7ys5d9kcP-WPr0-wK6KE,2136
|
|
54
51
|
tigrbl_kernel/transport_events.py,sha256=CyPhs69H7mnKU7gNgt4XtH-eRJcihSaXxQDzC0iD4w4,3903
|
|
55
|
-
tigrbl_kernel/types.py,sha256=
|
|
56
|
-
tigrbl_kernel/utils.py,sha256=
|
|
57
|
-
tigrbl_kernel/webtransport_events.py,sha256=
|
|
58
|
-
tigrbl_kernel-0.4.4.
|
|
59
|
-
tigrbl_kernel-0.4.4.
|
|
60
|
-
tigrbl_kernel-0.4.4.
|
|
61
|
-
tigrbl_kernel-0.4.4.
|
|
62
|
-
tigrbl_kernel-0.4.4.
|
|
52
|
+
tigrbl_kernel/types.py,sha256=Pf2e6xvZAcxD_uJZ7inMETpmhNyz4YGT27YuWdSHZ-I,2431
|
|
53
|
+
tigrbl_kernel/utils.py,sha256=xf4lZAIH64DhpdHHyzPJ0LSAiUKWSaC5wIL1NJkHVro,6979
|
|
54
|
+
tigrbl_kernel/webtransport_events.py,sha256=SWADw4m2JsCHHvMfH7QcVPtjOZ0kfjiCwwoiLhCokmk,10820
|
|
55
|
+
tigrbl_kernel-0.4.4.dev7.dist-info/METADATA,sha256=ufyVRMae0iEnJ_drtCBaKup4uDaeZ0PuYxrRC8STmjc,27960
|
|
56
|
+
tigrbl_kernel-0.4.4.dev7.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
|
|
57
|
+
tigrbl_kernel-0.4.4.dev7.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
58
|
+
tigrbl_kernel-0.4.4.dev7.dist-info/licenses/NOTICE,sha256=EvJMTshzsWz43LiK-DeN2ZuLtrP49cxvlrFlJ8F_buc,221
|
|
59
|
+
tigrbl_kernel-0.4.4.dev7.dist-info/RECORD,,
|
tigrbl_kernel/rust_compile.py
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
from typing import Any
|
|
3
|
-
|
|
4
|
-
from .rust_plan import RustPlan
|
|
5
|
-
import warnings
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def _raise_deprecated(action: str) -> None:
|
|
9
|
-
warnings.warn(
|
|
10
|
-
"tigrbl_kernel Rust planning is deprecated; kernel planning is Python-only.",
|
|
11
|
-
DeprecationWarning,
|
|
12
|
-
stacklevel=3,
|
|
13
|
-
)
|
|
14
|
-
raise RuntimeError(f"{action} is unavailable; Tigrbl kernel planning is Python-only.")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def build_rust_kernel(app: Any) -> RustPlan:
|
|
18
|
-
del app
|
|
19
|
-
_raise_deprecated("build_rust_kernel")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def normalize_rust_spec(app: Any) -> str:
|
|
23
|
-
del app
|
|
24
|
-
_raise_deprecated("normalize_rust_spec")
|
tigrbl_kernel/rust_plan.py
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from typing import Any
|
|
5
|
-
import warnings
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@dataclass(slots=True)
|
|
9
|
-
class RustPlan:
|
|
10
|
-
description: str
|
|
11
|
-
compiled_plan: dict[str, Any] | None = None
|
|
12
|
-
backend: str = "deprecated-rust"
|
|
13
|
-
normalized_spec: str | None = None
|
|
14
|
-
|
|
15
|
-
def __post_init__(self) -> None:
|
|
16
|
-
warnings.warn(
|
|
17
|
-
"RustPlan is deprecated; Tigrbl kernel planning is Python-only.",
|
|
18
|
-
DeprecationWarning,
|
|
19
|
-
stacklevel=2,
|
|
20
|
-
)
|
tigrbl_kernel/rust_spec.py
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import warnings
|
|
4
|
-
from typing import Any, NoReturn
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def _raise_deprecated(action: str) -> NoReturn:
|
|
8
|
-
warnings.warn(
|
|
9
|
-
"tigrbl_kernel Rust spec serialization is deprecated; "
|
|
10
|
-
"Tigrbl runtime execution is Python-only.",
|
|
11
|
-
DeprecationWarning,
|
|
12
|
-
stacklevel=3,
|
|
13
|
-
)
|
|
14
|
-
raise RuntimeError(f"{action} is unavailable; Tigrbl runtime execution is Python-only.")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def build_rust_app_spec(app: Any) -> dict[str, Any]:
|
|
18
|
-
del app
|
|
19
|
-
_raise_deprecated("build_rust_app_spec")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def coerce_rust_spec_dict(app: Any) -> dict[str, Any]:
|
|
23
|
-
del app
|
|
24
|
-
_raise_deprecated("coerce_rust_spec_dict")
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def coerce_rust_spec_json(app: Any) -> str:
|
|
28
|
-
del app
|
|
29
|
-
_raise_deprecated("coerce_rust_spec_json")
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
__all__ = [
|
|
33
|
-
"build_rust_app_spec",
|
|
34
|
-
"coerce_rust_spec_dict",
|
|
35
|
-
"coerce_rust_spec_json",
|
|
36
|
-
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|