实现完整的Freshdesk和Freshchat集成支持,包含会话守卫、错误定义、消息去重、配置管理、webhook处理、出站消息发送、状态监控、安全校验、配对功能和流式回复支持
50 lines
1.4 KiB
Python
50 lines
1.4 KiB
Python
import logging
|
|
import random
|
|
import string
|
|
import time
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
CODE_TTL_SECONDS = 600
|
|
CODE_LENGTH = 6
|
|
MAX_GENERATE_PER_PEER_PER_MINUTE = 3
|
|
|
|
|
|
class FreshdeskPairing:
|
|
def __init__(self):
|
|
self._codes: dict[str, tuple[str, float]] = {}
|
|
self._gen_timestamps: dict[str, list[float]] = {}
|
|
|
|
async def generate_code(self, peer_id: str) -> str | None:
|
|
now = time.time()
|
|
timestamps = self._gen_timestamps.setdefault(peer_id, [])
|
|
timestamps[:] = [ts for ts in timestamps if now - ts < 60]
|
|
|
|
if len(timestamps) >= MAX_GENERATE_PER_PEER_PER_MINUTE:
|
|
logger.warning("Pairing code rate limited for peer %s", peer_id)
|
|
return None
|
|
|
|
code = "".join(random.choices(string.digits, k=CODE_LENGTH))
|
|
self._codes[peer_id] = (code, now + CODE_TTL_SECONDS)
|
|
timestamps.append(now)
|
|
return code
|
|
|
|
async def verify(self, peer_id: str, code: str) -> bool:
|
|
now = time.time()
|
|
entry = self._codes.get(peer_id)
|
|
if entry is None:
|
|
return False
|
|
|
|
saved_code, expires_at = entry
|
|
if now > expires_at:
|
|
del self._codes[peer_id]
|
|
return False
|
|
|
|
return saved_code == code
|
|
|
|
def cleanup(self):
|
|
now = time.time()
|
|
expired = [k for k, (_, exp) in self._codes.items() if now > exp]
|
|
for k in expired:
|
|
del self._codes[k]
|