tigrbl-runtime 0.4.5.dev1__py3-none-any.whl → 0.4.5.dev6__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.
Files changed (28) hide show
  1. tigrbl_runtime/channel/_asgi_jsonrpc.py +11 -0
  2. tigrbl_runtime/channel/_asgi_send.py +79 -5
  3. tigrbl_runtime/channel/_asgi_webtransport.py +31 -4
  4. tigrbl_runtime/executors/ctx/context.py +1 -5
  5. tigrbl_runtime/executors/ctx/hot_namespace_values.py +200 -0
  6. tigrbl_runtime/executors/ctx/hot_namespaces.py +6 -187
  7. tigrbl_runtime/executors/packed/__init__.py +4 -0
  8. tigrbl_runtime/executors/packed/_shared.py +168 -0
  9. tigrbl_runtime/executors/packed/batch.py +337 -0
  10. tigrbl_runtime/executors/packed/error_edges.py +303 -0
  11. tigrbl_runtime/executors/packed/execute.py +368 -0
  12. tigrbl_runtime/executors/packed/executor.py +86 -0
  13. tigrbl_runtime/executors/packed/hot_access.py +222 -0
  14. tigrbl_runtime/executors/packed/hot_context.py +301 -0
  15. tigrbl_runtime/executors/packed/input_compile.py +336 -0
  16. tigrbl_runtime/executors/packed/input_extract.py +310 -0
  17. tigrbl_runtime/executors/packed/request_select.py +209 -0
  18. tigrbl_runtime/executors/packed/route_select.py +397 -0
  19. tigrbl_runtime/executors/packed/route_select_websocket.py +34 -0
  20. tigrbl_runtime/executors/packed/runner_resolve.py +379 -0
  21. tigrbl_runtime/executors/packed/segments.py +337 -0
  22. tigrbl_runtime/lowering_services.py +22 -0
  23. {tigrbl_runtime-0.4.5.dev1.dist-info → tigrbl_runtime-0.4.5.dev6.dist-info}/METADATA +21 -16
  24. {tigrbl_runtime-0.4.5.dev1.dist-info → tigrbl_runtime-0.4.5.dev6.dist-info}/RECORD +27 -11
  25. {tigrbl_runtime-0.4.5.dev1.dist-info → tigrbl_runtime-0.4.5.dev6.dist-info}/WHEEL +1 -1
  26. tigrbl_runtime/executors/packed.py +0 -3591
  27. {tigrbl_runtime-0.4.5.dev1.dist-info → tigrbl_runtime-0.4.5.dev6.dist-info}/licenses/LICENSE +0 -0
  28. {tigrbl_runtime-0.4.5.dev1.dist-info → tigrbl_runtime-0.4.5.dev6.dist-info}/licenses/NOTICE +0 -0
@@ -36,3 +36,14 @@ def _resolve_jsonrpc_endpoint(ctx: Any, channel: OpChannel) -> str | None:
36
36
  if path == _normalize_path(mapped_path):
37
37
  return endpoint
38
38
  return None
39
+
40
+
41
+ _NO_ERROR_DATA = object()
42
+
43
+
44
+ def _jsonrpc_error_payload(code: int, message: str, request_id: Any, *, data: Any = _NO_ERROR_DATA) -> dict[str, Any]:
45
+ """Construct the existing compatibility error envelope without choosing policy."""
46
+ error: dict[str, Any] = {"code": code, "message": message}
47
+ if data is not _NO_ERROR_DATA:
48
+ error["data"] = data
49
+ return {"jsonrpc": "2.0", "error": error, "id": request_id}
@@ -19,6 +19,52 @@ from ._asgi_webtransport import (
19
19
  )
20
20
 
21
21
 
