该提交新增了完整的 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 部署,内置安全防护与流量控制机制。
91 lines
2.8 KiB
Python
91 lines
2.8 KiB
Python
from __future__ import annotations
|
|
|
|
import time
|
|
from collections import defaultdict
|
|
from dataclasses import dataclass
|
|
|
|
|
|
@dataclass
|
|
class RelayHealthSnapshot:
|
|
url: str
|
|
score: float = 0.0
|
|
success_rate: float = 0.0
|
|
avg_latency_ms: float = 0.0
|
|
total_requests: int = 0
|
|
total_successes: int = 0
|
|
total_failures: int = 0
|
|
circuit_open: bool = False
|
|
|
|
|
|
@dataclass
|
|
class _HealthRecord:
|
|
success: int = 0
|
|
failure: int = 0
|
|
total_latency_ms: float = 0.0
|
|
last_success_time: float = 0.0
|
|
|
|
|
|
class RelayHealthTracker:
|
|
def __init__(self, window_sec: float = 60.0, freshness_reward_coeff: float = 0.3):
|
|
self._window_sec = window_sec
|
|
self._freshness_reward_coeff = freshness_reward_coeff
|
|
self._records: dict[str, _HealthRecord] = defaultdict(_HealthRecord)
|
|
|
|
def record_success(self, url: str, latency_ms: float = 0.0) -> None:
|
|
record = self._records[url]
|
|
record.success += 1
|
|
record.total_latency_ms += latency_ms
|
|
record.last_success_time = time.monotonic()
|
|
|
|
def record_failure(self, url: str) -> None:
|
|
self._records[url].failure += 1
|
|
|
|
def get_score(self, url: str) -> float:
|
|
record = self._records[url]
|
|
total = record.success + record.failure
|
|
if total == 0:
|
|
return 0.5
|
|
|
|
success_rate = record.success / total
|
|
|
|
recency = 0.0
|
|
if record.last_success_time > 0:
|
|
age = time.monotonic() - record.last_success_time
|
|
recency = max(0.0, 1.0 - age / (self._window_sec * 2))
|
|
|
|
avg_latency = record.total_latency_ms / record.success if record.success > 0 else 0.0
|
|
latency_penalty = min(avg_latency / 1000.0, 1.0)
|
|
|
|
score = (
|
|
0.5 * success_rate + self._freshness_reward_coeff * recency + 0.5 * max(0.0, 1.0 - latency_penalty)
|
|
) / (1.0 + self._freshness_reward_coeff)
|
|
|
|
return round(score, 4)
|
|
|
|
def snapshot(self, url: str) -> RelayHealthSnapshot:
|
|
record = self._records[url]
|
|
total = record.success + record.failure
|
|
success_rate = record.success / total if total > 0 else 0.0
|
|
avg_latency = record.total_latency_ms / record.success if record.success > 0 else 0.0
|
|
|
|
return RelayHealthSnapshot(
|
|
url=url,
|
|
score=self.get_score(url),
|
|
success_rate=success_rate,
|
|
avg_latency_ms=round(avg_latency, 1),
|
|
total_requests=total,
|
|
total_successes=record.success,
|
|
total_failures=record.failure,
|
|
)
|
|
|
|
def sorted_relays(self, urls: list[str]) -> list[str]:
|
|
scored = [(url, self.get_score(url)) for url in urls]
|
|
scored.sort(key=lambda x: x[1], reverse=True)
|
|
return [url for url, _ in scored]
|
|
|
|
def reset(self, url: str | None = None) -> None:
|
|
if url:
|
|
self._records.pop(url, None)
|
|
else:
|
|
self._records.clear()
|