package domain import ( "errors" "slices" "sort" "git.cin.su/m/Assistant/contracts/capability" ) var ErrInvalidFleetReadiness = errors.New("invalid fleet readiness") func BuildFleetReadiness(observedAt int64, members []capability.FleetMember) (capability.FleetReadiness, error) { if observedAt < 1 || len(members) == 0 { return capability.FleetReadiness{}, ErrInvalidFleetReadiness } result := capability.FleetReadiness{ObservedAtUnixMillis: observedAt, Members: append([]capability.FleetMember(nil), members...), FallbackTier: capability.FleetTierLifeboat} seen := map[capability.FleetTier]bool{} for i := range result.Members { member := &result.Members[i] if member.ProviderInstanceID == "" || member.ModelDescriptorID == "" || !validFleetTier(member.Tier) || seen[member.Tier] && member.Ready { return capability.FleetReadiness{}, ErrInvalidFleetReadiness } if member.Ready { seen[member.Tier] = true } } for _, tier := range []capability.FleetTier{capability.FleetTierFast, capability.FleetTierMedium, capability.FleetTierHeavy, capability.FleetTierLifeboat} { if seen[tier] { result.ReadyTiers = append(result.ReadyTiers, tier) } } return result, nil } func SelectFleetTier(readiness capability.FleetReadiness, preferred capability.FleetTier) (capability.FleetTier, error) { if readiness.ObservedAtUnixMillis < 1 || len(readiness.Members) == 0 || !validFleetTier(readiness.FallbackTier) { return "", ErrInvalidFleetReadiness } if !validFleetTier(preferred) { return "", ErrInvalidFleetReadiness } for _, tier := range fleetFailoverOrder(preferred) { if slices.Contains(readiness.ReadyTiers, tier) { return tier, nil } } if slices.Contains(readiness.ReadyTiers, readiness.FallbackTier) { return readiness.FallbackTier, nil } return "", ErrInvalidFleetReadiness } func fleetFailoverOrder(preferred capability.FleetTier) []capability.FleetTier { switch preferred { case capability.FleetTierHeavy: return []capability.FleetTier{capability.FleetTierHeavy, capability.FleetTierMedium, capability.FleetTierFast} case capability.FleetTierMedium: return []capability.FleetTier{capability.FleetTierMedium, capability.FleetTierFast} case capability.FleetTierFast: return []capability.FleetTier{capability.FleetTierFast} case capability.FleetTierLifeboat: return []capability.FleetTier{capability.FleetTierLifeboat} default: return nil } } func validFleetTier(value capability.FleetTier) bool { return value == capability.FleetTierFast || value == capability.FleetTierMedium || value == capability.FleetTierHeavy || value == capability.FleetTierLifeboat } func SortFleetMembers(members []capability.FleetMember) { sort.SliceStable(members, func(i, j int) bool { if members[i].Tier != members[j].Tier { return members[i].Tier < members[j].Tier } return members[i].ProviderInstanceID < members[j].ProviderInstanceID }) }