ForcePilot/backend/package/yuxi/channels/adapters/nostr/setup_plugin.py

99 lines
3.7 KiB
Python
Raw Normal View History

from __future__ import annotations
from typing import Any
from yuxi.channels.adapters.nostr.setup import NostrSetupAdapter
from yuxi.channels.adapters.nostr.crypto import NostrCrypto, NostrCryptoError
from yuxi.channels.adapters.nostr.config import NostrConfig
class NostrSetupPlugin:
channel_id: str = "nostr"
channel_label: str = "Nostr (Decentralized)"
channel_description: str = "Nostr 去中心化社交网络 DM 协议配置向导"
def __init__(self, config: dict[str, Any] | None = None):
self._config = config or {}
self._setup_adapter = NostrSetupAdapter()
@property
def config(self) -> dict[str, Any]:
return self._config
def get_setup_wizard(self) -> dict[str, Any]:
return {
"channel_id": self.channel_id,
"label": self.channel_label,
"description": self.channel_description,
"steps": self._setup_adapter.get_setup_steps(),
"help": "详细文档请参考: /docs/channels/nostr",
}
async def validate_credentials(self, private_key: str) -> dict[str, Any]:
result = await self._setup_adapter.verify_key(private_key)
if result.get("success"):
return {"valid": True, "npub": result.get("npub"), "hex": result.get("hex")}
return {"valid": False, "error": result.get("error", "unknown")}
async def probe_connectivity(self, relays: list[str], timeout_ms: int = 8000) -> dict[str, Any]:
result = await self._setup_adapter.probe_relays(relays)
return {
"connected": result.get("success", False),
"reachable": result.get("reachable", 0),
"total": result.get("total", 0),
"details": result.get("details", []),
}
def get_recommendations(self) -> dict[str, Any]:
return {
"relays": [
"wss://relay.damus.io",
"wss://relay.primal.net",
"wss://relay.nostr.info",
"wss://nos.lol",
],
"dm_policy": "pairing",
"nip17_enabled": True,
"streaming_mode": "block",
}
async def validate_full_config(self, full_config: dict[str, Any]) -> dict[str, Any]:
errors: list[str] = []
warnings: list[str] = []
try:
NostrConfig.from_dict(full_config)
except Exception as e:
errors.append(f"配置验证失败: {e}")
return {"valid": False, "errors": errors, "warnings": warnings}
private_key = full_config.get("private_key") or full_config.get("accounts", {}).get("default", {}).get(
"private_key", ""
)
if private_key:
try:
NostrCrypto(private_key)
except NostrCryptoError as e:
errors.append(f"私钥无效: {e}")
else:
warnings.append("未配置私钥,将自动生成临时密钥")
relays = full_config.get("relays") or full_config.get("accounts", {}).get("default", {}).get("relays")
if not relays:
warnings.append("未配置 Relay将使用默认 Relay 列表")
else:
invalid_relays = [r for r in relays if not r.startswith(("ws://", "wss://"))]
if invalid_relays:
warnings.append(f"以下 Relay URL 格式可能无效: {invalid_relays}")
return {"valid": len(errors) == 0, "errors": errors, "warnings": warnings}
def get_setup_plugin(config: dict[str, Any] | None = None) -> NostrSetupPlugin:
return NostrSetupPlugin(config)
async def verify_channel_setup(config: dict[str, Any]) -> dict[str, Any]:
plugin = NostrSetupPlugin(config)
return await plugin.validate_full_config(config)