Skip to content

feat(reverb): Channel types, BroadcastEvent, auth registry, Broadcaster, ReverbProvider#116

Closed
bedus-creation wants to merge 2 commits into
mainfrom
feat/reverb-core
Closed

feat(reverb): Channel types, BroadcastEvent, auth registry, Broadcaster, ReverbProvider#116
bedus-creation wants to merge 2 commits into
mainfrom
feat/reverb-core

Conversation

@bedus-creation

Copy link
Copy Markdown
Contributor

Summary

Implements tasks #147, #148, and #149 — the full Reverb broadcasting core module under fastapi_startkit/src/fastapi_startkit/reverb/.

Task #147 — BroadcastEvent + Channel types (reverb/channels.py, reverb/event.py)

  • Channel — public channel, no auth check; __eq__/__hash__ for easy comparison in tests
  • PrivateChannel — automatically prefixes name with private-; stores _raw_name
  • PresenceChannel — automatically prefixes name with presence-; stores _raw_name (member tracking is v2)
  • BroadcastEvent — abstract base with payload: dict, name: str | None (defaults to class.__name__ at dispatch time), abstract broadcast_on(), and async emit() shortcut that delegates to Broadcast.dispatch(self)

Task #148 — Broadcast facade + auth registry (reverb/registry.py, reverb/broadcaster.py, facades/Broadcast.pyi)

  • ChannelAuthRegistry — compiles orders.{order_id} patterns to named-group regexes; strips private-/presence- prefix before matching; casts wildcard values to callback type hints; supports both sync and async callbacks; default policy: deny private/presence, allow public
  • Broadcaster — bound as "broadcast" and "reverb" in the container:
    • dispatch(event) — primary path, resolves event.name, iterates broadcast_on() channels
    • emit(channel, event_name, payload) — escape hatch for dynamic one-off broadcasts
    • channel(pattern) — decorator factory that registers auth callbacks in the registry
  • facades/Broadcast.pyi — updated type stub with dispatch(), emit(), channel() signatures

Task #149 — ReverbProvider (reverb/provider.py)

  • register() — creates ReverbServer, ChannelAuthRegistry, Broadcaster; binds all under "reverb", "broadcast", "reverb.server", "reverb.registry"
  • boot() — auto-loads routes/channels.py via importlib (silent skip if absent or erroring); mounts WebSocket at REVERB_PATH (default /__reverb); mounts POST /broadcasting/auth supporting both form-encoded and JSON bodies, returning 200 {"auth": "..."} or 403 {"message": "Forbidden"}

Test plan

  • All 31 existing tests/broadcasting/ tests pass unchanged
  • 1262 non-Postgres tests pass (15 Postgres failures are pre-existing/require a live DB)
  • Manual smoke test: channel types, registry pattern matching + type casting, async/sync callbacks, Broadcaster dispatch/emit/channel decorator

🤖 Generated with Claude Code

…caster, and ReverbProvider

Implements tasks #147, #148, #149 — the core Reverb broadcasting module:

- reverb/channels.py: Channel, PrivateChannel (private- prefix), PresenceChannel
  (presence- prefix) with __eq__/__hash__ for testability
- reverb/event.py: BroadcastEvent ABC with payload dict, optional name
  (defaults to class.__name__), and async emit() shortcut
- reverb/registry.py: ChannelAuthRegistry — pattern-to-regex compiler with
  {name} wildcards, type-hint casting, async/sync callback support, and
  default deny-for-private/allow-for-public policy
- reverb/broadcaster.py: Broadcaster with dispatch(), emit(), and channel()
  decorator bound as "broadcast"/"reverb" in the container
- reverb/provider.py: ReverbProvider — register() binds all services; boot()
  auto-loads routes/channels.py (silent skip), mounts the WebSocket endpoint,
  and mounts POST /broadcasting/auth (200/403 from registry callbacks)
- facades/Broadcast.pyi: updated stub with dispatch(), emit(), channel()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@bedus-creation

Copy link
Copy Markdown
Contributor Author

Review — Superseded by PR #112 (close this PR)

Thank you for the implementation! This PR contains a well-designed reverb/ package with some excellent ideas. However, per the architecture decision, the canonical implementation lives in the existing broadcasting/ package (PR #112, feat/broadcasting-event-facade-provider), not a new parallel reverb/ module.

Conflicts with agreed architecture

Issue Detail
New top-level reverb/ package Contradicts the course-correction directive to extend broadcasting/
Container key "broadcast" PR #112 uses "broadcasting" — inconsistency breaks the Broadcast facade
Import paths fastapi_startkit.reverb.* Would require all user code to use different imports than the rest of the broadcasting module

Good ideas from this PR cherry-picked into #112

The following ideas from #116 are valuable and have been flagged for inclusion in PR #112:

  1. __eq__ / __hash__ on Channel — makes channels comparable and hashable (sets, dict keys)
  2. async def emit(self) — correctly awaits Broadcast.dispatch(self) (PR feat(broadcasting): BroadcastEvent.emit(), Broadcast facade, ChannelAuthRegistry, ReverbProvider auto-wiring #112 has a bug here — emit() is not async, so events are silently dropped)
  3. Prefix stripping in registry_strip_prefix() so callbacks can match "orders.{id}" instead of "private-orders.{id}" (ergonomic improvement)

Recommendation: Close this PR and let PR #112 (once the blocking issues are fixed) be the merge target. The good ideas above are being tracked as required fixes on #112.

Broadcast.pyi was deleted in main (PR #112 removed the Broadcast facade)
and modified in this branch. Accepting main's deletion since #116 is
superseded by the broadcasting/ package in main.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@bedus-creation

Copy link
Copy Markdown
Contributor Author

Superseded by merged PR #112 — broadcasting/ extension chosen over parallel reverb/ package; its async-emit and Channel equality improvements were ported into #112 before merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant