Files
video-gen/video-gen-api/app/services/sms.py
T
2026-05-25 17:08:18 +08:00

80 lines
2.3 KiB
Python

import logging
import random
import time
import httpx
from app.config import settings
from app.utils.redis import get_redis
logger = logging.getLogger("videogen")
# In-memory fallback for verification codes
_sms_code_store: dict[str, tuple[str, float]] = {}
def _generate_code(length: int = 6) -> str:
return "".join(random.choices("0123456789", k=length))
async def send_sms(phone: str, code: str) -> bool:
"""Send SMS verification code. Supports mock mode and real HTTP gateway."""
if settings.SMS_MOCK or not settings.SMS_API_URL:
logger.info(f"[SMS MOCK] To={phone}, Code={code}")
return True
try:
payload = {
"phone": phone,
"code": code,
"sign_name": settings.SMS_SIGN_NAME,
"template_code": settings.SMS_TEMPLATE_CODE,
}
headers = {
"Authorization": f"Bearer {settings.SMS_API_KEY}",
"Content-Type": "application/json",
}
async with httpx.AsyncClient(timeout=10) as client:
resp = await client.post(settings.SMS_API_URL, json=payload, headers=headers)
resp.raise_for_status()
return True
except Exception:
logger.exception(f"SMS send failed for {phone}")
return False
async def store_sms_code(phone: str, code: str, ttl: int = 300) -> None:
"""Store SMS verification code with TTL (default 5 minutes)."""
redis = get_redis()
if redis:
await redis.setex(f"sms_code:{phone}", ttl, code)
else:
_sms_code_store[phone] = (code, time.time() + ttl)
async def generate_and_send_sms(phone: str) -> bool:
"""Generate a code, store it, and send it via SMS."""
code = _generate_code()
ok = await send_sms(phone, code)
if ok:
await store_sms_code(phone, code)
return ok
async def verify_sms_code(phone: str, code: str) -> bool:
"""Verify an SMS verification code."""
redis = get_redis()
if redis:
stored = await redis.get(f"sms_code:{phone}")
if stored and stored == code:
await redis.delete(f"sms_code:{phone}")
return True
return False
else:
entry = _sms_code_store.pop(phone, None)
if entry:
stored_code, expires = entry
if time.time() < expires and stored_code == code:
return True
return False