package utils import ( "sfbase/core" // "context" "fmt" "log" "sfbase/global" "sfbase/redis" "sfbase/utils" "sfis/db" "sfis/lock" "sfis/model" "sfis/model/response" "strings" "time" "github.com/gin-gonic/gin" "go.uber.org/zap" ) func Check(appID string, productID int, c *gin.Context, getData func() ([]map[string]interface{}, int, error), param, ip string, concurrentTest bool) { lock.MainLock.Lock() userLock := lock.UserLockMap[appID] lock.MainLock.Unlock() var err error datas := []map[string]interface{}{} orderCode := "" errStr := "" /** 第二步:用户接口产品校验-加锁处理 */ //2.1 取用户接口状态校验-可加锁也可不加锁 这个没有太严谨 //userLock.Lock() userProduct := &model.UserProduct{} db.GetSFISDB().First(userProduct, &model.UserProduct{AppID: appID, ProductID: productID}) //userLock.Unlock() if userProduct.ID == 0 { response.FailWithDetailed(response.InterfaceDeleted, nil, "该用户接口未购买", c) return } else if userProduct.InterfaceStatus != 0 { response.FailWithDetailed(response.InterfaceDeleted, nil, "该用户接口暂不提供服务", c) return } //校验是否过期 now := time.Now().Unix() end := userProduct.EndAt if now > end.Unix() { response.FailWithDetailed(response.InterfaceExpired, nil, "剩余量已过期", c) return } //校验每日调用上限 limittodaykey := fmt.Sprintf("limittoday_%d_%d_%s", time.Now().Day(), productID, appID) limittoday := redis.GetInt("limit", limittodaykey) if limittoday >= userProduct.CallTimesLimitDay { //当天调用超过次数 response.FailWithDetailed(response.MoreThanEveryDayDataNumberLimit, nil, "请求超过每日调用总量限制", c) return } else { if limittoday == 0 { _, max := utils.GetDayMinMax(time.Now()) redis.Put("limit", limittodaykey, 0, int(max-now)) } } // limitrate := fmt.Sprintf("limitrate_%d_%s", userProduct.ProductID, userProduct.AppID) Exists, _ := redis.Exists("limit", limitrate) if Exists { response.FailWithDetailed(response.CallRate, nil, "请求频率过快,请稍后重试", c) } //2.2 取用户(产品余量|钱包账户余额)校验-必须加锁 costModel := userProduct.CostModel //扣费模式 0扣余量,1-扣余额 product := GetProductByID(productID) userLock.Lock() log.Println(param + "锁住......") db.GetSFISDB().First(userProduct, &model.UserProduct{AppID: appID, ProductID: productID}) // costModel = 0 switch costModel { case 0: //按剩余量扣费 datas, orderCode, err, errStr = costByLeftNum(getData, appID, productID, userProduct, product, param, ip) case 1: //按账户钱包余额扣费 datas, orderCode, err, errStr = costByAccountBalance(getData, appID, productID, userProduct, product, param, ip) case 2: //优先扣剩余量,剩余量为0,扣钱包余额 } userLock.Unlock() log.Println(param + "解锁......") if err == nil { db.GetQyfw().Save("user_data", map[string]interface{}{ "app_id": appID, "result_num": len(datas), "result_content": datas, "order_code": orderCode, "status": 200, "user_product_id": userProduct.ID, "create_at": time.Now().Unix(), }) limittodaykey := fmt.Sprintf("limittoday_%d_%d_%s", time.Now().Day(), userProduct.ProductID, userProduct.AppID) limitrate := fmt.Sprintf("limitrate_%d_%s", userProduct.ProductID, userProduct.AppID) rateTime := core.GetIntConf("base.session.interface_call_rate") redis.Incr("limit", limittodaykey) redis.Put("limit", limitrate, 1, rateTime) if !concurrentTest { response.FailWithDetailed(response.SUCCESS, datas, "OK", c) } } else { if strings.Contains(errStr, "不足") { response.FailWithDetailed(response.LeftNumEmpty, nil, errStr, c) } else { global.Logger.Error("数据库操作失败", zap.Any("error:", err)) response.FailWithDetailed(response.QueryError, nil, "内部错误", c) } } }