Move `Address` types to `discovery.types`
Keep address descriptors and structural protocols independent of concrete IPC, actor runtime, tunnel and optional dependency mods. Use `AddressDeclaration` for plain and tunnelled address values, while concrete TCP/UDS factory dispatch remains in `._addr`. Drop runtime model-name aliases to `Any` and the self-referential `get_type_hints()` regression. Also, - preserve lazy `multiaddr` and net imports - verify canonical type identity across discovery, IPC and tunnels - route random and bound address reconstruction through concrete types Prompt-IO: ai/prompt-io/opencode/20260903T201530Z_d097090f_discovery_types.md (this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))wkt/runtime_net_scopes
parent
41f34de3a4
commit
212a8f82ac
|
|
@ -0,0 +1,70 @@
|
||||||
|
---
|
||||||
|
model: openai/gpt-5.6-sol
|
||||||
|
service: opencode
|
||||||
|
session: dependency-neutral-discovery-types
|
||||||
|
timestamp: 2026-09-03T20:15:30Z
|
||||||
|
git_ref: d097090f
|
||||||
|
scope: code
|
||||||
|
substantive: true
|
||||||
|
raw_file: 20260903T201530Z_d097090f_discovery_types.raw.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prompt
|
||||||
|
|
||||||
|
The maintainer rejected annotation-only model names rebound to `Any`,
|
||||||
|
questioned the self-referential `get_type_hints()` regression, selected a
|
||||||
|
dependency-neutral `tractor.discovery.types` module as the preferred
|
||||||
|
direction, and then requested implementation of that first design layer.
|
||||||
|
|
||||||
|
The maintainer separately asked how to handle the disliked staged
|
||||||
|
`tractor/net/_bootstrap.py` implementation. That file was excluded from
|
||||||
|
this implementation boundary and retained as review evidence.
|
||||||
|
|
||||||
|
## Response summary
|
||||||
|
|
||||||
|
Added a dependency-neutral module for canonical primitive address
|
||||||
|
descriptors and separate structural contracts for concrete transport
|
||||||
|
addresses and tunnel-capable address declarations. Migrated discovery,
|
||||||
|
IPC, root, runtime, and tunnel annotations to import those real types,
|
||||||
|
removing every runtime model-name assignment to `Any`.
|
||||||
|
|
||||||
|
Kept parser table aliases beside `parse_endpoints()` instead of turning
|
||||||
|
the new module into a general alias registry. Kept transport-specific
|
||||||
|
factories on TCP and UDS classes because their accepted descriptor and
|
||||||
|
bindspace types differ. Replaced the old `get_type_hints()` assertions
|
||||||
|
with cold-import and canonical-identity coverage.
|
||||||
|
|
||||||
|
## Files changed
|
||||||
|
|
||||||
|
- `tractor/discovery/types.py` - dependency-neutral descriptors and
|
||||||
|
address protocols.
|
||||||
|
- `tractor/discovery/_addr.py` - imports and re-exports canonical types;
|
||||||
|
retains concrete factory registry.
|
||||||
|
- `tractor/discovery/_multiaddr.py` - uses the structural declaration
|
||||||
|
type and runtime-safe parsed table alias.
|
||||||
|
- `tractor/ipc/_tcp.py` - imports the real TCP descriptor alias.
|
||||||
|
- `tractor/ipc/_uds.py` - imports the real Unix descriptor alias.
|
||||||
|
- `tractor/ipc/_transport.py` - imports the concrete-address protocol
|
||||||
|
without cycling through `_addr`.
|
||||||
|
- `tractor/ipc/_chan.py` - accepts structural address declarations
|
||||||
|
without a `TunnelledAddress = Any` fallback.
|
||||||
|
- `tractor/ipc/_server.py` - retains declaration metadata structurally
|
||||||
|
and routes reconstruction through the concrete address registry.
|
||||||
|
- `tractor/net/_tunnel.py` - imports real dependency-neutral address
|
||||||
|
types while retaining dynamic `Any` only for external netlink data.
|
||||||
|
- `tractor/_root.py` - removes the `Bindspace = Any` fallback and uses
|
||||||
|
concrete address-factory dispatch.
|
||||||
|
- `tractor/runtime/_runtime.py` - infers concrete registry address types
|
||||||
|
for random listener allocation.
|
||||||
|
- `tests/test_lazy_imports.py` - replaces workaround introspection with
|
||||||
|
dependency and canonical-identity checks.
|
||||||
|
|
||||||
|
## Human edits
|
||||||
|
|
||||||
|
The maintainer identified the `Any` aliases and their introspection test
|
||||||
|
as an unjustified circular contract, directed investigation of the real
|
||||||
|
cycle/import-performance cause, selected `tractor.discovery.types`, and
|
||||||
|
approved beginning implementation. The maintainer also required that the
|
||||||
|
current bootstrap implementation not be treated as acceptable design and
|
||||||
|
provided direct review annotations which remain preserved in the
|
||||||
|
worktree.
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
---
|
||||||
|
model: openai/gpt-5.6-sol
|
||||||
|
service: opencode
|
||||||
|
timestamp: 2026-09-03T20:15:30Z
|
||||||
|
git_ref: d097090f
|
||||||
|
diff_cmd: git diff HEAD~1..HEAD
|
||||||
|
---
|
||||||
|
|
||||||
|
Implemented a dependency-neutral discovery typing layer after reviewing
|
||||||
|
the address, transport, tunnel, and lazy-import dependency graph.
|
||||||
|
|
||||||
|
> `git diff HEAD~1..HEAD -- tractor/discovery/types.py tractor/discovery/_addr.py tractor/discovery/_multiaddr.py tractor/ipc/_tcp.py tractor/ipc/_uds.py tractor/ipc/_transport.py tractor/ipc/_chan.py tractor/ipc/_server.py tractor/net/_tunnel.py tractor/_root.py tractor/runtime/_runtime.py tests/test_lazy_imports.py`
|
||||||
|
|
||||||
|
The generated changes move primitive address descriptors and structural
|
||||||
|
address protocols into `tractor.discovery.types`. Concrete transport
|
||||||
|
factories remain outside the shared protocol because TCP and UDS accept
|
||||||
|
different descriptor and bindspace inputs. Runtime names are no longer
|
||||||
|
rebound to `Any` merely to satisfy `typing.get_type_hints()`.
|
||||||
|
|
||||||
|
The old annotation-introspection regression was replaced with coverage
|
||||||
|
that checks dependency-neutral cold imports and canonical type identity
|
||||||
|
across discovery, IPC, and tunnel modules.
|
||||||
|
|
||||||
|
Verification completed with the worktree-local Python 3.13 environment:
|
||||||
|
|
||||||
|
- focused address/lazy/tunnel coverage: 69 passed;
|
||||||
|
- discovery, IPC, and local coverage: 77 passed, 2 xpassed;
|
||||||
|
- root/runtime coverage: 6 passed with 24 multiprocessing fork
|
||||||
|
deprecation warnings.
|
||||||
|
|
||||||
|
Ruff was unavailable in the existing `py313` environment. Scoped
|
||||||
|
`git diff --check` passed. The global whitespace check reports only a
|
||||||
|
pre-existing maintainer annotation in `tractor/net/_bootstrap.py`, which
|
||||||
|
was deliberately left untouched.
|
||||||
|
|
@ -7,21 +7,6 @@ import os
|
||||||
from statistics import median
|
from statistics import median
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from typing import (
|
|
||||||
Any,
|
|
||||||
get_type_hints,
|
|
||||||
)
|
|
||||||
|
|
||||||
import tractor
|
|
||||||
from tractor.discovery import (
|
|
||||||
_addr,
|
|
||||||
_multiaddr,
|
|
||||||
)
|
|
||||||
from tractor.ipc import (
|
|
||||||
_tcp,
|
|
||||||
_uds,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def run_cold_import(code: str) -> dict[str, object]:
|
def run_cold_import(code: str) -> dict[str, object]:
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
|
|
@ -260,28 +245,56 @@ def test_net_root_export_and_old_discovery_surface():
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_lazy_annotation_names_resolve():
|
def test_discovery_types_are_dependency_neutral():
|
||||||
'''
|
'''
|
||||||
Resolve annotations without importing optional dependencies.
|
Keep canonical address types independent of runtime implementations.
|
||||||
|
|
||||||
Moving annotation-only third-party names under `TYPE_CHECKING`
|
Annotation-only imports previously rebound unavailable model names
|
||||||
left their runtime globals undefined, causing
|
to `Any` so `get_type_hints()` could resolve them. That test only
|
||||||
`typing.get_type_hints()` to raise `NameError`. Resolve every
|
verified its own workaround and hid the `_addr`/transport import
|
||||||
affected API and prove the lazy aliases retain import-free runtime
|
cycle. Import the canonical declarations in a cold interpreter and
|
||||||
introspection.
|
prove they do not pull in optional networking modules. Then prove
|
||||||
|
each implementation imports the same real declarations instead of
|
||||||
|
substituting `Any` under the model names.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
assert get_type_hints(_multiaddr.mk_maddr)['return'] is Any
|
cold = run_cold_import(
|
||||||
assert get_type_hints(_tcp.MsgpackTCPStream.maddr.fget)[
|
'import json, sys; '
|
||||||
'return'
|
'from tractor.discovery import types; '
|
||||||
] is Any
|
'blocked = ('
|
||||||
assert get_type_hints(_uds.MsgpackUDSStream.maddr.fget)[
|
'"multiaddr", "multibase", "pyroute2", '
|
||||||
'return'
|
'"tractor.discovery._multiaddr", "tractor.net", '
|
||||||
] == Any|str
|
'"tractor.net._bindspace", "tractor.net._tunnel"); '
|
||||||
assert get_type_hints(_addr.Address.get_random)[
|
'print(json.dumps({'
|
||||||
'current_actor'
|
'"address_module": types.Address.__module__, '
|
||||||
] is Any
|
'"blocked": [name for name in blocked '
|
||||||
assert get_type_hints(tractor.open_root_actor)[
|
'if name in sys.modules]}))'
|
||||||
'bindspace'
|
)
|
||||||
] == Any|None
|
assert cold == {
|
||||||
assert _addr.__annotations__['_address_types'].startswith('dict')
|
'address_module': 'tractor.discovery.types',
|
||||||
|
'blocked': [],
|
||||||
|
}
|
||||||
|
|
||||||
|
from tractor.discovery import (
|
||||||
|
_addr,
|
||||||
|
_multiaddr,
|
||||||
|
types,
|
||||||
|
)
|
||||||
|
from tractor.ipc import (
|
||||||
|
_chan,
|
||||||
|
_server,
|
||||||
|
_tcp,
|
||||||
|
_transport,
|
||||||
|
_uds,
|
||||||
|
)
|
||||||
|
from tractor.net import _tunnel
|
||||||
|
|
||||||
|
assert _addr.Address is types.Address
|
||||||
|
assert _addr.UnwrappedAddress is types.UnwrappedAddress
|
||||||
|
assert _multiaddr.AddressDeclaration is types.AddressDeclaration
|
||||||
|
assert _tcp.TaggedTCPAddress is types.TaggedTCPAddress
|
||||||
|
assert _uds.TaggedUnixAddress is types.TaggedUnixAddress
|
||||||
|
assert _transport.Address is types.Address
|
||||||
|
assert _chan.AddressDeclaration is types.AddressDeclaration
|
||||||
|
assert _server.AddressDeclaration is types.AddressDeclaration
|
||||||
|
assert _tunnel.AddressDeclaration is types.AddressDeclaration
|
||||||
|
|
|
||||||
|
|
@ -53,12 +53,15 @@ from .runtime import _state
|
||||||
from . import log
|
from . import log
|
||||||
from .discovery._api import _probe_registry_addrs
|
from .discovery._api import _probe_registry_addrs
|
||||||
from .discovery._addr import (
|
from .discovery._addr import (
|
||||||
Address,
|
|
||||||
UnwrappedAddress,
|
|
||||||
default_lo_addrs,
|
default_lo_addrs,
|
||||||
|
get_address_cls,
|
||||||
mk_uuid,
|
mk_uuid,
|
||||||
wrap_address,
|
wrap_address,
|
||||||
)
|
)
|
||||||
|
from .discovery.types import (
|
||||||
|
Address,
|
||||||
|
UnwrappedAddress,
|
||||||
|
)
|
||||||
from .trionics import (
|
from .trionics import (
|
||||||
is_multi_cancelled,
|
is_multi_cancelled,
|
||||||
collapse_eg,
|
collapse_eg,
|
||||||
|
|
@ -69,8 +72,6 @@ from ._exceptions import (
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .net._bindspace import Bindspace
|
from .net._bindspace import Bindspace
|
||||||
else:
|
|
||||||
Bindspace = Any
|
|
||||||
|
|
||||||
|
|
||||||
logger = log.get_logger('tractor')
|
logger = log.get_logger('tractor')
|
||||||
|
|
@ -187,7 +188,7 @@ async def open_root_actor(
|
||||||
bindspace: Bindspace|None = None,
|
bindspace: Bindspace|None = None,
|
||||||
|
|
||||||
tpt_bind_addrs: list[
|
tpt_bind_addrs: list[
|
||||||
Address # `Address.get_random()` case
|
Address # concrete transport address case
|
||||||
|UnwrappedAddress # registrar case `= uw_reg_addrs`
|
|UnwrappedAddress # registrar case `= uw_reg_addrs`
|
||||||
]|None = None,
|
]|None = None,
|
||||||
|
|
||||||
|
|
@ -561,6 +562,9 @@ async def open_root_actor(
|
||||||
|
|
||||||
for addr in ponged_addrs:
|
for addr in ponged_addrs:
|
||||||
bindable_addr: Address = strip_tunnels(addr)
|
bindable_addr: Address = strip_tunnels(addr)
|
||||||
|
address_type = get_address_cls(
|
||||||
|
bindable_addr.proto_key
|
||||||
|
)
|
||||||
tpt_bind_addrs.append(
|
tpt_bind_addrs.append(
|
||||||
# XXX, these are `Address` NOT `UnwrappedAddress`.
|
# XXX, these are `Address` NOT `UnwrappedAddress`.
|
||||||
#
|
#
|
||||||
|
|
@ -568,7 +572,7 @@ async def open_root_actor(
|
||||||
# protos we allocate port=0 such that the system
|
# protos we allocate port=0 such that the system
|
||||||
# allocates a random value at bind time; this
|
# allocates a random value at bind time; this
|
||||||
# happens in the `.ipc.*` stack's backend.
|
# happens in the `.ipc.*` stack's backend.
|
||||||
bindable_addr.get_random(
|
address_type.get_random(
|
||||||
bindspace=bindable_addr.bindspace,
|
bindspace=bindable_addr.bindspace,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,19 +15,7 @@
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from typing import (
|
from typing import TypeAlias
|
||||||
Any,
|
|
||||||
Protocol,
|
|
||||||
ClassVar,
|
|
||||||
Literal,
|
|
||||||
Type,
|
|
||||||
TypeAlias,
|
|
||||||
TYPE_CHECKING,
|
|
||||||
)
|
|
||||||
|
|
||||||
from trio import (
|
|
||||||
SocketListener,
|
|
||||||
)
|
|
||||||
|
|
||||||
from ..log import get_logger
|
from ..log import get_logger
|
||||||
from ..runtime._state import (
|
from ..runtime._state import (
|
||||||
|
|
@ -38,70 +26,19 @@ from ..ipc._uds import (
|
||||||
UDSAddress,
|
UDSAddress,
|
||||||
HAS_UDS,
|
HAS_UDS,
|
||||||
)
|
)
|
||||||
|
from .types import (
|
||||||
if TYPE_CHECKING:
|
Address as Address,
|
||||||
# ONLY type-annots, the eager import costs ~4.5ms
|
AddressDeclaration,
|
||||||
# of `import tractor` wall-time (gh #470).
|
LegacyUnwrappedAddress,
|
||||||
from tractor.net._tunnel import (
|
TaggedAddress,
|
||||||
TunnelledAddress,
|
TaggedUDSAlias,
|
||||||
)
|
UnwrappedAddress,
|
||||||
from ..runtime._runtime import Actor
|
)
|
||||||
else:
|
|
||||||
Actor = Any
|
|
||||||
TunnelledAddress = Any
|
|
||||||
|
|
||||||
log = get_logger()
|
log = get_logger()
|
||||||
|
|
||||||
# TODO, maybe breakout the netns key to a struct?
|
_AddressType: TypeAlias = type[TCPAddress]|type[UDSAddress]
|
||||||
# class NetNs(Struct)[str, int]:
|
|
||||||
# ...
|
|
||||||
|
|
||||||
# TODO, can't we just use a type alias
|
|
||||||
# for this? namely just some `tuple[str, int, str, str]`?
|
|
||||||
#
|
|
||||||
# -[ ] would also just be simpler to keep this as SockAddr[tuple]
|
|
||||||
# or something, implying it's just a simple pair of values which can
|
|
||||||
# presumably be mapped to all transports?
|
|
||||||
# -[ ] `pydoc socket.socket.getsockname()` delivers a 4-tuple for
|
|
||||||
# ipv6 `(hostaddr, port, flowinfo, scope_id)`.. so how should we
|
|
||||||
# handle that?
|
|
||||||
# -[ ] as a further alternative to this wrap()/unwrap() approach we
|
|
||||||
# could just implement `enc/dec_hook()`s for the `Address`-types
|
|
||||||
# and just deal with our internal objs directly and always and
|
|
||||||
# leave it to the codec layer to figure out marshalling?
|
|
||||||
# |_ would mean only one spot to do the `.unwrap()` (which we may
|
|
||||||
# end up needing to call from the hook()s anyway?)
|
|
||||||
# -[x] rename to `UnwrappedAddress[Descriptor]` ??
|
|
||||||
# seems like the right name as per,
|
|
||||||
# https://www.geeksforgeeks.org/introduction-to-address-descriptor/
|
|
||||||
#
|
|
||||||
TaggedTCPAddress: TypeAlias = tuple[
|
|
||||||
Literal['tcp'],
|
|
||||||
str,
|
|
||||||
int,
|
|
||||||
]
|
|
||||||
TaggedUnixAddress: TypeAlias = tuple[
|
|
||||||
Literal['unix'],
|
|
||||||
str,
|
|
||||||
]
|
|
||||||
TaggedUDSAlias: TypeAlias = tuple[
|
|
||||||
Literal['uds'],
|
|
||||||
str,
|
|
||||||
]
|
|
||||||
TaggedAddress: TypeAlias = (
|
|
||||||
TaggedTCPAddress
|
|
||||||
|TaggedUnixAddress
|
|
||||||
)
|
|
||||||
|
|
||||||
# Input-only compatibility forms retained for older callers and
|
|
||||||
# serialized payloads.
|
|
||||||
LegacyTCPAddress: TypeAlias = tuple[str, int]
|
|
||||||
LegacyUDSAddress: TypeAlias = tuple[str, str]
|
|
||||||
LegacyUnwrappedAddress: TypeAlias = (
|
|
||||||
LegacyTCPAddress
|
|
||||||
|LegacyUDSAddress
|
|
||||||
)
|
|
||||||
UnwrappedAddress = TaggedAddress
|
|
||||||
# ?TODO? should we also include another 2 fields from our `Aid` msg
|
# ?TODO? should we also include another 2 fields from our `Aid` msg
|
||||||
# such that we include the runtime `Actor.uid` of `.name` and `.uuid`?
|
# such that we include the runtime `Actor.uid` of `.name` and `.uuid`?
|
||||||
# - would ensure uniqueness across entire net?
|
# - would ensure uniqueness across entire net?
|
||||||
|
|
@ -109,106 +46,14 @@ UnwrappedAddress = TaggedAddress
|
||||||
# name"
|
# name"
|
||||||
|
|
||||||
|
|
||||||
# TODO, maybe rename to `SocketAddress`?
|
|
||||||
class Address(Protocol):
|
|
||||||
proto_key: ClassVar[str]
|
|
||||||
unwrapped_type: ClassVar[type]
|
|
||||||
|
|
||||||
# TODO, i feel like an `.is_bound()` is a better thing to
|
|
||||||
# support?
|
|
||||||
# Lke, what use does this have besides a noop and if it's not
|
|
||||||
# valid why aren't we erroring on creation/use?
|
|
||||||
@property
|
|
||||||
def is_valid(self) -> bool:
|
|
||||||
...
|
|
||||||
|
|
||||||
# TODO, maybe `.netns` is a better name?
|
|
||||||
@property
|
|
||||||
def namespace(self) -> tuple[str, str|int]|None:
|
|
||||||
'''
|
|
||||||
The if-available, OS-specific "network namespace" key.
|
|
||||||
|
|
||||||
'''
|
|
||||||
...
|
|
||||||
|
|
||||||
@property
|
|
||||||
def bindspace(self) -> str:
|
|
||||||
'''
|
|
||||||
Deliver the socket address' "bindable space" from
|
|
||||||
a `socket.socket.bind()` and thus from the perspective of
|
|
||||||
specific transport protocol domain.
|
|
||||||
|
|
||||||
I.e. for most (layer-4) network-socket protocols this is
|
|
||||||
normally the ipv4/6 address, for UDS this is normally
|
|
||||||
a filesystem (sub-directory).
|
|
||||||
|
|
||||||
For (distributed) network protocols this is normally the routing
|
|
||||||
layer's domain/(ip-)address, though it might also include a "network namespace"
|
|
||||||
key different then the default.
|
|
||||||
|
|
||||||
For local-host-only transports this is either an explicit
|
|
||||||
namespace (with types defined by the OS: netns, Cgroup, IPC,
|
|
||||||
pid, etc. on linux) or failing that the sub-directory in the
|
|
||||||
filesys in which socket/shm files are located *under*.
|
|
||||||
|
|
||||||
'''
|
|
||||||
...
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_addr(cls, addr: UnwrappedAddress) -> Address:
|
|
||||||
...
|
|
||||||
|
|
||||||
def unwrap(self) -> UnwrappedAddress:
|
|
||||||
'''
|
|
||||||
Deliver the underying minimum field set in
|
|
||||||
a primitive python data type-structure.
|
|
||||||
'''
|
|
||||||
...
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_random(
|
|
||||||
cls,
|
|
||||||
current_actor: Actor,
|
|
||||||
bindspace: str|None = None,
|
|
||||||
) -> Address:
|
|
||||||
...
|
|
||||||
|
|
||||||
# TODO, this should be something like a `.get_def_registar_addr()`
|
|
||||||
# or similar since,
|
|
||||||
# - it should be a **host singleton** (not root/tree singleton)
|
|
||||||
# - we **only need this value** when one isn't provided to the
|
|
||||||
# runtime at boot and we want to implicitly provide a host-wide
|
|
||||||
# registrar.
|
|
||||||
# - each rooted-actor-tree should likely have its own
|
|
||||||
# micro-registry (likely the root being it), also see
|
|
||||||
@classmethod
|
|
||||||
def get_root(cls) -> Address:
|
|
||||||
...
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
...
|
|
||||||
|
|
||||||
def __eq__(self, other) -> bool:
|
|
||||||
...
|
|
||||||
|
|
||||||
async def open_listener(
|
|
||||||
self,
|
|
||||||
**kwargs,
|
|
||||||
) -> SocketListener:
|
|
||||||
...
|
|
||||||
|
|
||||||
async def close_listener(self):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
# the address types available on this host: TCP always, UDS only
|
# the address types available on this host: TCP always, UDS only
|
||||||
# where usable (`HAS_UDS`). Both registries derive from this single
|
# where usable (`HAS_UDS`). Both registries derive from this single
|
||||||
# list via each type's `proto_key`.
|
# list via each type's `proto_key`.
|
||||||
_address_protos: list[Type[Address]] = [TCPAddress]
|
_address_protos: list[_AddressType] = [TCPAddress]
|
||||||
if HAS_UDS:
|
if HAS_UDS:
|
||||||
_address_protos.append(UDSAddress)
|
_address_protos.append(UDSAddress)
|
||||||
|
|
||||||
_address_types: dict[str, Type[Address]] = {
|
_address_types: dict[str, _AddressType] = {
|
||||||
cls.proto_key: cls
|
cls.proto_key: cls
|
||||||
for cls in _address_protos
|
for cls in _address_protos
|
||||||
}
|
}
|
||||||
|
|
@ -216,13 +61,22 @@ _address_types: dict[str, Type[Address]] = {
|
||||||
|
|
||||||
# TODO! really these are discovery sys default addrs ONLY useful for
|
# TODO! really these are discovery sys default addrs ONLY useful for
|
||||||
# when none is provided to a root actor on first boot.
|
# when none is provided to a root actor on first boot.
|
||||||
|
#
|
||||||
|
# TODO, this should be something like a `.get_def_registar_addr()`
|
||||||
|
# or similar since,
|
||||||
|
# - it should be a **host singleton** (not root/tree singleton)
|
||||||
|
# - we **only need this value** when one isn't provided to the
|
||||||
|
# runtime at boot and we want to implicitly provide a host-wide
|
||||||
|
# registrar.
|
||||||
|
# - each rooted-actor-tree should likely have its own
|
||||||
|
# micro-registry (likely the root being it), also see
|
||||||
_default_lo_addrs: dict[str, UnwrappedAddress] = {
|
_default_lo_addrs: dict[str, UnwrappedAddress] = {
|
||||||
cls.proto_key: cls.get_root().unwrap()
|
cls.proto_key: cls.get_root().unwrap()
|
||||||
for cls in _address_protos
|
for cls in _address_protos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_address_cls(name: str) -> Type[Address]:
|
def get_address_cls(name: str) -> _AddressType:
|
||||||
try:
|
try:
|
||||||
return _address_types[name]
|
return _address_types[name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
@ -233,7 +87,7 @@ def get_address_cls(name: str) -> Type[Address]:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def is_wrapped_addr(addr: any) -> bool:
|
def is_wrapped_addr(addr: object) -> bool:
|
||||||
# XXX NOTE, a `TunnelledAddress` is genuinely "wrapped" but is
|
# XXX NOTE, a `TunnelledAddress` is genuinely "wrapped" but is
|
||||||
# deliberately NOT in `_address_types`: it has no
|
# deliberately NOT in `_address_types`: it has no
|
||||||
# `MsgTransport` of its own (a tunnel is transparent to
|
# `MsgTransport` of its own (a tunnel is transparent to
|
||||||
|
|
@ -264,10 +118,9 @@ def wrap_address(
|
||||||
|LegacyUnwrappedAddress
|
|LegacyUnwrappedAddress
|
||||||
|list[str|int]
|
|list[str|int]
|
||||||
|str
|
|str
|
||||||
|Address
|
|AddressDeclaration
|
||||||
|TunnelledAddress
|
|
||||||
),
|
),
|
||||||
) -> Address|TunnelledAddress:
|
) -> AddressDeclaration:
|
||||||
'''
|
'''
|
||||||
Wrap an `UnwrappedAddress` as an `Address`-type based
|
Wrap an `UnwrappedAddress` as an `Address`-type based
|
||||||
on matching builtin python data-structures which we adhoc
|
on matching builtin python data-structures which we adhoc
|
||||||
|
|
@ -284,7 +137,7 @@ def wrap_address(
|
||||||
if is_wrapped_addr(addr):
|
if is_wrapped_addr(addr):
|
||||||
return addr
|
return addr
|
||||||
|
|
||||||
cls: Type|None = None
|
cls: _AddressType|None = None
|
||||||
# if 'sock' in addr[0]:
|
# if 'sock' in addr[0]:
|
||||||
# import pdbp; pdbp.set_trace()
|
# import pdbp; pdbp.set_trace()
|
||||||
match addr:
|
match addr:
|
||||||
|
|
@ -328,7 +181,7 @@ def wrap_address(
|
||||||
|
|
|
|
||||||
[None, None]
|
[None, None]
|
||||||
):
|
):
|
||||||
cls: Type[Address] = get_address_cls(_def_tpt_proto)
|
cls = get_address_cls(_def_tpt_proto)
|
||||||
addr: UnwrappedAddress = cls.get_root().unwrap()
|
addr: UnwrappedAddress = cls.get_root().unwrap()
|
||||||
|
|
||||||
# multiaddr-format string, e.g.
|
# multiaddr-format string, e.g.
|
||||||
|
|
@ -354,7 +207,7 @@ def wrap_address(
|
||||||
|
|
||||||
def default_lo_addrs(
|
def default_lo_addrs(
|
||||||
transports: list[str],
|
transports: list[str],
|
||||||
) -> list[Type[Address]]:
|
) -> list[UnwrappedAddress]:
|
||||||
'''
|
'''
|
||||||
Return the default, host-singleton, registry address
|
Return the default, host-singleton, registry address
|
||||||
for an input transport key set.
|
for an input transport key set.
|
||||||
|
|
|
||||||
|
|
@ -27,24 +27,15 @@ Multiaddress support using the upstream `py-multiaddr` lib
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import ipaddress
|
import ipaddress
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import (
|
from typing import TYPE_CHECKING
|
||||||
Any,
|
|
||||||
TYPE_CHECKING,
|
from .types import AddressDeclaration
|
||||||
)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
# NOTE, `multiaddr` is lazy-imported at first use
|
# NOTE, `multiaddr` is lazy-imported at first use
|
||||||
# (in the fns below) to keep it off the eager
|
# (in the fns below) to keep it off the eager
|
||||||
# `import tractor` path (gh #470).
|
# `import tractor` path (gh #470).
|
||||||
from multiaddr import Multiaddr
|
from multiaddr import Multiaddr
|
||||||
from tractor.discovery._addr import Address
|
|
||||||
from tractor.net._tunnel import (
|
|
||||||
TunnelledAddress,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
Multiaddr = Any
|
|
||||||
Address = Any
|
|
||||||
TunnelledAddress = Any
|
|
||||||
|
|
||||||
# map from tractor-internal `proto_key` identifiers
|
# map from tractor-internal `proto_key` identifiers
|
||||||
# to the standard multiaddr protocol name strings.
|
# to the standard multiaddr protocol name strings.
|
||||||
|
|
@ -61,7 +52,7 @@ _maddr_to_tpt_proto: dict[str, str] = {
|
||||||
|
|
||||||
|
|
||||||
def mk_maddr(
|
def mk_maddr(
|
||||||
addr: 'Address|TunnelledAddress',
|
addr: AddressDeclaration,
|
||||||
) -> Multiaddr:
|
) -> Multiaddr:
|
||||||
'''
|
'''
|
||||||
Construct a `Multiaddr` from a tractor `Address` instance,
|
Construct a `Multiaddr` from a tractor `Address` instance,
|
||||||
|
|
@ -111,7 +102,7 @@ def mk_maddr(
|
||||||
|
|
||||||
def parse_maddr(
|
def parse_maddr(
|
||||||
maddr_str: str,
|
maddr_str: str,
|
||||||
) -> 'Address|TunnelledAddress':
|
) -> AddressDeclaration:
|
||||||
'''
|
'''
|
||||||
Parse a multiaddr string into a tractor `Address`.
|
Parse a multiaddr string into a tractor `Address`.
|
||||||
|
|
||||||
|
|
@ -173,15 +164,15 @@ def parse_maddr(
|
||||||
# or raw unwrapped-address tuples (as accepted by
|
# or raw unwrapped-address tuples (as accepted by
|
||||||
# `wrap_address()`).
|
# `wrap_address()`).
|
||||||
EndpointsTable = dict[
|
EndpointsTable = dict[
|
||||||
str, # actor/service name
|
str, # actor/service name
|
||||||
list[str|tuple], # maddr strs or UnwrappedAddress
|
list[str|tuple|AddressDeclaration],
|
||||||
]
|
]
|
||||||
|
|
||||||
# output table: actor/service name -> list of wrapped address
|
# output table: actor/service name -> list of wrapped address
|
||||||
# declarations ready for bindspace handling.
|
# declarations ready for bindspace handling.
|
||||||
ParsedEndpoints = dict[
|
ParsedEndpoints = dict[
|
||||||
str, # actor/service name
|
str, # actor/service name
|
||||||
list['Address|TunnelledAddress'],
|
list[AddressDeclaration],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
# tractor: structured concurrent "actors".
|
||||||
|
# Copyright 2018-eternity Tyler Goodlet.
|
||||||
|
|
||||||
|
# This program is free software: you can redistribute it and/or
|
||||||
|
# modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Affero General Public
|
||||||
|
# License along with this program. If not, see
|
||||||
|
# <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
'''
|
||||||
|
Dependency-neutral address typing declarations.
|
||||||
|
|
||||||
|
Keep this module independent of concrete IPC transports, actor
|
||||||
|
runtime models, network resources, tunnels, and optional
|
||||||
|
dependencies.
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import (
|
||||||
|
ClassVar,
|
||||||
|
Literal,
|
||||||
|
Protocol,
|
||||||
|
TypeAlias,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO, maybe breakout the netns key to a struct?
|
||||||
|
# class NetNs(Struct)[str, int]:
|
||||||
|
# ...
|
||||||
|
|
||||||
|
# TODO, can't we just use a type alias
|
||||||
|
# for this? namely just some `tuple[str, int, str, str]`?
|
||||||
|
#
|
||||||
|
# -[ ] would also just be simpler to keep this as
|
||||||
|
# SockAddr[tuple] or something, implying it's just a simple pair
|
||||||
|
# of values which can presumably be mapped to all transports?
|
||||||
|
# -[ ] `pydoc socket.socket.getsockname()` delivers a 4-tuple for
|
||||||
|
# ipv6 `(hostaddr, port, flowinfo, scope_id)`.. so how should we
|
||||||
|
# handle that?
|
||||||
|
# -[ ] as a further alternative to this wrap()/unwrap() approach we
|
||||||
|
# could just implement `enc/dec_hook()`s for the `Address`-types
|
||||||
|
# and just deal with our internal objs directly and always and
|
||||||
|
# leave it to the codec layer to figure out marshalling?
|
||||||
|
# |_ would mean only one spot to do the `.unwrap()` (which we may
|
||||||
|
# end up needing to call from the hook()s anyway?)
|
||||||
|
# -[x] rename to `UnwrappedAddress[Descriptor]` ??
|
||||||
|
# seems like the right name as per the GeeksForGeeks article,
|
||||||
|
# "Introduction to Address Descriptor".
|
||||||
|
#
|
||||||
|
TaggedTCPAddress: TypeAlias = tuple[
|
||||||
|
Literal['tcp'],
|
||||||
|
str,
|
||||||
|
int,
|
||||||
|
]
|
||||||
|
TaggedUnixAddress: TypeAlias = tuple[
|
||||||
|
Literal['unix'],
|
||||||
|
str,
|
||||||
|
]
|
||||||
|
TaggedUDSAlias: TypeAlias = tuple[
|
||||||
|
Literal['uds'],
|
||||||
|
str,
|
||||||
|
]
|
||||||
|
TaggedAddress: TypeAlias = (
|
||||||
|
TaggedTCPAddress
|
||||||
|
|TaggedUnixAddress
|
||||||
|
)
|
||||||
|
|
||||||
|
# Input-only compatibility forms retained for older callers and
|
||||||
|
# serialized payloads.
|
||||||
|
LegacyTCPAddress: TypeAlias = tuple[str, int]
|
||||||
|
LegacyUDSAddress: TypeAlias = tuple[str, str]
|
||||||
|
LegacyUnwrappedAddress: TypeAlias = (
|
||||||
|
LegacyTCPAddress
|
||||||
|
|LegacyUDSAddress
|
||||||
|
)
|
||||||
|
UnwrappedAddress = TaggedAddress
|
||||||
|
|
||||||
|
|
||||||
|
class AddressDeclaration(Protocol):
|
||||||
|
'''
|
||||||
|
Common instance shape of plain and tunnelled addresses.
|
||||||
|
|
||||||
|
This protocol deliberately excludes transport registration and
|
||||||
|
listener operations. A tunnel declaration delegates these address
|
||||||
|
properties to its innermost concrete transport address.
|
||||||
|
|
||||||
|
'''
|
||||||
|
@property
|
||||||
|
def proto_key(self) -> str:
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_valid(self) -> bool:
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def namespace(self) -> tuple[str, str|int]|None:
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bindspace(self) -> str|Path:
|
||||||
|
...
|
||||||
|
|
||||||
|
def unwrap(self) -> UnwrappedAddress:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
# TODO, maybe rename to `SocketAddress`?
|
||||||
|
class Address(Protocol):
|
||||||
|
'''
|
||||||
|
Concrete address contract used by IPC transport backends.
|
||||||
|
|
||||||
|
Unlike `AddressDeclaration`, transport registries require
|
||||||
|
class-level protocol metadata. Transport-specific factories stay
|
||||||
|
on their concrete address classes because their descriptor and
|
||||||
|
bindspace inputs differ.
|
||||||
|
|
||||||
|
'''
|
||||||
|
proto_key: ClassVar[str]
|
||||||
|
unwrapped_type: ClassVar[type]
|
||||||
|
|
||||||
|
# TODO, i feel like an `.is_bound()` is a better thing to
|
||||||
|
# support?
|
||||||
|
# Lke, what use does this have besides a noop and if it's not
|
||||||
|
# valid why aren't we erroring on creation/use?
|
||||||
|
@property
|
||||||
|
def is_valid(self) -> bool:
|
||||||
|
...
|
||||||
|
|
||||||
|
# TODO, maybe `.netns` is a better name?
|
||||||
|
@property
|
||||||
|
def namespace(self) -> tuple[str, str|int]|None:
|
||||||
|
'''
|
||||||
|
The if-available, OS-specific "network namespace" key.
|
||||||
|
|
||||||
|
'''
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bindspace(self) -> str|Path:
|
||||||
|
'''
|
||||||
|
Deliver the address' transport-specific bindable space.
|
||||||
|
|
||||||
|
'''
|
||||||
|
...
|
||||||
|
|
||||||
|
def unwrap(self) -> UnwrappedAddress:
|
||||||
|
'''
|
||||||
|
Deliver the underlying primitive address descriptor.
|
||||||
|
|
||||||
|
'''
|
||||||
|
...
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'Address',
|
||||||
|
'AddressDeclaration',
|
||||||
|
'LegacyTCPAddress',
|
||||||
|
'LegacyUDSAddress',
|
||||||
|
'LegacyUnwrappedAddress',
|
||||||
|
'TaggedAddress',
|
||||||
|
'TaggedTCPAddress',
|
||||||
|
'TaggedUDSAlias',
|
||||||
|
'TaggedUnixAddress',
|
||||||
|
'UnwrappedAddress',
|
||||||
|
)
|
||||||
|
|
@ -43,7 +43,10 @@ from ._types import (
|
||||||
from tractor.discovery._addr import (
|
from tractor.discovery._addr import (
|
||||||
is_wrapped_addr,
|
is_wrapped_addr,
|
||||||
wrap_address,
|
wrap_address,
|
||||||
|
)
|
||||||
|
from tractor.discovery.types import (
|
||||||
Address,
|
Address,
|
||||||
|
AddressDeclaration,
|
||||||
UnwrappedAddress,
|
UnwrappedAddress,
|
||||||
)
|
)
|
||||||
from tractor.log import get_logger
|
from tractor.log import get_logger
|
||||||
|
|
@ -59,9 +62,6 @@ from tractor.msg import (
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ._transport import MsgTransport
|
from ._transport import MsgTransport
|
||||||
from tractor.net._tunnel import TunnelledAddress
|
|
||||||
else:
|
|
||||||
TunnelledAddress = Any
|
|
||||||
|
|
||||||
|
|
||||||
log = get_logger()
|
log = get_logger()
|
||||||
|
|
@ -185,7 +185,7 @@ class Channel:
|
||||||
@classmethod
|
@classmethod
|
||||||
async def from_addr(
|
async def from_addr(
|
||||||
cls,
|
cls,
|
||||||
addr: UnwrappedAddress|Address|TunnelledAddress,
|
addr: UnwrappedAddress|AddressDeclaration,
|
||||||
**kwargs
|
**kwargs
|
||||||
) -> Channel:
|
) -> Channel:
|
||||||
|
|
||||||
|
|
@ -557,7 +557,7 @@ class Channel:
|
||||||
|
|
||||||
@acm
|
@acm
|
||||||
async def _connect_chan(
|
async def _connect_chan(
|
||||||
addr: UnwrappedAddress|Address|TunnelledAddress,
|
addr: UnwrappedAddress|AddressDeclaration,
|
||||||
close_timeout: float|None = None,
|
close_timeout: float|None = None,
|
||||||
) -> typing.AsyncGenerator[Channel, None]:
|
) -> typing.AsyncGenerator[Channel, None]:
|
||||||
'''
|
'''
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,10 @@ from ..msg import (
|
||||||
from ..trionics import maybe_open_nursery
|
from ..trionics import maybe_open_nursery
|
||||||
from ..runtime import _state
|
from ..runtime import _state
|
||||||
from .. import log
|
from .. import log
|
||||||
from ..discovery._addr import (
|
from ..discovery._addr import get_address_cls
|
||||||
|
from ..discovery.types import (
|
||||||
Address,
|
Address,
|
||||||
|
AddressDeclaration,
|
||||||
UnwrappedAddress,
|
UnwrappedAddress,
|
||||||
)
|
)
|
||||||
from ._chan import Channel
|
from ._chan import Channel
|
||||||
|
|
@ -68,7 +70,6 @@ from ._transport import MsgTransport
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ..net._tunnel import TunnelledAddress
|
|
||||||
from ..runtime._runtime import Actor
|
from ..runtime._runtime import Actor
|
||||||
from ..runtime._supervise import ActorNursery
|
from ..runtime._supervise import ActorNursery
|
||||||
|
|
||||||
|
|
@ -631,7 +632,7 @@ class Endpoint(Struct):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
addr: Address
|
addr: Address
|
||||||
declared_addr: Address|TunnelledAddress
|
declared_addr: AddressDeclaration
|
||||||
listen_tn: Nursery
|
listen_tn: Nursery
|
||||||
stream_handler_tn: Nursery|None = None
|
stream_handler_tn: Nursery|None = None
|
||||||
|
|
||||||
|
|
@ -689,7 +690,8 @@ class Endpoint(Struct):
|
||||||
!=
|
!=
|
||||||
self.addr.unwrap()
|
self.addr.unwrap()
|
||||||
):
|
):
|
||||||
self.addr=self.addr.from_addr(unwrapped)
|
address_type = get_address_cls(self.addr.proto_key)
|
||||||
|
self.addr = address_type.from_addr(unwrapped)
|
||||||
|
|
||||||
self._listener = lstnr
|
self._listener = lstnr
|
||||||
return lstnr
|
return lstnr
|
||||||
|
|
@ -991,7 +993,7 @@ class Server(Struct):
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
accept_addrs: list[
|
accept_addrs: list[
|
||||||
UnwrappedAddress|Address|TunnelledAddress
|
UnwrappedAddress|AddressDeclaration
|
||||||
]|None = None,
|
]|None = None,
|
||||||
stream_handler_nursery: Nursery|None = None,
|
stream_handler_nursery: Nursery|None = None,
|
||||||
) -> list[Endpoint]:
|
) -> list[Endpoint]:
|
||||||
|
|
@ -1075,7 +1077,7 @@ async def _serve_ipc_eps(
|
||||||
*,
|
*,
|
||||||
server: IPCServer,
|
server: IPCServer,
|
||||||
stream_handler_tn: Nursery,
|
stream_handler_tn: Nursery,
|
||||||
listen_addrs: list[Address|TunnelledAddress],
|
listen_addrs: list[AddressDeclaration],
|
||||||
|
|
||||||
task_status: TaskStatus[
|
task_status: TaskStatus[
|
||||||
Nursery,
|
Nursery,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ TCP implementation of tractor.ipc._transport.MsgTransport protocol
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import ipaddress
|
import ipaddress
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
|
||||||
ClassVar,
|
ClassVar,
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
)
|
)
|
||||||
|
|
@ -41,15 +40,12 @@ from tractor.ipc._transport import (
|
||||||
MsgTransport,
|
MsgTransport,
|
||||||
MsgpackTransport,
|
MsgpackTransport,
|
||||||
)
|
)
|
||||||
|
from tractor.discovery.types import TaggedTCPAddress
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
# ONLY type-annots, the eager import costs
|
# ONLY type-annots, the eager import costs
|
||||||
# `import tractor` wall-time (gh #470).
|
# `import tractor` wall-time (gh #470).
|
||||||
from multiaddr import Multiaddr
|
from multiaddr import Multiaddr
|
||||||
from tractor.discovery._addr import TaggedTCPAddress
|
|
||||||
else:
|
|
||||||
Multiaddr = Any
|
|
||||||
TaggedTCPAddress = Any
|
|
||||||
|
|
||||||
|
|
||||||
log = get_logger()
|
log = get_logger()
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,7 @@ from tractor.msg import (
|
||||||
types as msgtypes,
|
types as msgtypes,
|
||||||
pretty_struct,
|
pretty_struct,
|
||||||
)
|
)
|
||||||
|
from tractor.discovery.types import Address
|
||||||
if TYPE_CHECKING:
|
|
||||||
from tractor.discovery._addr import Address
|
|
||||||
|
|
||||||
log = get_logger()
|
log = get_logger()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,6 @@ except ImportError:
|
||||||
AF_UNIX = None
|
AF_UNIX = None
|
||||||
import struct
|
import struct
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
|
||||||
Type,
|
Type,
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
ClassVar,
|
ClassVar,
|
||||||
|
|
@ -71,17 +70,13 @@ from tractor.runtime._state import (
|
||||||
current_actor,
|
current_actor,
|
||||||
is_root_process,
|
is_root_process,
|
||||||
)
|
)
|
||||||
|
from tractor.discovery.types import TaggedUnixAddress
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
# ONLY type-annots, the eager import costs
|
# ONLY type-annots, the eager import costs
|
||||||
# `import tractor` wall-time (gh #470).
|
# `import tractor` wall-time (gh #470).
|
||||||
from multiaddr import Multiaddr
|
from multiaddr import Multiaddr
|
||||||
from tractor.discovery._addr import TaggedUnixAddress
|
|
||||||
from tractor.runtime._runtime import Actor
|
from tractor.runtime._runtime import Actor
|
||||||
else:
|
|
||||||
Multiaddr = Any
|
|
||||||
Actor = Any
|
|
||||||
TaggedUnixAddress = Any
|
|
||||||
|
|
||||||
|
|
||||||
# Platform-specific credential passing constants
|
# Platform-specific credential passing constants
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,11 @@ import multibase
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
from ..msg._local import ProcessLocal
|
from ..msg._local import ProcessLocal
|
||||||
|
from ..discovery.types import (
|
||||||
|
Address,
|
||||||
|
AddressDeclaration,
|
||||||
|
UnwrappedAddress,
|
||||||
|
)
|
||||||
from ._bindspace import (
|
from ._bindspace import (
|
||||||
Bindspace,
|
Bindspace,
|
||||||
BindspaceRef,
|
BindspaceRef,
|
||||||
|
|
@ -103,16 +108,6 @@ from ._bindspace import (
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from multiaddr import Multiaddr
|
from multiaddr import Multiaddr
|
||||||
|
|
||||||
from ..discovery._addr import (
|
|
||||||
Address,
|
|
||||||
UnwrappedAddress,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
Address = Any
|
|
||||||
Multiaddr = Any
|
|
||||||
UnwrappedAddress = Any
|
|
||||||
|
|
||||||
|
|
||||||
class WGTunnelSpec(
|
class WGTunnelSpec(
|
||||||
msgspec.Struct,
|
msgspec.Struct,
|
||||||
frozen=True,
|
frozen=True,
|
||||||
|
|
@ -879,7 +874,7 @@ class TunnelledAddress(
|
||||||
`strip_tunnels()`.
|
`strip_tunnels()`.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
overlay: Address|TunnelledAddress
|
overlay: AddressDeclaration
|
||||||
tunnel: TunnelSpec
|
tunnel: TunnelSpec
|
||||||
bindspace_ref: BindspaceRef|None = None
|
bindspace_ref: BindspaceRef|None = None
|
||||||
|
|
||||||
|
|
@ -1057,7 +1052,7 @@ def parse_wg_maddr(
|
||||||
match overlay_names:
|
match overlay_names:
|
||||||
case [('ip4' | 'ip6'), 'tcp']:
|
case [('ip4' | 'ip6'), 'tcp']:
|
||||||
from ..discovery._multiaddr import parse_maddr
|
from ..discovery._multiaddr import parse_maddr
|
||||||
overlay: Address|TunnelledAddress = parse_maddr(
|
overlay: AddressDeclaration = parse_maddr(
|
||||||
str(overlay_ma)
|
str(overlay_ma)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1172,7 +1167,7 @@ def mk_wg_maddr(
|
||||||
|
|
||||||
|
|
||||||
def strip_tunnels(
|
def strip_tunnels(
|
||||||
addr: Address|TunnelledAddress,
|
addr: AddressDeclaration,
|
||||||
) -> Address:
|
) -> Address:
|
||||||
'''
|
'''
|
||||||
Deliver the bindable `Address`, peeling any tunnel
|
Deliver the bindable `Address`, peeling any tunnel
|
||||||
|
|
@ -1191,7 +1186,7 @@ def strip_tunnels(
|
||||||
|
|
||||||
|
|
||||||
def tunnels_of(
|
def tunnels_of(
|
||||||
addr: Address|TunnelledAddress,
|
addr: AddressDeclaration,
|
||||||
) -> tuple[TunnelSpec, ...]:
|
) -> tuple[TunnelSpec, ...]:
|
||||||
'''
|
'''
|
||||||
Deliver every tunnel spec wrapping `addr`, outermost first.
|
Deliver every tunnel spec wrapping `addr`, outermost first.
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,6 @@ import sys
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
Callable,
|
Callable,
|
||||||
Type,
|
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
)
|
)
|
||||||
import uuid
|
import uuid
|
||||||
|
|
@ -1684,10 +1683,10 @@ async def async_main(
|
||||||
[_state._def_tpt_proto]
|
[_state._def_tpt_proto]
|
||||||
)
|
)
|
||||||
for transport_key in enable_transports:
|
for transport_key in enable_transports:
|
||||||
transport_cls: Type[Address] = get_address_cls(
|
address_type = get_address_cls(
|
||||||
transport_key
|
transport_key
|
||||||
)
|
)
|
||||||
addr: Address = transport_cls.get_random()
|
addr: Address = address_type.get_random()
|
||||||
accept_addrs.append(addr.unwrap())
|
accept_addrs.append(addr.unwrap())
|
||||||
|
|
||||||
# XXX, either passed in by caller or delivered
|
# XXX, either passed in by caller or delivered
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue