Documentation
¶
Overview ¶
directory.go — 联邦节点名录透传(2026-10-14 邀请信箱配套;2026-10-22 由 直传包搬入)。
名录端点无鉴权(零敏感,公开信息),registry URL 由宿主从管理端 SystemConfig 注入(已过 SSRF 校验)。直传未启用/二进制缺失不挡名录查询—— 名录可见性只取决于 registry 可达。
归属:名录是对端站点列表,属联邦域,不属直传域——本文件不依赖 p2pc 运行时。
命名(2026-10-22 L3):PeerDirectory = 联邦节点名录,**无条件**构造 (可见性只取决于 registry 可达,与联邦运行时是否启用无关;见 invite.go 文件头的三类服务命名约定)。
Package federation 将本站点接入 PigeonBox P2P 联邦(github.com/pigeonbox/p2p)。
职责(M2,设计文档 docs/specs/2026-10-04-p2p-registry-service-design.md §5):
- 节点注册/心跳:Ed25519 签名租约,断线自动重注册 + 全量补公告(自愈);
- 口令联邦路由:share 生命周期钩子公告/撤销 SHA-256(code)→本节点;
- 解析代理:GET /api/v1/federation/resolve 转查 registry(浏览器免跨域)。
信任模型:本包只做"发现",取件方直连源节点、源节点本地校验口令——零跨节点信任。 签名负载格式与 p2p 仓 README 契约逐字节一致(见 client.go 常量注释)。 依赖方向:本包不 import 生态任何兄弟模块(叶子约束,core CI dep guard)。
本包三类服务按**构造条件**分家(2026-10-22 L3 命名收口,读者一眼可辨):
Service 联邦运行时(注册/心跳/公告/解析)——**仅联邦启用时**构造
(NewService 在 !cfg.Enabled 时报错,由装配层降级为非联邦模式)。
InviteMailbox 联邦邀请收件箱——**无条件**构造:跨实例交接的凭证与状态机,
与联邦运行时无关(联邦关闭时公开收件端点仍可用)。
PeerDirectory 联邦节点名录——**无条件**构造:可见性只取决于 registry 可达。
后两者的实例由装配层(bootstrap/wiring.go)构造,直传编排层只消费 (setter 注入)——删掉直传编排层时联邦能力不受影响(Wave B')。
invite.go — 联邦信封管理(跨实例推送邀请;2026-10-22 由直传包搬入)。
语义:邀请 = 口令 bearer(与手工交接同信任级——口令本身即授权,通道只是 递送);收件箱内存态(cap 20 / TTL 10 分钟 = p2pc 配对窗口,进程重启丢弃 可接受,口令同样已失效);出站推送目标 URL 走 SSRF 守卫(与 registry_url 同策略,私网目标需 security.ssrf.allow_private_networks)。
归属:信封是跨实例交接的凭证与状态机,属联邦域,不属直传域——本文件不 依赖 p2pc 运行时(无 spawn / 子进程 / 任务环),Wave B 删直传包时 本包原样留存。
命名(2026-10-22 L3):本包三类服务按"构造条件"分家,读者一眼可辨——
- Service:联邦运行时(注册/心跳/公告),**仅联邦启用时**构造;
- InviteMailbox:联邦邀请收件箱,**无条件**构造(联邦关闭时仍可用, 它是跨实例交接的凭证与状态机,与联邦运行时无关);
- PeerDirectory:联邦节点名录,**无条件**构造(可见性只取决于 registry 可达,不取决于联邦是否启用)。
Index ¶
- func PushInvite(ctx context.Context, targetURL, code, fromName, note string) error
- type DirectoryPeer
- type Invite
- type InviteMailbox
- type InviteSnapshot
- type PeerDirectory
- type RegistryURLProvider
- type ResolveInfo
- type Service
- func (s *Service) Enabled() bool
- func (s *Service) Healthy() bool
- func (s *Service) NodeID() string
- func (s *Service) RegistryURLs() []string
- func (s *Service) Resolve(code string) (*ResolveInfo, error)
- func (s *Service) ShareCreated(code string, expiresAt *time.Time)
- func (s *Service) ShareDeleted(code string)
- func (s *Service) Start()
- func (s *Service) Stop()
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func PushInvite ¶ added in v0.27.0
PushInvite 把口令推送到目标实例的邀请收件端点(P3 免口令交接)。 targetURL = 目标实例基址(如 https://b.example.com); 实际 POST <target>/api/v1/p2p/invite,10s 超时。
Types ¶
type DirectoryPeer ¶ added in v0.27.0
type DirectoryPeer struct {
NodeID string `json:"node_id"`
Name string `json:"name"`
URL string `json:"url"` // 对外基址(NAT 后可为空)
BoxPub string `json:"box_pub"` // X25519 密封公钥 hex
OnlineSince int64 `json:"online_since"` // 租约起始 unix 秒
}
DirectoryPeer 名录对端(与 p2pd GET /v1/directory 条目同形)。
type InviteMailbox ¶ added in v0.27.0
type InviteMailbox struct {
// contains filtered or unexported fields
}
InviteMailbox 联邦信封收件箱(内存态;不依赖 p2pc 运行时)。
无条件构造(联邦关闭时仍可用——收件箱是跨实例交接的凭证与状态机,不是 联邦运行时的附属物;见文件头命名约定)。
clock 为构造期注入的时钟(nil=time.Now);构造后不再变更,故读路径无需 加锁(与搬迁前直传包的 nowFn 语义一致)。
func NewInviteMailbox ¶ added in v0.27.0
func NewInviteMailbox(clock func() time.Time) *InviteMailbox
NewInviteMailbox 构造收件箱(clock 可注入;nil=真实时钟)。
func (*InviteMailbox) AddInvite ¶ added in v0.27.0
func (m *InviteMailbox) AddInvite(code, fromName, note string) (Invite, error)
AddInvite 邀请入箱(口令格式校验 + 同码去重 + 满箱拒绝)。
func (*InviteMailbox) ExpiresIn ¶ added in v0.27.0
func (m *InviteMailbox) ExpiresIn(inv Invite) int64
ExpiresIn 某条信封的剩余有效期(秒;已过期返回 0)。
供**已出箱**信封的展示方使用(认领端点返回信封时算剩余时间)—— 收件箱只对在箱条目给快照,出箱后条目已不在列表里,无处可查。 时钟同收件箱(构造期注入的时钟优先,测试用假时钟一致)。
func (*InviteMailbox) ListInvites ¶ added in v0.27.0
func (m *InviteMailbox) ListInvites() []InviteSnapshot
ListInvites 未过期邀请(新到在前)。
func (*InviteMailbox) TakeInvite ¶ added in v0.27.0
func (m *InviteMailbox) TakeInvite(id string) (Invite, error)
TakeInvite 认领(出箱);不存在/已过期报错。
type InviteSnapshot ¶ added in v0.27.0
type InviteSnapshot struct {
ID string `json:"id"`
Code string `json:"code"`
FromName string `json:"from_name"`
Note string `json:"note"`
ReceivedAt time.Time `json:"received_at"`
ExpiresIn int64 `json:"expires_in"` // 秒
}
InviteSnapshot 对外快照(含过期倒计时,前端渲染用)。
type PeerDirectory ¶ added in v0.27.0
type PeerDirectory struct {
// contains filtered or unexported fields
}
PeerDirectory 联邦节点名录客户端。
func NewPeerDirectory ¶ added in v0.27.0
func NewPeerDirectory(provider RegistryURLProvider) *PeerDirectory
NewPeerDirectory 构造名录客户端(provider 由宿主注入;须非 nil)。
func (*PeerDirectory) Peers ¶ added in v0.27.0
func (d *PeerDirectory) Peers(ctx context.Context) ([]DirectoryPeer, error)
Peers 拉取在线名录(admin 目录对端选择器消费)。 直传未启用/二进制缺失不挡名录查询——名录可见性只取决于 registry 可达。
type RegistryURLProvider ¶ added in v0.27.0
RegistryURLProvider 注册中心基址提供者;ok=false 表示该来源不提供值 (段不存在 / 值为空)。
由宿主注入(配置读取面在本包之外——app 域不得互 import,配置读取在 bootstrap 装配层),本包只认"基址字符串"。
type ResolveInfo ¶
type ResolveInfo struct {
NodeID string `json:"node_id"`
URL string `json:"url"`
Name string `json:"name"`
ExpiresAt time.Time `json:"expires_at"`
SizeHint int64 `json:"size_hint"`
}
ResolveInfo 解析结果:口令在联邦内的源节点。
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service federation 客户端服务。实现 share.FederationNotifier 窄接口 (ShareCreated/ShareDeleted),由 bootstrap 注入 share service。
func NewService ¶
func NewService(cfg conf.FederationConfig, nodeName string) (*Service, error)
NewService 构造并加载/生成节点身份密钥。仅在 federation.enabled 时调用; 配置不合法返回错误,由 bootstrap 降级为非联邦模式(不影响单站功能)。
func (*Service) Healthy ¶
Healthy 最近一次 registry 心跳是否成功(未启动/尚未跑首个周期时为 false)。 供管理面(MCP federation_status 等)展示联邦健康度。
func (*Service) RegistryURLs ¶
RegistryURLs 主备 registry 基址列表(配置逗号分隔项的副本)。
func (*Service) Resolve ¶
func (s *Service) Resolve(code string) (*ResolveInfo, error)
Resolve 转查 registry(读路径依次主→备,首个命中即返回)。 全部未接入返回 (nil, nil)——调用方(resolve 代理 handler)以 available:false 回给前端,不区分"未启用/不存在"(降探测面)。
func (*Service) ShareCreated ¶
ShareCreated share 生命周期钩子:新分享公告到联邦(异步,registry 抖动 不拖慢建分享;失败由心跳循环补发)。熵门槛不过则静默跳过——短数字码 不出站,防 registry 侧在线枚举(安全模型见 p2p README)。
func (*Service) ShareDeleted ¶
ShareDeleted share 生命周期钩子:撤销公告(best-effort,索引立即移除; 撤销失败时 registry 条目按公告 TTL 自动过期)。