2025-08-14 20:05:06 +08:00
package service
import (
"errors"
"fmt"
"net/http"
2025-08-14 21:10:04 +08:00
"one-api/common"
2025-08-14 20:05:06 +08:00
"one-api/logger"
"one-api/model"
relaycommon "one-api/relay/common"
"one-api/types"
2025-08-15 12:50:27 +08:00
"github.com/bytedance/gopkg/util/gopool"
"github.com/gin-gonic/gin"
2025-08-14 20:05:06 +08:00
)
func ReturnPreConsumedQuota ( c * gin . Context , relayInfo * relaycommon . RelayInfo , preConsumedQuota int ) {
if preConsumedQuota != 0 {
2025-08-15 14:08:15 +08:00
logger . LogInfo ( c , fmt . Sprintf ( "用户 %d 请求失败, 返还预扣费额度 %s" , relayInfo . UserId , logger . FormatQuota ( preConsumedQuota ) ) )
2025-08-14 20:05:06 +08:00
gopool . Go ( func ( ) {
relayInfoCopy := * relayInfo
err := PostConsumeQuota ( & relayInfoCopy , - preConsumedQuota , 0 , false )
if err != nil {
2025-08-14 21:10:04 +08:00
common . SysLog ( "error return pre-consumed quota: " + err . Error ( ) )
2025-08-14 20:05:06 +08:00
}
} )
}
}
// PreConsumeQuota checks if the user has enough quota to pre-consume.
// It returns the pre-consumed quota if successful, or an error if not.
func PreConsumeQuota ( c * gin . Context , preConsumedQuota int , relayInfo * relaycommon . RelayInfo ) ( int , * types . NewAPIError ) {
userQuota , err := model . GetUserQuota ( relayInfo . UserId , false )
if err != nil {
return 0 , types . NewError ( err , types . ErrorCodeQueryDataError , types . ErrOptionWithSkipRetry ( ) )
}
if userQuota <= 0 {
return 0 , types . NewErrorWithStatusCode ( errors . New ( "user quota is not enough" ) , types . ErrorCodeInsufficientUserQuota , http . StatusForbidden , types . ErrOptionWithSkipRetry ( ) , types . ErrOptionWithNoRecordErrorLog ( ) )
}
if userQuota - preConsumedQuota < 0 {
2025-08-14 22:15:18 +08:00
return 0 , types . NewErrorWithStatusCode ( fmt . Errorf ( "预扣费额度失败, 用户剩余额度: %s, 需要预扣费额度: %s" , logger . FormatQuota ( userQuota ) , logger . FormatQuota ( preConsumedQuota ) ) , types . ErrorCodeInsufficientUserQuota , http . StatusForbidden , types . ErrOptionWithSkipRetry ( ) , types . ErrOptionWithNoRecordErrorLog ( ) )
2025-08-14 20:05:06 +08:00
}
2025-08-14 21:30:03 +08:00
trustQuota := common . GetTrustQuota ( )
2025-08-14 20:05:06 +08:00
relayInfo . UserQuota = userQuota
2025-08-14 21:30:03 +08:00
if userQuota > trustQuota {
2025-08-14 20:05:06 +08:00
// 用户额度充足,判断令牌额度是否充足
if ! relayInfo . TokenUnlimited {
// 非无限令牌,判断令牌额度是否充足
tokenQuota := c . GetInt ( "token_quota" )
2025-08-14 21:30:03 +08:00
if tokenQuota > trustQuota {
2025-08-14 20:05:06 +08:00
// 令牌额度充足,信任令牌
preConsumedQuota = 0
2025-08-15 14:08:15 +08:00
logger . LogInfo ( c , fmt . Sprintf ( "用户 %d 剩余额度 %s 且令牌 %d 额度 %d 充足, 信任且不需要预扣费" , relayInfo . UserId , logger . FormatQuota ( userQuota ) , relayInfo . TokenId , tokenQuota ) )
2025-08-14 20:05:06 +08:00
}
} else {
// in this case, we do not pre-consume quota
// because the user has enough quota
preConsumedQuota = 0
2025-08-15 14:08:15 +08:00
logger . LogInfo ( c , fmt . Sprintf ( "用户 %d 额度充足且为无限额度令牌, 信任且不需要预扣费" , relayInfo . UserId ) )
2025-08-14 20:05:06 +08:00
}
}
if preConsumedQuota > 0 {
err := PreConsumeTokenQuota ( relayInfo , preConsumedQuota )
if err != nil {
return 0 , types . NewErrorWithStatusCode ( err , types . ErrorCodePreConsumeTokenQuotaFailed , http . StatusForbidden , types . ErrOptionWithSkipRetry ( ) , types . ErrOptionWithNoRecordErrorLog ( ) )
}
err = model . DecreaseUserQuota ( relayInfo . UserId , preConsumedQuota )
if err != nil {
return 0 , types . NewError ( err , types . ErrorCodeUpdateDataError , types . ErrOptionWithSkipRetry ( ) )
}
2025-08-14 21:30:03 +08:00
logger . LogInfo ( c , fmt . Sprintf ( "用户 %d 预扣费 %s, 预扣费后剩余额度: %s" , relayInfo . UserId , logger . FormatQuota ( preConsumedQuota ) , logger . FormatQuota ( userQuota - preConsumedQuota ) ) )
2025-08-14 20:05:06 +08:00
}
relayInfo . FinalPreConsumedQuota = preConsumedQuota
return preConsumedQuota , nil
}