该提交新增了完整的 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 部署,内置安全防护与流量控制机制。
100 lines
3.5 KiB
Python
100 lines
3.5 KiB
Python
from __future__ import annotations
|
|
|
|
import time
|
|
from collections import defaultdict
|
|
from dataclasses import dataclass, field
|
|
|
|
|
|
@dataclass
|
|
class MetricsSnapshot:
|
|
counters: dict[str, int] = field(default_factory=dict)
|
|
gauges: dict[str, float] = field(default_factory=dict)
|
|
timestamp: float = field(default_factory=time.time)
|
|
|
|
|
|
class NostrMetrics:
|
|
def __init__(self):
|
|
self._counters: dict[str, int] = defaultdict(int)
|
|
self._gauges: dict[str, float] = defaultdict(float)
|
|
|
|
def increment(self, name: str, value: int = 1) -> None:
|
|
self._counters[name] += value
|
|
|
|
def set_gauge(self, name: str, value: float) -> None:
|
|
self._gauges[name] = value
|
|
|
|
def adjust_gauge(self, name: str, delta: float) -> None:
|
|
self._gauges[name] += delta
|
|
|
|
def get_counter(self, name: str) -> int:
|
|
return self._counters.get(name, 0)
|
|
|
|
def get_gauge(self, name: str) -> float:
|
|
return self._gauges.get(name, 0.0)
|
|
|
|
def snapshot(self) -> MetricsSnapshot:
|
|
return MetricsSnapshot(
|
|
counters=dict(self._counters),
|
|
gauges=dict(self._gauges),
|
|
timestamp=time.time(),
|
|
)
|
|
|
|
def reset(self) -> None:
|
|
self._counters.clear()
|
|
self._gauges.clear()
|
|
|
|
def record_event_received(self, kind: int) -> None:
|
|
self.increment("event.received.total", 1)
|
|
self.increment(f"event.received.kind_{kind}", 1)
|
|
|
|
def record_event_rejected(self, reason: str) -> None:
|
|
self.increment("event.rejected.total", 1)
|
|
self.increment(f"event.rejected.{reason}", 1)
|
|
|
|
def record_event_accepted(self) -> None:
|
|
self.increment("event.accepted.total", 1)
|
|
|
|
def record_relay_connect(self, url: str) -> None:
|
|
self.increment("relay.connect.total", 1)
|
|
self.increment(f"relay.connect.{self._safe_label(url)}", 1)
|
|
|
|
def record_relay_disconnect(self, url: str) -> None:
|
|
self.increment("relay.disconnect.total", 1)
|
|
self.increment(f"relay.disconnect.{self._safe_label(url)}", 1)
|
|
|
|
def record_relay_send_success(self, url: str) -> None:
|
|
self.increment("relay.send.success.total", 1)
|
|
self.increment(f"relay.send.success.{self._safe_label(url)}", 1)
|
|
|
|
def record_relay_send_failure(self, url: str) -> None:
|
|
self.increment("relay.send.failure.total", 1)
|
|
self.increment(f"relay.send.failure.{self._safe_label(url)}", 1)
|
|
|
|
def record_circuit_breaker_state(self, url: str, state: str) -> None:
|
|
self.set_gauge(
|
|
f"circuit_breaker.{self._safe_label(url)}.state", {"closed": 0, "half_open": 1, "open": 2}.get(state, -1)
|
|
)
|
|
self.increment(f"circuit_breaker.{self._safe_label(url)}.{state}", 1)
|
|
|
|
def record_rate_limit_hit(self, sender_pubkey: str = "", global_hit: bool = False) -> None:
|
|
if global_hit:
|
|
self.increment("rate_limit.global.hit", 1)
|
|
else:
|
|
self.increment("rate_limit.sender.hit", 1)
|
|
|
|
def record_decrypt_success(self, protocol: str = "nip04") -> None:
|
|
self.increment(f"decrypt.{protocol}.success", 1)
|
|
|
|
def record_decrypt_failure(self, protocol: str = "nip04") -> None:
|
|
self.increment(f"decrypt.{protocol}.failure", 1)
|
|
|
|
def record_seen_tracker_size(self, size: int) -> None:
|
|
self.set_gauge("memory.seen_tracker_size", size)
|
|
|
|
def record_inflight_size(self, size: int) -> None:
|
|
self.set_gauge("memory.inflight_size", size)
|
|
|
|
@staticmethod
|
|
def _safe_label(url: str) -> str:
|
|
return url.replace("://", "_").replace(".", "_").replace("/", "_").rstrip("_")
|