ForcePilot/backend/package/yuxi/channels/adapters/imessage/sticker_cache.py
Kris 068cf70fe9 feat(imessage): 实现完整的 iMessage 适配器基础模块
新增 iMessage 通道适配器完整实现,包含:
1. 核心适配器与工具工厂导出
2. 运行时存储、反射防护、会话路由等基础组件
3. 消息信封、线程管理、回复上下文格式化
4. Tapback 表情反应处理、自定义异常体系
5. 审批按钮、联系人解析、速率限制功能
6. 文本净化、目标解析、缓存管理模块
7. 配置 schema、多账户支持、安装向导等配置模块
8. 审计日志、媒体AI处理等扩展功能
2026-05-12 00:44:44 +08:00

52 lines
1.8 KiB
Python

from __future__ import annotations
import json
import time
from pathlib import Path
from typing import Any
class StickerCache:
def __init__(self, cache_dir: str | None = None, max_entries: int = 500):
self._cache_dir = Path(cache_dir or str(Path.home() / ".yuxi" / "imessage" / "stickers"))
self._max_entries = max_entries
self._index: dict[str, dict[str, Any]] = {}
self._cache_dir.mkdir(parents=True, exist_ok=True)
self._load_index()
def add(self, sticker_id: str, url: str, metadata: dict[str, Any] | None = None) -> None:
entry = {
"sticker_id": sticker_id,
"url": url,
"metadata": metadata or {},
"cached_at": time.time(),
}
self._index[sticker_id] = entry
if len(self._index) > self._max_entries:
oldest = min(self._index.values(), key=lambda e: e["cached_at"])
self._index.pop(oldest["sticker_id"], None)
self._save_index()
def get(self, sticker_id: str) -> dict[str, Any] | None:
return self._index.get(sticker_id)
def get_url(self, sticker_id: str) -> str | None:
entry = self._index.get(sticker_id)
return entry["url"] if entry else None
def clear(self) -> None:
self._index.clear()
self._save_index()
def _load_index(self) -> None:
index_path = self._cache_dir / "sticker_index.json"
if index_path.exists():
try:
self._index = json.loads(index_path.read_text(encoding="utf-8"))
except (json.JSONDecodeError, OSError):
self._index = {}
def _save_index(self) -> None:
index_path = self._cache_dir / "sticker_index.json"
index_path.write_text(json.dumps(self._index, ensure_ascii=False, indent=2), encoding="utf-8")