package service import ( "errors" "fmt" "net/http" "github.com/QuantumNous/new-api/common" "github.com/QuantumNous/new-api/model" "gorm.io/gorm" ) func ResolveAssetChannelForOperation(userID int, tokenGroup string, operation AssetOperation) (*model.Channel, AssetAdapter, *AssetError) { bindings, err := model.GetUserAssetChannelsByTypes(userID, RegisteredAssetChannelTypes(), tokenGroup) if err != nil { return nil, nil, newAssetError(AssetErrorServer, err.Error(), http.StatusInternalServerError) } if len(bindings) > 0 { binding := bindings[0] channel, err := model.CacheGetChannel(binding.ChannelId) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) || common.MemoryCacheEnabled { return nil, nil, newAssetError(AssetErrorBindingInvalid, "bound asset channel not found", http.StatusBadGateway) } return nil, nil, newAssetError(AssetErrorServer, err.Error(), http.StatusInternalServerError) } adapter, ok := GetAssetAdapter(channel.Type) if channel.Status != common.ChannelStatusEnabled || !assetChannelHasKey(channel) || !MatchDoubaoAssetGroup(channel.GetGroups(), tokenGroup) || !ok { return nil, nil, newAssetError(AssetErrorBindingInvalid, "bound asset channel is not available for asset library", http.StatusBadGateway) } if !adapter.Supports(operation) { return nil, nil, newAssetError(AssetErrorOperationNotSupported, fmt.Sprintf("asset operation %s is not supported by bound channel", operation), http.StatusBadRequest) } return channel, adapter, nil } channel, adapter, err := autoMatchAssetChannelForOperation(tokenGroup, operation) if err != nil { return nil, nil, newAssetError(AssetErrorServer, err.Error(), http.StatusInternalServerError) } if channel == nil { return nil, nil, newAssetError(AssetErrorChannelNotFound, "no available asset channel supports requested operation", http.StatusBadGateway) } return channel, adapter, nil } func autoMatchAssetChannelForOperation(tokenGroup string, operation AssetOperation) (*model.Channel, AssetAdapter, error) { for _, channelType := range RegisteredAssetChannelTypes() { adapter, ok := GetAssetAdapter(channelType) if !ok || !adapter.Supports(operation) { continue } for startIdx := 0; ; startIdx += DoubaoAssetChannelPageSize { candidates, err := model.GetChannelsByType(startIdx, DoubaoAssetChannelPageSize, true, channelType) if err != nil { return nil, nil, err } for _, candidate := range candidates { if candidate == nil || !MatchDoubaoAssetGroup(candidate.GetGroups(), tokenGroup) { continue } channel, err := model.CacheGetChannel(candidate.Id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) || common.MemoryCacheEnabled { continue } return nil, nil, err } if channel.Status == common.ChannelStatusEnabled && assetChannelHasKey(channel) && MatchDoubaoAssetGroup(channel.GetGroups(), tokenGroup) { return channel, adapter, nil } } if len(candidates) < DoubaoAssetChannelPageSize { break } } } return nil, nil, nil }