73 lines
2.0 KiB
Python
73 lines
2.0 KiB
Python
|
|
"""SmsProvider interface. Console impl for dev/tests; GSM gateway impl in gateway.py (M5)."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import logging
|
||
|
|
import uuid
|
||
|
|
from typing import Protocol
|
||
|
|
|
||
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
|
|
||
|
|
from gogo.config import get_settings
|
||
|
|
from gogo.models import SmsLog
|
||
|
|
|
||
|
|
log = logging.getLogger("gogo.sms")
|
||
|
|
|
||
|
|
|
||
|
|
class SmsProvider(Protocol):
|
||
|
|
async def send(self, tenant_id: uuid.UUID, to_msisdn: str, body: str) -> None:
|
||
|
|
"""Send one SMS from the tenant's assigned SIM. Raises on failure."""
|
||
|
|
...
|
||
|
|
|
||
|
|
|
||
|
|
class ConsoleSmsProvider:
|
||
|
|
"""Logs SMS instead of sending; keeps them in memory for tests."""
|
||
|
|
|
||
|
|
sent: list[tuple[str, str]]
|
||
|
|
|
||
|
|
def __init__(self) -> None:
|
||
|
|
self.sent = []
|
||
|
|
|
||
|
|
async def send(self, tenant_id: uuid.UUID, to_msisdn: str, body: str) -> None:
|
||
|
|
self.sent.append((to_msisdn, body))
|
||
|
|
log.info("SMS tenant=%s to=%s: %s", tenant_id, to_msisdn, body)
|
||
|
|
|
||
|
|
|
||
|
|
_provider: SmsProvider | None = None
|
||
|
|
|
||
|
|
|
||
|
|
def get_sms_provider() -> SmsProvider:
|
||
|
|
global _provider
|
||
|
|
if _provider is None:
|
||
|
|
if get_settings().sms_provider == "gsm_gateway":
|
||
|
|
from gogo.sms.gateway import GsmGatewaySmsProvider
|
||
|
|
|
||
|
|
_provider = GsmGatewaySmsProvider()
|
||
|
|
else:
|
||
|
|
_provider = ConsoleSmsProvider()
|
||
|
|
return _provider
|
||
|
|
|
||
|
|
|
||
|
|
def set_sms_provider(p: SmsProvider | None) -> None:
|
||
|
|
"""Test hook."""
|
||
|
|
global _provider
|
||
|
|
_provider = p
|
||
|
|
|
||
|
|
|
||
|
|
async def send_sms(
|
||
|
|
session: AsyncSession, tenant_id: uuid.UUID, to_msisdn: str, body: str, kind: str
|
||
|
|
) -> bool:
|
||
|
|
"""Send + log. Returns success. Never raises (SMS failure must not break the flow)."""
|
||
|
|
row = SmsLog(tenant_id=tenant_id, to_msisdn=to_msisdn, body=body, kind=kind)
|
||
|
|
try:
|
||
|
|
await get_sms_provider().send(tenant_id, to_msisdn, body)
|
||
|
|
row.status = "sent"
|
||
|
|
ok = True
|
||
|
|
except Exception as e: # noqa: BLE001
|
||
|
|
log.exception("SMS send failed tenant=%s to=%s", tenant_id, to_msisdn)
|
||
|
|
row.status = "failed"
|
||
|
|
row.error = str(e)
|
||
|
|
ok = False
|
||
|
|
session.add(row)
|
||
|
|
return ok
|