22
+ def _webtransport_event_projection(ctx: Any) -> Mapping[str, Any]:
23
+ projection = ctx.get("channel_event_projection")
24
+ if isinstance(projection, Mapping):
25
+ return projection
26
+ channel = ctx.get("channel")
27
+ state = getattr(channel, "state", None) if channel is not None else None
28
+ if isinstance(state, dict):
29
+ projection = state.get("event_projection")
30
+ if isinstance(projection, Mapping):
31
+ return projection
32
+ return {}
33
+
34
+
35
+ def _is_receive_only_webtransport_stream(ctx: Any) -> bool:
36
+ projection = _webtransport_event_projection(ctx)
37
+ if (
38
+ projection.get("lane") == "unidi_client_stream"
39
+ or projection.get("exchange") == "client_stream"
40
+ ):
41
+ return True
42
+ message = ctx.get("channel_message")
43
+ return bool(
44
+ isinstance(message, Mapping)
45
+ and message.get("type") == "webtransport.stream.receive"
46
+ and message.get("stream_direction") == "client_to_server"
47
+ )
48
+
49
+
50
+ def _validate_receive_only_webtransport_output(payload: Any) -> None:
51
+ if payload is None:
52
+ return
53
+ if not isinstance(payload, Mapping) or not any(
54
+ key in payload
55
+ for key in ("bidirectional_streams", "unidirectional_streams", "datagrams")
56
+ ):
57
+ raise ValueError(
58
+ "cannot automatically reply on a client_to_server WebTransport stream; "
59
+ "return None or emit an explicit server_to_client stream or datagram"
60
+ )
61
+ if payload.get("bidirectional_streams"):
62
+ raise ValueError(
63
+ "bidirectional_streams output is invalid for a client_to_server "
64
+ "WebTransport stream; use unidirectional_streams or datagrams"
65
+ )
66
+
67
+
22
68
  async def _send_session_payload(
23
69
  env: Any,
24
70
  payload: Any,
@@ -87,11 +133,15 @@ async def _send_webtransport_payload(env: Any, ctx: Any, payload: Any) -> None:
87
133
  for key in ("bidirectional_streams", "unidirectional_streams", "datagrams")
88
134
  )
89
135
  if structured_payload:
90
- if not queue and message_type in {
91
- "webtransport.stream.receive",
92
- "webtransport.datagram.receive",
93
- }:
94
- queue = [message]
136
+ if (
137
+ message_type
138
+ in {
139
+ "webtransport.stream.receive",
140
+ "webtransport.datagram.receive",
141
+ }
142
+ and message not in queue
143
+ ):
144
+ queue.append(message)
95
145
  if not queue:
96
146
  raise ValueError(
97
147
  "structured WebTransport payloads require inbound stream.receive or datagram.receive events"
@@ -125,6 +175,12 @@ async def _send_webtransport_payload(env: Any, ctx: Any, payload: Any) -> None:
125
175
  )
126
176
  if payload is not None:
127
177
  base = {**message, "session_id": session_id}
178
+ temp = getattr(ctx, "temp", None)
179
+ dispatch = temp.get("dispatch") if isinstance(temp, Mapping) else None
180
+ if isinstance(dispatch, Mapping):
181
+ request = dispatch.get("rpc") or dispatch.get("rpc_envelope")
182
+ if isinstance(request, Mapping) and request.get("id") is not None:
183
+ base["jsonrpc_request_id"] = request.get("id")
128
184
  if structured_payload:
129
185
  for event in _webtransport_structured_payload_events(
130
186
  session_id=session_id,
@@ -151,6 +207,14 @@ async def _send_webtransport_payload(env: Any, ctx: Any, payload: Any) -> None:
151
207
  )
152
208
  await _run_webtransport_hooks(env, ctx, direction="send", message=event)
153
209
  await send(event)
210
+ if isinstance(state, dict):
211
+ raw_queue = state.get("receive_queue")
212
+ consumed = min(len(queue), len(raw_queue or ()))
213
+ if isinstance(raw_queue, deque):
214
+ for _ in range(consumed):
215
+ raw_queue.popleft()
216
+ elif isinstance(raw_queue, list):
217
+ del raw_queue[:consumed]
154
218
  else:
