Browse Source

add user_willet

tags/v0.0.3
dengbiao 1 month ago
parent
commit
6f0d7edcdb
7 changed files with 158 additions and 6 deletions
  1. +1
    -0
      enum/sys_cfg.go
  2. +1
    -1
      md/app_redis_key.go
  3. +13
    -0
      md/user_wallet.go
  4. +2
    -2
      rule/egg_energy/give_activty_coin.go
  5. +1
    -1
      rule/user_virtual_coin.go
  6. +121
    -0
      rule/user_wallet.go
  7. +19
    -2
      svc/svc_user_virtual_amount_redis_mutex_lock.go

+ 1
- 0
enum/sys_cfg.go View File

@@ -0,0 +1 @@
package enum

+ 1
- 1
md/app_redis_key.go View File

@@ -7,7 +7,7 @@ const (
EggEnergyNowPriceUpdateLock = "egg_energy_core_data_update_lock" // 当前价格(能拿到锁才能更新价格)
DealEggEnergyNowPriceRequestIdPrefix = "egg_energy_core_data:%d"

UserFinValidUpdateLock = "%s:user_fin_valid_update_lock:%s" // 用户余额更新锁(能拿到锁才能更新余额)
UserFinValidUpdateLock = "user_fin_valid_update_lock:%s" // 用户余额更新锁(能拿到锁才能更新余额)
UserVirtualAmountUpdateLock = "%s:user_virtual_amount_update_lock:%s" // 用户虚拟币更新锁(能拿到锁才能更新余额)

)

+ 13
- 0
md/user_wallet.go View File

@@ -0,0 +1,13 @@
package md

const (
UserWalletRedisKey = "user_wallet_user:%d"
)

type DealUserWalletReq struct {
Direction string `json:"direction"`
Kind int `json:"kind"`
Title string `json:"title"`
Uid int64 `json:"uid"`
Amount float64 `json:"amount"`
}

+ 2
- 2
rule/egg_energy/give_activty_coin.go View File

