Fix DM presence indicator never updating live (#63)

The sidebar shows every DM's online/offline dot at once, but the only
existing signal for a presence change (member_updated) is broadcast to
a room's own channel, which Presence only delivers to a connection that
currently has that specific room joined -- never true for a DM sitting
unopened in the sidebar. Add a dedicated per-user broadcast
(dm_presence_update) sent to each of a user's DM partners on their own
per-user channel whenever their global online/offline state changes, so
the sidebar dot updates without needing that DM to be the open room.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-27 20:41:57 -06:00
co-authored by Claude Sonnet 5
parent d42bf114dd
commit 4cc3823adf
7 changed files with 142 additions and 5 deletions
+3
View File
@@ -9,6 +9,7 @@ from app.database import get_db
from app.models import ApiToken, Message, MessageFile, MessageImage, RoomMembership, User
from app.services.bot_service import resolve_token
from app.services.message_events import (
broadcast_dm_presence_update,
broadcast_member_updated,
broadcast_message_update,
broadcast_new_message,
@@ -96,6 +97,7 @@ async def chat_endpoint(websocket: WebSocket, db: AsyncSession = Depends(get_db)
# visible.
if await global_presence.connect(user.id):
await broadcast_member_updated(db, broadcaster, user.id)
await broadcast_dm_presence_update(db, broadcaster, user.id, online=True)
# This session is shared for the connection's entire lifetime (which can
# be hours) -- SQLAlchemy opens a transaction implicitly on first use,
# and every read above (the auth lookup, broadcast_member_updated's own
@@ -300,3 +302,4 @@ async def chat_endpoint(websocket: WebSocket, db: AsyncSession = Depends(get_db)
await focus_presence.mark_focused(user.id)
if await global_presence.disconnect(user.id):
await broadcast_member_updated(db, broadcaster, user.id)
await broadcast_dm_presence_update(db, broadcaster, user.id, online=False)