155
219
  event = _webtransport_payload_event(base=base, payload=payload)
156
220
  if isinstance(session, WebTransportSessionState):
@@ -222,6 +286,16 @@ async def send_transport_via_channel(env: Any, ctx: Any) -> None:
222
286
  if payload is None:
223
287
  payload = getattr(ctx, "result", None)
224
288
  if scope_type == "webtransport":
289
+ if _is_receive_only_webtransport_stream(ctx):
290
+ _validate_receive_only_webtransport_output(payload)
291
+ if payload is None:
292
+ if isinstance(state, dict):
293
+ state["egress_disposition"] = "suppressed_receive_only"
294
+ state["emitted"] = False
295
+ if isinstance(egress, dict):
296
+ egress["response_suppressed"] = True
297
+ egress["suppression_reason"] = "receive_only_stream"
298
+ return
225
299
  await _send_webtransport_payload(env, ctx, payload)
226
300
  else:
227
301
  await _send_session_payload(
@@ -15,9 +15,12 @@ from tigrbl_kernel.channel_taxonomy import (
15
15
  webtransport_event_metadata as _webtransport_event_metadata,
16
16
  )
17
17
  from tigrbl_kernel.webtransport_events import validate_webtransport_event_payload
18
+ from tigrbl_kernel.webtransport_session_plan import WebTransportSessionPlan
18
19
  from tigrbl_atoms.runtime_channel import WebTransportSessionState
19
20
  from tigrbl_typing.channel import OpChannel
20
21
 
22
+ MAX_EAGER_DRAIN_EVENTS = 16
23
+
21
24
 
22
25
  def _webtransport_scope_state(env: Any) -> dict[str, Any]:
23
26
  scope = getattr(env, "scope", {}) or {}
@@ -242,6 +245,20 @@ async def _receive_webtransport_session_messages(
242
245
  queue: deque[Mapping[str, Any]] = deque()
243
246
  session: WebTransportSessionState | None = None
244
247
 
248
+ session_plan = shared_state.get("session_plan")
249
+ if not isinstance(session_plan, WebTransportSessionPlan):
250
+ session_plan = WebTransportSessionPlan()
251
+ shared_state["session_plan"] = session_plan
252
+
253
+ async def _receive_record_or_event() -> Mapping[str, Any]:
254
+ if session_plan.has_pending():
255
+ return session_plan.pop_pending()
256
+ while True:
257
+ raw = _enrich_webtransport_message(env, await receive())
258
+ session_plan.project_receive(raw)
259
+ if session_plan.has_pending():
260
+ return session_plan.pop_pending()
261
+
245
262
  def _ensure_session(message: Mapping[str, Any]) -> WebTransportSessionState | None:
246
263
  nonlocal session
247
264
  session_id = message.get("session_id") or _webtransport_scope_session_id(env)
@@ -292,6 +309,8 @@ async def _receive_webtransport_session_messages(
292
309
  channel="receive",
293
310
  payload={**message, "session_id": state.get("session_id")},
294
311
  )
312
+ state["event_projection"] = dict(projection)
313
+ ctx["channel_event_projection"] = dict(projection)
295
314
  if current_session is not None:
296
315
  current_session.apply_event(
297
316
  event=message_type,
@@ -334,18 +353,26 @@ async def _receive_webtransport_session_messages(
334
353
  return
335
354
  ctx["channel_message"] = message
336
355
 
337
- message = await receive()
356
+ message = await _receive_record_or_event()
338
357
  await _record_payload_message(message)
339
358
  if message.get("type") == "webtransport.connect":
340
359
  if "channel_message" not in ctx:
341
- message = await receive()
360
+ message = await _receive_record_or_event()
342
361
  await _record_payload_message(message)
343
362
 
344
- while shared_state.get("eager_drain") is True and not state.get("disconnected"):
363
+ drained_events = 0
364
+ while (
365
+ shared_state.get("eager_drain") is True
366
+ and not state.get("disconnected")
367
+ and drained_events < MAX_EAGER_DRAIN_EVENTS
368
+ ):
345
369
  try:
346
- message = await asyncio.wait_for(receive(), timeout=0.001)
370
+ message = await asyncio.wait_for(
371
+ _receive_record_or_event(), timeout=0.001
372
+ )
347
373
  except TimeoutError:
348
374
  break
349
375
  await _record_payload_message(message)
376
+ drained_events += 1
350
377
 
351
378
  state["receive_queue"] = queue
@@ -16,11 +16,7 @@ from typing import (
16
16
  runtime_checkable,
17
17
  )
18
18
 
19
- try:
20
- from sqlalchemy.ext.asyncio import AsyncSession
21
- from sqlalchemy.orm import Session
22
- except Exception: # pragma: no cover - optional ORM dependency for runtime typing
23
- AsyncSession = Session = Any # type: ignore[assignment]
19
+ AsyncSession = Session = Any # type: ignore[assignment]
24
20
 
25
21
  from tigrbl_atoms.types import BaseCtx
26
22
  from tigrbl_base._base import AttrDict
@@ -0,0 +1,200 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping as ABCMapping
4
+ from typing import Any, Mapping
5
+
6
+ from .hot_state import (
7
+ HotCtx,
8
+ _ensure_hot_assembled_values_view,
9
+ _ensure_hot_in_values_view,
10
+ _ensure_hot_virtual_in_view,
11
+ _LAZY_MISSING,
12
+ )
13
+
14
+
15
+ def _coerce_optional_dict(value: Any) -> dict[str, Any] | None:
16
+ if isinstance(value, dict):
17
+ return value
18
+ if isinstance(value, ABCMapping):
19
+ return dict(value)
20
+ return None
21
+
22
+
23
+ def _namespace_lazy_value(kind: str, hot: HotCtx, key: str) -> Any:
24
+ if kind == "route":
25
+ if key == "selector":
26
+ value = hot.route_selector
27
+ return value if value else _LAZY_MISSING
28
+ if key == "protocol":
29
+ value = hot.route_protocol
30
+ return value if value else _LAZY_MISSING
31
+ if key == "program_id":
32
+ value = (
33
+ hot.route_program_id if hot.route_program_id >= 0 else hot.program_id
34
+ )
35
+ return value if value >= 0 else _LAZY_MISSING
36
+ if key == "opmeta_index":
37
+ value = (
38
+ hot.route_opmeta_index
39
+ if hot.route_opmeta_index >= 0
40
+ else hot.route_program_id
41
+ )
42
+ return value if value >= 0 else _LAZY_MISSING
43
+ if key == "method_not_allowed":
44
+ return True if hot.route_method_not_allowed else _LAZY_MISSING
45
+ if key == "short_circuit":
46
+ return True if hot.route_short_circuit else _LAZY_MISSING
47
+ if key == "payload":
48
+ if hot.route_payload is not None:
49
+ return hot.route_payload
50
+ value = _ensure_hot_in_values_view(hot)
51
+ return value if value is not None else _LAZY_MISSING
52
+ if key == "path_params":
53
+ value = hot.route_path_params or hot.path_params
54
+ return value if value is not None else _LAZY_MISSING
55
+ if key == "rpc_envelope":
56
+ value = hot.route_rpc_envelope or hot.dispatch_rpc_envelope
57
+ return value if value is not None else _LAZY_MISSING
58
+ return _LAZY_MISSING
59
+ if kind == "dispatch":
60
+ if key == "binding_protocol":
61
+ value = hot.dispatch_binding_protocol
62
+ return value if value else _LAZY_MISSING
63
+ if key == "binding_selector":
64
+ value = hot.dispatch_binding_selector
65
+ return value if value else _LAZY_MISSING
66
+ if key == "channel_protocol":
67
+ value = hot.dispatch_channel_protocol
68
+ return value if value else _LAZY_MISSING
69
+ if key == "channel_selector":
70
+ value = hot.dispatch_channel_selector
71
+ return value if value else _LAZY_MISSING
72
+ if key in {"normalized_input", "parsed_payload"}:
73
+ value = _ensure_hot_in_values_view(hot)
74
+ return value if value is not None else _LAZY_MISSING
75
+ if key == "rpc":
76
+ value = hot.dispatch_rpc_envelope or hot.route_rpc_envelope
77
+ return value if value is not None else _LAZY_MISSING
78
+ if key == "rpc_method":
79
+ value = hot.dispatch_rpc_method
80
+ return value if value is not None else _LAZY_MISSING
81
+ return _LAZY_MISSING
82
+ if kind == "egress":
83
+ if key == "transport_response":
84
+ value = hot.egress_transport_response
85
+ return value if value is not None else _LAZY_MISSING
86
+ if key == "sent":
87
+ return True if hot.egress_sent else _LAZY_MISSING
88
+ return _LAZY_MISSING
89
+ return _LAZY_MISSING
90
+
91
+
92
+ def _sync_hot_namespace_value(kind: str, hot: HotCtx, key: str, value: Any) -> None:
93
+ if kind == "route":
94
+ if key == "selector" and isinstance(value, str):
95
+ hot.route_selector = value
96
+ elif key == "protocol" and isinstance(value, str):
97
+ hot.route_protocol = value
98
+ elif key == "program_id" and isinstance(value, int):
99
+ hot.route_program_id = value
100
+ hot.program_id = value
101
+ elif key == "opmeta_index" and isinstance(value, int):
102
+ hot.route_opmeta_index = value
103
+ if hot.route_program_id < 0:
104
+ hot.route_program_id = value
105
+ if hot.program_id < 0:
106
+ hot.program_id = value
107
+ elif key == "method_not_allowed":
108
+ hot.route_method_not_allowed = bool(value)
109
+ elif key == "short_circuit":
110
+ hot.route_short_circuit = bool(value)
111
+ elif key == "payload":
112
+ hot.route_payload = _coerce_optional_dict(value)
113
+ elif key == "path_params":
114
+ path_params = _coerce_optional_dict(value)
115
+ hot.route_path_params = path_params
116
+ hot.path_params = path_params
117
+ elif key == "rpc_envelope":
118
+ envelope = _coerce_optional_dict(value)
119
+ hot.route_rpc_envelope = envelope
120
+ if envelope is not None:
121
+ hot.dispatch_jsonrpc_request_id = envelope.get("id")
122
+ method = envelope.get("method")
123
+ hot.dispatch_rpc_method = method if isinstance(method, str) else None
124
+ elif kind == "dispatch":
125
+ if key == "binding_protocol" and isinstance(value, str):
126
+ hot.dispatch_binding_protocol = value
127
+ elif key == "binding_selector" and isinstance(value, str):
128
+ hot.dispatch_binding_selector = value
129
+ elif key == "channel_protocol" and isinstance(value, str):
130
+ hot.dispatch_channel_protocol = value
131
+ elif key == "channel_selector" and isinstance(value, str):
132
+ hot.dispatch_channel_selector = value
133
+ elif key == "rpc":
134
+ envelope = _coerce_optional_dict(value)
135
+ hot.dispatch_rpc_envelope = envelope
136
+ if envelope is not None:
137
+ hot.dispatch_jsonrpc_request_id = envelope.get("id")
138
+ method = envelope.get("method")
139
+ hot.dispatch_rpc_method = method if isinstance(method, str) else None
140
+ elif key == "rpc_method":
141
+ hot.dispatch_rpc_method = value if isinstance(value, str) else None
142
+ elif key in {"normalized_input", "parsed_payload"}:
143
+ route_payload = _coerce_optional_dict(value)
144
+ if route_payload is not None:
145
+ hot.route_payload = route_payload
146
+ elif key == "jsonrpc_request_id":
147
+ hot.dispatch_jsonrpc_request_id = value
148
+ elif kind == "egress":
149
+ if key == "transport_response":
150
+ hot.egress_transport_response = _coerce_optional_dict(value)
151
+ elif key == "sent":
152
+ hot.egress_sent = bool(value)
153
+
154
+
155
+ def _clear_hot_namespace_value(kind: str, hot: HotCtx, key: str) -> None:
156
+ if kind == "route":
157
+ if key == "selector":
158
+ hot.route_selector = ""
159
+ elif key == "protocol":
160
+ hot.route_protocol = ""
161
+ elif key == "program_id":
162
+ hot.route_program_id = -1
163
+ elif key == "opmeta_index":
164
+ hot.route_opmeta_index = -1
165
+ elif key == "method_not_allowed":
166
+ hot.route_method_not_allowed = False
167
+ elif key == "short_circuit":
168
+ hot.route_short_circuit = False
169
+ elif key == "payload":
170
+ hot.route_payload = None
171
+ elif key == "path_params":
172
+ hot.route_path_params = None
173
+ hot.path_params = None
174
+ elif key == "rpc_envelope":
175
+ hot.route_rpc_envelope = None
176
+ hot.dispatch_jsonrpc_request_id = None
177
+ hot.dispatch_rpc_method = None
178
+ elif kind == "dispatch":
179
+ if key == "binding_protocol":
180
+ hot.dispatch_binding_protocol = ""
181
+ elif key == "binding_selector":
182
+ hot.dispatch_binding_selector = ""
183
+ elif key == "channel_protocol":
184
+ hot.dispatch_channel_protocol = ""
185
+ elif key == "channel_selector":
186
+ hot.dispatch_channel_selector = ""
187
+ elif key == "rpc":
188
+ hot.dispatch_rpc_envelope = None
189
+ hot.dispatch_jsonrpc_request_id = None
190
+ hot.dispatch_rpc_method = None
191
+ elif key == "rpc_method":
192
+ hot.dispatch_rpc_method = None
193
+ elif key == "jsonrpc_request_id":
194
+ hot.dispatch_jsonrpc_request_id = None
195
+ elif kind == "egress":
196
+ if key == "transport_response":
197
+ hot.egress_transport_response = None
198
+ elif key == "sent":
199
+ hot.egress_sent = False
200
+
@@ -10,193 +10,12 @@ from .hot_state import (
10
10
  _ensure_hot_virtual_in_view,
11
11
  _LAZY_MISSING,
12
12
  )
13
-
14
-
15
- def _coerce_optional_dict(value: Any) -> dict[str, Any] | None:
16
- if isinstance(value, dict):
17
- return value
18
- if isinstance(value, ABCMapping):
19
- return dict(value)
20
- return None
21
-
22
-
23
- def _namespace_lazy_value(kind: str, hot: HotCtx, key: str) -> Any:
24
- if kind == "route":
25
- if key == "selector":
26
- value = hot.route_selector
27
- return value if value else _LAZY_MISSING
28
- if key == "protocol":
29
- value = hot.route_protocol
30
- return value if value else _LAZY_MISSING
31
- if key == "program_id":
32
- value = (
33
- hot.route_program_id if hot.route_program_id >= 0 else hot.program_id
34
- )
35
- return value if value >= 0 else _LAZY_MISSING
36
- if key == "opmeta_index":
37
- value = (
38
- hot.route_opmeta_index
39
- if hot.route_opmeta_index >= 0
40
- else hot.route_program_id
41
- )
42
- return value if value >= 0 else _LAZY_MISSING
43
- if key == "method_not_allowed":
44
- return True if hot.route_method_not_allowed else _LAZY_MISSING
45
- if key == "short_circuit":
46
- return True if hot.route_short_circuit else _LAZY_MISSING
47
- if key == "payload":
48
- if hot.route_payload is not None:
49
- return hot.route_payload
50
- value = _ensure_hot_in_values_view(hot)
51
- return value if value is not None else _LAZY_MISSING
52
- if key == "path_params":
53
- value = hot.route_path_params or hot.path_params
54
- return value if value is not None else _LAZY_MISSING
55
- if key == "rpc_envelope":
56
- value = hot.route_rpc_envelope or hot.dispatch_rpc_envelope
57
- return value if value is not None else _LAZY_MISSING
58
- return _LAZY_MISSING
59
- if kind == "dispatch":
60
- if key == "binding_protocol":
61
- value = hot.dispatch_binding_protocol
62
- return value if value else _LAZY_MISSING
63
- if key == "binding_selector":
64
- value = hot.dispatch_binding_selector
65
- return value if value else _LAZY_MISSING
66
- if key == "channel_protocol":
67
- value = hot.dispatch_channel_protocol
68
- return value if value else _LAZY_MISSING
69
- if key == "channel_selector":
70
- value = hot.dispatch_channel_selector
71
- return value if value else _LAZY_MISSING
72
- if key in {"normalized_input", "parsed_payload"}:
73
- value = _ensure_hot_in_values_view(hot)
74
- return value if value is not None else _LAZY_MISSING
75
- if key == "rpc":
76
- value = hot.dispatch_rpc_envelope or hot.route_rpc_envelope
77
- return value if value is not None else _LAZY_MISSING
78
- if key == "rpc_method":
79
- value = hot.dispatch_rpc_method
80
- return value if value is not None else _LAZY_MISSING
81
- return _LAZY_MISSING
82
- if kind == "egress":
83
- if key == "transport_response":
84
- value = hot.egress_transport_response
85
- return value if value is not None else _LAZY_MISSING
86
- if key == "sent":
87
- return True if hot.egress_sent else _LAZY_MISSING
88
- return _LAZY_MISSING
89
- return _LAZY_MISSING
90
-
91
-
92
- def _sync_hot_namespace_value(kind: str, hot: HotCtx, key: str, value: Any) -> None:
93
- if kind == "route":
94
- if key == "selector" and isinstance(value, str):
95
- hot.route_selector = value
96
- elif key == "protocol" and isinstance(value, str):
97
- hot.route_protocol = value
98
- elif key == "program_id" and isinstance(value, int):
99
- hot.route_program_id = value
100
- hot.program_id = value
101
- elif key == "opmeta_index" and isinstance(value, int):
102
- hot.route_opmeta_index = value
103
- if hot.route_program_id < 0:
104
- hot.route_program_id = value
105
- if hot.program_id < 0:
106
- hot.program_id = value
107
- elif key == "method_not_allowed":
108
- hot.route_method_not_allowed = bool(value)
109
- elif key == "short_circuit":
110
- hot.route_short_circuit = bool(value)
111
- elif key == "payload":
112
- hot.route_payload = _coerce_optional_dict(value)
113
- elif key == "path_params":
114
- path_params = _coerce_optional_dict(value)
115
- hot.route_path_params = path_params
116
- hot.path_params = path_params
117
- elif key == "rpc_envelope":
118
- envelope = _coerce_optional_dict(value)
119
- hot.route_rpc_envelope = envelope
120
- if envelope is not None:
121
- hot.dispatch_jsonrpc_request_id = envelope.get("id")
122
- method = envelope.get("method")
123
- hot.dispatch_rpc_method = method if isinstance(method, str) else None
124
- elif kind == "dispatch":
125
- if key == "binding_protocol" and isinstance(value, str):
126
- hot.dispatch_binding_protocol = value
127
- elif key == "binding_selector" and isinstance(value, str):
128
- hot.dispatch_binding_selector = value
129
- elif key == "channel_protocol" and isinstance(value, str):
130
- hot.dispatch_channel_protocol = value
131
- elif key == "channel_selector" and isinstance(value, str):
132
- hot.dispatch_channel_selector = value
133
- elif key == "rpc":
134
- envelope = _coerce_optional_dict(value)
135
- hot.dispatch_rpc_envelope = envelope
136
- if envelope is not None:
137
- hot.dispatch_jsonrpc_request_id = envelope.get("id")
138
- method = envelope.get("method")
139
- hot.dispatch_rpc_method = method if isinstance(method, str) else None
140
- elif key == "rpc_method":
141
- hot.dispatch_rpc_method = value if isinstance(value, str) else None
142
- elif key in {"normalized_input", "parsed_payload"}:
143
- route_payload = _coerce_optional_dict(value)
144
- if route_payload is not None:
145
- hot.route_payload = route_payload
146
- elif key == "jsonrpc_request_id":
147
- hot.dispatch_jsonrpc_request_id = value
148
- elif kind == "egress":
149
- if key == "transport_response":
150
- hot.egress_transport_response = _coerce_optional_dict(value)
151
- elif key == "sent":
152
- hot.egress_sent = bool(value)
153
-
154
-
155
- def _clear_hot_namespace_value(kind: str, hot: HotCtx, key: str) -> None:
156
- if kind == "route":
157
- if key == "selector":
158
- hot.route_selector = ""
159
- elif key == "protocol":
160
- hot.route_protocol = ""
161
- elif key == "program_id":
162
- hot.route_program_id = -1
163
- elif key == "opmeta_index":
164
- hot.route_opmeta_index = -1
165
- elif key == "method_not_allowed":
166
- hot.route_method_not_allowed = False
167
- elif key == "short_circuit":
168
- hot.route_short_circuit = False
169
- elif key == "payload":
170
- hot.route_payload = None
171
- elif key == "path_params":
172
- hot.route_path_params = None
173
- hot.path_params = None
174
- elif key == "rpc_envelope":
175
- hot.route_rpc_envelope = None
176
- hot.dispatch_jsonrpc_request_id = None
177
- hot.dispatch_rpc_method = None
178
- elif kind == "dispatch":
179
- if key == "binding_protocol":
180
- hot.dispatch_binding_protocol = ""
181
- elif key == "binding_selector":
182
- hot.dispatch_binding_selector = ""
183
- elif key == "channel_protocol":
184
- hot.dispatch_channel_protocol = ""
185
- elif key == "channel_selector":
186
- hot.dispatch_channel_selector = ""
187
- elif key == "rpc":
188
- hot.dispatch_rpc_envelope = None
189
- hot.dispatch_jsonrpc_request_id = None
190
- hot.dispatch_rpc_method = None
191
- elif key == "rpc_method":
192
- hot.dispatch_rpc_method = None
193
- elif key == "jsonrpc_request_id":
194
- hot.dispatch_jsonrpc_request_id = None
195
- elif kind == "egress":
196
- if key == "transport_response":
197
- hot.egress_transport_response = None
198
- elif key == "sent":
199
- hot.egress_sent = False
13
+ from .hot_namespace_values import (
14
+ _clear_hot_namespace_value,
15
+ _coerce_optional_dict,
16
+ _namespace_lazy_value,
17
+ _sync_hot_namespace_value,
18
+ )
200
19
 
201
20
 
202
21
  class _HotNamespaceDict(dict[str, Any]):
@@ -0,0 +1,4 @@
1
+ from ._shared import _DirectWebSocketUnary
2
+ from .executor import PackedPlanExecutor
3
+
4
+ __all__ = ["PackedPlanExecutor"]