@@ -142,8 +142,8 @@ func SettlementGiveActivityCoin(engine *xorm.Engine, uid int64, ch *rabbit.Chann
Uid: uid,
NextWatchAdDate: now.Add(time.Hour * time.Duration(egg_system_rules.StrToInt(videoRewardSystem.EachRoundHour))),
ResidueWatchAdNum: egg_system_rules.StrToInt(videoRewardSystem.RewardTotalNum) - 1,
CreateAt: now,
UpdateAt: now,
CreateAt: now.Format("2006-01-02 15:04:05"),
UpdateAt: now.Format("2006-01-02 15:04:05"),
})
if err2 != nil {
return err2


+ 1
- 1
rule/user_virtual_coin.go View File

@@ -23,7 +23,7 @@ func DealUserVirtualCoin(session *xorm.Session, req md.DealUserVirtualCoinReq) (
}
//1、分布式锁阻拦
requestIdPrefix := fmt.Sprintf(md2.DealUserCoinRequestIdPrefix, req.CoinId, req.Uid)
cb, err := svc.HandleDistributedLock(zhios_order_relate_utils.Int64ToStr(req.Uid), requestIdPrefix, strconv.Itoa(req.CoinId))
cb, err := svc.HandleDistributedLock(zhios_order_relate_utils.Int64ToStr(req.Uid), strconv.Itoa(req.CoinId), requestIdPrefix)
if err != nil {
return err
}


+ 121
- 0
rule/user_wallet.go View File

@@ -0,0 +1,121 @@
package rule

import (
"code.fnuoos.com/EggPlanet/egg_models.git/src/implement"
"code.fnuoos.com/EggPlanet/egg_models.git/src/model"
zhios_order_relate_utils "code.fnuoos.com/EggPlanet/egg_models.git/utils"
"code.fnuoos.com/EggPlanet/egg_system_rules.git/md"
"code.fnuoos.com/EggPlanet/egg_system_rules.git/svc"
"code.fnuoos.com/EggPlanet/egg_system_rules.git/utils/cache"
"errors"
"fmt"
"github.com/shopspring/decimal"
"time"
"xorm.io/xorm"
)

// DealUserWallet 处理给用户金额
func DealUserWallet(session *xorm.Session, req md.DealUserWalletReq) (err error) {
if req.Amount < 0 {
req.Amount = 0
}
//1、分布式锁阻拦
requestIdPrefix := fmt.Sprintf(md.UserWalletRedisKey, req.Uid)
cb, err := svc.HandleDistributedLockForUserWallet(zhios_order_relate_utils.Int64ToStr(req.Uid), requestIdPrefix)
if err != nil {
return err
}
if cb != nil {
defer cb() // 释放锁
}

//2、计算&&组装数据
now := time.Now()
userAmount, err := GetUserWalletAmount(session, req.Uid)
if err != nil {
return err
}
amountValue := decimal.NewFromFloat(req.Amount).RoundFloor(4)

var userWalletFlow model.UserWalletFlow
userWalletFlow.Uid = req.Uid
userWalletFlow.Title = req.Title
userWalletFlow.Kind = req.Kind
userWalletFlow.BeforeAmount = userAmount
userWalletFlow.Amount = amountValue.String()
userWalletFlow.CreateAt = now.Format("2006-01-02 15:04:05")

if req.Direction == "add" {
userWalletFlow.Direction = 1
userWalletFlow.AfterAmount = amountValue.Add(amountValue).RoundFloor(8).String()
} else if req.Direction == "sub" {
userWalletFlow.Direction = 2
userWalletFlow.AfterAmount = amountValue.Sub(amountValue).RoundFloor(8).String()
if zhios_order_relate_utils.StrToFloat64(userWalletFlow.AfterAmount) < 0 {
return errors.New("用户钱包余额不足")
}
} else {
err = errors.New("错误的Direction类型")
return err
}

//3、插入 `user_wallet_flow` 记录
userWalletFlowDb := implement.NewUserWalletFlowDb(session.Engine())
_, err = userWalletFlowDb.UserWalletFlowInsertBySession(session, &userWalletFlow)
if err != nil {
return err
}

//4、修改 `user_wallet`的amount值 && 及缓存
err = SetUserWalletAmount(session, userWalletFlow.AfterAmount, req.Uid, true)
if err != nil {
return err
}

return nil
}

// GetUserWalletAmount 获取用户钱包余额
func GetUserWalletAmount(session *xorm.Session, uid int64) (amount string, err error) {
redisKey := fmt.Sprintf(md.UserWalletRedisKey, uid)
amount, err = cache.GetString(redisKey)
if err != nil {
if err.Error() == "redigo: nil returned" {
userWalletDb := implement.NewUserWalletDb(session.Engine())
userVirtualAmount, err := userWalletDb.GetUserVirtualWallet(uid)
if err != nil {
return amount, err
}
if userVirtualAmount == nil {
amount = "0"
} else {
amount = userVirtualAmount.Amount
}
//将获取到的余额值缓存至redis
_ = SetUserWalletAmount(session, amount, uid, false)
return amount, nil
}
return amount, err
}
return amount, nil
}

// SetUserWalletAmount 设置缓存的用户虚拟币积分余额
func SetUserWalletAmount(session *xorm.Session, amount string, uid int64, isUpdateDb bool) error {
redisKey := fmt.Sprintf(md.UserWalletRedisKey, uid)
if isUpdateDb {
_, err := session.Where("uid=?", uid).Update(model.UserWallet{
Uid: uid,
Amount: amount,
})
if err != nil {
return err
}
}
//TODO::默认缓存1小时 (先调整为 20 min)
_, err := cache.SetEx(redisKey, zhios_order_relate_utils.StrToFloat64(amount), 60*20)
if err != nil {
return err
}
return nil
}

+ 19
- 2
svc/svc_user_virtual_amount_redis_mutex_lock.go View File

@@ -66,9 +66,9 @@ func GetDistributedLockRequestId(prefix string) string {
return prefix + zhios_order_relate_utils.IntToStr(rand.Intn(100000000))
}

// HandleDistributedLock 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁
// HandleDistributedLock 处理虚拟币更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁
func HandleDistributedLock(uid, coinId, requestIdPrefix string) (cb func(), err error) {
// 获取余额更新锁
// 获取虚拟币更新锁
balanceLockKey := fmt.Sprintf(md.UserVirtualAmountUpdateLock, uid, coinId)
requestId := GetDistributedLockRequestId(requestIdPrefix)
balanceLockOk := TryGetDistributedLock(balanceLockKey, requestId, true)
@@ -82,3 +82,20 @@ func HandleDistributedLock(uid, coinId, requestIdPrefix string) (cb func(), err

return cb, nil
}

// HandleDistributedLockForUserWallet 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁
func HandleDistributedLockForUserWallet(uid, requestIdPrefix string) (cb func(), err error) {
// 获取虚拟币更新锁
balanceLockKey := fmt.Sprintf(md.UserFinValidUpdateLock, uid)
requestId := GetDistributedLockRequestId(requestIdPrefix)
balanceLockOk := TryGetDistributedLock(balanceLockKey, requestId, true)
if !balanceLockOk {
return nil, errors.New("系统繁忙,请稍后再试")
}

cb = func() {
_, _ = ReleaseDistributedLock(balanceLockKey, requestId)
}

return cb, nil
}

Loading…
Cancel
Save