Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 

99 řádky
3.9 KiB

  1. package service
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "strings"
  7. "github.com/QuantumNous/new-api/common"
  8. "github.com/QuantumNous/new-api/constant"
  9. "github.com/QuantumNous/new-api/model"
  10. "gorm.io/gorm"
  11. )
  12. // assetCredentialConfigured guards channel types whose asset adapter signs
  13. // requests with a dedicated AK/SK pair stored in channel_asset_credentials
  14. // (currently only official Volcengine DoubaoVideo). Without the credential
  15. // the channel must not serve, be bound, or be auto-matched for assets; a DB
  16. // error is treated as not configured so auto-match falls through to other
  17. // candidate channels.
  18. func assetCredentialConfigured(channel *model.Channel) bool {
  19. if channel.Type != constant.ChannelTypeDoubaoVideo {
  20. return true
  21. }
  22. credential, err := model.GetChannelAssetCredential(channel.Id)
  23. if err != nil || credential == nil {
  24. return false
  25. }
  26. return strings.TrimSpace(credential.AccessKey) != "" && strings.TrimSpace(credential.SecretKey) != ""
  27. }
  28. func ResolveAssetChannelForOperation(userID int, tokenGroup string, operation AssetOperation) (*model.Channel, AssetAdapter, *AssetError) {
  29. bindings, err := model.GetUserAssetChannelsByTypes(userID, RegisteredAssetChannelTypes(), tokenGroup)
  30. if err != nil {
  31. return nil, nil, newAssetError(AssetErrorServer, err.Error(), http.StatusInternalServerError)
  32. }
  33. if len(bindings) > 0 {
  34. binding := bindings[0]
  35. channel, err := model.CacheGetChannel(binding.ChannelId)
  36. if err != nil {
  37. if errors.Is(err, gorm.ErrRecordNotFound) || common.MemoryCacheEnabled {
  38. return nil, nil, newAssetError(AssetErrorBindingInvalid, "bound asset channel not found", http.StatusBadGateway)
  39. }
  40. return nil, nil, newAssetError(AssetErrorServer, err.Error(), http.StatusInternalServerError)
  41. }
  42. adapter, ok := GetAssetAdapter(channel.Type)
  43. if channel.Status != common.ChannelStatusEnabled || !assetChannelHasKey(channel) || !MatchDoubaoAssetGroup(channel.GetGroups(), tokenGroup) || !ok || !assetCredentialConfigured(channel) {
  44. return nil, nil, newAssetError(AssetErrorBindingInvalid, "bound asset channel is not available for asset library", http.StatusBadGateway)
  45. }
  46. if !adapter.Supports(operation) {
  47. return nil, nil, newAssetError(AssetErrorOperationNotSupported, fmt.Sprintf("asset operation %s is not supported by bound channel", operation), http.StatusBadRequest)
  48. }
  49. return channel, adapter, nil
  50. }
  51. channel, adapter, err := autoMatchAssetChannelForOperation(tokenGroup, operation)
  52. if err != nil {
  53. return nil, nil, newAssetError(AssetErrorServer, err.Error(), http.StatusInternalServerError)
  54. }
  55. if channel == nil {
  56. return nil, nil, newAssetError(AssetErrorChannelNotFound, "no available asset channel supports requested operation", http.StatusBadGateway)
  57. }
  58. return channel, adapter, nil
  59. }
  60. func autoMatchAssetChannelForOperation(tokenGroup string, operation AssetOperation) (*model.Channel, AssetAdapter, error) {
  61. for _, channelType := range RegisteredAssetChannelTypes() {
  62. adapter, ok := GetAssetAdapter(channelType)
  63. if !ok || !adapter.Supports(operation) {
  64. continue
  65. }
  66. for startIdx := 0; ; startIdx += DoubaoAssetChannelPageSize {
  67. candidates, err := model.GetChannelsByType(startIdx, DoubaoAssetChannelPageSize, true, channelType)
  68. if err != nil {
  69. return nil, nil, err
  70. }
  71. for _, candidate := range candidates {
  72. if candidate == nil || !MatchDoubaoAssetGroup(candidate.GetGroups(), tokenGroup) {
  73. continue
  74. }
  75. channel, err := model.CacheGetChannel(candidate.Id)
  76. if err != nil {
  77. if errors.Is(err, gorm.ErrRecordNotFound) || common.MemoryCacheEnabled {
  78. continue
  79. }
  80. return nil, nil, err
  81. }
  82. if channel.Status == common.ChannelStatusEnabled && assetChannelHasKey(channel) && MatchDoubaoAssetGroup(channel.GetGroups(), tokenGroup) && assetCredentialConfigured(channel) {
  83. return channel, adapter, nil
  84. }
  85. }
  86. if len(candidates) < DoubaoAssetChannelPageSize {
  87. break
  88. }
  89. }
  90. }
  91. return nil, nil, nil
  92. }