99 lines
3.7 KiB
Python
99 lines
3.7 KiB
Python
|
|
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)
|