Documentation
¶
Overview ¶
Package peer implements the local P2P node (plan C15, goal.md §15): announcing cached sample artifacts to the central tracker, serving them to other peers over HTTP, and fetching artifacts with the fallback order local CAS → tracker peers → server → MISS. Announce payloads carry ONLY the rotating-free persistent peer id, the listen port, capability tags, and content-addressed sample ids — never paths, project names, or any other machine-identifying detail (§2.2).
Index ¶
- Variables
- type AnnounceResult
- type Node
- func (n *Node) Announce(ctx context.Context) error
- func (n *Node) Fetch(ctx context.Context, sampleID string) ([]byte, string, error)
- func (n *Node) Handler() http.Handler
- func (n *Node) LastAnnounce() AnnounceResult
- func (n *Node) ListenAndServe(ctx context.Context) error
- func (n *Node) SeedHot(ctx context.Context, hotIDs []string, budgetMB int) (int, error)
- func (n *Node) StartAnnouncing(ctx context.Context)
Constants ¶
This section is empty.
Variables ¶
var ErrMiss = errors.New("peer: sample artifact not found in any source")
ErrMiss is returned by Fetch when the artifact exists in no reachable source: local CAS, announced peers, and the server all came up empty.
Functions ¶
This section is empty.
Types ¶
type AnnounceResult ¶
type AnnounceResult struct {
Done bool
Addr string `json:"addr"`
Registered bool `json:"registered"`
Reason string `json:"reason"`
}
AnnounceResult is what the tracker made of the last announce. Registered false means the tracker could not dial this peer back, so it will not be handed to other peers — normal behind NAT, and harmless: evidence, uploads, and fetching all still work, this peer just cannot serve.
type Node ¶
type Node struct {
CAS *cas.Store
DB *localdb.DB
Ident *identity.Identity
HTTP *http.Client
ServerURL string
Port int
// BindAddr is the interface ListenAndServe binds to. Empty means every
// interface, which is what a real peer needs: the tracker dials it back
// and other peers fetch from it, so a loopback-only peer cannot serve.
//
// Tests set it to 127.0.0.1. A test binary that binds every interface
// makes Windows Defender Firewall prompt on every single run — the
// binary is recompiled to a fresh temp path each time, so the allow
// decision can never be remembered — and it briefly exposes the port to
// the local network for a test that only ever talks to loopback.
BindAddr string
// contains filtered or unexported fields
}
Node is one peer: a CAS full of verified sample artifacts, the local DB tracking which samples have artifacts, and the identity that names this peer on the tracker.
func (*Node) Announce ¶
Announce registers this peer with the tracker: peer id, listen port, blob capability, and the content-addressed ids of samples whose artifacts are locally cached. Sample ids are SHA-256 digests, so the payload can never carry paths or project names.
func (*Node) Fetch ¶
Fetch returns the artifact bytes for sampleID and where they came from: "local" (CAS hit), "peer" (another node), or "server" (Main Seeder fallback), in that fixed order (§15.1). Every remote payload is re-verified against the content id before it is trusted, cached, or returned; peers or servers sending wrong bytes are skipped. Peer and server errors never abort the chain — the next source is tried — so a fully offline node still serves local hits (§3.9).
func (*Node) Handler ¶
Handler returns the peer HTTP surface (plan P9.1):
GET /peer/v1/ping → 200 "csx-peer" (liveness / protocol probe)
GET /peer/v1/samples/{id} → artifact bytes from the CAS, 404 if absent
It serves ONLY content-addressed artifacts already public on the network; it never exposes local paths, the DB, or anything else.
func (*Node) LastAnnounce ¶
func (n *Node) LastAnnounce() AnnounceResult
LastAnnounce reports the tracker's verdict on the most recent announce. Done is false until the first announce completes.
func (*Node) ListenAndServe ¶
ListenAndServe serves the peer handler on n.Port until ctx is canceled, then shuts down gracefully. A canceled ctx returns nil; listener errors (port in use, …) are returned as-is.
func (*Node) SeedHot ¶
SeedHot warms the cache with network-HOT samples (§15.3): each id not yet cached is fetched while total CAS usage stays under budgetMB. It stops at the budget and NEVER evicts — eviction belongs to the cache policy, not the seeder. Individual fetch misses/errors skip to the next id. Returns how many samples were newly seeded.
func (*Node) StartAnnouncing ¶
StartAnnouncing launches the background announce loop: one immediate announce, then one every 10 minutes until ctx is canceled. Announce failures (server down, §3.9) are tolerated silently — the next tick retries; local serving and fetching are unaffected.