Files
PierrunoYTandClaude Opus 5.5 13e2596b2e chore: move repository references to Twigpine/zero (#1105)
Update the Go module path, imports, install scripts, docs, workflows,
packaging and action defaults from Gitlawb/zero to Twigpine/zero. The npm
scope (already @twigpine/zero on main, with its @gitlawb/zero migration
notes), LICENSE, action author, the OpenGateway provider and historical
CHANGELOG links are unchanged.

The X-AIMLAPI-Integration-Repo header keeps Gitlawb/zero: it is what
AIMLAPI sees for attribution, so changing it needs a maintainer's yes.
docs/INSTALL.md keeps `go install github.com/Gitlawb/zero/...`, because
every tagged release so far declares that module path. The Homebrew
formula comment names the Twigpine/homebrew-tap tap.

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-17 07:13:21 +08:00

1235 lines
35 KiB
Go

package peermsg
import (
"bufio"
"context"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"time"
"unicode"
"github.com/Twigpine/zero/internal/fsutil"
)
type Handler func(InboundMessage) bool
type StatusHandler func(StatusEvent)
type HeldEvictionHandler func(string)
type HeldReleaseHandler func(InboundMessage)
const (
peerBucketCapacity = 30.0
peerRefillPerSecond = 0.5
peerDedupWindow = 30 * time.Second
peerMaxSelfHops = 10
peerMaxChainLength = 28
peerMaxTrackedSenders = 256
peerMaxHeldMessages = 100
peerMaxOutstanding = 256
peerOutstandingTTL = 6 * time.Minute
peerProbeWorkers = 8
peerProbeTimeout = 300 * time.Millisecond
peerInboundWorkers = 32
peerReceiptWorkers = peerMaxHeldMessages
peerReceiptTimeout = 750 * time.Millisecond
peerRegistryCacheTTL = 250 * time.Millisecond
peerFrameTimeout = 5 * time.Second
peerRefHexLength = 12
peerErrorMaxRunes = 512
)
type inboundContextKey struct{}
type senderGuard struct {
tokens float64
lastRefill time.Time
lastBody string
lastBodyAt time.Time
lastActivity time.Time
}
type outstandingMessage struct {
peer Peer
createdAt time.Time
}
type Options struct {
RootDir string
Identity Identity
Now func() time.Time
Transport localTransport
PID int
InboundPolicy InboundPolicy
}
// Service owns one live peer endpoint plus the registry used to discover other
// local Zero sessions. The transport is platform-specific, while framing,
// identity resolution, limits, and delivery policy remain shared.
type Service struct {
mu sync.RWMutex
root string
identity Identity
now func() time.Time
transport localTransport
pid int
nonce string
self Peer
listener net.Listener
handler Handler
statusHandler StatusHandler
evictionHandler HeldEvictionHandler
releaseHandler HeldReleaseHandler
policy InboundPolicy
outstanding map[string]outstandingMessage
held map[string]InboundMessage
heldOrder []string
guards map[string]*senderGuard
closed bool
wg sync.WaitGroup
done chan struct{}
inboundSlots chan struct{}
registryMu sync.Mutex
registryCache []Peer
registryModTime time.Time
registryCached time.Time
registryValid bool
}
func New(options Options) (*Service, error) {
root := strings.TrimSpace(options.RootDir)
if root == "" {
var err error
root, err = DefaultRoot()
if err != nil {
return nil, err
}
}
abs, err := filepath.Abs(root)
if err != nil {
return nil, fmt.Errorf("peer messaging: resolve runtime directory: %w", err)
}
abs, err = canonicalRuntimePath(abs)
if err != nil {
return nil, fmt.Errorf("peer messaging: canonicalize runtime directory: %w", err)
}
nonce, err := randomHex(8)
if err != nil {
return nil, fmt.Errorf("peer messaging: generate endpoint id: %w", err)
}
now := options.Now
if now == nil {
now = time.Now
}
transport := options.Transport
if transport == nil {
transport = platformTransport()
}
pid := options.PID
if pid <= 0 {
pid = os.Getpid()
}
return &Service{
root: abs,
identity: normalizeIdentity(options.Identity),
now: now,
transport: transport,
pid: pid,
nonce: nonce,
policy: normalizeInboundPolicy(options.InboundPolicy),
outstanding: make(map[string]outstandingMessage),
held: make(map[string]InboundMessage),
guards: make(map[string]*senderGuard),
done: make(chan struct{}),
inboundSlots: make(chan struct{}, peerInboundWorkers),
}, nil
}
// canonicalRuntimePath normalizes aliases in the existing prefix. It does not
// establish a security boundary; ensurePrivateDir validates that boundary when
// the service starts.
func canonicalRuntimePath(path string) (string, error) {
missing := make([]string, 0, 4)
existing := filepath.Clean(path)
for {
_, err := os.Lstat(existing)
if err == nil {
break
}
if !errors.Is(err, os.ErrNotExist) {
return "", err
}
parent := filepath.Dir(existing)
if parent == existing {
return "", err
}
missing = append(missing, filepath.Base(existing))
existing = parent
}
resolved, err := filepath.EvalSymlinks(existing)
if err != nil {
return "", err
}
for index := len(missing) - 1; index >= 0; index-- {
resolved = filepath.Join(resolved, missing[index])
}
return resolved, nil
}
// WithInboundMessage carries a peer message's relay chain through the agent
// turn so a deliberate send_message reply or forward can extend it. Ordinary
// user turns have no chain and start a fresh one.
func WithInboundMessage(ctx context.Context, message InboundMessage) context.Context {
if ctx == nil {
ctx = context.Background()
}
chain := append([]string(nil), message.HopChain...)
return context.WithValue(ctx, inboundContextKey{}, chain)
}
func DefaultRoot() (string, error) {
if runtimeDir := strings.TrimSpace(os.Getenv("XDG_RUNTIME_DIR")); runtimeDir != "" {
return filepath.Join(runtimeDir, "zero", "peers"), nil
}
cacheDir, err := os.UserCacheDir()
if err != nil {
return "", fmt.Errorf("peer messaging: resolve user cache directory: %w", err)
}
return filepath.Join(cacheDir, "zero", "peers"), nil
}
func (service *Service) Start(handler Handler) error {
service.mu.Lock()
defer service.mu.Unlock()
if service.listener != nil {
return nil
}
if service.closed {
return errors.New("peer messaging: service is closed")
}
if err := ensurePrivateDir(service.root); err != nil {
return fmt.Errorf("peer messaging: create runtime directory: %w", err)
}
if err := ensurePrivateDir(service.registryDir()); err != nil {
return fmt.Errorf("peer messaging: create registry: %w", err)
}
endpoint, err := service.transport.Endpoint(service.root, service.nonce, service.pid)
if err != nil {
return err
}
listener, err := service.transport.Listen(endpoint)
if err != nil {
return fmt.Errorf("peer messaging: listen: %w", err)
}
now := service.now().UTC()
if service.identity.SessionID == "" {
service.identity.SessionID = "live-" + service.nonce
}
service.self = Peer{
Identity: service.identity,
Endpoint: endpoint,
PID: service.pid,
StartedAt: now,
UpdatedAt: now,
Ref: peerRef(endpoint),
}
service.listener = listener
service.handler = handler
if err := service.writeRecordLocked(); err != nil {
service.listener = nil
return errors.Join(err, listener.Close(), service.transport.Remove(endpoint))
}
service.wg.Add(1)
go service.acceptLoop(listener)
return nil
}
func (service *Service) SetStatusHandler(handler StatusHandler) {
service.mu.Lock()
defer service.mu.Unlock()
service.statusHandler = handler
}
func (service *Service) SetHeldEvictionHandler(handler HeldEvictionHandler) {
service.mu.Lock()
defer service.mu.Unlock()
service.evictionHandler = handler
}
func (service *Service) SetHeldReleaseHandler(handler HeldReleaseHandler) {
service.mu.Lock()
defer service.mu.Unlock()
service.releaseHandler = handler
}
func (service *Service) Close() error {
service.mu.Lock()
if service.closed {
service.mu.Unlock()
return nil
}
service.closed = true
close(service.done)
listener := service.listener
endpoint := service.self.Endpoint
held := make([]InboundMessage, 0, len(service.held))
for _, message := range service.held {
held = append(held, message)
}
service.held = make(map[string]InboundMessage)
service.heldOrder = nil
service.outstanding = make(map[string]outstandingMessage)
service.listener = nil
service.mu.Unlock()
service.sendStatuses(held, DeliveryExpired)
var closeErrs []error
if listener != nil {
if err := listener.Close(); err != nil && !errors.Is(err, net.ErrClosed) {
closeErrs = append(closeErrs, err)
}
}
service.wg.Wait()
if endpoint != "" {
if err := service.transport.Remove(endpoint); err != nil && !errors.Is(err, os.ErrNotExist) {
closeErrs = append(closeErrs, err)
}
}
if err := service.removeOwnRecord(endpoint); err != nil {
closeErrs = append(closeErrs, err)
}
return errors.Join(closeErrs...)
}
// ResolveHeld settles a message that was parked for local approval and sends a
// terminal receipt back to its sender. Repeated or stale decisions are ignored.
func (service *Service) ResolveHeld(ctx context.Context, messageID string, status DeliveryStatus) error {
if status != DeliveryDelivered && status != DeliveryDenied && status != DeliveryExpired {
return fmt.Errorf("peer messaging: invalid held-message status %q", status)
}
service.mu.Lock()
message, ok := service.held[messageID]
if ok {
delete(service.held, messageID)
service.removeHeldOrderLocked(messageID)
}
service.mu.Unlock()
if !ok {
return nil
}
return service.sendStatus(ctx, message, status)
}
func (service *Service) UpdateIdentity(identity Identity) error {
service.mu.Lock()
service.identity = normalizeIdentity(identity)
if service.listener == nil {
service.mu.Unlock()
return nil
}
service.self.Identity = service.identity
service.self.UpdatedAt = service.now().UTC()
if err := service.writeRecordLocked(); err != nil {
service.mu.Unlock()
return err
}
released := make([]InboundMessage, 0)
if service.policy == InboundPolicyParity && service.releaseHandler != nil {
for _, messageID := range append([]string(nil), service.heldOrder...) {
message, ok := service.held[messageID]
if !ok {
service.removeHeldOrderLocked(messageID)
continue
}
status, _ := service.inboundDecision(message.From.PermissionClass, service.self.PermissionClass)
if status != DeliveryAccepted {
continue
}
delete(service.held, messageID)
service.removeHeldOrderLocked(messageID)
message.RequiresApproval = false
message.HoldCause = ""
released = append(released, message)
}
}
releaseHandler := service.releaseHandler
service.mu.Unlock()
for _, message := range released {
if releaseHandler != nil {
releaseHandler(message)
}
}
if len(released) > 0 {
service.launchStatuses(released, DeliveryDelivered)
}
return nil
}
func (service *Service) Self() Peer {
service.mu.RLock()
defer service.mu.RUnlock()
return service.self
}
func (service *Service) List(ctx context.Context) ([]Peer, error) {
candidates, err := service.registryPeers()
if err != nil {
return nil, err
}
self := service.Self()
type probeResult struct {
peer Peer
reachable bool
}
jobs := make(chan Peer)
results := make(chan probeResult, len(candidates))
workers := min(peerProbeWorkers, len(candidates))
var wg sync.WaitGroup
for range workers {
wg.Add(1)
go func() {
defer wg.Done()
for peer := range jobs {
if peer.Endpoint == self.Endpoint || peer.SessionID == "" {
continue
}
probeCtx, cancel := context.WithTimeout(ctx, peerProbeTimeout)
conn, dialErr := service.transport.Dial(probeCtx, peer.Endpoint)
cancel()
if dialErr == nil {
_ = conn.Close()
}
results <- probeResult{peer: peer, reachable: dialErr == nil}
}
}()
}
go func() {
defer close(jobs)
for _, peer := range candidates {
select {
case jobs <- peer:
case <-ctx.Done():
return
}
}
}()
go func() { wg.Wait(); close(results) }()
peers := make([]Peer, 0, len(candidates))
for result := range results {
if result.reachable {
peers = append(peers, result.peer)
}
}
if err := ctx.Err(); err != nil {
return nil, fmt.Errorf("peer messaging: list sessions: %w", err)
}
sort.Slice(peers, func(i, j int) bool {
if strings.EqualFold(peers[i].Name, peers[j].Name) {
return peers[i].Ref < peers[j].Ref
}
return strings.ToLower(peers[i].Name) < strings.ToLower(peers[j].Name)
})
return peers, nil
}
func (service *Service) registryPeers() ([]Peer, error) {
service.registryMu.Lock()
defer service.registryMu.Unlock()
info, statErr := os.Stat(service.registryDir())
if errors.Is(statErr, os.ErrNotExist) {
service.registryCache = nil
service.registryModTime = time.Time{}
service.registryCached = service.now()
service.registryValid = true
return nil, nil
}
if statErr != nil {
return nil, fmt.Errorf("peer messaging: inspect registry: %w", statErr)
}
now := service.now()
if service.registryValid && info.ModTime().Equal(service.registryModTime) && now.Sub(service.registryCached) < peerRegistryCacheTTL {
return append([]Peer(nil), service.registryCache...), nil
}
entries, err := os.ReadDir(service.registryDir())
if errors.Is(err, os.ErrNotExist) {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("peer messaging: read registry: %w", err)
}
peers := make([]Peer, 0, len(entries))
for _, entry := range entries {
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".json") {
continue
}
peer, readErr := readPeerRecord(filepath.Join(service.registryDir(), entry.Name()))
if readErr == nil && peer.Endpoint != "" && peer.SessionID != "" {
peers = append(peers, peer)
}
}
service.registryCache = append(service.registryCache[:0], peers...)
service.registryModTime = info.ModTime()
service.registryCached = now
service.registryValid = true
return append([]Peer(nil), peers...), nil
}
// registeredPeer replaces all sender-controlled identity metadata with the
// record published by the live service that owns the claimed endpoint.
func (service *Service) registeredPeer(claimed Peer) (Peer, error) {
peers, err := service.registryPeers()
if err != nil {
return Peer{}, err
}
for _, peer := range peers {
if peer.Endpoint == claimed.Endpoint && peer.SessionID == claimed.SessionID && peer.Ref == claimed.Ref {
return peer, nil
}
}
return Peer{}, errors.New("peer messaging: unregistered sender")
}
func (service *Service) Send(ctx context.Context, to, summary, body string) (SendResult, error) {
body = normalizeBody(body)
summary = normalizeSummary(summary)
if body == "" {
return SendResult{}, errors.New("peer messaging: message must not be empty")
}
if len(body) > maxMessageBytes {
return SendResult{}, fmt.Errorf("peer messaging: message exceeds %d bytes", maxMessageBytes)
}
if summary == "" {
return SendResult{}, errors.New("peer messaging: summary is required")
}
peers, err := service.List(ctx)
if err != nil {
return SendResult{}, err
}
peer, err := resolvePeer(peers, to)
if err != nil {
return SendResult{}, err
}
id, err := randomHex(16)
if err != nil {
return SendResult{}, fmt.Errorf("peer messaging: generate message id: %w", err)
}
self := service.Self()
hopChain := inboundHopChain(ctx)
if len(hopChain) == 0 || hopChain[len(hopChain)-1] != self.Ref {
hopChain = append(hopChain, self.Ref)
}
if err := validateHopChain(hopChain); err != nil {
return SendResult{}, err
}
frame := sendFrame{
Version: ProtocolVersion,
Type: "message",
ID: id,
From: self,
To: peer.SessionID,
Summary: summary,
Body: body,
HopChain: hopChain,
}
service.mu.Lock()
service.pruneOutstandingLocked(service.now())
service.outstanding[id] = outstandingMessage{peer: peer, createdAt: service.now()}
service.mu.Unlock()
keepOutstanding := false
defer func() {
if keepOutstanding {
return
}
service.mu.Lock()
delete(service.outstanding, id)
service.mu.Unlock()
}()
conn, err := service.transport.Dial(ctx, peer.Endpoint)
if err != nil {
return SendResult{}, fmt.Errorf("peer messaging: connect to %s: %w", displayPeer(peer), err)
}
defer conn.Close()
_ = conn.SetDeadline(deadlineFromContext(ctx, peerFrameTimeout))
if err := json.NewEncoder(conn).Encode(frame); err != nil {
return SendResult{}, fmt.Errorf("peer messaging: send to %s: %w", displayPeer(peer), err)
}
var response responseFrame
if err := decodeFrame(conn, &response); err != nil {
return SendResult{}, fmt.Errorf("peer messaging: receive delivery status from %s: %w", displayPeer(peer), err)
}
if response.Version != ProtocolVersion || response.Type != "delivery" || response.ID != id {
return SendResult{}, errors.New("peer messaging: invalid delivery response")
}
if response.Error != "" {
return SendResult{}, fmt.Errorf("peer messaging: receiver rejected message: %s", normalizeRemoteError(response.Error))
}
if response.Status != DeliveryAccepted && response.Status != DeliveryHeld && response.Status != DeliveryRefused {
return SendResult{}, errors.New("peer messaging: invalid delivery status")
}
keepOutstanding = response.Status == DeliveryHeld
return SendResult{MessageID: id, Peer: peer, Status: response.Status}, nil
}
func (service *Service) acceptLoop(listener net.Listener) {
defer service.wg.Done()
var retryDelay time.Duration
for {
conn, err := listener.Accept()
if err != nil {
if errors.Is(err, net.ErrClosed) {
return
}
service.mu.RLock()
closed := service.closed
service.mu.RUnlock()
if closed {
return
}
if retryDelay == 0 {
retryDelay = 5 * time.Millisecond
} else {
retryDelay *= 2
}
retryDelay = min(retryDelay, time.Second)
timer := time.NewTimer(retryDelay)
select {
case <-timer.C:
case <-service.done:
if !timer.Stop() {
<-timer.C
}
return
}
continue
}
retryDelay = 0
select {
case service.inboundSlots <- struct{}{}:
default:
_ = conn.Close()
continue
}
service.wg.Add(1)
go func() {
defer service.wg.Done()
defer func() { <-service.inboundSlots }()
defer conn.Close()
service.handleConn(conn)
}()
}
}
func (service *Service) handleConn(conn net.Conn) {
_ = conn.SetDeadline(time.Now().Add(peerFrameTimeout))
var frame sendFrame
if err := decodeFrame(conn, &frame); err != nil {
if !errors.Is(err, io.EOF) {
_ = json.NewEncoder(conn).Encode(responseFrame{Version: ProtocolVersion, Type: "delivery", Status: DeliveryRefused, Error: "invalid peer message"})
}
return
}
if frame.Type == "status" {
service.handleStatusFrame(frame)
return
}
response := responseFrame{Version: ProtocolVersion, Type: "delivery", ID: frame.ID, Status: DeliveryRefused}
if frame.Version != ProtocolVersion || frame.Type != "message" || frame.ID == "" ||
frame.From.SessionID == "" || frame.From.Endpoint == "" || !validPeerRef(frame.From.Endpoint, frame.From.Ref) {
response.Error = "peer messaging: invalid message envelope"
_ = json.NewEncoder(conn).Encode(response)
return
}
trustedSender, err := service.registeredPeer(frame.From)
if err != nil {
response.Error = "peer messaging: sender identity is not registered"
_ = json.NewEncoder(conn).Encode(response)
return
}
frame.From = trustedSender
if len(frame.Body) == 0 || len(frame.Body) > maxMessageBytes {
response.Error = "peer messaging: invalid message size"
_ = json.NewEncoder(conn).Encode(response)
return
}
body := normalizeBody(frame.Body)
if body == "" {
response.Error = "peer messaging: invalid message content"
_ = json.NewEncoder(conn).Encode(response)
return
}
service.mu.RLock()
self := service.self
handler := service.handler
service.mu.RUnlock()
if self.SessionID == "" || frame.To != self.SessionID {
response.Error = "peer messaging: target session is no longer active"
_ = json.NewEncoder(conn).Encode(response)
return
}
if len(frame.HopChain) == 0 {
frame.HopChain = []string{frame.From.Ref}
}
if err := validateHopChain(frame.HopChain); err != nil || frame.HopChain[len(frame.HopChain)-1] != frame.From.Ref {
response.Error = "peer messaging: invalid relay chain"
_ = json.NewEncoder(conn).Encode(response)
return
}
if reason := service.admitMessage(frame.From, body, frame.HopChain, self.Ref); reason != "" {
response.Error = "peer messaging: message dropped: " + reason
_ = json.NewEncoder(conn).Encode(response)
return
}
if handler == nil {
response.Status = DeliveryRefused
response.Error = "peer messaging: receiving session is unavailable"
_ = json.NewEncoder(conn).Encode(response)
return
}
status, holdCause := service.inboundDecision(frame.From.PermissionClass, self.PermissionClass)
response.Status = status
if status == DeliveryRefused {
_ = json.NewEncoder(conn).Encode(response)
return
}
message := InboundMessage{
ID: frame.ID,
From: frame.From,
Body: body,
Summary: normalizeSummary(frame.Summary),
ReceivedAt: service.now().UTC(),
RequiresApproval: status == DeliveryHeld,
HoldCause: holdCause,
HopChain: append([]string(nil), frame.HopChain...),
}
if status == DeliveryHeld {
var evicted InboundMessage
var evictionHandler HeldEvictionHandler
service.mu.Lock()
if len(service.held) >= peerMaxHeldMessages {
evicted = service.popOldestHeldLocked()
evictionHandler = service.evictionHandler
}
service.held[message.ID] = message
service.heldOrder = append(service.heldOrder, message.ID)
service.mu.Unlock()
if evicted.ID != "" {
if evictionHandler != nil {
evictionHandler(evicted.ID)
}
service.launchStatuses([]InboundMessage{evicted}, DeliveryExpired)
}
}
_ = conn.SetDeadline(time.Now().Add(peerFrameTimeout))
if !handler(message) {
if status == DeliveryHeld {
service.mu.Lock()
delete(service.held, message.ID)
service.removeHeldOrderLocked(message.ID)
service.mu.Unlock()
}
response.Status = DeliveryRefused
response.Error = "peer messaging: message dropped: receiver queue is full or unavailable"
_ = json.NewEncoder(conn).Encode(response)
return
}
_ = json.NewEncoder(conn).Encode(response)
}
func (service *Service) handleStatusFrame(frame sendFrame) {
if frame.Version != ProtocolVersion || frame.OrigID == "" || frame.From.SessionID == "" ||
frame.From.Endpoint == "" || !validPeerRef(frame.From.Endpoint, frame.From.Ref) || !terminalDeliveryStatus(frame.Status) {
return
}
trustedSender, err := service.registeredPeer(frame.From)
if err != nil {
return
}
frame.From = trustedSender
service.mu.Lock()
self := service.self
outstanding, ok := service.outstanding[frame.OrigID]
if !ok || frame.To != self.SessionID || outstanding.peer.Endpoint != frame.From.Endpoint || outstanding.peer.SessionID != frame.From.SessionID {
service.mu.Unlock()
return
}
delete(service.outstanding, frame.OrigID)
handler := service.statusHandler
service.mu.Unlock()
if handler != nil {
handler(StatusEvent{MessageID: frame.OrigID, Peer: outstanding.peer, Status: frame.Status})
}
}
func (service *Service) sendStatus(ctx context.Context, message InboundMessage, status DeliveryStatus) error {
if !terminalDeliveryStatus(status) {
return fmt.Errorf("peer messaging: invalid delivery status %q", status)
}
target := message.From
if target.Endpoint == "" || target.SessionID == "" || !validPeerRef(target.Endpoint, target.Ref) {
return errors.New("peer messaging: original sender identity is invalid")
}
self := service.Self()
frame := sendFrame{
Version: ProtocolVersion,
Type: "status",
From: self,
To: target.SessionID,
OrigID: message.ID,
Status: status,
}
conn, err := service.transport.Dial(ctx, target.Endpoint)
if err != nil {
return fmt.Errorf("peer messaging: send status to %s: %w", displayPeer(target), err)
}
defer conn.Close()
_ = conn.SetDeadline(deadlineFromContext(ctx, peerFrameTimeout))
if err := json.NewEncoder(conn).Encode(frame); err != nil {
return fmt.Errorf("peer messaging: send status to %s: %w", displayPeer(target), err)
}
return nil
}
func (service *Service) sendStatuses(messages []InboundMessage, status DeliveryStatus) {
jobs := make(chan InboundMessage)
workers := min(peerReceiptWorkers, len(messages))
var wg sync.WaitGroup
for range workers {
wg.Add(1)
go func() {
defer wg.Done()
for message := range jobs {
ctx, cancel := context.WithTimeout(context.Background(), peerReceiptTimeout)
_ = service.sendStatus(ctx, message, status)
cancel()
}
}()
}
for _, message := range messages {
jobs <- message
}
close(jobs)
wg.Wait()
}
func deadlineFromContext(ctx context.Context, maximum time.Duration) time.Time {
deadline := time.Now().Add(maximum)
if contextDeadline, ok := ctx.Deadline(); ok && contextDeadline.Before(deadline) {
return contextDeadline
}
return deadline
}
func (service *Service) launchStatuses(messages []InboundMessage, status DeliveryStatus) {
service.mu.Lock()
if service.closed {
service.mu.Unlock()
return
}
service.wg.Add(1)
service.mu.Unlock()
go func() {
defer service.wg.Done()
service.sendStatuses(messages, status)
}()
}
func (service *Service) pruneOutstandingLocked(now time.Time) {
for id, pending := range service.outstanding {
if now.Sub(pending.createdAt) >= peerOutstandingTTL {
delete(service.outstanding, id)
}
}
for len(service.outstanding) >= peerMaxOutstanding {
var oldestID string
var oldest time.Time
for id, pending := range service.outstanding {
if oldestID == "" || pending.createdAt.Before(oldest) {
oldestID, oldest = id, pending.createdAt
}
}
delete(service.outstanding, oldestID)
}
}
func (service *Service) inboundDecision(sender, receiver PermissionClass) (DeliveryStatus, HoldCause) {
switch service.policy {
case InboundPolicyAccept:
return DeliveryAccepted, ""
case InboundPolicyHold:
return DeliveryHeld, HoldCauseExplicit
case InboundPolicyRefuse:
return DeliveryRefused, ""
default:
if sender == "" {
if receiver == PermissionBypass {
return DeliveryHeld, HoldCauseModeUnknown
}
return DeliveryAccepted, ""
}
if sender == receiver {
return DeliveryAccepted, ""
}
return DeliveryHeld, HoldCauseModeMismatch
}
}
func (service *Service) admitMessage(sender Peer, body string, chain []string, selfRef string) string {
if len(chain) > peerMaxChainLength {
return "relay chain is too long"
}
selfHops := 0
for _, ref := range chain {
if ref == selfRef {
selfHops++
}
}
if selfHops >= peerMaxSelfHops {
return "peer messaging loop detected"
}
now := service.now()
key := sender.Endpoint
service.mu.Lock()
defer service.mu.Unlock()
guard := service.guards[key]
if guard == nil {
if len(service.guards) >= peerMaxTrackedSenders {
var oldestKey string
var oldest time.Time
for candidate, state := range service.guards {
if oldestKey == "" || state.lastActivity.Before(oldest) {
oldestKey, oldest = candidate, state.lastActivity
}
}
delete(service.guards, oldestKey)
}
guard = &senderGuard{tokens: peerBucketCapacity, lastRefill: now}
service.guards[key] = guard
}
elapsed := now.Sub(guard.lastRefill).Seconds()
if elapsed > 0 {
guard.tokens = min(peerBucketCapacity, guard.tokens+elapsed*peerRefillPerSecond)
guard.lastRefill = now
}
if guard.tokens < 1 {
return "sender exceeded the peer message rate limit"
}
guard.tokens--
if guard.lastBody == body && now.Sub(guard.lastBodyAt) < peerDedupWindow {
return "duplicate of a recent message from this sender"
}
guard.lastActivity = now
guard.lastBody = body
guard.lastBodyAt = now
return ""
}
func (service *Service) removeHeldOrderLocked(messageID string) {
for index, candidate := range service.heldOrder {
if candidate == messageID {
service.heldOrder = append(service.heldOrder[:index], service.heldOrder[index+1:]...)
return
}
}
}
func (service *Service) popOldestHeldLocked() InboundMessage {
for len(service.heldOrder) > 0 {
messageID := service.heldOrder[0]
service.heldOrder = service.heldOrder[1:]
if message, ok := service.held[messageID]; ok {
delete(service.held, messageID)
return message
}
}
var oldestID string
var oldest InboundMessage
for messageID, message := range service.held {
if oldestID == "" || message.ReceivedAt.Before(oldest.ReceivedAt) {
oldestID, oldest = messageID, message
}
}
if oldestID != "" {
delete(service.held, oldestID)
}
return oldest
}
func inboundHopChain(ctx context.Context) []string {
if ctx == nil {
return nil
}
chain, _ := ctx.Value(inboundContextKey{}).([]string)
return append([]string(nil), chain...)
}
func validateHopChain(chain []string) error {
if len(chain) == 0 || len(chain) > peerMaxChainLength {
return errors.New("peer messaging: invalid relay chain")
}
for _, ref := range chain {
if len(ref) < 8 || len(ref) > peerRefHexLength || len(ref)%2 != 0 {
return errors.New("peer messaging: invalid relay chain")
}
if _, err := hex.DecodeString(ref); err != nil {
return errors.New("peer messaging: invalid relay chain")
}
}
return nil
}
func terminalDeliveryStatus(status DeliveryStatus) bool {
return status == DeliveryDelivered || status == DeliveryDenied || status == DeliveryExpired
}
func normalizeInboundPolicy(policy InboundPolicy) InboundPolicy {
switch policy {
case InboundPolicyAccept, InboundPolicyHold, InboundPolicyRefuse:
return policy
default:
return InboundPolicyParity
}
}
func decodeFrame(reader io.Reader, target any) error {
buffered := bufio.NewReader(io.LimitReader(reader, maxFrameBytes+1))
line, err := buffered.ReadBytes('\n')
if err != nil {
return err
}
if len(line) > maxFrameBytes {
return errors.New("peer messaging: frame is too large")
}
if err := json.Unmarshal(line, target); err != nil {
return fmt.Errorf("peer messaging: decode frame: %w", err)
}
return nil
}
func (service *Service) registryDir() string { return filepath.Join(service.root, "registry") }
func (service *Service) recordPath() string {
return filepath.Join(service.registryDir(), fmt.Sprintf("%d-%s.json", service.pid, service.nonce))
}
func (service *Service) writeRecordLocked() error {
data, err := json.Marshal(service.self)
if err != nil {
return fmt.Errorf("peer messaging: encode registry record: %w", err)
}
path := service.recordPath()
tmp, err := os.CreateTemp(service.registryDir(), filepath.Base(path)+".*.tmp")
if err != nil {
return fmt.Errorf("peer messaging: create registry temporary file: %w", err)
}
tmpPath := tmp.Name()
defer os.Remove(tmpPath)
if err := tmp.Chmod(0o600); err != nil {
_ = tmp.Close()
return err
}
if _, err := tmp.Write(append(data, '\n')); err != nil {
_ = tmp.Close()
return err
}
if err := tmp.Sync(); err != nil {
_ = tmp.Close()
return err
}
if err := tmp.Close(); err != nil {
return err
}
if err := fsutil.RenameWithRetry(tmpPath, path, nil); err != nil {
return fmt.Errorf("peer messaging: publish registry record: %w", err)
}
return nil
}
func readPeerRecord(path string) (Peer, error) {
data, err := os.ReadFile(path)
if err != nil {
return Peer{}, err
}
var peer Peer
if err := json.Unmarshal(data, &peer); err != nil {
return Peer{}, err
}
if peer.PID <= 0 || peer.Endpoint == "" || !validPeerRef(peer.Endpoint, peer.Ref) {
return Peer{}, errors.New("peer messaging: invalid registry record")
}
peer.Identity = normalizeIdentity(peer.Identity)
return peer, nil
}
func (service *Service) removeOwnRecord(endpoint string) error {
path := service.recordPath()
peer, err := readPeerRecord(path)
if errors.Is(err, os.ErrNotExist) {
return nil
}
if err != nil {
return fmt.Errorf("peer messaging: verify registry record before removal: %w", err)
}
if peer.Endpoint != endpoint {
return nil
}
if err := os.Remove(path); err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("peer messaging: remove registry record: %w", err)
}
return nil
}
func resolvePeer(peers []Peer, target string) (Peer, error) {
target = strings.TrimSpace(target)
if target == "" {
return Peer{}, errors.New("peer messaging: recipient must not be empty")
}
for _, peer := range peers {
if peer.SessionID == target {
return peer, nil
}
}
if name, ref, ok := splitPeerTarget(target); ok {
for _, peer := range peers {
peerName := strings.TrimSpace(peer.Name)
if peerName == "" {
peerName = "Zero session"
}
if strings.EqualFold(peer.Ref, ref) && strings.EqualFold(peerName, name) {
return peer, nil
}
}
return Peer{}, fmt.Errorf("peer messaging: no reachable session named %q", target)
}
matches := make([]Peer, 0, 2)
for _, peer := range peers {
if strings.EqualFold(peer.Name, target) {
matches = append(matches, peer)
}
}
if len(matches) == 1 {
return matches[0], nil
}
if len(matches) > 1 {
return Peer{}, fmt.Errorf("peer messaging: %q is ambiguous; use name [ref] from list_sessions", target)
}
return Peer{}, fmt.Errorf("peer messaging: no reachable session named %q", target)
}
func splitPeerTarget(target string) (name, ref string, ok bool) {
open := strings.LastIndex(target, " [")
if open <= 0 || !strings.HasSuffix(target, "]") {
return "", "", false
}
name = strings.TrimSpace(target[:open])
ref = target[open+2 : len(target)-1]
if name == "" || len(ref) < 8 || len(ref) > peerRefHexLength || len(ref)%2 != 0 {
return "", "", false
}
if _, err := hex.DecodeString(ref); err != nil {
return "", "", false
}
return name, ref, true
}
func displayPeer(peer Peer) string {
name := strings.TrimSpace(peer.Name)
if name == "" {
name = "Zero session"
}
return fmt.Sprintf("%s [%s]", name, peer.Ref)
}
func normalizeIdentity(identity Identity) Identity {
identity.SessionID = truncateRunes(strings.TrimSpace(sanitizePlainText(identity.SessionID, false)), 256)
identity.Name = truncateRunes(strings.TrimSpace(sanitizePlainText(identity.Name, false)), 80)
if strings.ContainsAny(identity.Name, "[]") {
identity.Name = ""
}
identity.Cwd = truncateRunes(strings.TrimSpace(sanitizePlainText(identity.Cwd, false)), 4096)
switch identity.PermissionClass {
case PermissionPrompting, PermissionBypass:
default:
identity.PermissionClass = ""
}
return identity
}
func truncateRunes(value string, limit int) string {
runes := []rune(value)
if len(runes) <= limit {
return value
}
return string(runes[:limit])
}
func normalizeSummary(summary string) string {
summary = strings.Split(summary, "\n")[0]
summary = strings.TrimSpace(sanitizePlainText(summary, false))
runes := []rune(summary)
if len(runes) > 200 {
summary = string(runes[:200])
}
return summary
}
func normalizeBody(body string) string {
return strings.TrimSpace(sanitizePlainText(body, true))
}
func normalizeRemoteError(message string) string {
message = truncateRunes(strings.TrimSpace(sanitizePlainText(message, false)), peerErrorMaxRunes)
if message == "" {
return "receiver rejected the message"
}
return message
}
func sanitizePlainText(value string, multiline bool) string {
return strings.Map(func(char rune) rune {
if multiline && (char == '\n' || char == '\t') {
return char
}
if unicode.IsControl(char) {
return -1
}
return char
}, value)
}
func peerRef(endpoint string) string {
sum := sha256.Sum256([]byte(endpoint))
return hex.EncodeToString(sum[:peerRefHexLength/2])
}
func validPeerRef(endpoint, ref string) bool {
if ref == peerRef(endpoint) {
return true
}
// Accept references from a process that was already running during an
// in-place upgrade. New sessions always publish the wider reference.
sum := sha256.Sum256([]byte(endpoint))
return ref == hex.EncodeToString(sum[:4])
}
func randomHex(bytes int) (string, error) {
value := make([]byte, bytes)
if _, err := rand.Read(value); err != nil {
return "", err
}
return hex.EncodeToString(value), nil
}