ForcePilot/backend/package/yuxi/channels/adapters/whatsapp/pairing.py
Kris e9b57546ea feat(whatsapp): 新增WhatsApp适配器完整功能模块
新增大量WhatsApp适配器相关代码,包括账号管理、会话处理、消息收发、验证授权、媒体处理、互动命令、审批流程、健康检测等完整功能模块,搭建基础的Baileys协议WhatsApp接入能力
2026-05-12 00:51:58 +08:00

76 lines
2.4 KiB
Python

from __future__ import annotations
import asyncio
import threading
from dataclasses import dataclass
from yuxi.utils.logging_config import logger
@dataclass
class PairRequest:
phone_number: str
pairing_code: str | None = None
expires_at: float | None = None
@property
def is_expired(self) -> bool:
if self.expires_at is None:
return False
return asyncio.get_event_loop().time() > self.expires_at
class PairingManager:
def __init__(self):
self._pending: dict[str, PairRequest] = {}
self._paired: set[str] = set()
self._lock = threading.Lock()
def create_pair_request(self, phone_number: str, code: str, timeout: float = 300) -> PairRequest:
req = PairRequest(
phone_number=phone_number,
pairing_code=code,
expires_at=asyncio.get_event_loop().time() + timeout,
)
with self._lock:
self._pending[phone_number] = req
logger.info(f"PairingManager: pair request created for {phone_number}")
return req
def confirm_pair(self, phone_number: str) -> bool:
with self._lock:
req = self._pending.get(phone_number)
if req is None or req.is_expired:
logger.warning(f"PairingManager: no valid request for {phone_number}")
return False
del self._pending[phone_number]
self._paired.add(phone_number)
logger.info(f"PairingManager: confirmed pair for {phone_number}")
return True
def is_paired(self, phone_number: str) -> bool:
with self._lock:
return phone_number in self._paired
def revoke_pair(self, phone_number: str) -> bool:
with self._lock:
removed_pending = self._pending.pop(phone_number, None) is not None
removed_paired = phone_number in self._paired
self._paired.discard(phone_number)
return removed_pending or removed_paired
def get_pending_phones(self) -> list[str]:
with self._lock:
return list(self._pending.keys())
def cleanup_expired(self) -> int:
count = 0
with self._lock:
expired = [phone for phone, req in self._pending.items() if req.is_expired]
for phone in expired:
del self._pending[phone]
count += 1
if count:
logger.info(f"PairingManager: cleaned {count} expired requests")
return count