Private
Public Access
Push a live signal when a user is added to a room (#26)
Previously GET /api/rooms/mine was only ever fetched once at app mount, so a room added mid-session stayed invisible until a full page reload -- add_member had no way to reach an already-open client at all. Backend: ConnectionManager and Broadcaster (renamed from RoomBroadcaster) now support per-user channels alongside the existing per-room ones, so a signal can reach a user's socket even for a room they haven't joined (and by definition can't have, until this fires). add_member publishes a room_added event on the target user's channel. Frontend: the WebSocket connection is no longer scoped to whichever room is open -- ChatShellPage now owns one persistent connection for the whole session (including while no room is open, which is exactly when this bug showed), and ChatPane joins/leaves rooms on top of it. A room_added event triggers a room-list refetch with no reload needed. Verified end-to-end in the browser: a user sitting on the empty room list saw a newly-added room appear live, then chatted in it normally. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@ from app.models import Message, MessageFile, Room, RoomMembership, User
|
||||
from app.schemas.message import ReactionSummary
|
||||
from app.services.push_service import send_push_to_user
|
||||
from app.services.webhook_service import dispatch_event
|
||||
from app.ws.broadcaster import RoomBroadcaster
|
||||
from app.ws.broadcaster import Broadcaster
|
||||
from app.ws.presence import Presence
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ async def _message_payload(db: AsyncSession, message: Message, username: str) ->
|
||||
|
||||
async def broadcast_new_message(
|
||||
db: AsyncSession,
|
||||
broadcaster: RoomBroadcaster,
|
||||
broadcaster: Broadcaster,
|
||||
presence: Presence,
|
||||
room_id: uuid.UUID,
|
||||
message: Message,
|
||||
@@ -86,7 +86,7 @@ async def broadcast_new_message(
|
||||
|
||||
|
||||
async def broadcast_message_update(
|
||||
db: AsyncSession, broadcaster: RoomBroadcaster, room_id: uuid.UUID, message: Message
|
||||
db: AsyncSession, broadcaster: Broadcaster, room_id: uuid.UUID, message: Message
|
||||
) -> None:
|
||||
payload = {
|
||||
"type": "message_update",
|
||||
@@ -100,7 +100,7 @@ async def broadcast_message_update(
|
||||
|
||||
|
||||
async def broadcast_reaction_update(
|
||||
broadcaster: RoomBroadcaster,
|
||||
broadcaster: Broadcaster,
|
||||
room_id: uuid.UUID,
|
||||
message_id: uuid.UUID,
|
||||
reactions: list[ReactionSummary],
|
||||
@@ -115,3 +115,15 @@ async def broadcast_reaction_update(
|
||||
# Deliberately no dispatch_event() call -- reactions don't get an
|
||||
# outgoing-webhook event type, matching the same scope cut made for
|
||||
# image uploads (see backend/README.md).
|
||||
|
||||
|
||||
async def broadcast_room_added(broadcaster: Broadcaster, user_id: uuid.UUID, room: Room) -> None:
|
||||
"""The only signal a user's open client gets that they were just added
|
||||
to a room -- without it, GET /rooms/mine is only ever fetched once at
|
||||
app mount, so a room added mid-session stays invisible until a full
|
||||
reload. Published on the user's own channel rather than the room's,
|
||||
since the whole point is reaching someone who hasn't joined that room's
|
||||
channel yet (and by definition can't have)."""
|
||||
await broadcaster.publish_to_user(
|
||||
user_id, {"type": "room_added", "room_id": str(room.id)}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user