tractor/examples/uds_transport_actor_tree.py

60 lines
1.8 KiB
Python
Raw Normal View History

'''
Demonstrate an actor tree which talks over unix-domain-socket
(UDS) transport instead of the default TCP: pass
`enable_transports=['uds']` when opening the root and every
subactor inherits the preference.
Every channel address is a filesystem socket path (no TCP port
in sight!) and, as a kernel-provided bonus, the peer's pid is
exchanged for free via `SO_PEERCRED`.
'''
import os
import trio
import tractor
async def report_addr() -> str:
'''
Return this actor's own accept (bind) addr + pid.
'''
actor = tractor.current_actor()
addr: tuple = actor.accept_addr
pid: int = os.getpid()
return f'{actor.name}@{addr} pid={pid}'
async def main() -> None:
an: tractor.ActorNursery
async with tractor.open_nursery(
enable_transports=['uds'],
) as an:
portal: tractor.Portal = await an.start_actor(
'uds_child',
enable_modules=[__name__],
)
# the channel's remote addr is a `UDSAddress`: a
# filesystem socket path, NOT a (host, port) pair!
raddr = portal.chan.raddr
assert raddr.proto_key == 'uds'
# NOTE, `.sockpath` is the *shared listener* socket file
# (named for the root registrar) this channel rode in
# on, NOT a per-child path; the child-specific identity
# we get for free is the kernel-reported peer pid (via
# `SO_PEERCRED`).
print(
f'portal chan tpt proto: {raddr.proto_key!r}\n'
f'listener sock file: {raddr.sockpath}\n'
f'kernel-reported peer pid: {raddr.maybe_pid}\n'
)
# ask the child for its OWN distinct bind addr: another
# socket-file path under the runtime dir.
print(f'child says: {await portal.run(report_addr)}')
await portal.cancel_actor()
if __name__ == '__main__':
trio.run(main)