61 lines
1.8 KiB
Python
61 lines
1.8 KiB
Python
"""Realtime synchronization for chat access changes.
|
|
|
|
The channel layer is an integration boundary: model signals publish only a
|
|
small access invalidation event, while the consumer owns group membership.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from asgiref.sync import async_to_sync
|
|
from channels.layers import get_channel_layer
|
|
from django.db import transaction
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def schedule_chat_access_changed(
|
|
*,
|
|
chat_id: int,
|
|
user_id: int,
|
|
membership_active: bool,
|
|
) -> None:
|
|
"""Notify every live session after the membership transaction commits."""
|
|
|
|
def _send() -> None:
|
|
channel_layer = get_channel_layer()
|
|
if channel_layer is None:
|
|
logger.warning(
|
|
"Chat access update skipped because channel layer is unavailable",
|
|
extra={
|
|
"event": "chat.realtime_access.channel_layer_unavailable",
|
|
"chat_id": chat_id,
|
|
"participant_id": user_id,
|
|
},
|
|
)
|
|
return
|
|
|
|
try:
|
|
async_to_sync(channel_layer.group_send)(
|
|
f"user_{user_id}",
|
|
{
|
|
"type": "chat_access_changed",
|
|
"chat_id": chat_id,
|
|
"membership_active": membership_active,
|
|
},
|
|
)
|
|
except Exception as error:
|
|
logger.exception(
|
|
"Chat access realtime update failed",
|
|
extra={
|
|
"event": "chat.realtime_access.send_failed",
|
|
"chat_id": chat_id,
|
|
"participant_id": user_id,
|
|
"membership_active": membership_active,
|
|
"error_type": type(error).__name__,
|
|
},
|
|
)
|
|
|
|
transaction.on_commit(_send)
|