diff --git a/pkg/agent/endpoint/manifest.go b/pkg/agent/endpoint/manifest.go index 6d827d448..93797a86a 100644 --- a/pkg/agent/endpoint/manifest.go +++ b/pkg/agent/endpoint/manifest.go @@ -16,7 +16,9 @@ package endpoint import ( "fmt" + "hash/fnv" "slices" + "strconv" "strings" "github.com/livekit/protocol/livekit" @@ -37,6 +39,27 @@ type Manifest struct { routes []Route } +// Version is a stable fnv64a digest of the route set, used to detect manifest +// skew across nodes serving the same deployment (all-agree => safe to route +// without inspecting the path). It is order-independent: two workers on the +// same revision hash identically regardless of route declaration order. +func (m *Manifest) Version() uint64 { + lines := make([]string, 0, len(m.routes)) + for i := range m.routes { + r := &m.routes[i] + methods := append([]string(nil), r.Methods...) + slices.Sort(methods) + lines = append(lines, strconv.Itoa(int(r.Kind))+" "+r.Template.String()+" "+strings.Join(methods, ",")+" "+strconv.FormatBool(r.Public)) + } + slices.Sort(lines) + h := fnv.New64a() + for _, l := range lines { + _, _ = h.Write([]byte(l)) + _, _ = h.Write([]byte{0}) + } + return h.Sum64() +} + // MatchResult mirrors starlette's Match enum: a FULL match selects the route, a // PARTIAL match (path matched, method didn't) yields 405 only after the whole // table has been scanned, so a later route with the right method still wins.