pre_consume_quota.go 3.3 KB

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