Files
netbird/management/internals/shared/grpc/sync_message_versions.go
T
2026-07-14 16:42:44 +02:00

128 lines
3.9 KiB
Go

package grpc
import (
"cmp"
"errors"
"fmt"
"slices"
"github.com/netbirdio/netbird/shared/management/proto"
)
type SyncMessageVersion uint16
const (
Base SyncMessageVersion = iota
ComponentNetworkMap
)
var (
AllSyncMessageVersions = []SyncMessageVersion{Base, ComponentNetworkMap}
ProtoToMessageSyncVersion = map[proto.PeerCapability]SyncMessageVersion{
proto.PeerCapability_PeerCapabilityComponentNetworkMap: ComponentNetworkMap,
}
MessageSyncVersionToProto = map[SyncMessageVersion]proto.PeerCapability{
ComponentNetworkMap: proto.PeerCapability_PeerCapabilityComponentNetworkMap,
}
)
var ErrorUnrecognizedSyncMessageVersion = errors.New("unrecognized SyncMessageVersion")
func (sm SyncMessageVersion) String() string {
return [...]string{"Base", "ComponentNetworkMap"}[sm]
}
func AllSupportedSyncMessageVersions() []SyncMessageVersion {
return AllSyncMessageVersions
}
func ValidateSyncMessageVersions(tovalidate []string) error {
// empty list == we support all available versions
if len(tovalidate) == 0 {
return nil
}
allversions := make(map[string]SyncMessageVersion, len(AllSyncMessageVersions))
for _, v := range AllSyncMessageVersions {
allversions[v.String()] = v
}
for _, s := range tovalidate {
if _, ok := allversions[s]; !ok {
return fmt.Errorf("%s: %w", s, ErrorUnrecognizedSyncMessageVersion)
}
}
return nil
}
// convert human-readable versions to enums
// please note no validation on input strings is done, misses are silently discarded
// the assumption is ValidateSyncMessageVersions() has been called before using SyncMessageVersionsFromString()
func SyncMessageVersionsFromString(toconvert []string) []SyncMessageVersion {
// empty list == we support all available versions
if len(toconvert) == 0 {
return AllSyncMessageVersions
}
allversions := make(map[string]SyncMessageVersion, len(AllSyncMessageVersions))
for _, v := range AllSyncMessageVersions {
allversions[v.String()] = v
}
toret := make([]SyncMessageVersion, 0)
for _, s := range toconvert {
toret = append(toret, allversions[s])
}
return toret
}
// convert per-account human-readable versions to enums
// please note no validation on versions strings is done, misses are silently discarded
// the assumption is ValidateSyncMessageVersions() has been called before using SyncMessageVersionsFromMap()
func SyncMessageVersionsFromMap(toconvert map[string][]string) map[string][]SyncMessageVersion {
// no per-account overrides
if len(toconvert) == 0 {
return nil
}
allversions := make(map[string]SyncMessageVersion, len(AllSyncMessageVersions))
for _, v := range AllSyncMessageVersions {
allversions[v.String()] = v
}
toret := make(map[string][]SyncMessageVersion, len(toconvert))
for account, versions := range toconvert {
toret[account] = SyncMessageVersionsFromString(versions)
}
return toret
}
// these come from the client; peer capabilities are expected to contain all enabled sync message versions.
// an empty list is interpreted as all but the base version are disabled.
func SyncMessageVersionsFromProtoEnums(peerCapabilities []int32) []SyncMessageVersion {
toret := make([]SyncMessageVersion, 0)
for _, pc := range peerCapabilities {
if _, ok := ProtoToMessageSyncVersion[proto.PeerCapability(pc)]; ok {
toret = append(toret, ProtoToMessageSyncVersion[proto.PeerCapability(pc)])
}
}
return toret
}
// return highest common sync message version, or Default (which is always available)
func CommonSyncMessageVersions(a []SyncMessageVersion, b []SyncMessageVersion) []SyncMessageVersion {
toret := []SyncMessageVersion{Base}
aversions := make(map[SyncMessageVersion]struct{})
for _, va := range a {
aversions[va] = struct{}{}
}
for _, vb := range b {
if _, ok := aversions[vb]; ok && vb != Base { // we already added 'Base' version
toret = append(toret, vb)
}
}
slices.SortFunc(toret, func(a SyncMessageVersion, b SyncMessageVersion) int {
return -1 * cmp.Compare(a, b)
})
return toret
}