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 联邦面(跨实例口令路由 + 邀请交接)。
三个角色与构造条件(2026-10-22 命名统一) ¶
本包导出三个服务,**构造条件不同**,这是设计使然、不是遗漏:
Node 本机节点运行时:节点身份(ed25519)、注册中心心跳、分享公告。
仅在 federation.enabled 时构造;配置不合法时 bootstrap 降级
为非联邦模式(单站功能不受影响)。
PeerDirectory 在线名录:列出联邦内可发现的对端。**无条件构造**——联邦关闭时
名录仍要能读出「为什么不可用」,且注册中心地址来自配置而非运行态。
InviteMailbox 邀请信箱:待收邀请的出箱/留痕。**无条件构造**——收件箱在联邦
关闭时也必须可用(邀请可以先到、联邦后开)。
与设备直传的关系 ¶
2026-10-22 Wave B' 起,Box 侧**不再编排设备直传**(原 p2px 域已整包删除), 直传本体归独立应用 PigeonBeam。本包只保留联邦面(口令路由 + 邀请信封交接)。
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 Node
- func (s *Node) Enabled() bool
- func (s *Node) Healthy() bool
- func (s *Node) NodeID() string
- func (s *Node) RegistryURLs() []string
- func (s *Node) Resolve(code string) (*ResolveInfo, error)
- func (s *Node) ShareCreated(code string, expiresAt *time.Time)
- func (s *Node) ShareDeleted(code string)
- func (s *Node) Start()
- func (s *Node) Stop()
- type PeerDirectory
- type RegistryURLProvider
- type ResolveInfo
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 Node ¶ added in v0.27.1
type Node struct {
// contains filtered or unexported fields
}
Node 本机联邦节点运行时:节点身份(ed25519)+ 注册中心心跳 + 分享公告。 实现 share.FederationNotifier 窄接口(ShareCreated/ShareDeleted), 由 bootstrap 注入 share service。
命名(2026-10-22):原名 Service 太含糊——同包另有两个无条件构造的 角色(PeerDirectory 在线名录 / InviteMailbox 邀请信箱),「哪个是 federation 的主体」看不出来。改 Node 后三个角色一目了然:
Node 本机节点运行时(**联邦启用时才构造**) PeerDirectory 在线名录(无条件构造——联邦关闭时名录仍要能读配置) InviteMailbox 邀请信箱(无条件构造——收件箱在联邦关闭时也必须可用)
func NewNode ¶ added in v0.27.1
func NewNode(cfg conf.FederationConfig, nodeName string) (*Node, error)
NewNode 构造并加载/生成节点身份密钥。仅在 federation.enabled 时调用; 配置不合法返回错误,由 bootstrap 降级为非联邦模式(不影响单站功能)。
func (*Node) Healthy ¶ added in v0.27.1
Healthy 最近一次 registry 心跳是否成功(未启动/尚未跑首个周期时为 false)。 供管理面(MCP federation_status 等)展示联邦健康度。
func (*Node) RegistryURLs ¶ added in v0.27.1
RegistryURLs 主备 registry 基址列表(配置逗号分隔项的副本)。
func (*Node) Resolve ¶ added in v0.27.1
func (s *Node) Resolve(code string) (*ResolveInfo, error)
Resolve 转查 registry(读路径依次主→备,首个命中即返回)。 全部未接入返回 (nil, nil)——调用方(resolve 代理 handler)以 available:false 回给前端,不区分"未启用/不存在"(降探测面)。
func (*Node) ShareCreated ¶ added in v0.27.1
ShareCreated share 生命周期钩子:新分享公告到联邦(异步,registry 抖动 不拖慢建分享;失败由心跳循环补发)。熵门槛不过则静默跳过——短数字码 不出站,防 registry 侧在线枚举(安全模型见 p2p README)。
func (*Node) ShareDeleted ¶ added in v0.27.1
ShareDeleted share 生命周期钩子:撤销公告(best-effort,索引立即移除; 撤销失败时 registry 条目按公告 TTL 自动过期)。
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 装配层),本包只认"基址字符串"。