ForcePilot/backend/package/yuxi/channels/adapters/slack/dm_cache.py
Kris a2aa782b86 feat(slack adapter): 实现完整的Slack频道适配器基础功能
新增Slack适配器全套核心模块,包括消息处理流水线、会话管理、配置适配、权限控制等完整功能:
1. 新增语音、视觉相关的TTS和图像分析导出接口
2. 实现消息预处理、路由、线程上下文处理的完整流水线
3. 新增账号管理、缓存机制、房间上下文提取功能
4. 支持Webhook和Socket Mode两种事件接收方式
5. 实现权限白名单、审批配对、自动状态管理功能
6. 新增配置迁移、作用域校验、重连策略等辅助模块
2026-05-12 00:48:57 +08:00

56 lines
1.7 KiB
Python

from __future__ import annotations
from collections import OrderedDict
from slack_sdk.errors import SlackApiError
from slack_sdk.web.async_client import AsyncWebClient
from yuxi.utils.logging_config import logger
MAX_DM_CACHE_SIZE = 1024
class DmChannelCache:
def __init__(self, max_size: int = MAX_DM_CACHE_SIZE):
self._cache: OrderedDict[str, str] = OrderedDict()
self._max_size = max_size
def get(self, user_id: str) -> str | None:
channel_id = self._cache.get(user_id)
if channel_id is not None:
self._cache.move_to_end(user_id)
return channel_id
def put(self, user_id: str, channel_id: str) -> None:
if user_id in self._cache:
self._cache.move_to_end(user_id)
else:
if len(self._cache) >= self._max_size:
self._cache.popitem(last=False)
self._cache[user_id] = channel_id
def clear(self) -> None:
self._cache.clear()
@property
def size(self) -> int:
return len(self._cache)
async def resolve(self, client: AsyncWebClient, user_id: str) -> str | None:
cached = self.get(user_id)
if cached:
return cached
try:
result = await client.conversations_open(users=[user_id])
if not result.get("ok"):
logger.warning(f"conversations.open failed for {user_id}: {result.get('error')}")
return None
channel_id = result.get("channel", {}).get("id", "")
if channel_id:
self.put(user_id, channel_id)
return channel_id
except SlackApiError as e:
logger.warning(f"Failed to resolve DM channel for {user_id}: {e}")
return None