QUIC Portal (experimental)
⚠️ Warning: This library is experimental and not intended for production use.
High-performance QUIC communication library with automatic NAT traversal within Modal applications.
Current features
- Automatic NAT traversal: Built-in STUN discovery and UDP hole punching, using Modal Dict for rendezvous.
- High-performance QUIC: Rust-based implementation for maximum throughput and minimal latency
- Simple synchronous API: Easy-to-use Portal class with static methods for server/client creation. WebSocket-style messaging.
Upcoming roadmap
- TODO: Improved NAT traversal: Handle more complex client-side NATs using port scanning + birthday technique. Currently only supports clients behind "easy" NATs.
- TODO: Shared server certificates: Use a modal.Dict to share server/client certificates, to mutually validate identity.
Installation
# Install from PyPi (only certain wheels built)
pip install quic-portal
# Install from source (requires Rust toolchain)
git clone <repository>
cd quic-portal
pip install .
Quick Start
Usage with Modal
import modal
from quic_portal import Portal
app = modal.App("my-quic-app")
@app.function()
def server_function(coord_dict: modal.Dict):
# Create server with automatic NAT traversal
portal = Portal.create_server(dict=coord_dict, local_port=5555)
# Receive and echo messages
while True:
data = portal.recv(timeout_ms=10000)
if data:
message = data.decode("utf-8")
print(f"Received: {message}")
portal.send(f"Echo: {message}".encode("utf-8"))
@app.function()
def client_function(coord_dict: modal.Dict):
# Create client with automatic NAT traversal
portal = Portal.create_client(dict=coord_dict, local_port=5556)
# Send messages
portal.send(b"Hello, QUIC!")
response = portal.recv(timeout_ms=5000)
if response:
print(f"Got response: {response.decode('utf-8')}")
@app.local_entrypoint()
def main(local: bool = False):
# Create coordination dict
with modal.Dict.ephemeral() as coord_dict:
# Start server
server_task = server_function.spawn(coord_dict)
# Run client
if local:
# Run test between local environment and remote container.
client_function.local(coord_dict)
else:
# Run test between two containers.
client_function.remote(coord_dict)
server_task.cancel()
Manual NAT Traversal
For advanced use cases where you handle NAT traversal yourself, or the server has a public IP:
from quic_portal import Portal
# After NAT hole punching is complete...
# Server side
server = Portal()
server.listen(5555)
# Client side
client = Portal()
client.connect("server_ip", 5555, 5556)
# WebSocket-style messaging
client.send(b"Hello!")
response = server.recv(timeout_ms=1000)
API Reference
Portal Class
Static Methods
Portal.create_server(dict, local_port=5555, stun_server=("stun.ekiga.net", 3478), punch_timeout=15)
Create a server portal with automatic NAT traversal. Synchronous operation.
Parameters:
dict(modal.Dict or dict): Modal Dict or regular dict for peer coordinationlocal_port(int): Local port for QUIC server (default: 5555)stun_server(tuple): STUN server for NAT discovery (default: ("stun.ekiga.net", 3478))punch_timeout(int): Timeout in seconds for NAT punching (default: 15)
Returns: Connected Portal instance ready for communication
Portal.create_client(dict, local_port=5556, stun_server=("stun.ekiga.net", 3478), punch_timeout=15)
Create a client portal with automatic NAT traversal. Synchronous operation.
Parameters:
dict(modal.Dict or dict): Modal Dict or regular dict for peer coordination (must be same as server)local_port(int): Local port for QUIC client (default: 5556)stun_server(tuple): STUN server for NAT discovery (default: ("stun.ekiga.net", 3478))punch_timeout(int): Timeout in seconds for NAT punching (default: 15)
Returns: Connected Portal instance ready for communication
Instance Methods
send(data: Union[bytes, str]) -> None
Send data over QUIC connection (WebSocket-style). Synchronous operation.
recv(timeout_ms: Optional[int] = None) -> Optional[bytes]
Receive data from QUIC connection. Blocks until message arrives or timeout. Synchronous operation.
Parameters:
timeout_ms(int, optional): Timeout in milliseconds (None for blocking)
Returns: Received data as bytes, or None if timeout
connect(server_ip: str, server_port: int, local_port: int) -> None
Connect to a QUIC server (for manual NAT traversal). Synchronous operation.
Parameters:
server_ip(str): Server IP addressserver_port(int): Server portlocal_port(int): Local port to bind to
listen(local_port: int) -> None
Start QUIC server and wait for connection (for manual NAT traversal). Synchronous operation.
Parameters:
local_port(int): Local port to bind to
is_connected() -> bool
Check if connected to peer.
close() -> None
Close the connection and clean up resources.
Examples
See the examples/ directory for complete working examples:
modal_simple.py- Basic server/client communicationmodal_benchmark.py- Performance benchmarking
Requirements
- Python 3.9+
- Modal (for automatic NAT traversal)
- Rust toolchain (for building from source)
Third-party Libraries
This project uses code from:
pynatby Ariel Antonitis, licensed under MIT License
License
MIT License
Metadata
Release files for quic-portal 0.1.13
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| quic_portal-0.1.13.tar.gz | 34.2 kB | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| quic_portal-0.1.13-cp39-abi3-manylinux_2_34_x86_64.whl | CPython 3.9 | abi3 | Linux glibc 2.34+ x86-64 | Details |
| quic_portal-0.1.13-cp39-abi3-macosx_11_0_arm64.whl | CPython 3.9 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 2.5 MB
Release files / quic_portal-0.1.13.tar.gz
| Download URL | quic_portal-0.1.13.tar.gz |
|---|---|
| Size | 34.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6b0eaba945570bc055f34543f6d9b63fc33c9e366aa788bcb5549a4ff84a2aaf
|
|
BLAKE2b-256 checksum How to use checksums |
68e7bbc4c89ca16db2012cd98caa945ea78ff948324ee6006dfe34c3806089d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.9.0
|
Release files / quic_portal-0.1.13-cp39-abi3-manylinux_2_34_x86_64.whl
| Download URL | quic_portal-0.1.13-cp39-abi3-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 1.3 MB |
| Tags | CPython 3.9 Linux glibc 2.34+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
2afeddc2fe2e94199818800f1b2b4e730c52cd6621738733ae4ad0f7de4c5b60
|
|
BLAKE2b-256 checksum How to use checksums |
a21261d2df8bdc475ffe4c00d6ed4c99e72356afb0f2598e984dd56481f411ec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.7.8
|
Release files / quic_portal-0.1.13-cp39-abi3-macosx_11_0_arm64.whl
| Download URL | quic_portal-0.1.13-cp39-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | CPython 3.9 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
8665c61fde7d665221eee17e246acaa04de5df302acc5f1c849845547467b7d2
|
|
BLAKE2b-256 checksum How to use checksums |
1e4d648c08f44ee0af6e1a0ef2aec9deb3a9b06c2b1e33189e886306cb8cdc84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.9.0
|