Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

73 lines
1.8 KiB
Go

package devicelink
import (
"context"
"net"
"net/netip"
"strings"
"time"
)
const (
ALPN = "tutti-device-link/1"
defaultHandshakeTimeout = 3 * time.Second
defaultKeepAlive = 5 * time.Second
defaultIdleTimeout = 15 * time.Second
)
type CandidateType string
const (
CandidateTypeLANIPv4 CandidateType = "lan_ipv4"
CandidateTypeULAIPv6 CandidateType = "ula_ipv6"
CandidateTypeGlobalIPv6 CandidateType = "global_ipv6"
)
const (
CandidatePriorityLANIPv4 = 300
CandidatePriorityULAIPv6 = 250
CandidatePriorityGlobalIPv6 = 200
MaxCandidates = 4
)
// Candidate is a UDP endpoint that can be exchanged through the
// authenticated rendezvous service. Raw candidate values are sensitive and
// must not be written to ordinary logs or metrics.
type Candidate struct {
CandidateID string `json:"candidateId"`
Address string `json:"address"`
CandidateType CandidateType `json:"candidateType"`
Priority int `json:"priority"`
// InterfaceName, InterfaceIndex, and InterfacePrefix are local-only
// discovery metadata. They must not be required by peers or exchanged with
// the rendezvous service.
InterfaceName string `json:"-"`
InterfaceIndex int `json:"-"`
InterfacePrefix netip.Prefix `json:"-"`
}
func (c Candidate) ID() string {
return strings.TrimSpace(c.CandidateID)
}
// BoundEndpoint owns the UDP socket used first for connectivity checking and
// then for QUIC. Reusing the socket is required so stateful firewalls observe
// the same local endpoint throughout the attempt.
type BoundEndpoint struct {
Candidate Candidate
Conn *net.UDPConn
}
func (e *BoundEndpoint) Close() error {
if e == nil || e.Conn == nil {
return nil
}
return e.Conn.Close()
}
type StreamDialer interface {
OpenStream(context.Context) (net.Conn, error)
}