Skip to content

Python-to-Python connections (bitbang.Listener / bitbang.Client) #1

Description

@richlegrand

bitbang-python implements only the listener/device role today -- the connecting peer has to be a browser or the Go CLI. So two Python programs can't talk to each other without running the CLI as a port-forwarding sidecar.

This adds a Python connector role plus a blocking API over it, deliberately mirroring the stdlib's multiprocessing.connection:

# machine A
from bitbang import Listener
with Listener() as l:                      # prints its address
    conn = l.accept()
    conn.send({'temp': 22.5})

# machine B, anywhere
from bitbang import Client
conn = Client('g4x-WQfW…#7jIyMYY…')
print(conn.recv())

Three substitutions from the stdlib version: (ip, port) becomes the identity address, authkey disappears (identity verification is already stronger than the stdlib's HMAC handshake), and plaintext TCP becomes DTLS over P2P WebRTC. The pitch is one sentence — the stdlib API you already know, minus the same-network requirement.

Scope. Generic TCP/HTTP forwarding stays the CLI's job; it's faster and more general. This is for in-code messaging: a model, a sensor loop, or a job queue on one machine made callable from Python on another, with no web framework, no serialization boilerplate, and no deployment step.

Work involved:

  • connector.py -- the connecting side. A third implementation of an already-specced protocol (code_exchange.md), not new protocol. ~300 lines.
  • connection.py -- sync Connection facade: queues, backpressure, format tags. ~300 lines.
  • listener.py -- thin wrapper over the device-role core. ~150 lines.
  • One new SWSP stream type, conn, reusing the existing websocket MORE chunking verbatim. Requires 'conn' in the device's ready.caps. No signaling-server changes.
  • The main surgery on existing code: extract the device-role signaling/PC/stream-0 core out of BitBangBase, which currently assumes a WSGI/ASGI app, so Listener and BitBangWSGI/BitBangASGI share it. Behavior-preserving for existing apps.

v1 scope decisions: direct + STUN only, no TURN or ice_restart (matches the current Python listener's capability); no reconnect — a drop surfaces as BrokenPipeError/EOFError and the caller constructs a new Client; JSON serialization by default, with pickle as an explicit opt-in required on both sides.

Full design, including wire format, threading model, and two worked examples (remote system monitor, remote Whisper transcription): python2python.md.

Open:

  • accept() queue -- unbounded, or a stdlib-style backlog cap? (leaning unbounded, revisit if abused)
  • Should Client retry transient signaling failures internally, or fail fast? (leaning fail fast, with a retry loop shown in the examples)

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is needed

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions