package model import ( "slices" "github.com/QuantumNous/new-api/constant" "github.com/QuantumNous/new-api/dto" ) var filterEvalOrder = []dto.ChannelFilterKind{ dto.FilterRequestPath, dto.FilterTaskPluginIdentity, } // ChannelSatisfiesFilters reports whether ch passes every filter. // On false, it returns the kind of the first violated filter (request_path // then task_plugin_identity) for error attribution. func ChannelSatisfiesFilters(ch *Channel, modelName string, filters []dto.ChannelFilter) (bool, dto.ChannelFilterKind) { if ch == nil { return false, "" } for _, kind := range filterEvalOrder { for _, filter := range filters { if filter.Kind != kind { continue } if !channelMatchesFilter(ch, modelName, filter) { return false, kind } } } return true, "" } // filterCandidateIDs applies filters to a cached candidate id list. // Caller must hold channelSyncLock (read lock). The input slice is never mutated. // A missing id in channelsIDM is kept for request_path (downstream consistency // error) and dropped for task_plugin_identity, matching the previous filters. func filterCandidateIDs(ids []int, modelName string, filters []dto.ChannelFilter) (kept []int, emptiedBy dto.ChannelFilterKind) { if len(ids) == 0 { return ids, "" } kept = ids for _, kind := range filterEvalOrder { kindFilters := filtersByKind(filters, kind) if len(kindFilters) == 0 { continue } next := make([]int, 0, len(kept)) for _, id := range kept { channel, exists := channelsIDM[id] if candidatePassesKindFilters(channel, exists, modelName, kind, kindFilters) { next = append(next, id) } } if len(kept) > 0 && len(next) == 0 { return next, kind } kept = next } return kept, "" } func filtersByKind(filters []dto.ChannelFilter, kind dto.ChannelFilterKind) []dto.ChannelFilter { var matched []dto.ChannelFilter for _, filter := range filters { if filter.Kind == kind { matched = append(matched, filter) } } return matched } func candidatePassesKindFilters(ch *Channel, exists bool, modelName string, kind dto.ChannelFilterKind, filters []dto.ChannelFilter) bool { if kind == dto.FilterRequestPath && !exists { return true } if !exists || ch == nil { return false } for _, filter := range filters { if !channelMatchesFilter(ch, modelName, filter) { return false } } return true } func channelMatchesFilter(ch *Channel, modelName string, filter dto.ChannelFilter) bool { switch filter.Kind { case dto.FilterRequestPath: if filter.RequestPath == "" { return true } if ch.Type != constant.ChannelTypeAdvancedCustom { return true } config := ch.GetOtherSettings().AdvancedCustom return config != nil && config.SupportsPathForModel(filter.RequestPath, modelName) case dto.FilterTaskPluginIdentity: if ch.Type == constant.ChannelTypeTaskPlugin { return filter.TaskPluginKey != "" && ch.GetSetting().TaskPluginKey == filter.TaskPluginKey } return filter.TaskPluginKey == "" || slices.Contains(filter.TaskPluginChannelTypes, ch.Type) default: return true } }