api_util.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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. if userProduct.CostModel != 1 {
  44. now := time.Now().Unix()
  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. }
  70. }
  71. //2.2 取用户(产品余量|钱包账户余额)校验-必须加锁
  72. costModel := userProduct.CostModel //扣费模式 0扣余量,1-扣余额
  73. product := GetProductByID(productID)
  74. userLock.Lock()
  75. log.Println(param + "锁住......")
  76. db.GetSFISDB().First(userProduct, &model.UserProduct{AppID: appID, ProductID: productID})
  77. // costModel = 0
  78. switch costModel {
  79. case 0:
  80. //按剩余量扣费
  81. datas, orderCode, err, errStr = costByLeftNum(getData, appID, productID, userProduct, product, param, ip)
  82. case 1:
  83. //按账户钱包余额扣费
  84. datas, orderCode, err, errStr = costByAccountBalance(getData, appID, productID, userProduct, product, param, ip)
  85. case 2:
  86. //优先扣剩余量,剩余量为0,扣钱包余额
  87. }
  88. userLock.Unlock()
  89. log.Println(param + "解锁......")
  90. if err == nil {
  91. db.GetQyfw().Save("user_data", map[string]interface{}{
  92. "app_id": appID,
  93. "result_num": len(datas),
  94. "result_content": datas,
  95. "order_code": orderCode,
  96. "status": 200,
  97. "user_product_id": userProduct.ID,
  98. "create_at": time.Now().Unix(),
  99. })
  100. limittodaykey := fmt.Sprintf("limittoday_%d_%d_%s", time.Now().Day(), userProduct.ProductID, userProduct.AppID)
  101. limitrate := fmt.Sprintf("limitrate_%d_%s", userProduct.ProductID, userProduct.AppID)
  102. rateTime := core.GetIntConf("base.session.interface_call_rate")
  103. redis.Incr("limit", limittodaykey)
  104. redis.Put("limit", limitrate, 1, rateTime)
  105. if !concurrentTest {
  106. response.FailWithDetailed(response.SUCCESS, datas, "OK", c)
  107. }
  108. } else {
  109. if strings.Contains(errStr, "不足") {
  110. response.FailWithDetailed(response.LeftNumEmpty, nil, errStr, c)
  111. } else {
  112. global.Logger.Error("数据库操作失败", zap.Any("error:", err))
  113. response.FailWithDetailed(response.QueryError, nil, "内部错误", c)
  114. }
  115. }
  116. }