Skip to main content

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

pondsocket-0.0.1.tar.gz (34.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pondsocket-0.0.1-py3-none-any.whl (33.6 kB view details)

Uploaded Python 3

File details

Details for the file pondsocket-0.0.1.tar.gz.

File metadata

  • Download URL: pondsocket-0.0.1.tar.gz
  • Upload date:
  • Size: 34.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for pondsocket-0.0.1.tar.gz
Algorithm Hash digest
SHA256 6f9b1fa764d76e3c887d47a5a37c1f9d2eff54990ecc371a3c12dbc211f00a07
MD5 87c5a9f7d4823b3e29676ba542016456
BLAKE2b-256 e109d85dc81dec78e3452f3da7c03e2e7a045f7fd2f0d168fae219d1ea3253b2

See more details on using hashes here.

File details

Details for the file pondsocket-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: pondsocket-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 33.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for pondsocket-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3bcb1819416200b45444121205b6555e1fa93d078bb26f79092422eadd3d3681
MD5 4df12466fd9edd31033442b8e9c1127a
BLAKE2b-256 2982cdecc6dfa669c7276e607c029073f3c5356f6d96b795e00ead8e5b3ee50b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page