PondSocket - channel-based real-time framework with bring-your-own-server design.
Project description
pondsocket
PondSocket - channel-based real-time framework for Python. Bring-your-own-server design: the core knows nothing about HTTP frameworks or WebSocket libraries. You build the layered API (Server -> Endpoint -> Channel -> User), and an adapter (e.g. pondsocket-asgi) bridges it to your HTTP stack.
Install
pip install pondsocket
pip install "pondsocket[redis]" # multi-node deployments
Concepts
PondSocket top-level facade, holds endpoints
└── Endpoint one URL path, runs the connection auth handler, owns transports
└── Lobby one channel pattern (e.g. "/chat/:room_id"), holds shared middleware
└── Channel one live channel instance, holds users + presence
Five contexts, scoped to lifecycle moments
| Context | When | What it decides / does |
|---|---|---|
ConnectionContext |
HTTP upgrade | accept / decline socket, set initial assigns |
JoinContext |
per channel join | accept / decline membership, track presence |
EventContext |
per incoming event | broadcast, reply, update presence/assigns, evict |
OutgoingContext |
per recipient, per send | transform payload or block delivery |
LeaveContext |
user gone | final cleanup (user already removed) |
Minimal example
from pondsocket import ConnectionContext, EventContext, JoinContext, PondSocket
async def auth(ctx: ConnectionContext) -> None:
if ctx.query.get("token") != "secret":
ctx.decline(401, "Invalid token")
return
ctx.accept(user_id=ctx.query.get("uid", "anon"))
async def on_join(ctx: JoinContext) -> None:
await ctx.accept()
await ctx.track({"status": "online"})
async def on_message(ctx: EventContext) -> None:
await ctx.broadcast(ctx.event_name, ctx.get_payload())
pond = PondSocket()
endpoint = pond.create_endpoint("/api/socket", auth)
lobby = endpoint.create_channel("/chat/:room_id", on_join)
lobby.on_message("message", on_message)
To actually serve traffic, wrap pond in an adapter — see pondsocket-asgi for the canonical one.
Distributed (multi-node)
from redis.asyncio import Redis
from pondsocket import PondSocket
from pondsocket.distributed import RedisPubSub
redis = Redis(host="localhost", port=6379)
pubsub = RedisPubSub(redis, owns_client=True)
pond = PondSocket(pubsub=pubsub)
Cross-node broadcasts and presence events propagate via Redis PSUBSCRIBE. node_id is auto-generated when a pubsub is configured. Each broadcast carries the nodeId so emitters filter their own echo.
See pondsocket.distributed.RedisPubSub for the implementation. The PubSub protocol is implementable for other backends.
Hooks & metrics
from pondsocket import Hooks, NoopMetrics, Options, PondSocket, TokenBucketRateLimiter
hooks = Hooks(
rate_limiter=TokenBucketRateLimiter(rate=10, capacity=20),
metrics=NoopMetrics(),
)
pond = PondSocket(options=Options(hooks=hooks))
Auto-fired by the framework: connection_opened/connection_closed, channel_created/channel_destroyed/channel_joined/channel_left, plus on_connect/on_disconnect/before_join/after_join/before_message/after_message.
Opt-in middleware factories for per-handler instrumentation:
from pondsocket import with_metrics, with_rate_limiter
lobby.on_message(
"message",
on_message,
with_rate_limiter(hooks, key_fn=lambda msg: msg.user.id),
with_metrics(hooks),
)
Testing
InMemoryTransport is a public test utility that satisfies the Transport protocol without any network I/O:
from pondsocket import InMemoryTransport
t = InMemoryTransport("alice")
await endpoint.register_transport(t)
await t.push_inbound(some_event)
sent = await t.receive_sent()
Public API
from pondsocket import ...
- Core:
PondSocket,Endpoint,Lobby,Channel,Options,Event,User,MessageEvent,RecipientSpec - Contexts:
ConnectionContext,JoinContext,EventContext,LeaveContext,OutgoingContext - Transport:
Transport(Protocol),InMemoryTransport,SSEServerTransport,TransportType,OnCloseCallback,OnMessageHandler - PubSub:
PubSub(Protocol),LocalPubSub,format_topic,match_topic,PubSubClosedError - Hooks:
Hooks,RateLimiter,MetricsCollector,NoopMetrics,TokenBucketRateLimiter,with_rate_limiter,with_metrics - Wire:
event_to_json,event_to_wire,parse_inbound_text,wire_to_event,event_to_pubsub_bytes,pubsub_bytes_to_event - Errors:
PondError, status constructors,error_event
License
GPL-3.0-or-later.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pondsocket-0.0.3.tar.gz.
File metadata
- Download URL: pondsocket-0.0.3.tar.gz
- Upload date:
- Size: 37.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7ed7f98e8fcc5774313ff3e050172a51ae87f4e503e335893cde8ab3a27448f
|
|
| MD5 |
e8d75130489f6e272678243a05697a88
|
|
| BLAKE2b-256 |
96ebad4e28b530e7c5b16b7dabd72245ec798409ad220b19ca741a395be38541
|
File details
Details for the file pondsocket-0.0.3-py3-none-any.whl.
File metadata
- Download URL: pondsocket-0.0.3-py3-none-any.whl
- Upload date:
- Size: 35.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4656ba44886f946c2d4779e57d7a140d30a5cbaaf89ede98edee77956436e921
|
|
| MD5 |
6ee4ab22da9a45b17d958c78a7f7e705
|
|
| BLAKE2b-256 |
193e2e4fd465f0b5ab75a8adcb3eca2a05c095ca03e5cacc50306fd0c6b4c557
|