Files
quicproquo/sdks/python/README.md
Christian Nennemann 2e081ead8e chore: rename quicproquo → quicprochat in docs, Docker, CI, and packaging
Rename all project references from quicproquo/qpq to quicprochat/qpc
across documentation, Docker configuration, CI workflows, packaging
scripts, operational configs, and build tooling.

- Docker: crate paths, binary names, user/group, data dirs, env vars
- CI: workflow crate references, binary names, artifact names
- Docs: all markdown files under docs/, SDK READMEs, book.toml
- Packaging: OpenWrt Makefile, init script, UCI config (file renames)
- Scripts: justfile, dev-shell, screenshot, cross-compile, ai_team
- Operations: Prometheus config, alert rules, Grafana dashboard
- Config: .env.example (QPQ_* → QPC_*), CODEOWNERS paths
- Top-level: README, CONTRIBUTING, ROADMAP, CLAUDE.md
2026-03-21 19:14:06 +01:00

4.4 KiB

quicprochat Python SDK

Python client library for the quicprochat E2E encrypted messenger.

Prerequisites

  • Python 3.10+
  • A running quicprochat server

Installation

pip install quicprochat

For development:

pip install -e ".[dev]"

Transport Backends

1. Async QUIC (pure Python)

Uses aioquic for native QUIC transport with the v2 protobuf wire format. No Rust dependency required.

import asyncio
from quicprochat import QpqClient, ConnectOptions

async def main():
    client = await QpqClient.connect(ConnectOptions(
        addr="127.0.0.1:5001",
        ca_cert_path="ca.pem",
    ))

    health = await client.health()
    print(f"Server: {health.status}")

    # OPAQUE auth (requires external OPAQUE library for crypto)
    server_resp = await client.login_start("alice", opaque_request_bytes)
    # ... process server_resp with OPAQUE library ...
    token = await client.login_finish("alice", finalization, identity_key)

    # Resolve a user
    key, proof = await client.resolve_user("bob")

    # Send a message
    seq, proof = await client.send(recipient_key, b"hello")

    # Receive messages (long-poll)
    messages = await client.receive_wait(my_key, timeout_ms=5000)
    for msg in messages:
        print(f"[{msg.seq}] {msg.data}")

    await client.close()

asyncio.run(main())

2. Rust FFI (synchronous)

Wraps libquicprochat_ffi via CFFI for full Rust crypto stack (MLS, hybrid KEM, OPAQUE) at native speed.

# Build the FFI library first
cargo build --release -p quicprochat-ffi
from quicprochat import QpqClient, ConnectOptions

client = QpqClient.connect_ffi(ConnectOptions(
    addr="127.0.0.1:5001",
    ca_cert_path="ca.pem",
))

client.ffi_login("alice", "password123")
client.ffi_send("bob", b"hello from Python!")

messages = client.ffi_receive(timeout_ms=5000)
for msg in messages:
    print(msg)

client.close_sync()

API Reference

Connection

Method Transport Description
QpqClient.connect(opts) QUIC Async connect to server
QpqClient.connect_ffi(opts) FFI Sync connect via Rust FFI
client.close() QUIC Async disconnect
client.close_sync() Both Sync disconnect

Authentication (QUIC)

Method Description
client.register_start(username, request) Start OPAQUE registration
client.register_finish(username, upload, identity_key) Complete registration
client.login_start(username, request) Start OPAQUE login
client.login_finish(username, finalization, identity_key) Complete login
client.set_session_token(token) Set pre-existing session token

Authentication (FFI)

Method Description
client.ffi_login(username, password) Full OPAQUE login (Rust handles crypto)

Messaging (QUIC)

Method Description
client.health() Server health check
client.resolve_user(username) Look up identity key
client.resolve_identity(key) Reverse look up username
client.create_channel(peer_key) Create 1:1 DM channel
client.send(recipient_key, payload) Send a message
client.receive(recipient_key) Fetch queued messages
client.receive_wait(recipient_key, timeout_ms=5000) Long-poll for messages
client.ack(recipient_key, seq_up_to) Acknowledge messages
client.upload_key_package(key, package) Upload MLS key package
client.fetch_key_package(key) Fetch MLS key package
client.delete_account() Permanently delete account

Messaging (FFI)

Method Description
client.ffi_send(recipient, message) Send message by username
client.ffi_receive(timeout_ms=5000) Receive pending messages

Wire Format

The SDK implements the qpc v2 wire format:

[method_id:u16][req_id:u32][len:u32][protobuf payload]

Each RPC is sent over its own QUIC bidirectional stream.

Structure

  • quicprochat/client.py -- High-level client API
  • quicprochat/transport.py -- QUIC transport (aioquic)
  • quicprochat/ffi.py -- Rust FFI transport (CFFI)
  • quicprochat/proto.py -- Protobuf encode/decode (no codegen)
  • quicprochat/wire.py -- v2 wire format framing
  • quicprochat/types.py -- Data types and exceptions
  • examples/bot.py -- Async echo bot example
  • examples/ffi_demo.py -- Synchronous FFI example

Running Tests

pip install -e ".[dev]"
pytest