ForcePilot/backend/package/yuxi/channel/extensions/mattermost/pairing.py
Kris ebab14660a feat(channel): 添加 Mattermost 渠道扩展
新增 Mattermost 渠道扩展,支持在 Yuxi 平台中集成 Mattermost 团队协作平台。

包含以下功能模块:
- client: Mattermost API 客户端封装
- config: 渠道配置管理
- gateway: SSE/WebSocket 网关接入
- websocket: WebSocket 实时连接
- outbound: 外发消息管理
- streaming: 流式消息处理
- pairing: 用户配对与绑定
- security: 安全校验
- dedup: 消息去重
- monitor: 渠道状态监控
- status: 会话状态管理
- session: 会话管理
- interactions: 交互处理
- slash_commands: 斜杠指令
- actions: 动作处理
- approval: 审批流程
- delivery: 消息送达确认
- directory: 目录管理
- threading: 线程管理
- gating: 门控管理
- reconnect: 重连机制
- reactions: 表情反应
- media: 媒体资源处理
- model_picker: 模型选择
- types: 类型定义
2026-05-21 11:22:43 +08:00

85 lines
2.2 KiB
Python

from __future__ import annotations
import logging
import secrets
import string
from yuxi.channel.extensions.mattermost.security import normalize_allow_entry
logger = logging.getLogger(__name__)
PAIRING_CODE_LENGTH = 8
PAIRING_CODE_EXPIRY_SECONDS = 600
class MattermostPairingAdapter:
def __init__(self):
self._pending: dict[str, tuple[str, float]] = {}
def generate_code(self, peer_id: str) -> str:
import time as _time
code = _generate_pairing_code()
self._pending[peer_id] = (code, _time.time())
existing = [peer_id]
for pid, (c, _) in list(self._pending.items()):
if c == code:
existing.append(pid)
return code
def verify_code(self, peer_id: str, code: str) -> bool:
import time as _time
if peer_id not in self._pending:
return False
stored_code, timestamp = self._pending[peer_id]
now = _time.time()
if now - timestamp > PAIRING_CODE_EXPIRY_SECONDS:
self._pending.pop(peer_id, None)
return False
if stored_code != code.strip():
return False
self._pending.pop(peer_id, None)
return True
def get_pending_code(self, peer_id: str) -> str | None:
import time as _time
if peer_id not in self._pending:
return None
code, timestamp = self._pending[peer_id]
if _time.time() - timestamp > PAIRING_CODE_EXPIRY_SECONDS:
self._pending.pop(peer_id, None)
return None
return code
def clear_expired(self) -> None:
import time as _time
now = _time.time()
expired = [
pid for pid, (_, ts) in self._pending.items()
if now - ts > PAIRING_CODE_EXPIRY_SECONDS
]
for pid in expired:
self._pending.pop(pid, None)
def is_paired(self, peer_id: str, allow_list: list[str]) -> bool:
normalized = [normalize_allow_entry(e) for e in allow_list]
return peer_id in normalized
def _generate_pairing_code() -> str:
chars = string.ascii_uppercase + string.digits
raw = "".join(secrets.choice(chars) for _ in range(PAIRING_CODE_LENGTH))
return f"{raw[:4]}-{raw[4:]}"