api_util.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package utils
  2. import (
  3. "sfbase/core"
  4. // "context"
  5. "fmt"
  6. "log"
  7. "sfbase/global"
  8. "sfbase/redis"
  9. "sfbase/utils"
  10. "sfis/db"
  11. "sfis/lock"
  12. "sfis/model"
  13. "sfis/model/response"
  14. "strings"
  15. "time"
  16. "github.com/gin-gonic/gin"
  17. "go.uber.org/zap"
  18. )
  19. func Check(appID string, productID int, c *gin.Context, getData func() ([]map[string]interface{}, int, error), param, ip string, concurrentTest bool) {
  20. lock.MainLock.Lock()
  21. userLock := lock.UserLockMap[appID]
  22. lock.MainLock.Unlock()
  23. var err error
  24. datas := []map[string]interface{}{}
  25. orderCode := ""
  26. errStr := ""
  27. /**
  28. 第二步:用户接口产品校验-加锁处理
  29. */
  30. //2.1 取用户接口状态校验-可加锁也可不加锁 这个没有太严谨
  31. //userLock.Lock()
  32. userProduct := &model.UserProduct{}
  33. db.GetSFISDB().First(userProduct, &model.UserProduct{AppID: appID, ProductID: productID})
  34. //userLock.Unlock()
  35. if userProduct.ID == 0 {
  36. response.FailWithDetailed(response.InterfaceDeleted, nil, "该用户接口未购买", c)
  37. return
  38. } else if userProduct.InterfaceStatus != 0 {
  39. response.FailWithDetailed(response.InterfaceDeleted, nil, "该用户接口暂不提供服务", c)
  40. return
  41. }
  42. //校验是否过期
  43. now := time.Now().Unix()
  44. if userProduct.CostModel != 1 {
  45. end := userProduct.EndAt
  46. if now > end.Unix() {
  47. response.FailWithDetailed(response.InterfaceExpired, nil, "剩余量已过期", c)
  48. return
  49. }
  50. }
  51. //校验每日调用上限
  52. limittodaykey := fmt.Sprintf("limittoday_%d_%d_%s", time.Now().Day(), productID, appID)
  53. limittoday := redis.GetInt("limit", limittodaykey)
  54. if limittoday >= userProduct.CallTimesLimitDay { //当天调用超过次数
  55. response.FailWithDetailed(response.MoreThanEveryDayDataNumberLimit, nil, "请求超过每日调用总量限制", c)
  56. return
  57. } else {
  58. if limittoday == 0 {
  59. _, max := utils.GetDayMinMax(time.Now())
  60. redis.Put("limit", limittodaykey, 0, int(max-now))
  61. }
  62. }
  63. //请求频率限制
  64. if !concurrentTest {
  65. limitrate := fmt.Sprintf("limitrate_%d_%s", userProduct.ProductID, userProduct.AppID)
  66. Exists, _ := redis.Exists("limit", limitrate)
  67. if Exists {
  68. response.FailWithDetailed(response.CallRate, nil, "请求频率过快,请稍后重试", c)
  69. return
  70. }
  71. }
  72. //2.2 取用户(产品余量|钱包账户余额)校验-必须加锁
  73. costModel := userProduct.CostModel //扣费模式 0扣余量,1-扣余额
  74. product := GetProductByID(productID)
  75. userLock.Lock()
  76. log.Println(param + "锁住......")
  77. db.GetSFISDB().First(userProduct, &model.UserProduct{AppID: appID, ProductID: productID})
  78. // costModel = 0
  79. switch costModel {
  80. case 0:
  81. //按剩余量扣费
  82. datas, orderCode, err, errStr = costByLeftNum(getData, appID, productID, userProduct, product, param, ip)
  83. case 1:
  84. //按账户钱包余额扣费
  85. datas, orderCode, err, errStr = costByAccountBalance(getData, appID, productID, userProduct, product, param, ip)
  86. case 2:
  87. //优先扣剩余量,剩余量为0,扣钱包余额
  88. }
  89. userLock.Unlock()
  90. log.Println(param + "解锁......")
  91. if err == nil {
  92. db.GetQyfw().Save("user_data", map[string]interface{}{
  93. "app_id": appID,
  94. "result_num": len(datas),
  95. "result_content": datas,
  96. "order_code": orderCode,
  97. "status": 200,
  98. "user_product_id": userProduct.ID,
  99. "create_at": time.Now().Unix(),
  100. })
  101. limittodaykey := fmt.Sprintf("limittoday_%d_%d_%s", time.Now().Day(), userProduct.ProductID, userProduct.AppID)
  102. limitrate := fmt.Sprintf("limitrate_%d_%s", userProduct.ProductID, userProduct.AppID)
  103. rateTime := core.GetIntConf("base.session.interface_call_rate")
  104. redis.Incr("limit", limittodaykey)
  105. redis.Put("limit", limitrate, 1, rateTime)
  106. if !concurrentTest {
  107. response.FailWithDetailed(response.SUCCESS, datas, "OK", c)
  108. }
  109. } else {
  110. if strings.Contains(errStr, "不足") {
  111. response.FailWithDetailed(response.LeftNumEmpty, nil, errStr, c)
  112. } else {
  113. global.Logger.Error("数据库操作失败", zap.Any("error:", err))
  114. response.FailWithDetailed(response.QueryError, nil, "内部错误", c)
  115. }
  116. }
  117. }