实现了完整的Nextcloud Talk聊天适配器,包含以下核心功能: 1. 基础客户端通信与认证 2. 会话路由与聊天类型解析 3. 消息分块与格式转换 4. 用户配对与权限校验 5. 轮询式消息监听 6. 配置验证与诊断工具 7. 安全策略与去重缓存 8. 指标统计与状态快照 新增配套的配对用户缓存文件与模块导出入口。
71 lines
1.9 KiB
Python
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()
|