port_registry
port_registry
¶
Shared port registry for multi-user isolation.
Every port allocation — infrastructure services and container web ports —
flows through PortRegistry. Claims are persisted as per-user
JSON files in a shared directory (default /tmp/terok-ports/). All
users' claim files are read at allocation time to avoid collisions;
socket bind tests verify the port is actually free.
A module-level singleton (_default) provides the convenience API
(claim_port, release_port, etc.) used by the rest of the stack.
SERVICE_GATE = 'gate'
module-attribute
¶
SERVICE_PROXY = 'proxy'
module-attribute
¶
SERVICE_SSH_AGENT = 'ssh_agent'
module-attribute
¶
PORT_RANGE = _default.port_range
module-attribute
¶
Contiguous range for all auto-allocated ports (infra + web).
ServicePorts(gate, proxy, ssh_agent)
dataclass
¶
PortRegistry(registry_dir, port_range)
¶
File-based shared port registry for multi-user isolation.
Each instance manages its own in-memory claim set and shared directory.
Use the module-level singleton (_default) for production code;
tests can construct isolated instances with a temporary directory.
Source code in src/terok_sandbox/port_registry.py
registry_dir = registry_dir
instance-attribute
¶
port_range = port_range
instance-attribute
¶
resolve_service_ports(gate_pref, proxy_pref, ssh_pref, *, gate_explicit=False, proxy_explicit=False, ssh_explicit=False, state_dir=None)
¶
Resolve and claim infrastructure ports (cached after first call).
Each _pref is a preferred starting port or None for auto-allocation.
When *_explicit is True the port is a hard pin (SystemExit if busy).
When state_dir is provided, port assignments are persisted across
restarts. If a previously saved port cannot be reclaimed, the call
fails with SystemExit so the user can resolve the conflict.
Source code in src/terok_sandbox/port_registry.py
claim(service_key, preferred=None, *, explicit=False, trusted=False)
¶
Claim one port via the shared file-based registry.
Reads all users' claim files to avoid collisions, then verifies via socket bind that the port is actually free. The claim is persisted to the shared directory so other users can see it.
When trusted is True the port originates from a prior
allocation by this user — the saved claims file
(port-claims.json). Our own service may be listening, so
the _is_port_free bind check is skipped; other-user
collision checks still apply. The trusted flag is set by
resolve_service_ports during the preference resolution
phase.
Source code in src/terok_sandbox/port_registry.py
release(service_key)
¶
Release a previously claimed port and update the shared claim file.
Source code in src/terok_sandbox/port_registry.py
resolve_service_ports(gate_pref, proxy_pref, ssh_pref, *, gate_explicit=False, proxy_explicit=False, ssh_explicit=False, state_dir=None)
¶
Resolve and claim infrastructure ports via the default registry.
Source code in src/terok_sandbox/port_registry.py
claim_port(service_key, preferred=None, *, explicit=False)
¶
Claim one port via the default registry.