ForcePilot/backend/package/yuxi/channels/adapters/nostr/send_cache.py
Kris a1f8288d20 feat(nostr): 实现完整的 Nostr 协议适配器模块
该提交新增了完整的 Nostr 去中心化社交网络适配器实现,包含以下核心功能:
1. 基础加密与密钥处理:支持 nsec/npub/hex 格式密钥转换,实现 NIP-04/NIP-17 加解密
2. Relay 管理与健康监控:支持多 Relay 连接、自动重连、健康评分与自动选优
3. 事件与消息处理:实现事件校验、去重、速率限制、消息缓存与状态持久化
4. 个人资料管理:支持发布/导入/合并 Nostr Kind 0 元数据事件
5. 配对机制:实现安全的双向配对通信流程
6. Zap 功能:支持 NIP-57 打赏请求与收据解析
7. NIP-05 验证:实现域名身份验证
8. 配置系统:完整的配置校验与多账户支持
9. 监控与指标:提供连接监控、事件统计与健康快照
10. HTTP API:提供个人资料管理的 RESTful 接口
11. 安装向导:命令行配置向导与初始化流程

所有模块均遵循 Nostr 协议规范,支持多账户、多 Relay 部署,内置安全防护与流量控制机制。
2026-05-12 00:47:41 +08:00

69 lines
2.2 KiB
Python

from __future__ import annotations
import time
from collections import OrderedDict
from dataclasses import dataclass, field
@dataclass
class SendCacheEntry:
event_id: str
content: str = ""
status: str = "sent"
timestamp: float = field(default_factory=time.time)
class SendCache:
def __init__(self, max_size: int = 100):
self._max_size = max_size
self._store: OrderedDict[str, SendCacheEntry] = OrderedDict()
def record(self, event_id: str, content: str = "", status: str = "sent") -> None:
if event_id in self._store:
self._store.move_to_end(event_id)
self._store[event_id].status = status
self._store[event_id].timestamp = time.time()
return
self._store[event_id] = SendCacheEntry(event_id=event_id, content=content[:200], status=status)
while len(self._store) > self._max_size:
self._store.popitem(last=False)
def update_status(self, event_id: str, status: str) -> None:
entry = self._store.get(event_id)
if entry:
entry.status = status
def get(self, event_id: str) -> SendCacheEntry | None:
return self._store.get(event_id)
def list_recent(self, limit: int = 10) -> list[SendCacheEntry]:
return list(self._store.values())[-limit:]
def to_dict_list(self) -> list[dict]:
return [
{
"event_id": e.event_id,
"content": e.content[:100],
"status": e.status,
"timestamp": e.timestamp,
}
for e in reversed(list(self._store.values()))
][: self._max_size]
@classmethod
def from_dict_list(cls, entries: list[dict], max_size: int = 100) -> SendCache:
cache = cls(max_size=max_size)
for entry in entries:
eid = entry.get("event_id", "")
if eid:
cache._store[eid] = SendCacheEntry(
event_id=eid,
content=entry.get("content", ""),
status=entry.get("status", "sent"),
timestamp=entry.get("timestamp", time.time()),
)
return cache
def __len__(self) -> int:
return len(self._store)