pre_consume_quota.go 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. package service
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/bytedance/gopkg/util/gopool"
  6. "github.com/gin-gonic/gin"
  7. "net/http"
  8. "one-api/common"
  9. "one-api/logger"
  10. "one-api/model"
  11. relaycommon "one-api/relay/common"
  12. "one-api/types"
  13. )
  14. func ReturnPreConsumedQuota(c *gin.Context, relayInfo *relaycommon.RelayInfo, preConsumedQuota int) {
  15. if preConsumedQuota != 0 {
  16. gopool.Go(func() {
  17. relayInfoCopy := *relayInfo
  18. err := PostConsumeQuota(&relayInfoCopy, -preConsumedQuota, 0, false)
  19. if err != nil {
  20. common.SysLog("error return pre-consumed quota: " + err.Error())
  21. }
  22. })
  23. }
  24. }
  25. // PreConsumeQuota checks if the user has enough quota to pre-consume.
  26. // It returns the pre-consumed quota if successful, or an error if not.
  27. func PreConsumeQuota(c *gin.Context, preConsumedQuota int, relayInfo *relaycommon.RelayInfo) (int, *types.NewAPIError) {
  28. userQuota, err := model.GetUserQuota(relayInfo.UserId, false)
  29. if err != nil {
  30. return 0, types.NewError(err, types.ErrorCodeQueryDataError, types.ErrOptionWithSkipRetry())
  31. }
  32. if userQuota <= 0 {
  33. return 0, types.NewErrorWithStatusCode(errors.New("user quota is not enough"), types.ErrorCodeInsufficientUserQuota, http.StatusForbidden, types.ErrOptionWithSkipRetry(), types.ErrOptionWithNoRecordErrorLog())
  34. }
  35. if userQuota-preConsumedQuota < 0 {
  36. return 0, types.NewErrorWithStatusCode(fmt.Errorf("pre-consume quota failed, user quota: %s, need quota: %s", logger.FormatQuota(userQuota), logger.FormatQuota(preConsumedQuota)), types.ErrorCodeInsufficientUserQuota, http.StatusForbidden, types.ErrOptionWithSkipRetry(), types.ErrOptionWithNoRecordErrorLog())
  37. }
  38. trustQuota := common.GetTrustQuota()
  39. relayInfo.UserQuota = userQuota
  40. if userQuota > trustQuota {
  41. // 用户额度充足,判断令牌额度是否充足
  42. if !relayInfo.TokenUnlimited {
  43. // 非无限令牌,判断令牌额度是否充足
  44. tokenQuota := c.GetInt("token_quota")
  45. if tokenQuota > trustQuota {
  46. // 令牌额度充足,信任令牌
  47. preConsumedQuota = 0
  48. logger.LogInfo(c, fmt.Sprintf("user %d quota %s and token %d quota %d are enough, trusted and no need to pre-consume", relayInfo.UserId, logger.FormatQuota(userQuota), relayInfo.TokenId, tokenQuota))
  49. }
  50. } else {
  51. // in this case, we do not pre-consume quota
  52. // because the user has enough quota
  53. preConsumedQuota = 0
  54. logger.LogInfo(c, fmt.Sprintf("user %d with unlimited token has enough quota %s, trusted and no need to pre-consume", relayInfo.UserId, logger.FormatQuota(userQuota)))
  55. }
  56. }
  57. if preConsumedQuota > 0 {
  58. err := PreConsumeTokenQuota(relayInfo, preConsumedQuota)
  59. if err != nil {
  60. return 0, types.NewErrorWithStatusCode(err, types.ErrorCodePreConsumeTokenQuotaFailed, http.StatusForbidden, types.ErrOptionWithSkipRetry(), types.ErrOptionWithNoRecordErrorLog())
  61. }
  62. err = model.DecreaseUserQuota(relayInfo.UserId, preConsumedQuota)
  63. if err != nil {
  64. return 0, types.NewError(err, types.ErrorCodeUpdateDataError, types.ErrOptionWithSkipRetry())
  65. }
  66. logger.LogInfo(c, fmt.Sprintf("用户 %d 预扣费 %s, 预扣费后剩余额度: %s", relayInfo.UserId, logger.FormatQuota(preConsumedQuota), logger.FormatQuota(userQuota-preConsumedQuota)))
  67. }
  68. relayInfo.FinalPreConsumedQuota = preConsumedQuota
  69. return preConsumedQuota, nil
  70. }