ForcePilot/backend/package/yuxi/channel/extensions/nostr/profile_publisher.py
Kris 16455cb303 feat(channel): 添加 Nostr 渠道扩展
新增 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: 状态存储
2026-05-21 11:31:51 +08:00

59 lines
1.8 KiB
Python

import asyncio
import hashlib
import json
import time
from dataclasses import dataclass, field
from .event_utils import sign_event
from .defaults import PROFILE_KIND, PROFILE_PUBLISH_TIMEOUT_S
from .profile_core import NostrProfile, profile_to_content
@dataclass
class ProfilePublishResult:
event_id: str
created_at: int
successes: list[str] = field(default_factory=list)
failures: list[dict] = field(default_factory=list)
persisted: bool = False
async def publish_profile(bus, profile: NostrProfile, last_published_at: int | None = None) -> ProfilePublishResult:
now = int(time.time())
created_at = max(now, (last_published_at or 0) + 1)
content = profile_to_content(profile)
event = sign_event(bus.sk, bus.pk, kind=PROFILE_KIND, content=content, tags=[])
serialized = json.dumps(
[0, event["pubkey"], created_at, PROFILE_KIND, [], content],
separators=(",", ":"),
ensure_ascii=False,
)
event["created_at"] = created_at
event["id"] = hashlib.sha256(serialized.encode()).hexdigest()
sig = bus._sign_event_hash(event["id"])
event["sig"] = sig.hex()
results = {}
for relay in bus.relays:
try:
success = await asyncio.wait_for(
bus.pool.publish(relay, event), timeout=PROFILE_PUBLISH_TIMEOUT_S
)
results[relay] = "ok" if success else "failed"
except TimeoutError:
results[relay] = "timeout"
except Exception:
results[relay] = "failed"
persisted = any(v == "ok" for v in results.values())
return ProfilePublishResult(
event_id=event["id"],
created_at=created_at,
successes=[r for r, v in results.items() if v == "ok"],
failures=[{"relay": r, "error": v} for r, v in results.items() if v != "ok"],
persisted=persisted,
)