新增 Nostr 渠道扩展,支持在 Yuxi 平台中集成 Nostr 去中心化社交协议。 包含以下功能模块: - bus: 事件总线与中继通信 - account: 账户管理 - key_utils: 密钥工具 - gateway: SSE/WebSocket 网关接入 - outbound: 外发消息管理 - gift_wrap: Gift Wrap 加密 - nip44: NIP-44 加密协议 - config_schema: 配置模式 - defaults: 默认配置 - profile_core: 用户资料核心 - profile_publisher: 资料发布 - event_utils: 事件工具 - deletion: 事件删除 - reactions: 表情反应 - metrics: 指标监控 - seen_tracker: 已读追踪 - session_route: 会话路由 - state_store: 状态存储
104 lines
3.8 KiB
Python
104 lines
3.8 KiB
Python
import time
|
|
from collections import defaultdict
|
|
from collections.abc import Callable
|
|
from dataclasses import dataclass, field
|
|
|
|
|
|
@dataclass
|
|
class RelayMetrics:
|
|
connect: int = 0
|
|
disconnect: int = 0
|
|
reconnect: int = 0
|
|
error: int = 0
|
|
event: int = 0
|
|
eose: int = 0
|
|
closed: int = 0
|
|
notice: int = 0
|
|
ok: int = 0
|
|
auth: int = 0
|
|
circuit_breaker_open: int = 0
|
|
circuit_breaker_close: int = 0
|
|
circuit_breaker_half_open: int = 0
|
|
|
|
|
|
@dataclass
|
|
class MetricsSnapshot:
|
|
events_received: int = 0
|
|
events_processed: int = 0
|
|
events_duplicate: int = 0
|
|
events_self_message: int = 0
|
|
events_rejected: dict[str, int] = field(default_factory=dict)
|
|
relays: dict[str, RelayMetrics] = field(default_factory=dict)
|
|
rate_limiting: dict[str, int] = field(
|
|
default_factory=lambda: {"per_sender": 0, "global": 0}
|
|
)
|
|
decrypt: dict[str, int] = field(
|
|
default_factory=lambda: {"success": 0, "failure": 0}
|
|
)
|
|
memory: dict[str, int] = field(
|
|
default_factory=lambda: {"seen_tracker_size": 0, "rate_limiter_entries": 0}
|
|
)
|
|
snapshot_at: float = 0.0
|
|
|
|
|
|
class MetricsCollector:
|
|
def __init__(self, on_metric: Callable | None = None):
|
|
self._counters: dict[str, int] = defaultdict(int)
|
|
self._relay_stats: dict[str, dict] = defaultdict(lambda: defaultdict(int))
|
|
self._on_metric = on_metric
|
|
|
|
def emit(self, name: str, relay: str | None = None, value: int = 1):
|
|
self._counters[name] += value
|
|
if relay:
|
|
self._relay_stats[relay][name] += value
|
|
if self._on_metric:
|
|
self._on_metric(name, relay, value)
|
|
|
|
def snapshot(
|
|
self, seen_tracker_size: int = 0, rate_limiter_entries: int = 0
|
|
) -> MetricsSnapshot:
|
|
rejected = {}
|
|
for k, v in self._counters.items():
|
|
if k.startswith("event.rejected."):
|
|
rejected[k.replace("event.rejected.", "")] = v
|
|
|
|
relay_snapshots = {}
|
|
for relay, stats in self._relay_stats.items():
|
|
relay_snapshots[relay] = RelayMetrics(
|
|
connect=stats.get("relay.connect", 0),
|
|
disconnect=stats.get("relay.disconnect", 0),
|
|
reconnect=stats.get("relay.reconnect", 0),
|
|
error=stats.get("relay.error", 0),
|
|
event=stats.get("relay.message.event", 0),
|
|
eose=stats.get("relay.message.eose", 0),
|
|
closed=stats.get("relay.message.closed", 0),
|
|
notice=stats.get("relay.message.notice", 0),
|
|
ok=stats.get("relay.message.ok", 0),
|
|
auth=stats.get("relay.message.auth", 0),
|
|
circuit_breaker_open=stats.get("relay.circuit_breaker.open", 0),
|
|
circuit_breaker_close=stats.get("relay.circuit_breaker.close", 0),
|
|
circuit_breaker_half_open=stats.get("relay.circuit_breaker.half_open", 0),
|
|
)
|
|
|
|
return MetricsSnapshot(
|
|
events_received=self._counters.get("event.received", 0),
|
|
events_processed=self._counters.get("event.processed", 0),
|
|
events_duplicate=self._counters.get("event.duplicate", 0),
|
|
events_self_message=self._counters.get("event.rejected.self_message", 0),
|
|
events_rejected=rejected,
|
|
relays=relay_snapshots,
|
|
rate_limiting={
|
|
"per_sender": self._counters.get("rate_limit.per_sender", 0),
|
|
"global": self._counters.get("rate_limit.global", 0),
|
|
},
|
|
decrypt={
|
|
"success": self._counters.get("decrypt.success", 0),
|
|
"failure": self._counters.get("decrypt.failure", 0),
|
|
},
|
|
memory={
|
|
"seen_tracker_size": seen_tracker_size,
|
|
"rate_limiter_entries": rate_limiter_entries,
|
|
},
|
|
snapshot_at=time.time(),
|
|
)
|