Move network APIs to lazy `tractor.net`
Move bindspace, tunnel and WireGuard lifecycles out of actor discovery and expose them through one lazy public package. Deats, - keep `import tractor` free of multiaddr, pyroute2 and WG impls - move network-focused tests under `tests/net` - update IPC, spawn, docs and multihost callers to the new API - pin `CURRENT_NETNS` through the calling thread's procfs link Prompt-IO: ai/prompt-io/opencode/20260830T025201Z_b1f6ade8_prompt_io.md (this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))wkt/wg_pyroute2_read
parent
b1f6ade840
commit
3e5a699df6
|
|
@ -0,0 +1,47 @@
|
||||||
|
---
|
||||||
|
model: gpt-5.6-sol
|
||||||
|
service: opencode
|
||||||
|
session: tractor-net-api-extraction
|
||||||
|
timestamp: 2026-08-30T02:52:01Z
|
||||||
|
git_ref: b1f6ade8
|
||||||
|
scope: code
|
||||||
|
substantive: true
|
||||||
|
raw_file: 20260830T025201Z_b1f6ade8_prompt_io.raw.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prompt
|
||||||
|
|
||||||
|
After rebasing the WireGuard Layer C stack, the human questioned the
|
||||||
|
placement of bindspace APIs under `tractor.discovery`, considered new
|
||||||
|
public package names, selected `tractor.net`, and authorized the
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
## Response summary
|
||||||
|
|
||||||
|
Extracted bindspace and tunnel implementations into a lazy
|
||||||
|
`tractor.net` package. Moved public multiaddr, bindspace, tunnel, and
|
||||||
|
WireGuard symbols out of `tractor.discovery`, updated internal imports,
|
||||||
|
tests, examples, and documentation, and added cold-import regressions
|
||||||
|
that keep optional networking dependencies off the root import path.
|
||||||
|
Current-netns attachment pins `/proc/thread-self/ns/net` so calls from
|
||||||
|
non-leader threads retain the caller's namespace rather than the process
|
||||||
|
leader's.
|
||||||
|
|
||||||
|
## Files changed
|
||||||
|
|
||||||
|
- `tractor/net/` - lazy public network API and implementation modules.
|
||||||
|
- `tractor/discovery/` - retain actor discovery and internal address parsing.
|
||||||
|
- `tractor/__init__.py` - expose `tractor.net` lazily.
|
||||||
|
- `tests/net/` - network declaration and lifecycle coverage.
|
||||||
|
- `tests/test_lazy_imports.py` - enforce the lazy package boundary.
|
||||||
|
- `examples/multihost/wg_lan/` - use the public network package.
|
||||||
|
- `docs/` - document network APIs separately from actor discovery.
|
||||||
|
|
||||||
|
## Human edits
|
||||||
|
|
||||||
|
The human rejected `tractor.discovery` as the long-term public home,
|
||||||
|
considered tunnel- and namespace-specific alternatives, and selected
|
||||||
|
the broader `tractor.net` boundary because bindspaces may include plain
|
||||||
|
netns, WireGuard, VRF, veth, and later network resources. The agent
|
||||||
|
applied the resulting source changes; no direct manual edits were
|
||||||
|
observed.
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
model: gpt-5.6-sol
|
||||||
|
service: opencode
|
||||||
|
timestamp: 2026-08-30T02:52:01Z
|
||||||
|
git_ref: b1f6ade8
|
||||||
|
diff_cmd: git diff HEAD~1..HEAD
|
||||||
|
---
|
||||||
|
|
||||||
|
# Raw output - extract public network APIs
|
||||||
|
|
||||||
|
The human questioned whether bindspace and WireGuard lifecycle APIs
|
||||||
|
belonged under actor discovery, selected the proposed `tractor.net`
|
||||||
|
boundary, and authorized implementation.
|
||||||
|
|
||||||
|
## Generated code
|
||||||
|
|
||||||
|
> `git diff HEAD~1..HEAD -- tractor/net tractor/discovery tractor/__init__.py`
|
||||||
|
|
||||||
|
Move bindspace and tunnel implementations into a lazy public network
|
||||||
|
package. Keep actor discovery focused on registry and lookup behavior,
|
||||||
|
while exposing bindspace, tunnel, WireGuard, and multiaddr declarations
|
||||||
|
through `tractor.net` without loading optional networking dependencies
|
||||||
|
during `import tractor`.
|
||||||
|
|
||||||
|
> `git diff HEAD~1..HEAD -- tests/net tests/test_lazy_imports.py tests/ipc examples/multihost/wg_lan docs`
|
||||||
|
|
||||||
|
Move network-focused tests to `tests/net`, update internal and public
|
||||||
|
imports, verify lazy symbol resolution and removed discovery exports,
|
||||||
|
and document the new package boundary.
|
||||||
|
|
@ -47,7 +47,7 @@ Here is a small example from piker,
|
||||||
We should take whatever common API is needed to support this and
|
We should take whatever common API is needed to support this and
|
||||||
distill it into a
|
distill it into a
|
||||||
```python
|
```python
|
||||||
tractor.discovery.parse_endpoints(
|
tractor.net.parse_endpoints(
|
||||||
) -> dict[
|
) -> dict[
|
||||||
str,
|
str,
|
||||||
list[Address]
|
list[Address]
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,7 @@ Observed protocol-name lists, for writing the `match`:
|
||||||
### 3.3 pure codecs + explicit verification
|
### 3.3 pure codecs + explicit verification
|
||||||
|
|
||||||
Port #482 §2's pure helpers into
|
Port #482 §2's pure helpers into
|
||||||
`tractor/discovery/_tunnel.py`, keeping the impure probe cleanly
|
`tractor/net/_tunnel.py`, keeping the impure probe cleanly
|
||||||
separated until layer B:
|
separated until layer B:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ Most-used names at a glance:
|
||||||
core
|
core
|
||||||
context
|
context
|
||||||
discovery
|
discovery
|
||||||
|
net
|
||||||
errors
|
errors
|
||||||
msg
|
msg
|
||||||
trionics
|
trionics
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ already distributed-system aware.
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
:doc:`/explain/architecture` for the transport/server
|
:doc:`/explain/architecture` for the transport/server
|
||||||
internals, :doc:`/api/discovery` for how channel addresses
|
internals, :doc:`/api/net` for network declarations,
|
||||||
get registered and found, and :doc:`/api/msg` for the codec
|
:doc:`/api/discovery` for how channel addresses get registered
|
||||||
layer every channel speaks.
|
and found, and :doc:`/api/msg` for the codec layer every channel
|
||||||
|
speaks.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
Network declarations and lifecycles
|
||||||
|
===================================
|
||||||
|
|
||||||
|
``tractor.net`` provides address composition, bindspace declarations,
|
||||||
|
and tunnel configuration. The package is lazy: importing
|
||||||
|
``tractor`` or ``tractor.net`` does not load multiaddr, WireGuard, or
|
||||||
|
pyroute2 implementation modules until a public symbol is used.
|
||||||
|
|
||||||
|
Multiaddr helpers
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. currentmodule:: tractor.net
|
||||||
|
|
||||||
|
.. autofunction:: mk_maddr
|
||||||
|
|
||||||
|
.. autofunction:: parse_maddr
|
||||||
|
|
||||||
|
.. autofunction:: parse_endpoints
|
||||||
|
|
||||||
|
Bindspaces
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. autoclass:: BindspaceSpec
|
||||||
|
|
||||||
|
.. autoclass:: BindspaceRef
|
||||||
|
|
||||||
|
.. autoclass:: Bindspace
|
||||||
|
|
||||||
|
.. autofunction:: attach_netns
|
||||||
|
|
||||||
|
.. autofunction:: open_netns
|
||||||
|
|
||||||
|
.. autofunction:: open_bindspace
|
||||||
|
|
||||||
|
Tunnels and WireGuard
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
.. autoclass:: TunnelledAddress
|
||||||
|
|
||||||
|
.. autoclass:: WGTunnelSpec
|
||||||
|
|
||||||
|
.. autoclass:: WGInterfaceConfig
|
||||||
|
|
||||||
|
.. autoclass:: WGPeerConfig
|
||||||
|
|
||||||
|
.. autofunction:: parse_wg_maddr
|
||||||
|
|
||||||
|
.. autofunction:: mk_wg_maddr
|
||||||
|
|
||||||
|
.. autofunction:: strip_tunnels
|
||||||
|
|
||||||
|
.. autofunction:: tunnels_of
|
||||||
|
|
||||||
|
.. autofunction:: open_wg_iface
|
||||||
|
|
||||||
|
.. autofunction:: open_wg_bindspace
|
||||||
|
|
||||||
|
.. autofunction:: read_wg_pubkey
|
||||||
|
|
||||||
|
.. autofunction:: read_wg_peers
|
||||||
|
|
||||||
|
.. autofunction:: verify_wg_peer
|
||||||
|
|
@ -264,7 +264,7 @@ terminology is retired: it's *registrar*/*registry* everywhere now
|
||||||
substitute "registrar" and you're up to date.
|
substitute "registrar" and you're up to date.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Multihoming nerds: ``tractor.discovery`` also ships
|
Multihoming nerds: ``tractor.net`` ships
|
||||||
libp2p-style *multiaddr* helpers — ``mk_maddr()`` and
|
libp2p-style *multiaddr* helpers — ``mk_maddr()`` and
|
||||||
``parse_maddr()`` — for describing transport endpoints as
|
``parse_maddr()`` — for describing transport endpoints as
|
||||||
structured strings.
|
structured strings.
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ ping -c1 10.0.11.1 # from B
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python -c "
|
python -c "
|
||||||
from tractor.discovery import mb_pubkey
|
from tractor.net import mb_pubkey
|
||||||
key = open('wg_pub.key').read().strip()
|
key = open('wg_pub.key').read().strip()
|
||||||
print(mb_pubkey(key))
|
print(mb_pubkey(key))
|
||||||
"
|
"
|
||||||
|
|
@ -166,7 +166,7 @@ Four corrections, all from
|
||||||
|
|
||||||
## next
|
## next
|
||||||
|
|
||||||
Layer A's `TunnelledAddress` and native maddr parser plus Layer B's
|
The `TunnelledAddress`, native maddr parser, bindspace lifecycle, and
|
||||||
explicit pyroute2 verification now live in `tractor.discovery`. Next,
|
explicit pyroute2 verification APIs live in `tractor.net`. Root actor
|
||||||
add `open_bindspace()` `@acm`s which create/tear down the iface and
|
bindspace integration remains future work; callers compose these
|
||||||
netns.
|
lifecycles explicitly for now.
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import tractor
|
import tractor
|
||||||
import trio
|
import trio
|
||||||
from tractor.discovery import (
|
from tractor.net import (
|
||||||
TunnelledAddress,
|
TunnelledAddress,
|
||||||
mk_maddr,
|
mk_maddr,
|
||||||
parse_wg_maddr,
|
parse_wg_maddr,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import tractor
|
import tractor
|
||||||
import trio
|
import trio
|
||||||
from tractor.discovery import (
|
from tractor.net import (
|
||||||
TunnelledAddress,
|
TunnelledAddress,
|
||||||
parse_wg_maddr,
|
parse_wg_maddr,
|
||||||
verify_wg_peer,
|
verify_wg_peer,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ from tractor.devx import dump_on_hang
|
||||||
from tractor.trionics import collapse_eg
|
from tractor.trionics import collapse_eg
|
||||||
from tractor._testing import tractor_test
|
from tractor._testing import tractor_test
|
||||||
from tractor.discovery._addr import wrap_address
|
from tractor.discovery._addr import wrap_address
|
||||||
from tractor.discovery._multiaddr import mk_maddr
|
from tractor.net import mk_maddr
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ from tractor.discovery import _api
|
||||||
from tractor.discovery._addr import (
|
from tractor.discovery._addr import (
|
||||||
wrap_address,
|
wrap_address,
|
||||||
)
|
)
|
||||||
from tractor.discovery._multiaddr import mk_maddr
|
from tractor.net import mk_maddr
|
||||||
from tractor.ipc import _connect_chan
|
from tractor.ipc import _connect_chan
|
||||||
from tractor._testing.addr import get_rando_addr
|
from tractor._testing.addr import get_rando_addr
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from __future__ import annotations
|
||||||
import pytest
|
import pytest
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
from tractor.discovery import (
|
from tractor.net import (
|
||||||
TunnelledAddress,
|
TunnelledAddress,
|
||||||
WGTunnelSpec,
|
WGTunnelSpec,
|
||||||
tunnels_of,
|
tunnels_of,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
from tractor.discovery import (
|
from tractor.net import (
|
||||||
BindspaceRef,
|
BindspaceRef,
|
||||||
TunnelledAddress,
|
TunnelledAddress,
|
||||||
WGTunnelSpec,
|
WGTunnelSpec,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
'''Network declaration and lifecycle tests.'''
|
||||||
|
|
@ -13,7 +13,7 @@ import msgspec
|
||||||
import pytest
|
import pytest
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
from tractor.discovery import (
|
from tractor.net import (
|
||||||
Bindspace,
|
Bindspace,
|
||||||
BindspaceOwnership,
|
BindspaceOwnership,
|
||||||
BindspaceRef,
|
BindspaceRef,
|
||||||
|
|
@ -23,7 +23,7 @@ from tractor.discovery import (
|
||||||
open_bindspace,
|
open_bindspace,
|
||||||
open_netns,
|
open_netns,
|
||||||
)
|
)
|
||||||
from tractor.discovery import _bindspace
|
from tractor.net import _bindspace
|
||||||
from tractor.msg import ProcessLocal
|
from tractor.msg import ProcessLocal
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -261,10 +261,11 @@ def test_open_bindspace_attaches_current_netns() -> None:
|
||||||
'''
|
'''
|
||||||
The unnamed spec must borrow and pin the caller's current netns.
|
The unnamed spec must borrow and pin the caller's current netns.
|
||||||
|
|
||||||
Open `/proc/self/ns/net`, prove the yielded bindspace records its
|
Opening `/proc/self/ns/net` could pin the thread-group leader's
|
||||||
stable inode and borrowed ownership, then exit the context and
|
namespace when this context runs from another thread. Prove the
|
||||||
prove the exact descriptor was closed without altering the
|
implementation selects `/proc/thread-self/ns/net`, records the
|
||||||
namespace itself.
|
calling thread's stable inode and borrowed ownership, then closes
|
||||||
|
the exact descriptor without altering the namespace itself.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
async def main() -> int:
|
async def main() -> int:
|
||||||
|
|
@ -276,6 +277,9 @@ def test_open_bindspace_attaches_current_netns() -> None:
|
||||||
kind='netns',
|
kind='netns',
|
||||||
)
|
)
|
||||||
assert spec.key is CURRENT_NETNS
|
assert spec.key is CURRENT_NETNS
|
||||||
|
assert _bindspace._THREAD_NETNS == Path(
|
||||||
|
'/proc/thread-self/ns/net'
|
||||||
|
)
|
||||||
async with open_bindspace(spec) as bindspace:
|
async with open_bindspace(spec) as bindspace:
|
||||||
namespace_fd: int|None = bindspace.namespace_fd
|
namespace_fd: int|None = bindspace.namespace_fd
|
||||||
assert namespace_fd is not None
|
assert namespace_fd is not None
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
'''
|
'''
|
||||||
Multiaddr construction, parsing, and round-trip tests for
|
Multiaddr construction, parsing, and round-trip tests for
|
||||||
`tractor.discovery._multiaddr.mk_maddr()` and
|
`tractor.net.mk_maddr()` and `tractor.net.parse_maddr()`.
|
||||||
`tractor.discovery._multiaddr.parse_maddr()`.
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
@ -10,20 +9,20 @@ from types import SimpleNamespace
|
||||||
import pytest
|
import pytest
|
||||||
from multiaddr import Multiaddr
|
from multiaddr import Multiaddr
|
||||||
|
|
||||||
from tractor.discovery import (
|
from tractor.net import (
|
||||||
TunnelledAddress,
|
TunnelledAddress,
|
||||||
WGTunnelSpec,
|
WGTunnelSpec,
|
||||||
mb_pubkey,
|
mb_pubkey,
|
||||||
mk_wg_maddr,
|
mk_wg_maddr,
|
||||||
|
mk_maddr,
|
||||||
|
parse_endpoints,
|
||||||
|
parse_maddr,
|
||||||
parse_wg_maddr,
|
parse_wg_maddr,
|
||||||
tunnels_of,
|
tunnels_of,
|
||||||
)
|
)
|
||||||
from tractor.ipc._tcp import TCPAddress
|
from tractor.ipc._tcp import TCPAddress
|
||||||
from tractor.ipc._uds import UDSAddress
|
from tractor.ipc._uds import UDSAddress
|
||||||
from tractor.discovery._multiaddr import (
|
from tractor.discovery._multiaddr import (
|
||||||
mk_maddr,
|
|
||||||
parse_maddr,
|
|
||||||
parse_endpoints,
|
|
||||||
_tpt_proto_to_maddr,
|
_tpt_proto_to_maddr,
|
||||||
_maddr_to_tpt_proto,
|
_maddr_to_tpt_proto,
|
||||||
)
|
)
|
||||||
|
|
@ -14,7 +14,7 @@ from __future__ import annotations
|
||||||
import msgspec
|
import msgspec
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tractor.discovery import (
|
from tractor.net import (
|
||||||
BindspaceRef,
|
BindspaceRef,
|
||||||
TunnelledAddress,
|
TunnelledAddress,
|
||||||
WGTunnelSpec,
|
WGTunnelSpec,
|
||||||
|
|
@ -7,7 +7,7 @@ from __future__ import annotations
|
||||||
import msgspec
|
import msgspec
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tractor.discovery import (
|
from tractor.net import (
|
||||||
WGInterfaceConfig,
|
WGInterfaceConfig,
|
||||||
WGPeerConfig,
|
WGPeerConfig,
|
||||||
)
|
)
|
||||||
|
|
@ -13,7 +13,7 @@ from typing import BinaryIO
|
||||||
import pytest
|
import pytest
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
from tractor.discovery import (
|
from tractor.net import (
|
||||||
Bindspace,
|
Bindspace,
|
||||||
BindspaceRef,
|
BindspaceRef,
|
||||||
BindspaceSpec,
|
BindspaceSpec,
|
||||||
|
|
@ -23,7 +23,7 @@ from tractor.discovery import (
|
||||||
open_wg_bindspace,
|
open_wg_bindspace,
|
||||||
open_wg_iface,
|
open_wg_iface,
|
||||||
)
|
)
|
||||||
from tractor.discovery import _tunnel
|
from tractor.net import _tunnel
|
||||||
|
|
||||||
|
|
||||||
_LOCAL_KEY: str = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='
|
_LOCAL_KEY: str = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='
|
||||||
|
|
@ -13,13 +13,13 @@ from typing import (
|
||||||
import pytest
|
import pytest
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
from tractor.discovery import (
|
from tractor.net import (
|
||||||
read_wg_peers,
|
read_wg_peers,
|
||||||
read_wg_pubkey,
|
read_wg_pubkey,
|
||||||
verify_wg_peer,
|
verify_wg_peer,
|
||||||
WGTunnelSpec,
|
WGTunnelSpec,
|
||||||
)
|
)
|
||||||
from tractor.discovery import _tunnel
|
from tractor.net import _tunnel
|
||||||
|
|
||||||
pyroute2: Any = pytest.importorskip('pyroute2')
|
pyroute2: Any = pytest.importorskip('pyroute2')
|
||||||
|
|
||||||
|
|
@ -44,8 +44,8 @@ def test_lazy_to_asyncio_package_api():
|
||||||
Before the lazy conversion, package import side effects exposed
|
Before the lazy conversion, package import side effects exposed
|
||||||
`to_asyncio` to `dir()` and wildcard imports. Exercise those APIs
|
`to_asyncio` to `dir()` and wildcard imports. Exercise those APIs
|
||||||
in cold interpreters so this test proves normal `import tractor`
|
in cold interpreters so this test proves normal `import tractor`
|
||||||
leaves `asyncio` unloaded, while discovery and wildcard access
|
leaves `asyncio` unloaded, while introspection and wildcard
|
||||||
still advertise and resolve the public submodule.
|
access still advertise and resolve the public submodule.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
cold = run_cold_import(
|
cold = run_cold_import(
|
||||||
|
|
@ -102,6 +102,12 @@ def test_cold_import_budget():
|
||||||
'bidict',
|
'bidict',
|
||||||
'colorlog',
|
'colorlog',
|
||||||
'multiaddr',
|
'multiaddr',
|
||||||
|
'multibase',
|
||||||
|
'pyroute2',
|
||||||
|
'tractor.discovery._multiaddr',
|
||||||
|
'tractor.net',
|
||||||
|
'tractor.net._bindspace',
|
||||||
|
'tractor.net._tunnel',
|
||||||
'wrapt',
|
'wrapt',
|
||||||
)
|
)
|
||||||
code = (
|
code = (
|
||||||
|
|
@ -136,6 +142,123 @@ def test_cold_import_budget():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_lazy_net_package_api():
|
||||||
|
'''
|
||||||
|
Keep the public network package cold until symbol access.
|
||||||
|
|
||||||
|
The old discovery re-exports imported bindspace, tunnel,
|
||||||
|
multiaddr and optional dependencies while initializing a package.
|
||||||
|
Import `tractor.net` in a clean interpreter, inspect its public
|
||||||
|
surface, and prove no implementation or optional dependency was
|
||||||
|
loaded. Then resolve one symbol from each backing module and
|
||||||
|
prove the facade caches each value while preserving boundaries.
|
||||||
|
|
||||||
|
'''
|
||||||
|
modules: tuple[str, ...] = (
|
||||||
|
'tractor.net._bindspace',
|
||||||
|
'tractor.net._tunnel',
|
||||||
|
'tractor.discovery._multiaddr',
|
||||||
|
'multiaddr',
|
||||||
|
'multibase',
|
||||||
|
'pyroute2',
|
||||||
|
)
|
||||||
|
cold: dict[str, object] = run_cold_import(
|
||||||
|
'import json, sys; import tractor.net as net; '
|
||||||
|
f'names = {modules!r}; '
|
||||||
|
'print(json.dumps({'
|
||||||
|
'"public": all(name in dir(net) for name in net.__all__), '
|
||||||
|
'"loaded": [name for name in names if name in sys.modules]'
|
||||||
|
'}))'
|
||||||
|
)
|
||||||
|
assert cold == {
|
||||||
|
'public': True,
|
||||||
|
'loaded': [],
|
||||||
|
}
|
||||||
|
|
||||||
|
resolved: dict[str, object] = run_cold_import(
|
||||||
|
'import json, sys; import tractor.net as net; '
|
||||||
|
'bindspace = net.BindspaceSpec; '
|
||||||
|
'bindspace_cached = net.BindspaceSpec is bindspace; '
|
||||||
|
'maddr = net.mk_maddr; '
|
||||||
|
'maddr_cached = net.mk_maddr is maddr; '
|
||||||
|
'tunnel = net.WGTunnelSpec; '
|
||||||
|
'tunnel_cached = net.WGTunnelSpec is tunnel; '
|
||||||
|
'print(json.dumps({'
|
||||||
|
'"bindspace_cached": bindspace_cached, '
|
||||||
|
'"maddr_cached": maddr_cached, '
|
||||||
|
'"tunnel_cached": tunnel_cached, '
|
||||||
|
'"bindspace_module": bindspace.__module__, '
|
||||||
|
'"maddr_module": maddr.__module__, '
|
||||||
|
'"tunnel_module": tunnel.__module__, '
|
||||||
|
'"multiaddr_loaded": "multiaddr" in sys.modules, '
|
||||||
|
'"pyroute2_loaded": "pyroute2" in sys.modules'
|
||||||
|
'}))'
|
||||||
|
)
|
||||||
|
assert resolved == {
|
||||||
|
'bindspace_cached': True,
|
||||||
|
'maddr_cached': True,
|
||||||
|
'tunnel_cached': True,
|
||||||
|
'bindspace_module': 'tractor.net._bindspace',
|
||||||
|
'maddr_module': 'tractor.discovery._multiaddr',
|
||||||
|
'tunnel_module': 'tractor.net._tunnel',
|
||||||
|
'multiaddr_loaded': False,
|
||||||
|
'pyroute2_loaded': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_net_root_export_and_old_discovery_surface():
|
||||||
|
'''
|
||||||
|
Publish networking only from its approved namespace.
|
||||||
|
|
||||||
|
Before extraction, unshipped network names and implementation
|
||||||
|
modules lived under `tractor.discovery`. Exercise root attribute
|
||||||
|
and wildcard access in clean interpreters, proving `tractor.net`
|
||||||
|
is discoverable and cached without loading implementations. Also
|
||||||
|
prove the old exports are absent and their modules no longer
|
||||||
|
resolve, preventing accidental compatibility aliases.
|
||||||
|
|
||||||
|
'''
|
||||||
|
root: dict[str, object] = run_cold_import(
|
||||||
|
'import json, sys, tractor; '
|
||||||
|
'advertised = "net" in dir(tractor); '
|
||||||
|
'net = tractor.net; '
|
||||||
|
'print(json.dumps({'
|
||||||
|
'"advertised": advertised, '
|
||||||
|
'"cached": tractor.net is net, '
|
||||||
|
'"module": net.__name__, '
|
||||||
|
'"bindspace_loaded": '
|
||||||
|
'"tractor.net._bindspace" in sys.modules, '
|
||||||
|
'"tunnel_loaded": "tractor.net._tunnel" in sys.modules'
|
||||||
|
'}))'
|
||||||
|
)
|
||||||
|
assert root == {
|
||||||
|
'advertised': True,
|
||||||
|
'cached': True,
|
||||||
|
'module': 'tractor.net',
|
||||||
|
'bindspace_loaded': False,
|
||||||
|
'tunnel_loaded': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
old: dict[str, object] = run_cold_import(
|
||||||
|
'import importlib.util, json; '
|
||||||
|
'import tractor.discovery as discovery; '
|
||||||
|
'old_names = ("Bindspace", "TunnelledAddress", '
|
||||||
|
'"mk_maddr", "parse_maddr", "parse_endpoints"); '
|
||||||
|
'old_modules = ("tractor.discovery._bindspace", '
|
||||||
|
'"tractor.discovery._tunnel"); '
|
||||||
|
'print(json.dumps({'
|
||||||
|
'"exports": [name for name in old_names '
|
||||||
|
'if hasattr(discovery, name)], '
|
||||||
|
'"modules": [name for name in old_modules '
|
||||||
|
'if importlib.util.find_spec(name) is not None]'
|
||||||
|
'}))'
|
||||||
|
)
|
||||||
|
assert old == {
|
||||||
|
'exports': [],
|
||||||
|
'modules': [],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_lazy_annotation_names_resolve():
|
def test_lazy_annotation_names_resolve():
|
||||||
'''
|
'''
|
||||||
Resolve annotations without importing optional dependencies.
|
Resolve annotations without importing optional dependencies.
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import trio
|
||||||
import tractor
|
import tractor
|
||||||
from tractor import _child
|
from tractor import _child
|
||||||
from tractor.devx import _proctitle
|
from tractor.devx import _proctitle
|
||||||
from tractor.discovery._bindspace import (
|
from tractor.net._bindspace import (
|
||||||
Bindspace,
|
Bindspace,
|
||||||
BindspaceRef,
|
BindspaceRef,
|
||||||
BindspaceSpec,
|
BindspaceSpec,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
tractor: structured concurrent ``trio``-"actors".
|
tractor: structured concurrent ``trio``-"actors".
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from types import ModuleType as _ModuleType
|
||||||
|
|
||||||
from ._clustering import (
|
from ._clustering import (
|
||||||
open_actor_cluster as open_actor_cluster,
|
open_actor_cluster as open_actor_cluster,
|
||||||
|
|
@ -82,6 +83,7 @@ __all__: tuple[str, ...] = tuple(
|
||||||
for name in globals()
|
for name in globals()
|
||||||
if not name.startswith('_')
|
if not name.startswith('_')
|
||||||
) + (
|
) + (
|
||||||
|
'net',
|
||||||
'to_asyncio',
|
'to_asyncio',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -92,21 +94,18 @@ def __dir__() -> list[str]:
|
||||||
|
|
||||||
def __getattr__(name: str):
|
def __getattr__(name: str):
|
||||||
'''
|
'''
|
||||||
PEP 562 lazy sub-module loading, presently only for
|
PEP 562 lazy public sub-package loading.
|
||||||
`.to_asyncio` which (transitively) imports `asyncio`
|
|
||||||
itself: a non-trivial multi-ms chunk of the eager
|
|
||||||
`import tractor` cost (gh #470) unneeded by
|
|
||||||
`trio`-only apps.
|
|
||||||
|
|
||||||
Any `tractor.to_asyncio.<attr>` access (or a
|
`tractor.to_asyncio` transitively imports `asyncio`, while
|
||||||
`from tractor import to_asyncio`) still works, the
|
`tractor.net` owns optional network dependencies. Neither is
|
||||||
sub-mod is simply imported on first-access instead
|
needed by most applications merely importing the root package.
|
||||||
of at pkg-import time.
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
if name == 'to_asyncio':
|
if name in ('net', 'to_asyncio'):
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
return import_module('.to_asyncio', __name__)
|
module: _ModuleType = import_module(f'.{name}', __name__)
|
||||||
|
globals()[name] = module
|
||||||
|
return module
|
||||||
|
|
||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
f'module {__name__!r} has no attribute {name!r}'
|
f'module {__name__!r} has no attribute {name!r}'
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,6 @@ from .discovery._addr import (
|
||||||
mk_uuid,
|
mk_uuid,
|
||||||
wrap_address,
|
wrap_address,
|
||||||
)
|
)
|
||||||
from .discovery._tunnel import strip_tunnels
|
|
||||||
from .trionics import (
|
from .trionics import (
|
||||||
is_multi_cancelled,
|
is_multi_cancelled,
|
||||||
collapse_eg,
|
collapse_eg,
|
||||||
|
|
@ -505,6 +504,8 @@ async def open_root_actor(
|
||||||
# XXX INSTEAD, bind random addrs using the same tpt
|
# XXX INSTEAD, bind random addrs using the same tpt
|
||||||
# proto if not already provided.
|
# proto if not already provided.
|
||||||
if not tpt_bind_addrs:
|
if not tpt_bind_addrs:
|
||||||
|
from .net._tunnel import strip_tunnels
|
||||||
|
|
||||||
for addr in ponged_addrs:
|
for addr in ponged_addrs:
|
||||||
bindable_addr: Address = strip_tunnels(addr)
|
bindable_addr: Address = strip_tunnels(addr)
|
||||||
tpt_bind_addrs.append(
|
tpt_bind_addrs.append(
|
||||||
|
|
|
||||||
|
|
@ -15,48 +15,8 @@
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Discovery (protocols) API for automatic addressing
|
Actor discovery and registrar implementation package.
|
||||||
and location management of (service) actors.
|
|
||||||
|
|
||||||
NOTE: this ``__init__`` only eagerly imports the lightweight
|
Network declarations and helpers are public from `tractor.net`.
|
||||||
``._multiaddr`` and ``._tunnel`` submodules for public re-exports.
|
|
||||||
Heavier submodules like ``._addr`` and ``._api`` are NOT imported
|
|
||||||
here to avoid circular imports; use direct module paths for those.
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
from ._bindspace import (
|
|
||||||
Bindspace as Bindspace,
|
|
||||||
BindspaceKind as BindspaceKind,
|
|
||||||
BindspaceLifecycle as BindspaceLifecycle,
|
|
||||||
BindspaceOwnership as BindspaceOwnership,
|
|
||||||
BindspaceRef as BindspaceRef,
|
|
||||||
BindspaceSpec as BindspaceSpec,
|
|
||||||
CURRENT_NETNS as CURRENT_NETNS,
|
|
||||||
attach_netns as attach_netns,
|
|
||||||
open_bindspace as open_bindspace,
|
|
||||||
open_netns as open_netns,
|
|
||||||
)
|
|
||||||
from ._multiaddr import (
|
|
||||||
parse_endpoints as parse_endpoints,
|
|
||||||
parse_maddr as parse_maddr,
|
|
||||||
mk_maddr as mk_maddr,
|
|
||||||
)
|
|
||||||
from ._tunnel import (
|
|
||||||
TunnelledAddress as TunnelledAddress,
|
|
||||||
TunnelSpec as TunnelSpec,
|
|
||||||
WGTunnelSpec as WGTunnelSpec,
|
|
||||||
WGInterfaceConfig as WGInterfaceConfig,
|
|
||||||
WGPeerConfig as WGPeerConfig,
|
|
||||||
WGRole as WGRole,
|
|
||||||
mb_pubkey as mb_pubkey,
|
|
||||||
mk_wg_maddr as mk_wg_maddr,
|
|
||||||
open_wg_bindspace as open_wg_bindspace,
|
|
||||||
open_wg_iface as open_wg_iface,
|
|
||||||
parse_wg_maddr as parse_wg_maddr,
|
|
||||||
read_wg_peers as read_wg_peers,
|
|
||||||
read_wg_pubkey as read_wg_pubkey,
|
|
||||||
strip_tunnels as strip_tunnels,
|
|
||||||
tunnels_of as tunnels_of,
|
|
||||||
verify_wg_peer as verify_wg_peer,
|
|
||||||
wg8_pubkey as wg8_pubkey,
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ from ..ipc._uds import (
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
# ONLY type-annots, the eager import costs ~4.5ms
|
# ONLY type-annots, the eager import costs ~4.5ms
|
||||||
# of `import tractor` wall-time (gh #470).
|
# of `import tractor` wall-time (gh #470).
|
||||||
from ._tunnel import (
|
from tractor.net._tunnel import (
|
||||||
TunnelledAddress,
|
TunnelledAddress,
|
||||||
)
|
)
|
||||||
from ..runtime._runtime import Actor
|
from ..runtime._runtime import Actor
|
||||||
|
|
@ -237,8 +237,9 @@ def is_wrapped_addr(addr: any) -> 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
|
||||||
# `socket(2)`), so it gets no proto-key entry. See `._tunnel`.
|
# `socket(2)`), so it gets no proto-key entry. See
|
||||||
from ._tunnel import TunnelledAddress
|
# `tractor.net._tunnel`.
|
||||||
|
from tractor.net._tunnel import TunnelledAddress
|
||||||
return (
|
return (
|
||||||
type(addr) in _address_types.values()
|
type(addr) in _address_types.values()
|
||||||
or
|
or
|
||||||
|
|
@ -333,7 +334,7 @@ def wrap_address(
|
||||||
# multiaddr-format string, e.g.
|
# multiaddr-format string, e.g.
|
||||||
# '/ip4/127.0.0.1/tcp/1616'
|
# '/ip4/127.0.0.1/tcp/1616'
|
||||||
case str() if addr.startswith('/'):
|
case str() if addr.startswith('/'):
|
||||||
from tractor.discovery._multiaddr import (
|
from tractor.net import (
|
||||||
parse_maddr,
|
parse_maddr,
|
||||||
)
|
)
|
||||||
return parse_maddr(addr)
|
return parse_maddr(addr)
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ if TYPE_CHECKING:
|
||||||
# `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.discovery._addr import Address
|
||||||
from tractor.discovery._tunnel import (
|
from tractor.net._tunnel import (
|
||||||
TunnelledAddress,
|
TunnelledAddress,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
@ -71,7 +71,7 @@ def mk_maddr(
|
||||||
'''
|
'''
|
||||||
from multiaddr import Multiaddr
|
from multiaddr import Multiaddr
|
||||||
|
|
||||||
from ._tunnel import (
|
from tractor.net._tunnel import (
|
||||||
TunnelledAddress,
|
TunnelledAddress,
|
||||||
mk_wg_maddr,
|
mk_wg_maddr,
|
||||||
)
|
)
|
||||||
|
|
@ -130,7 +130,7 @@ def parse_maddr(
|
||||||
# fails. Pre-checking the raw string would misclassify valid
|
# fails. Pre-checking the raw string would misclassify valid
|
||||||
# values such as `/unix/tmp/wg/service.sock`.
|
# values such as `/unix/tmp/wg/service.sock`.
|
||||||
if '/wg/' in maddr_str:
|
if '/wg/' in maddr_str:
|
||||||
from ._tunnel import _wg_proto_code
|
from tractor.net._tunnel import _wg_proto_code
|
||||||
_wg_proto_code()
|
_wg_proto_code()
|
||||||
raise
|
raise
|
||||||
proto_names: list[str] = [
|
proto_names: list[str] = [
|
||||||
|
|
@ -156,7 +156,7 @@ def parse_maddr(
|
||||||
)
|
)
|
||||||
|
|
||||||
case _ if 'wg' in proto_names:
|
case _ if 'wg' in proto_names:
|
||||||
from ._tunnel import parse_wg_maddr
|
from tractor.net._tunnel import parse_wg_maddr
|
||||||
return parse_wg_maddr(maddr)
|
return parse_wg_maddr(maddr)
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,6 @@ from tractor.discovery._addr import (
|
||||||
Address,
|
Address,
|
||||||
UnwrappedAddress,
|
UnwrappedAddress,
|
||||||
)
|
)
|
||||||
from tractor.discovery._tunnel import (
|
|
||||||
TunnelledAddress,
|
|
||||||
strip_tunnels,
|
|
||||||
)
|
|
||||||
from tractor.log import get_logger
|
from tractor.log import get_logger
|
||||||
from tractor._exceptions import (
|
from tractor._exceptions import (
|
||||||
MsgTypeError,
|
MsgTypeError,
|
||||||
|
|
@ -63,6 +59,9 @@ 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()
|
||||||
|
|
@ -190,6 +189,8 @@ class Channel:
|
||||||
**kwargs
|
**kwargs
|
||||||
) -> Channel:
|
) -> Channel:
|
||||||
|
|
||||||
|
from tractor.net._tunnel import strip_tunnels
|
||||||
|
|
||||||
if not is_wrapped_addr(addr):
|
if not is_wrapped_addr(addr):
|
||||||
addr = wrap_address(addr)
|
addr = wrap_address(addr)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ from ._transport import MsgTransport
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ..discovery._tunnel import TunnelledAddress
|
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
|
||||||
|
|
||||||
|
|
@ -1091,7 +1091,7 @@ async def _serve_ipc_eps(
|
||||||
`.cancel_server()` is called.
|
`.cancel_server()` is called.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
from ..discovery._tunnel import strip_tunnels
|
from ..net._tunnel import strip_tunnels
|
||||||
|
|
||||||
try:
|
try:
|
||||||
listen_tn: Nursery
|
listen_tn: Nursery
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ from trio import (
|
||||||
|
|
||||||
from tractor.msg import MsgCodec
|
from tractor.msg import MsgCodec
|
||||||
from tractor.log import get_logger
|
from tractor.log import get_logger
|
||||||
from tractor.discovery._multiaddr import mk_maddr
|
|
||||||
from tractor.ipc._transport import (
|
from tractor.ipc._transport import (
|
||||||
MsgTransport,
|
MsgTransport,
|
||||||
MsgpackTransport,
|
MsgpackTransport,
|
||||||
|
|
@ -235,6 +234,8 @@ class MsgpackTCPStream(MsgpackTransport):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def maddr(self) -> Multiaddr:
|
def maddr(self) -> Multiaddr:
|
||||||
|
from tractor.net import mk_maddr
|
||||||
|
|
||||||
return mk_maddr(self.raddr)
|
return mk_maddr(self.raddr)
|
||||||
|
|
||||||
def connected(self) -> bool:
|
def connected(self) -> bool:
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,6 @@ from trio._highlevel_open_unix_stream import (
|
||||||
|
|
||||||
from tractor.msg import MsgCodec
|
from tractor.msg import MsgCodec
|
||||||
from tractor.log import get_logger
|
from tractor.log import get_logger
|
||||||
from tractor.discovery._multiaddr import mk_maddr
|
|
||||||
from tractor.ipc._transport import (
|
from tractor.ipc._transport import (
|
||||||
MsgpackTransport,
|
MsgpackTransport,
|
||||||
)
|
)
|
||||||
|
|
@ -611,6 +610,8 @@ class MsgpackUDSStream(MsgpackTransport):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def maddr(self) -> Multiaddr|str:
|
def maddr(self) -> Multiaddr|str:
|
||||||
|
from tractor.net import mk_maddr
|
||||||
|
|
||||||
if not self.raddr:
|
if not self.raddr:
|
||||||
return '<unknown-peer>'
|
return '<unknown-peer>'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
# tractor: structured concurrent "actors".
|
||||||
|
# Copyright 2018-eternity Tyler Goodlet.
|
||||||
|
|
||||||
|
'''
|
||||||
|
Network declarations, bindspaces and tunnels.
|
||||||
|
|
||||||
|
Public symbols are imported and cached on first access so importing
|
||||||
|
this package does not load optional network dependencies.
|
||||||
|
|
||||||
|
'''
|
||||||
|
from importlib import import_module
|
||||||
|
|
||||||
|
|
||||||
|
_SYMBOL_MODULES: dict[str, str] = {
|
||||||
|
'Bindspace': '._bindspace',
|
||||||
|
'BindspaceKind': '._bindspace',
|
||||||
|
'BindspaceLifecycle': '._bindspace',
|
||||||
|
'BindspaceOwnership': '._bindspace',
|
||||||
|
'BindspaceRef': '._bindspace',
|
||||||
|
'BindspaceSpec': '._bindspace',
|
||||||
|
'CURRENT_NETNS': '._bindspace',
|
||||||
|
'attach_netns': '._bindspace',
|
||||||
|
'open_bindspace': '._bindspace',
|
||||||
|
'open_netns': '._bindspace',
|
||||||
|
'TunnelledAddress': '._tunnel',
|
||||||
|
'TunnelSpec': '._tunnel',
|
||||||
|
'WGTunnelSpec': '._tunnel',
|
||||||
|
'WGInterfaceConfig': '._tunnel',
|
||||||
|
'WGPeerConfig': '._tunnel',
|
||||||
|
'WGRole': '._tunnel',
|
||||||
|
'mb_pubkey': '._tunnel',
|
||||||
|
'mk_wg_maddr': '._tunnel',
|
||||||
|
'open_wg_bindspace': '._tunnel',
|
||||||
|
'open_wg_iface': '._tunnel',
|
||||||
|
'parse_wg_maddr': '._tunnel',
|
||||||
|
'read_wg_peers': '._tunnel',
|
||||||
|
'read_wg_pubkey': '._tunnel',
|
||||||
|
'strip_tunnels': '._tunnel',
|
||||||
|
'tunnels_of': '._tunnel',
|
||||||
|
'verify_wg_peer': '._tunnel',
|
||||||
|
'wg8_pubkey': '._tunnel',
|
||||||
|
'mk_maddr': '..discovery._multiaddr',
|
||||||
|
'parse_maddr': '..discovery._multiaddr',
|
||||||
|
'parse_endpoints': '..discovery._multiaddr',
|
||||||
|
}
|
||||||
|
|
||||||
|
__all__: tuple[str, ...] = tuple(_SYMBOL_MODULES)
|
||||||
|
|
||||||
|
|
||||||
|
def __dir__() -> list[str]:
|
||||||
|
'''
|
||||||
|
Advertise the complete lazy public API.
|
||||||
|
|
||||||
|
'''
|
||||||
|
return sorted(set(globals()) | set(__all__))
|
||||||
|
|
||||||
|
|
||||||
|
def __getattr__(name: str) -> object:
|
||||||
|
'''
|
||||||
|
Import and cache one public network symbol on first access.
|
||||||
|
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
module_name: str = _SYMBOL_MODULES[name]
|
||||||
|
except KeyError:
|
||||||
|
raise AttributeError(
|
||||||
|
f'module {__name__!r} has no attribute {name!r}'
|
||||||
|
) from None
|
||||||
|
|
||||||
|
value: object = getattr(
|
||||||
|
import_module(module_name, __name__),
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
globals()[name] = value
|
||||||
|
return value
|
||||||
|
|
@ -51,7 +51,7 @@ BindspaceOwnership: TypeAlias = Literal[
|
||||||
]
|
]
|
||||||
|
|
||||||
_NETNS_RUN_DIR: Path = Path('/var/run/netns')
|
_NETNS_RUN_DIR: Path = Path('/var/run/netns')
|
||||||
_SELF_NETNS: Path = Path('/proc/self/ns/net')
|
_THREAD_NETNS: Path = Path('/proc/thread-self/ns/net')
|
||||||
|
|
||||||
CURRENT_NETNS: Final[None] = None
|
CURRENT_NETNS: Final[None] = None
|
||||||
|
|
||||||
|
|
@ -124,7 +124,7 @@ class BindspaceSpec(
|
||||||
Serializable declaration of one requested bindspace.
|
Serializable declaration of one requested bindspace.
|
||||||
|
|
||||||
For a netns spec, `.key = CURRENT_NETNS` selects the calling
|
For a netns spec, `.key = CURRENT_NETNS` selects the calling
|
||||||
process's current namespace without a named-path lookup.
|
thread's current namespace without a named-path lookup.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
kind: BindspaceKind
|
kind: BindspaceKind
|
||||||
|
|
@ -277,7 +277,7 @@ async def _pin_netns(
|
||||||
'''
|
'''
|
||||||
key: str|None = spec.key
|
key: str|None = spec.key
|
||||||
namespace_path: Path = (
|
namespace_path: Path = (
|
||||||
_SELF_NETNS
|
_THREAD_NETNS
|
||||||
if key is CURRENT_NETNS
|
if key is CURRENT_NETNS
|
||||||
else _NETNS_RUN_DIR / key
|
else _NETNS_RUN_DIR / key
|
||||||
)
|
)
|
||||||
|
|
@ -19,7 +19,8 @@ Tunnelled addresses: an `Address` that rides *inside* a tunnel.
|
||||||
A tunnel (`wg`, and later plain ip-in-udp, `veth`-in-netns, ..) is
|
A tunnel (`wg`, and later plain ip-in-udp, `veth`-in-netns, ..) is
|
||||||
**not** a `MsgTransport`. Its data plane is transparent to the
|
**not** a `MsgTransport`. Its data plane is transparent to the
|
||||||
application's `socket(2)`, so it never gets its own entry in
|
application's `socket(2)`, so it never gets its own entry in
|
||||||
`._addr._address_types` nor a `MsgpackTransport` impl. Instead it
|
`tractor.discovery._addr._address_types` nor a `MsgpackTransport`
|
||||||
|
impl. Instead it
|
||||||
*annotates* an existing L4 addr, and this module carries that
|
*annotates* an existing L4 addr, and this module carries that
|
||||||
annotation beside it.
|
annotation beside it.
|
||||||
|
|
||||||
|
|
@ -102,7 +103,7 @@ from ._bindspace import (
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from multiaddr import Multiaddr
|
from multiaddr import Multiaddr
|
||||||
|
|
||||||
from ._addr import (
|
from ..discovery._addr import (
|
||||||
Address,
|
Address,
|
||||||
UnwrappedAddress,
|
UnwrappedAddress,
|
||||||
)
|
)
|
||||||
|
|
@ -1055,7 +1056,7 @@ def parse_wg_maddr(
|
||||||
]
|
]
|
||||||
match overlay_names:
|
match overlay_names:
|
||||||
case [('ip4' | 'ip6'), 'tcp']:
|
case [('ip4' | 'ip6'), 'tcp']:
|
||||||
from ._multiaddr import parse_maddr
|
from ..discovery._multiaddr import parse_maddr
|
||||||
overlay: Address|TunnelledAddress = parse_maddr(
|
overlay: Address|TunnelledAddress = parse_maddr(
|
||||||
str(overlay_ma)
|
str(overlay_ma)
|
||||||
)
|
)
|
||||||
|
|
@ -1161,7 +1162,7 @@ def mk_wg_maddr(
|
||||||
f'/wg/{mb_pubkey(addr.tunnel.peer_pubkey)}'
|
f'/wg/{mb_pubkey(addr.tunnel.peer_pubkey)}'
|
||||||
)
|
)
|
||||||
|
|
||||||
from ._multiaddr import mk_maddr
|
from ..discovery._multiaddr import mk_maddr
|
||||||
overlay_ma: Multiaddr = mk_maddr(addr.overlay)
|
overlay_ma: Multiaddr = mk_maddr(addr.overlay)
|
||||||
return (
|
return (
|
||||||
bearer_ma
|
bearer_ma
|
||||||
|
|
@ -65,7 +65,7 @@ from ..spawn import _spawn
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
from ..discovery._bindspace import Bindspace
|
from ..net._bindspace import Bindspace
|
||||||
# from ..ipc._server import IPCServer
|
# from ..ipc._server import IPCServer
|
||||||
from ..ipc import IPCServer
|
from ..ipc import IPCServer
|
||||||
from ..spawn._spawn import ProcessType
|
from ..spawn._spawn import ProcessType
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ from ._spawn import (
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from tractor.discovery._bindspace import Bindspace
|
from tractor.net._bindspace import Bindspace
|
||||||
from tractor.ipc import (
|
from tractor.ipc import (
|
||||||
_server,
|
_server,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ from tractor.msg import types as msgtypes
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from tractor.discovery._bindspace import Bindspace
|
from tractor.net._bindspace import Bindspace
|
||||||
from tractor.ipc import (
|
from tractor.ipc import (
|
||||||
_server,
|
_server,
|
||||||
Channel,
|
Channel,
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ from ._spawn import (
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from tractor.discovery._bindspace import Bindspace
|
from tractor.net._bindspace import Bindspace
|
||||||
from tractor.ipc import (
|
from tractor.ipc import (
|
||||||
_server,
|
_server,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ from ..runtime._supervise import (
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ..discovery._addr import UnwrappedAddress
|
from ..discovery._addr import UnwrappedAddress
|
||||||
from ..discovery._bindspace import Bindspace
|
from ..net._bindspace import Bindspace
|
||||||
from ..runtime._portal import Portal
|
from ..runtime._portal import Portal
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue