from __future__ import annotations import random import time from dataclasses import dataclass, field PAIRING_CODE_TTL = 600 PAIRING_RATE_LIMIT = 3600 CODE_LENGTH = 6 @dataclass class PendingPairing: buyer_id: str code: str created_at: float = field(default_factory=time.time) def is_expired(self) -> bool: return time.time() - self.created_at > PAIRING_CODE_TTL class PinduoduoPairing: def __init__(self): self._pending: dict[str, PendingPairing] = {} self._last_generated: dict[str, float] = {} self._paired: set[str] = set() def generate_code(self, buyer_id: str) -> str | None: last = self._last_generated.get(buyer_id, 0) if time.time() - last < PAIRING_RATE_LIMIT: return None self._clean_expired() active = [p for p in self._pending.values() if p.buyer_id == buyer_id and not p.is_expired()] if len(active) >= 3: return None code = f"{random.randint(0, 999999):06d}" self._pending[buyer_id] = PendingPairing(buyer_id=buyer_id, code=code) self._last_generated[buyer_id] = time.time() return code def verify_code(self, buyer_id: str, code: str) -> bool: self._clean_expired() pending = self._pending.get(buyer_id) if pending is None: return False if pending.is_expired(): return False if pending.code != code: return False self._paired.add(buyer_id) del self._pending[buyer_id] return True def is_paired(self, buyer_id: str) -> bool: return buyer_id in self._paired @staticmethod def normalize_allow_entry(entry: str) -> str: return entry.strip().lower() def _clean_expired(self) -> None: expired = [bid for bid, p in self._pending.items() if p.is_expired()] for bid in expired: del self._pending[bid]