import time import logging import requests import jwt from django.conf import settings logger = logging.getLogger(__name__) def generate_centrifugo_token(user, exp_seconds: int = 86400 * 7) -> str: """ Generates an HMAC-SHA256 connection JWT for Centrifugo v5. Subject ('sub') is the unique user ID string. """ secret = getattr(settings, 'CENTRIFUGO_SECRET', 'super_secret_centrifugo_token_key_hmac_256') now = int(time.time()) payload = { 'sub': str(user.id), 'exp': now + exp_seconds, 'iat': now, 'info': { 'id': user.id, 'email': user.email or '', 'fullname': user.fullname or user.email or '', 'user_type': getattr(user, 'user_type', 'client'), } } return jwt.encode(payload, secret, algorithm='HS256') def publish_to_centrifugo(channel: str, data: dict) -> bool: """ Publishes real-time JSON payload to a Centrifugo v5 channel via HTTP API. Channel format: 'chat:{room_id}' or 'notifications:{user_id}'. """ api_url = getattr(settings, 'CENTRIFUGO_API_URL', 'http://centrifugo:8000/api') api_key = getattr(settings, 'CENTRIFUGO_API_KEY', 'centrifugo_internal_api_access_key') # Centrifugo v5 API publish payload endpoint = f"{api_url.rstrip('/')}/publish" headers = { 'Content-Type': 'application/json', 'X-API-Key': api_key, 'Authorization': f'apikey {api_key}', } payload = { 'channel': channel, 'data': data } try: response = requests.post(endpoint, json=payload, headers=headers, timeout=2.0) if response.status_code in (200, 201): logger.debug(f"Centrifugo published to {channel}: {data.get('type', 'message')}") return True else: logger.warning(f"Centrifugo API error ({response.status_code}): {response.text}") return False except Exception as exc: # Graceful fallback: allow persistence to succeed even if Centrifugo container is offline in dev/test logger.warning(f"Centrifugo publish failed (offline or unreachable): {exc}") return False