ForcePilot/backend/package/yuxi/channels/adapters/nextcloudtalk/room_info.py
Kris b018ad25da feat(backend): add Nextcloud Talk channel adapter implementation
实现了完整的Nextcloud Talk聊天适配器,包含以下核心功能:
1. 基础客户端通信与认证
2. 会话路由与聊天类型解析
3. 消息分块与格式转换
4. 用户配对与权限校验
5. 轮询式消息监听
6. 配置验证与诊断工具
7. 安全策略与去重缓存
8. 指标统计与状态快照

新增配套的配对用户缓存文件与模块导出入口。
2026-05-12 00:47:06 +08:00

71 lines
1.9 KiB
Python

from __future__ import annotations
import logging
import time
from typing import Any
from yuxi.channels.models import ChatType
logger = logging.getLogger(__name__)
_CACHE_TTL_SUCCESS = 300
_CACHE_TTL_ERROR = 30
_room_kind_cache: dict[str, tuple[float, str | None]] = {}
async def resolve_room_kind(
client,
api_base: str,
token: str,
api_user: str = "",
api_password: str = "",
) -> dict[str, Any]:
now = time.time()
cached = _room_kind_cache.get(token)
if cached:
cached_ts, cached_kind = cached
if cached_kind is not None and now - cached_ts < _CACHE_TTL_SUCCESS:
return _kind_result(cached_kind)
if cached_kind is None and now - cached_ts < _CACHE_TTL_ERROR:
return _kind_result(None)
try:
path = f"{api_base}/room/{token}"
result = await client.get(path)
ocs = result.get("ocs", {})
data = ocs.get("data", {})
room_type = data.get("type")
kind = _map_room_type(room_type)
_room_kind_cache[token] = (now, kind)
return _kind_result(kind)
except Exception as e:
logger.warning(f"[NextcloudTalk] Room type query failed for {token}: {e}")
_room_kind_cache[token] = (now, None)
return _kind_result(None)
def _map_room_type(room_type: int | None) -> str | None:
if room_type is None:
return None
if room_type in (1, 5, 6):
return "direct"
if room_type in (2, 3, 4):
return "group"
return None
def _kind_result(kind: str | None) -> dict[str, Any]:
if kind == "direct":
return {"kind": "direct", "chat_type": ChatType.DIRECT}
if kind == "group":
return {"kind": "group", "chat_type": ChatType.GROUP}
return {"kind": None, "chat_type": ChatType.GROUP, "source": "cache_fallback"}
def invalidate_room_cache(token: str | None = None) -> None:
if token:
_room_kind_cache.pop(token, None)
else:
_room_kind_cache.clear()