You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

62 lines
2.1 KiB

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