| """Proxy dataplane table — runtime view of egress nodes and clearance bundles. |
| |
| Thin wrapper around ProxyDirectory's internal state, formalizing the |
| dataplane/control-plane boundary. The control-plane ProxyDirectory owns |
| mutation; this module provides a read-only snapshot for selector logic. |
| """ |
|
|
| from dataclasses import dataclass, field |
| from typing import TYPE_CHECKING |
|
|
| from app.control.proxy.models import ( |
| EgressNode, ClearanceBundle, EgressMode, ClearanceMode, |
| ) |
|
|
| if TYPE_CHECKING: |
| from app.control.proxy import ProxyDirectory |
|
|
| BundleKey = tuple[str, str] |
|
|
|
|
| @dataclass |
| class ProxyRuntimeTable: |
| """Read-only snapshot of proxy state for dataplane selection.""" |
|
|
| egress_mode: EgressMode = EgressMode.DIRECT |
| clearance_mode: ClearanceMode = ClearanceMode.NONE |
| nodes: list[EgressNode] = field(default_factory=list) |
| bundles: dict[BundleKey, ClearanceBundle] = field(default_factory=dict) |
|
|
| @property |
| def node_count(self) -> int: |
| return len(self.nodes) |
|
|
| @property |
| def has_nodes(self) -> bool: |
| return len(self.nodes) > 0 |
|
|
| def healthy_nodes(self) -> list[EgressNode]: |
| from app.control.proxy.models import EgressNodeState |
| return [n for n in self.nodes if n.state == EgressNodeState.HEALTHY] |
|
|
|
|
| def snapshot_from_directory(directory: "ProxyDirectory") -> ProxyRuntimeTable: |
| """Build a ProxyRuntimeTable from the current ProxyDirectory state. |
| |
| This is a point-in-time snapshot — not kept in sync automatically. |
| """ |
| return ProxyRuntimeTable( |
| egress_mode=directory.egress_mode, |
| clearance_mode=directory.clearance_mode, |
| nodes=directory.nodes, |
| bundles=directory.bundles, |
| ) |
|
|
|
|
| __all__ = ["ProxyRuntimeTable", "snapshot_from_directory"] |
|
|