import json import logging from google.oauth2 import service_account from google.auth.transport.requests import Request as GoogleAuthRequest import httpx from app.core.config import Settings logger = logging.getLogger(__name__) class PushService: def __init__(self, settings: Settings): self.settings = settings async def send_challenge(self, fcm_token: str | None, challenge_id: str) -> None: if not fcm_token: logger.info("Skipping push: device has no FCM token for challenge %s", challenge_id) return if not self.settings.fcm_project_id or not self.settings.fcm_service_account_json: logger.info("Skipping push: FCM credentials not configured for challenge %s", challenge_id) return credentials = service_account.Credentials.from_service_account_info( json.loads(self.settings.fcm_service_account_json), scopes=["https://www.googleapis.com/auth/firebase.messaging"], ) credentials.refresh(GoogleAuthRequest()) payload = { "message": { "token": fcm_token, "data": {"challenge_id": challenge_id}, "android": {"priority": "high"}, } } logger.debug("Prepared FCM payload: %s", json.dumps(payload)) async with httpx.AsyncClient(timeout=10) as client: response = await client.post( f"https://fcm.googleapis.com/v1/projects/{self.settings.fcm_project_id}/messages:send", json=payload, headers={"Authorization": f"Bearer {credentials.token}"}, ) response.raise_for_status()