@@ -17,9 +17,6 @@ func AddOrderJackpot(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { | |||
var data = &model.DayLuckDrawOrderJackpot{ | |||
Oid: req.Oid, | |||
Pvd: req.Pvd, | |||
Amount: req.Amount, | |||
Commission: req.Commission, | |||
Reward: req.Reward, | |||
Uid: zhios_day_luck_draw_utils.StrToInt(req.Uid), | |||
CreateTime: time.Now(), | |||
} | |||
@@ -33,18 +30,6 @@ func AddOrderJackpot(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { | |||
return nil | |||
} | |||
/*** | |||
1.创建期数 | |||
2.获取还没分配的金额 就是 期数为0的 | |||
3.把期数设置到订单 | |||
4.查出所有订单号 | |||
5.随机出订单号(每个名额随机一次 如果重复再次循环) 先按一等奖分 | |||
*/ | |||
func GetAllOrderSum(sess *xorm.Session) float64 { | |||
sum, _ := sess.Where("period=0").Sum(&model.DayLuckDrawOrderJackpot{}, "reward") | |||
return sum | |||
} | |||
func GetAllOrderOid(sess *xorm.Session) []string { | |||
sql := `SELECT oid,uid FROM day_luck_draw_order_jackpot where period=0;` | |||
data, _ := QueryNativeStringSess(sess, sql) | |||
@@ -8,11 +8,12 @@ import ( | |||
"xorm.io/xorm" | |||
) | |||
func AddPeriod(sess *xorm.Session, req md.DayLuckDrawPeriodReq) bool { | |||
func AddPeriod(sess *xorm.Session, req md.DayLuckDrawPeriodReq, base string) bool { | |||
var data = &model.DayLuckDrawPeriod{ | |||
Reward: req.Reward, | |||
CreateTime: time.Now(), | |||
Period: zhios_day_luck_draw_utils.StrToInt(req.Period), | |||
Base: base, | |||
} | |||
insert, err := sess.Insert(data) | |||
if insert == 0 || err != nil { | |||
@@ -9,8 +9,8 @@ import ( | |||
"xorm.io/xorm" | |||
) | |||
func AddPeriodReward(eg *xorm.Engine, req md.DayLuckDrawRewardReq) error { | |||
count, _ := eg.Where("uid=? and period=?", req.Uid, req.Period).Count(&model.DayLuckDrawPeriodReward{}) | |||
func AddPeriodReward(sess *xorm.Session, req md.DayLuckDrawRewardReq) error { | |||
count, _ := sess.Where("uid=? and period=?", req.Uid, req.Period).Count(&model.DayLuckDrawPeriodReward{}) | |||
if count > 0 { | |||
return nil | |||
} | |||
@@ -21,7 +21,7 @@ func AddPeriodReward(eg *xorm.Engine, req md.DayLuckDrawRewardReq) error { | |||
Period: zhios_day_luck_draw_utils.StrToInt(req.Period), | |||
Lv: zhios_day_luck_draw_utils.StrToInt(req.Lv), | |||
} | |||
one, err := eg.InsertOne(data) | |||
one, err := sess.Insert(data) | |||
if one == 0 { | |||
return errors.New("失败") | |||
} | |||
@@ -2,6 +2,8 @@ package db | |||
import ( | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" | |||
zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | |||
"time" | |||
"xorm.io/xorm" | |||
) | |||
@@ -19,6 +21,23 @@ func GetDayLuckDrawSetting(eg *xorm.Engine) *model.DayLuckDrawSetting { | |||
} | |||
return &data | |||
} | |||
func CheckSetting(eg *xorm.Engine, pvd string) bool { | |||
setting := GetDayLuckDrawSetting(eg) | |||
if setting == nil { | |||
return false | |||
} | |||
now := time.Now().Unix() | |||
if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() { | |||
return false | |||
} | |||
if now < setting.StartTime.Unix() || now > setting.EndTime.Unix() { | |||
return false | |||
} | |||
if setting.OrderSoruce == "mall" && pvd != "" && zhios_day_luck_draw_utils.InArr(pvd, []string{"mall_goods", "mall_group_buy", "mall_goods_user_lv", "super_group_buy", "mall_supply", "mall_group_own_buy"}) == false { | |||
return false | |||
} | |||
return true | |||
} | |||
func GetDayLuckDrawSettingSess(sess *xorm.Session) *model.DayLuckDrawSetting { | |||
var data model.DayLuckDrawSetting | |||
get, err := sess.Get(&data) | |||
@@ -0,0 +1,38 @@ | |||
package db | |||
import ( | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | |||
zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | |||
"errors" | |||
"time" | |||
"xorm.io/xorm" | |||
) | |||
func GetSettleAllOrderSum(sess *xorm.Session) float64 { | |||
sum, _ := sess.Where("is_send=0").Sum(&model.DayLuckDrawSettleOrder{}, "commission") | |||
return sum | |||
} | |||
func AddSettle(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { | |||
count, _ := eg.Where("oid=? and uid=? and pvd=?", req.Oid, req.Uid, req.Pvd).Count(&model.DayLuckDrawSettleOrder{}) | |||
if count > 0 { | |||
return nil | |||
} | |||
var data = &model.DayLuckDrawSettleOrder{ | |||
Oid: req.Oid, | |||
Pvd: req.Pvd, | |||
Amount: req.Amount, | |||
Commission: req.Commission, | |||
Uid: zhios_day_luck_draw_utils.StrToInt(req.Uid), | |||
CreateTime: time.Now(), | |||
} | |||
one, err := eg.InsertOne(data) | |||
if one == 0 { | |||
return errors.New("失败") | |||
} | |||
if err != nil { | |||
return err | |||
} | |||
return nil | |||
} |
@@ -14,3 +14,12 @@ func UserFindByMobile(Db *xorm.Engine, mobile string) (*model.User, error) { | |||
} | |||
return &m, nil | |||
} | |||
func UserProfileFindByIDWithSession(sess *xorm.Session, id interface{}) (*model.UserProfile, error) { | |||
var m model.UserProfile | |||
if has, err := sess.Where("uid = ?", id). | |||
Get(&m); err != nil || has == false { | |||
return nil, err | |||
} | |||
return &m, nil | |||
} |
@@ -8,9 +8,6 @@ type DayLuckDrawOrderJackpot struct { | |||
Id int `json:"id" xorm:"not null pk autoincr INT(11)"` | |||
Oid string `json:"oid" xorm:"index unique(oid_pvd) VARCHAR(255)"` | |||
Pvd string `json:"pvd" xorm:"unique(oid_pvd) index VARCHAR(255)"` | |||
Amount string `json:"amount" xorm:"DECIMAL(11,6)"` | |||
Commission string `json:"commission" xorm:"DECIMAL(11,6)"` | |||
Reward string `json:"reward" xorm:"DECIMAL(11,6)"` | |||
Uid int `json:"uid" xorm:"index INT(11)"` | |||
CreateTime time.Time `json:"create_time" xorm:"DATETIME"` | |||
Period int `json:"period" xorm:"default 0 INT(11)"` | |||
@@ -7,6 +7,7 @@ import ( | |||
type DayLuckDrawPeriod struct { | |||
Id int `json:"id" xorm:"not null pk autoincr INT(11)"` | |||
Reward string `json:"reward" xorm:"VARCHAR(255)"` | |||
Base string `json:"base" xorm:"TEXT"` | |||
CreateTime time.Time `json:"create_time" xorm:"DATETIME"` | |||
Period int `json:"period" xorm:"default 0 INT(11)"` | |||
} |
@@ -0,0 +1,16 @@ | |||
package model | |||
import ( | |||
"time" | |||
) | |||
type DayLuckDrawSettleOrder struct { | |||
Id int `json:"id" xorm:"not null pk autoincr INT(11)"` | |||
Oid string `json:"oid" xorm:"index unique(oid_pvd) VARCHAR(255)"` | |||
Pvd string `json:"pvd" xorm:"unique(oid_pvd) index VARCHAR(255)"` | |||
Amount string `json:"amount" xorm:"DECIMAL(11,6)"` | |||
Commission string `json:"commission" xorm:"DECIMAL(11,6)"` | |||
Uid int `json:"uid" xorm:"index INT(11)"` | |||
CreateTime time.Time `json:"create_time" xorm:"DATETIME"` | |||
IsSend int `json:"is_send" xorm:"default 0 INT(11)"` | |||
} |
@@ -0,0 +1,29 @@ | |||
package model | |||
import ( | |||
"time" | |||
) | |||
type FinUserFlow struct { | |||
Id int64 `json:"id" xorm:"pk autoincr comment('流水编号') BIGINT(20)"` | |||
Uid int `json:"uid" xorm:"not null default 0 comment('用户id') INT(11)"` | |||
Type int `json:"type" xorm:"not null default 0 comment('0收入,1支出') TINYINT(1)"` | |||
Amount string `json:"amount" xorm:"not null default 0.0000 comment('变动金额') DECIMAL(11,4)"` | |||
BeforeAmount string `json:"before_amount" xorm:"not null default 0.0000 comment('变动前金额') DECIMAL(11,4)"` | |||
AfterAmount string `json:"after_amount" xorm:"not null default 0.0000 comment('变动后金额') DECIMAL(11,4)"` | |||
SysFee string `json:"sys_fee" xorm:"not null default 0.0000 comment('手续费') DECIMAL(11,4)"` | |||
PaymentType int `json:"payment_type" xorm:"not null default 1 comment('1支付宝,2微信.3手动转账') TINYINT(1)"` | |||
OrdType string `json:"ord_type" xorm:"not null default '' comment('订单类型taobao,jd,pdd,vip,suning,kaola,own自营,withdraw提现') VARCHAR(20)"` | |||
OrdId string `json:"ord_id" xorm:"not null default '' comment('对应订单编号') VARCHAR(50)"` | |||
OrdTitle string `json:"ord_title" xorm:"not null default '' comment('订单标题') VARCHAR(50)"` | |||
OrdAction int `json:"ord_action" xorm:"not null default 0 comment('10自购,11推广,12团队,20提现,21消费') TINYINT(2)"` | |||
OrdTime int `json:"ord_time" xorm:"not null default 0 comment('下单时间or提现时间') INT(11)"` | |||
OrdDetail string `json:"ord_detail" xorm:"not null default '' comment('记录商品ID或提现账号') VARCHAR(50)"` | |||
ExpectedTime string `json:"expected_time" xorm:"not null default '0' comment('预期到账时间,字符串用于直接显示,结算后清除内容') VARCHAR(30)"` | |||
State int `json:"state" xorm:"not null default 1 comment('1未到账,2已到账') TINYINT(1)"` | |||
Memo string `json:"memo" xorm:"not null default '' comment('备注') VARCHAR(2000)"` | |||
OtherId int64 `json:"other_id" xorm:"not null default 0 comment('其他关联订单,具体根据订单类型判断') BIGINT(20)"` | |||
AliOrdId string `json:"ali_ord_id" xorm:"default '' comment('支付宝订单号') VARCHAR(128)"` | |||
CreateAt time.Time `json:"create_at" xorm:"created not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` | |||
UpdateAt time.Time `json:"update_at" xorm:"updated not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` | |||
} |
@@ -0,0 +1,91 @@ | |||
package model | |||
import ( | |||
"time" | |||
) | |||
type UserProfile struct { | |||
Uid int `json:"uid" xorm:"not null pk comment('关联userID') INT(20)"` | |||
ArkidUid int `json:"arkid_uid" xorm:"not null default 0 comment('Arkid 用户ID') INT(20)"` | |||
ParentUid int `json:"parent_uid" xorm:"not null default 0 comment('上级ID') INT(20)"` | |||
ArkidToken string `json:"arkid_token" xorm:"not null default '' comment('token') VARCHAR(2000)"` | |||
AvatarUrl string `json:"avatar_url" xorm:"not null default '' comment('头像URL') VARCHAR(2000)"` | |||
CustomInviteCode string `json:"custom_invite_code" xorm:"not null default '' comment('邀请码(自定义)') VARCHAR(16)"` | |||
InviteCode string `json:"invite_code" xorm:"not null default '' comment('邀请码(系统)') VARCHAR(16)"` | |||
Gender int `json:"gender" xorm:"not null default 2 comment('性别0女,1男,2未知') TINYINT(1)"` | |||
Birthday int `json:"birthday" xorm:"not null default 0 comment('出生日期') INT(10)"` | |||
AccWxId string `json:"acc_wx_id" xorm:"not null default '' comment('账户_微信id') VARCHAR(50)"` | |||
AccWxOpenid string `json:"acc_wx_openid" xorm:"not null default '' comment('账户_微信openid') VARCHAR(80)"` | |||
AccTaobaoNickname string `json:"acc_taobao_nickname" xorm:"not null default '' comment('淘宝昵称') VARCHAR(50)"` | |||
AccTaobaoAuthTime int64 `json:"acc_taobao_auth_time" xorm:"not null default 0 comment('淘宝授权备案时间') BIGINT(11)"` | |||
AccTaobaoShareId int64 `json:"acc_taobao_share_id" xorm:"not null default 0 comment('淘宝分享relationId,') index BIGINT(12)"` | |||
AccTaobaoSelfId int64 `json:"acc_taobao_self_id" xorm:"not null default 0 comment('淘宝自购specialId') index BIGINT(12)"` | |||
AccJdSelfId string `json:"acc_jd_self_id" xorm:"not null default '' comment('京东自购ID') index VARCHAR(50)"` | |||
AccJdShareId string `json:"acc_jd_share_id" xorm:"not null default '' comment('京东分享ID') index VARCHAR(50)"` | |||
AccJdFreeId string `json:"acc_jd_free_id" xorm:"not null default '' comment('京东新人免单ID') VARCHAR(50)"` | |||
AccSuningSelfId string `json:"acc_suning_self_id" xorm:"not null default '' comment('苏宁自购ID') index VARCHAR(50)"` | |||
AccSuningShareId string `json:"acc_suning_share_id" xorm:"not null default '' comment('苏宁分享ID') index VARCHAR(50)"` | |||
AccSuningFreeId string `json:"acc_suning_free_id" xorm:"not null default '' comment('苏宁新人免单ID') VARCHAR(50)"` | |||
AccPddSelfId string `json:"acc_pdd_self_id" xorm:"not null default '' comment('拼多多自购ID') index VARCHAR(50)"` | |||
AccPddShareId string `json:"acc_pdd_share_id" xorm:"not null default '' comment('拼多多分享ID') index VARCHAR(50)"` | |||
AccPddFreeId string `json:"acc_pdd_free_id" xorm:"not null default '' comment('拼多多新人免单ID') VARCHAR(50)"` | |||
AccPddBind int `json:"acc_pdd_bind" xorm:"not null default 0 comment('拼多多是否授权绑定') TINYINT(1)"` | |||
AccVipSelfId string `json:"acc_vip_self_id" xorm:"not null default '' comment('唯品会自购ID') index VARCHAR(50)"` | |||
AccVipShareId string `json:"acc_vip_share_id" xorm:"not null default '' comment('唯品会分享ID') index VARCHAR(50)"` | |||
AccVipFreeId string `json:"acc_vip_free_id" xorm:"not null default '' comment('唯品会新人免单ID') VARCHAR(50)"` | |||
AccKaolaSelfId string `json:"acc_kaola_self_id" xorm:"not null default '' comment('考拉自购ID') index VARCHAR(50)"` | |||
AccKaolaShareId string `json:"acc_kaola_share_id" xorm:"not null default '' comment('考拉分享ID') index VARCHAR(50)"` | |||
AccKaolaFreeId string `json:"acc_kaola_free_id" xorm:"not null default '' comment('考拉新人免单ID') VARCHAR(50)"` | |||
AccDuomaiShareId int64 `json:"acc_duomai_share_id" xorm:"not null pk default 0 comment('多麦联盟分享ID') BIGINT(12)"` | |||
AccAlipay string `json:"acc_alipay" xorm:"not null default '' comment('支付宝账号') VARCHAR(50)"` | |||
AccAlipayRealName string `json:"acc_alipay_real_name" xorm:"not null default '' comment('支付宝账号真实姓名') VARCHAR(50)"` | |||
CertTime int `json:"cert_time" xorm:"not null default 0 comment('认证时间') INT(10)"` | |||
CertName string `json:"cert_name" xorm:"not null default '' comment('证件上名字,也是真实姓名') VARCHAR(50)"` | |||
CertNum string `json:"cert_num" xorm:"not null default '' comment('证件号码') VARCHAR(50)"` | |||
CertState int `json:"cert_state" xorm:"not null default 0 comment('认证状态(0为未认证,1为认证中,2为已认证,3为认证失败)') TINYINT(1)"` | |||
FinCommission string `json:"fin_commission" xorm:"not null default 0.0000 comment('累计佣金') DECIMAL(10,4)"` | |||
FinValid string `json:"fin_valid" xorm:"not null default 0.0000 comment('可用余额,fin=>finance财务') DECIMAL(10,4)"` | |||
FinInvalid string `json:"fin_invalid" xorm:"not null default 0.0000 comment('不可用余额,冻结余额') DECIMAL(10,4)"` | |||
FinSelfOrderCount int `json:"fin_self_order_count" xorm:"not null default 0 comment('自购订单数,包括未完成') INT(11)"` | |||
FinSelfOrderCountDone int `json:"fin_self_order_count_done" xorm:"not null default 0 comment('自购已完成订单') INT(11)"` | |||
FinSelfRebate float32 `json:"fin_self_rebate" xorm:"not null default 0.000000 comment('累积自购获得返利金额') FLOAT(14,6)"` | |||
FinTotal float32 `json:"fin_total" xorm:"not null default 0.000000 comment('累计总收益') FLOAT(14,6)"` | |||
Lat float32 `json:"lat" xorm:"not null default 0.000000 comment('纬度') FLOAT(15,6)"` | |||
Lng float32 `json:"lng" xorm:"not null default 0.000000 comment('经度') FLOAT(15,6)"` | |||
Memo string `json:"memo" xorm:"not null default '' comment('用户简述备注') VARCHAR(2048)"` | |||
IsNew int `json:"is_new" xorm:"not null default 1 comment('是否是新用户') TINYINT(1)"` | |||
IsVerify int `json:"is_verify" xorm:"not null default 0 comment('是否有效会员') TINYINT(1)"` | |||
IsOrdered int `json:"is_ordered" xorm:"not null default 0 comment('是否已完成首单(0否,1是)') TINYINT(1)"` | |||
FromWay string `json:"from_way" xorm:"not null default '' comment('注册来源: | |||
no_captcha_phone:免验证码手机号注册; | |||
manual_phone:手动手机验证码注册; | |||
wx:微信授权; | |||
wx_mp:小程序授权; | |||
wx_pub:公众号授权; | |||
wx_bind_phone:微信注册绑定手机号; | |||
admin:管理员添加;taobao_bind_phone:淘宝注册绑定手机号,apple_bind_phone:苹果注册绑定手机号') VARCHAR(16)"` | |||
HidOrder int `json:"hid_order" xorm:"not null default 0 comment('隐藏订单') TINYINT(3)"` | |||
HidContact int `json:"hid_contact" xorm:"not null default 0 comment('隐藏联系方式') TINYINT(4)"` | |||
NewMsgNotice int `json:"new_msg_notice" xorm:"not null default 1 comment('新消息通知') TINYINT(1)"` | |||
WxAccount string `json:"wx_account" xorm:"not null default '' comment('微信号') VARCHAR(100)"` | |||
WxQrcode string `json:"wx_qrcode" xorm:"not null default '' comment('微信二维码') VARCHAR(100)"` | |||
ThirdPartyTaobaoOid string `json:"third_party_taobao_oid" xorm:"not null default '' comment('淘宝第三方登录openID') VARCHAR(100)"` | |||
ThirdPartyTaobaoSid string `json:"third_party_taobao_sid" xorm:"not null default '' comment('淘宝第三方登录sID') VARCHAR(255)"` | |||
ThirdPartyTaobaoAcctoken string `json:"third_party_taobao_acctoken" xorm:"not null default '' comment('淘宝第三方登录topaccesstoken') VARCHAR(100)"` | |||
ThirdPartyTaobaoAuthcode string `json:"third_party_taobao_authcode" xorm:"not null default '' comment('淘宝第三方登录topAuthCode') VARCHAR(100)"` | |||
ThirdPartyAppleToken string `json:"third_party_apple_token" xorm:"not null default '' comment('苹果第三方登录token') VARCHAR(1024)"` | |||
ThirdPartyQqAccessToken string `json:"third_party_qq_access_token" xorm:"not null default '' comment('QQ第三方登录access_token') VARCHAR(255)"` | |||
ThirdPartyQqExpiresIn string `json:"third_party_qq_expires_in" xorm:"not null default '' comment('QQ第三方登录expires_in(剩余时长)') VARCHAR(255)"` | |||
ThirdPartyQqOpenid string `json:"third_party_qq_openid" xorm:"not null default '' comment('QQ第三方登陆openid(不变,用于认证)') VARCHAR(255)"` | |||
ThirdPartyQqUnionid string `json:"third_party_qq_unionid" xorm:"not null default '' comment('QQ第三方登陆unionid') VARCHAR(255)"` | |||
ThirdPartyWechatExpiresIn string `json:"third_party_wechat_expires_in" xorm:"not null default '' comment('微信第三方登录expires_in(剩余时长)') VARCHAR(255)"` | |||
ThirdPartyWechatOpenid string `json:"third_party_wechat_openid" xorm:"not null default '' comment('微信第三方登陆openid(不变,用于认证)') VARCHAR(255)"` | |||
ThirdPartyWechatUnionid string `json:"third_party_wechat_unionid" xorm:"not null default '' comment('微信第三方登陆unionid') VARCHAR(255)"` | |||
ThirdPartyWechatMiniOpenid string `json:"third_party_wechat_mini_openid" xorm:"not null default '' comment('微信小程序登录open_id') VARCHAR(255)"` | |||
ThirdPartyWechatH5Openid string `json:"third_party_wechat_h5_openid" xorm:"not null default '' comment('微信H5登录open_id') VARCHAR(255)"` | |||
FreeRemainTime int `json:"free_remain_time" xorm:"not null default 0 comment('免单剩余次数') INT(11)"` | |||
FreeCumulativeTime int `json:"free_cumulative_time" xorm:"not null default 0 comment('免单累计次数') INT(11)"` | |||
IsDelete int `json:"is_delete" xorm:"not null default 0 comment('是否已删除') TINYINT(1)"` | |||
UpdateAt time.Time `json:"update_at" xorm:"updated not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` | |||
SignDay int `json:"sign_day" xorm:"not null default 0 comment('签到天数') INT(11)"` | |||
} |
@@ -9,4 +9,5 @@ require ( | |||
go.uber.org/zap v1.13.0 | |||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 | |||
xorm.io/xorm v1.3.1 | |||
github.com/shopspring/decimal v1.3.1 | |||
) |
@@ -0,0 +1,20 @@ | |||
package md | |||
// 缓存key统一管理, %s格式化为masterId | |||
const ( | |||
AppCfgCacheKey = "%s:cfg_cache:%s" // 占位符: masterId, key的第一个字母 | |||
VirtualCoinCfgCacheKey = "%s:virtual_coin_cfg" | |||
PlanRewardCfgCacheKey = "%s:plan_reward_cfg" | |||
UnionSetCacheCfg = "%s:union_set_cfg:%s" // 联盟设置缓存key | |||
UserFinValidUpdateLock = "%s:user_fin_valid_update_lock:%s" // 用户余额更新锁(能拿到锁才能更新余额) | |||
UserVirtualAmountUpdateLock = "%s:user_virtual_amount_update_lock:%s" // 用户虚拟币更新锁(能拿到锁才能更新余额) | |||
WithdrawApplyQueueListKey = "withdraw_apply_queue" // 提现队列 | |||
TplBottomNavRedisKey = "%s:tpl_nav_bottom_key:%s" // master_id platform | |||
SysModByIdRedisKey = "%s:sys_mod_tpl_by_id:%s" | |||
CfgCacheTime = 86400 | |||
) |
@@ -4,4 +4,5 @@ type RewardData struct { | |||
Key string `json:"key"` | |||
Bili string `json:"bili"` | |||
Num string `json:"num"` | |||
Probability string `json:"probability"` | |||
} |
@@ -0,0 +1,45 @@ | |||
package md | |||
const ( | |||
FinUserFlowDirectionIncome = 1 //流水 - 收入 | |||
FinUserFlowDirectionExpenditure = 2 //流水 - 支出 | |||
) | |||
const ( | |||
FinUserFlowRedisDataBase = 0 | |||
FinUserFlowRedisKey = "%s:fin_user_flow:%d:user:%d" | |||
) | |||
const ( | |||
IntegralReleaseServiceRevenueTitleForFinUserFlow = "积分释放-服务收益" | |||
IntegralReleaseServiceRevenueRefundTitleForFinUserFlow = "订单退款-服务收益扣除" | |||
) | |||
const ( | |||
IntegralReleaseServiceRevenueOrderTypeForFinUserFlow = 50 // 积分释放-服务收益 | |||
IntegralReleaseServiceRevenueOrderRefundTypeForFinUserFlow = 51 // 积分释放-服务收益退款 | |||
) | |||
const DealUserAmountRequestIdPrefix = "%s:deal_user_amount:%d" | |||
const UserAmountRedisKey = "%s:user_amount:%d" | |||
type DealIntegralReleaseInterpositionUserAmountReq struct { | |||
Kind string `json:"kind"` | |||
Mid string `json:"mid"` | |||
OrdId string `json:"ord_id"` | |||
CoinId int `json:"coin_id"` | |||
Uid int `json:"uid"` | |||
OriginalUid int `json:"original_uid"` | |||
Amount float64 `json:"amount"` | |||
} | |||
type DealUserAmount struct { | |||
Kind string `json:"kind"` | |||
Mid string `json:"mid"` | |||
Title string `json:"title"` | |||
OrderType string `json:"order_type"` | |||
OrdAction int `json:"ord_action"` | |||
OrdId string `json:"ord_id"` | |||
Uid int `json:"uid"` | |||
Amount float64 `json:"amount"` | |||
} |
@@ -3,21 +3,12 @@ package svc | |||
import ( | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | |||
zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | |||
"time" | |||
"xorm.io/xorm" | |||
) | |||
func AddOrderJackpot(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { | |||
setting := db.GetDayLuckDrawSetting(eg) | |||
if setting == nil { | |||
return nil | |||
} | |||
now := time.Now().Unix() | |||
if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() || (now > setting.StartTime.Unix() && now < setting.EndTime.Unix()) { | |||
return nil | |||
} | |||
if setting.OrderSoruce == "mall" && zhios_day_luck_draw_utils.InArr(req.Pvd, []string{"mall_goods", "mall_group_buy", "mall_goods_user_lv", "super_group_buy", "mall_supply", "mall_group_own_buy"}) == false { | |||
setting := db.CheckSetting(eg, req.Pvd) | |||
if setting == false { | |||
return nil | |||
} | |||
err := db.AddOrderJackpot(eg, req) | |||
@@ -2,14 +2,27 @@ package svc | |||
import ( | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | |||
zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils/cache" | |||
"encoding/json" | |||
"errors" | |||
"fmt" | |||
"github.com/shopspring/decimal" | |||
"math/rand" | |||
"time" | |||
"xorm.io/xorm" | |||
) | |||
func InitForDayLuckDraw(redisAddr string) (err error) { | |||
if redisAddr != "" { | |||
cache.NewRedis(redisAddr) | |||
} | |||
_, err = cache.SelectDb(0) | |||
return | |||
} | |||
//随机几个用户 | |||
func RandUser(sess *xorm.Session) []string { | |||
var newOid = make([]string, 0) | |||
@@ -19,7 +32,10 @@ func RandUser(sess *xorm.Session) []string { | |||
return newOid | |||
} | |||
now := time.Now().Unix() | |||
if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() || (now > setting.StartTime.Unix() && now < setting.EndTime.Unix()) { | |||
if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() { | |||
return newOid | |||
} | |||
if now < setting.StartTime.Unix() || now > setting.EndTime.Unix() { | |||
return newOid | |||
} | |||
count := 0 | |||
@@ -38,6 +54,224 @@ func RandUser(sess *xorm.Session) []string { | |||
return newOid | |||
} | |||
/*** | |||
1.创建期数 | |||
2.获取还没分配的金额 就是 期数为0的 | |||
3.把期数设置到订单 | |||
4.查出所有订单号 | |||
5.随机出订单号(每个名额随机一次 如果重复再次循环) 按概率分几等奖 | |||
*/ | |||
func GetUserReward(eg *xorm.Engine, mid string, isTask bool) error { | |||
// 加锁 防止频繁操作 | |||
mutexKey := fmt.Sprintf("%s:day_lucky_raw_settle", mid) | |||
operationSumAvailable, err := cache.Do("SET", mutexKey, 1, "EX", 3600, "NX") | |||
if err != nil { | |||
return err | |||
} | |||
defer cache.Del(mutexKey) | |||
if operationSumAvailable != "OK" { | |||
return errors.New("上一次未运行完成") | |||
} | |||
sess := eg.NewSession() | |||
defer func() { | |||
sess.Close() | |||
if err := recover(); err != nil { | |||
fmt.Println(err) | |||
} | |||
}() | |||
sess.Begin() | |||
key := fmt.Sprintf("%s:day_lucky_draw_bingo_rate_calculate", mid) | |||
isDone, _ := cache.GetString(key) | |||
if isDone == "" || isDone == "0" { | |||
SetAllAwardsProbability(sess, mid) | |||
} | |||
probabilityMap := make([]map[int]int64, 0) | |||
key = fmt.Sprintf("%s:day_lucky_draw_rotary_bingo_rate", mid) | |||
err = cache.GetJson(key, &probabilityMap) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
setting := db.GetDayLuckDrawSettingSess(sess) | |||
var rewardData = make([]md.RewardData, 0) | |||
err = json.Unmarshal([]byte(setting.RewardData), &rewardData) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
now := time.Now().Unix() | |||
if isTask { | |||
if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() { | |||
return errors.New("未开始") | |||
} | |||
if now < setting.StartTime.Unix() || now > setting.EndTime.Unix() { | |||
return errors.New("未开始") | |||
} | |||
if setting.OpenTime.IsZero() { | |||
return errors.New("没抽奖时间") | |||
} | |||
if now < setting.OpenTime.Unix() { | |||
return errors.New("没到时间") | |||
} | |||
} | |||
if setting.Source == "" { | |||
return errors.New("未选择奖励池数据类型") | |||
} | |||
//设置期数 | |||
max := db.GetPeriodMax(sess) | |||
sum := db.GetSettleAllOrderSum(sess) | |||
if setting.Source == "amount" { | |||
sum = zhios_day_luck_draw_utils.StrToFloat64(setting.Amount) | |||
} else { | |||
sum = sum * zhios_day_luck_draw_utils.StrToFloat64(setting.CommissionBili) / 100 | |||
} | |||
if sum == 0 { //没金额中断了 | |||
setting.OpenTime = time.Unix(now+int64(setting.CycleDay)*86400, 0) | |||
update, err := sess.Where("id=?", setting.Id).Cols("open_time").Update(setting) | |||
if err != nil || update == 0 { | |||
sess.Rollback() | |||
return errors.New("失败") | |||
} | |||
sess.Commit() | |||
return errors.New("没金额") | |||
} | |||
period := 1 | |||
if max != nil { | |||
period = max.Period + 1 | |||
} | |||
req := md.DayLuckDrawPeriodReq{ | |||
Reward: zhios_day_luck_draw_utils.Float64ToStrByPrec(sum, 7), | |||
Period: zhios_day_luck_draw_utils.IntToStr(period), | |||
} | |||
settingStr, _ := json.Marshal(setting) | |||
bools := db.AddPeriod(sess, req, string(settingStr)) | |||
if bools == false { | |||
return errors.New("期数写入错误") | |||
} | |||
rewardDataMap := make(map[int64]int, 0) | |||
for _, v := range rewardData { | |||
rewardDataMap[zhios_day_luck_draw_utils.StrToInt64(v.Key)] = zhios_day_luck_draw_utils.StrToInt(v.Num) | |||
} | |||
uids := RandUser(sess) | |||
var award = make(map[string]int64) | |||
var awardIdMap = make(map[int64]int) | |||
for _, v := range uids { | |||
for i := 0; i < 10; i++ { | |||
key := AwardRandomNumberFor100000() | |||
awardId := int64(0) | |||
for _, awardProbabilityMap := range probabilityMap { | |||
id, ok := awardProbabilityMap[key] | |||
if ok { | |||
awardId = id | |||
} else { | |||
continue | |||
} | |||
} | |||
if awardId == 0 || award[v] > 0 { | |||
continue | |||
} | |||
//查下已产生用户数量 | |||
awardCount, ok := awardIdMap[awardId] | |||
//查下总数量 | |||
rewardDataCount, ok := rewardDataMap[awardId] | |||
if ok == false { | |||
continue | |||
} | |||
if ok { | |||
if awardCount+1 > rewardDataCount { | |||
continue | |||
} | |||
} | |||
if rewardDataCount == 0 { | |||
continue | |||
} | |||
awardIdMap[awardId] = awardCount + 1 | |||
award[v] = awardId | |||
} | |||
} | |||
//处理奖励 | |||
var awardMap = make(map[int64][]string) | |||
for k, v := range award { | |||
awardMap[v] = append(awardMap[v], k) | |||
} | |||
for _, v := range rewardData { | |||
uid, ok := awardMap[zhios_day_luck_draw_utils.StrToInt64(v.Key)] | |||
if ok { | |||
err := SendReward(sess, uid, mid, period, sum, v) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
} | |||
} | |||
setting.OpenTime = time.Unix(now+int64(setting.CycleDay)*86400, 0) | |||
update, err := sess.Where("id=?", setting.Id).Cols("open_time").Update(setting) | |||
if err != nil || update == 0 { | |||
sess.Rollback() | |||
return errors.New("失败") | |||
} | |||
update1, err1 := sess.Where("is_send=0").Cols("is_send").Update(&model.DayLuckDrawSettleOrder{IsSend: 1}) | |||
if err1 != nil || update1 == 0 { | |||
sess.Rollback() | |||
return errors.New("失败") | |||
} | |||
update2, err2 := sess.Where("period=0").Cols("period").Update(&model.DayLuckDrawOrderJackpot{Period: period}) | |||
if err2 != nil || update2 == 0 { | |||
sess.Rollback() | |||
return errors.New("失败") | |||
} | |||
sess.Commit() | |||
return nil | |||
} | |||
func SendReward(sess *xorm.Session, uid []string, mid string, period int, sum float64, rewardData md.RewardData) error { | |||
count := len(uid) | |||
if count == 0 { | |||
return nil | |||
} | |||
bili := zhios_day_luck_draw_utils.StrToFloat64(rewardData.Bili) | |||
if bili == 0 { | |||
return nil | |||
} | |||
amount := sum * bili / float64(count) | |||
for _, v := range uid { | |||
var req = md.DayLuckDrawRewardReq{ | |||
Uid: v, | |||
Period: zhios_day_luck_draw_utils.IntToStr(period), | |||
Reward: zhios_day_luck_draw_utils.Float64ToStrByPrec(amount, 7), | |||
Lv: rewardData.Key, | |||
} | |||
err := db.AddPeriodReward(sess, req) | |||
if err != nil { | |||
return err | |||
} | |||
var dealUserAmount = md.DealUserAmount{ | |||
Kind: "add", | |||
Mid: mid, | |||
Title: "每日抽奖奖励", | |||
OrderType: "", | |||
OrdAction: 85, | |||
OrdId: "", | |||
Uid: zhios_day_luck_draw_utils.StrToInt(v), | |||
Amount: amount, | |||
} | |||
err = DealUserAmount(sess, dealUserAmount) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
return nil | |||
} | |||
func AwardRandomNumberFor100000() int { | |||
rand.Seed(time.Now().UnixNano()) | |||
num := rand.Intn(100000) | |||
return num | |||
} | |||
func MicsSlice(origin []string, count int) []string { | |||
tmpOrigin := make([]string, len(origin)) | |||
copy(tmpOrigin, origin) | |||
@@ -47,12 +281,99 @@ func MicsSlice(origin []string, count int) []string { | |||
tmpOrigin[i], tmpOrigin[j] = tmpOrigin[j], tmpOrigin[i] | |||
}) | |||
result := make([]string, 0, count) | |||
for index, value := range tmpOrigin { | |||
if index == count { | |||
result := make([]string, 0) | |||
for _, value := range tmpOrigin { | |||
if len(result) == count { | |||
break | |||
} | |||
if zhios_day_luck_draw_utils.InArr(value, result) { | |||
continue | |||
} | |||
result = append(result, value) | |||
} | |||
return result | |||
} | |||
func SetAllAwardsProbability(sess *xorm.Session, mid string) error { | |||
defer func() { | |||
//处理异常错误 | |||
if r := recover(); r != nil { | |||
fmt.Println(r) | |||
} | |||
}() | |||
setting := db.GetDayLuckDrawSettingSess(sess) | |||
var rewardData = make([]md.RewardData, 0) | |||
err := json.Unmarshal([]byte(setting.RewardData), &rewardData) | |||
if err != nil { | |||
key := fmt.Sprintf("%s:day_lucky_draw_bingo_rate_calculate", mid) | |||
_, err = cache.SetEx(key, "0", 39528000) // 半年 | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
//建立协程池 | |||
workerCount := 0 | |||
ProbabilityKeyChan := make(chan int, 100000) | |||
awardsMapChan := make(chan map[int]int64, len(rewardData)) | |||
doneChan := make(chan bool, len(rewardData)) | |||
for i := 0; i < 10; i++ { | |||
go func(endNum int) { | |||
for startNum := (endNum * 10000) + 1; startNum <= (endNum+1)*10000; startNum++ { | |||
ProbabilityKeyChan <- startNum | |||
} | |||
if i == 9 { | |||
close(ProbabilityKeyChan) | |||
} | |||
}(i) | |||
} | |||
for _, award := range rewardData { | |||
probabilityD, err := decimal.NewFromString(award.Num) | |||
if err != nil { | |||
probabilityD = decimal.NewFromInt(0) | |||
} | |||
probabilityD = probabilityD.Div(decimal.NewFromInt(100)) | |||
probability, _ := probabilityD.Float64() | |||
go CalculateAwardsProbability(zhios_day_luck_draw_utils.StrToInt64(award.Key), probability, ProbabilityKeyChan, awardsMapChan, doneChan) | |||
workerCount++ | |||
} | |||
probabilityMap := make([]map[int]int64, 0) | |||
WaitChain(workerCount, awardsMapChan, doneChan) | |||
for awards := range awardsMapChan { | |||
probabilityMap = append(probabilityMap, awards) | |||
} | |||
key := fmt.Sprintf("%s:day_lucky_draw_rotary_bingo_rate", mid) | |||
_, err = cache.SetEx(key, zhios_day_luck_draw_utils.SerializeStr(probabilityMap), 39528000) // 半年 | |||
if err != nil { | |||
return err | |||
} | |||
key = fmt.Sprintf("%s:day_lucky_draw_bingo_rate_calculate", mid) | |||
_, err = cache.SetEx(key, "1", 39528000) // 半年 | |||
if err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
func CalculateAwardsProbability(awardsId int64, probability float64, ProbabilityKeyChan chan int, awardsMapChan chan map[int]int64, doneChan chan bool) { | |||
//计算要循环多少次 | |||
var awardsMap = make(map[int]int64) | |||
for i := 0; i < int(100000*probability); i++ { | |||
key := <-ProbabilityKeyChan | |||
awardsMap[key] = awardsId | |||
} | |||
awardsMapChan <- awardsMap | |||
doneChan <- true | |||
} | |||
func WaitChain(workerCount int, awardsMapChan chan map[int]int64, doneChan chan bool) { | |||
for { | |||
select { | |||
case <-doneChan: | |||
workerCount-- | |||
if workerCount == 0 { | |||
close(awardsMapChan) | |||
return | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,19 @@ | |||
package svc | |||
import ( | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | |||
"xorm.io/xorm" | |||
) | |||
func AddSettleOrder(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { | |||
setting := db.CheckSetting(eg, req.Pvd) | |||
if setting == false { | |||
return nil | |||
} | |||
err := db.AddSettle(eg, req) | |||
if err != nil { | |||
return err | |||
} | |||
return nil | |||
} |
@@ -0,0 +1,126 @@ | |||
package svc | |||
import ( | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | |||
zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils/cache" | |||
"errors" | |||
"fmt" | |||
"github.com/shopspring/decimal" | |||
"strconv" | |||
"time" | |||
"xorm.io/xorm" | |||
) | |||
// DealUserAmount 处理给用户余额 | |||
func DealUserAmount(session *xorm.Session, req md.DealUserAmount) (err error) { | |||
if req.Amount < 0 { | |||
req.Amount = 0 | |||
} | |||
//1、分布式锁阻拦 | |||
requestIdPrefix := fmt.Sprintf(md.DealUserAmountRequestIdPrefix, req.Mid, req.Uid) | |||
cb, err := HandleBalanceDistributedLockForAmount(req.Mid, strconv.Itoa(req.Uid), requestIdPrefix) | |||
if err != nil { | |||
return err | |||
} | |||
if cb != nil { | |||
defer cb() // 释放锁 | |||
} | |||
//2、计算&&组装数据 | |||
now := time.Now() | |||
userAmount, err := GetUserAmount(session, req.Mid, req.Uid) | |||
if err != nil { | |||
return err | |||
} | |||
userAmountValue := decimal.NewFromFloat(zhios_day_luck_draw_utils.StrToFloat64(userAmount)) | |||
amountValue := decimal.NewFromFloat(req.Amount).RoundFloor(8) | |||
var finUserFlow = model.FinUserFlow{ | |||
Uid: req.Uid, | |||
Amount: amountValue.String(), | |||
BeforeAmount: userAmount, | |||
OrdType: req.OrderType, | |||
OrdId: req.OrdId, | |||
OrdTitle: req.Title, | |||
OrdAction: req.OrdAction, | |||
OrdTime: int(now.Unix()), | |||
State: 1, | |||
CreateAt: now, | |||
UpdateAt: now, | |||
} | |||
if req.Kind == "add" { | |||
finUserFlow.Type = 0 | |||
finUserFlow.AfterAmount = userAmountValue.Add(amountValue).RoundFloor(8).String() | |||
} else if req.Kind == "sub" { | |||
finUserFlow.Type = 1 | |||
finUserFlow.AfterAmount = userAmountValue.Sub(amountValue).RoundFloor(8).String() | |||
} else { | |||
err = errors.New("错误的kind类型") | |||
return err | |||
} | |||
if zhios_day_luck_draw_utils.StrToFloat64(finUserFlow.AfterAmount) < 0 { | |||
return errors.New("用户余额不足") | |||
} | |||
//3、插入 `user_virtual_coin_flow` 记录 | |||
affected, err := session.Insert(&finUserFlow) | |||
if affected == 0 || err != nil { | |||
return err | |||
} | |||
//4、修改 `user_profile`的fin_valid值 && 及缓存 | |||
err = SetCacheUserAmount(session, req.Mid, finUserFlow.AfterAmount, req.Uid, true) | |||
if err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
// GetUserAmount 获取用户余额 | |||
func GetUserAmount(session *xorm.Session, masterId string, uid int) (amount string, err error) { | |||
redisKey := fmt.Sprintf(md.UserAmountRedisKey, masterId, uid) | |||
amount, err = cache.GetString(redisKey) | |||
if err != nil { | |||
if err.Error() == "redigo: nil returned" { | |||
userAmount, err := db.UserProfileFindByIDWithSession(session, uid) | |||
if err != nil { | |||
return amount, err | |||
} | |||
if userAmount == nil { | |||
amount = "0" | |||
} else { | |||
amount = userAmount.FinValid | |||
} | |||
//将获取到的余额值缓存至redis | |||
_ = SetCacheUserAmount(session, masterId, amount, uid, false) | |||
return amount, nil | |||
} | |||
return amount, err | |||
} | |||
return amount, nil | |||
} | |||
// SetCacheUserAmount 设置缓存的用户余额 | |||
func SetCacheUserAmount(session *xorm.Session, masterId, amount string, uid int, isUpdateDb bool) error { | |||
redisKey := fmt.Sprintf(md.UserAmountRedisKey, masterId, uid) | |||
if isUpdateDb { | |||
_, err := session.Where("uid=?", uid).Update(model.UserProfile{ | |||
Uid: uid, | |||
FinValid: amount, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
//_, err := cache.Set(redisKey, int64(utils.StrToFloat64(amount))) | |||
//TODO::默认缓存1小时 (先调整为 2 min) | |||
_, err := cache.SetEx(redisKey, zhios_day_luck_draw_utils.StrToFloat64(amount), 60*2) | |||
if err != nil { | |||
return err | |||
} | |||
return nil | |||
} |
@@ -0,0 +1,84 @@ | |||
package svc | |||
import ( | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | |||
zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils/cache" | |||
"errors" | |||
"fmt" | |||
"math/rand" | |||
"reflect" | |||
"time" | |||
) | |||
const redisMutexLockExpTime = 15 | |||
// TryGetDistributedLock 分布式锁获取 | |||
// requestId 用于标识请求客户端,可以是随机字符串,需确保唯一 | |||
func TryGetDistributedLock(lockKey, requestId string, isNegative bool) bool { | |||
if isNegative { // 多次尝试获取 | |||
retry := 1 | |||
for { | |||
ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX") | |||
// 获取锁成功 | |||
if err == nil && ok == "OK" { | |||
return true | |||
} | |||
// 尝试多次没获取成功 | |||
if retry > 10 { | |||
return false | |||
} | |||
time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000))) | |||
retry += 1 | |||
} | |||
} else { // 只尝试一次 | |||
ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX") | |||
// 获取锁成功 | |||
if err == nil && ok == "OK" { | |||
return true | |||
} | |||
return false | |||
} | |||
} | |||
// ReleaseDistributedLock 释放锁,通过比较requestId,用于确保客户端只释放自己的锁,使用lua脚本保证操作的原子型 | |||
func ReleaseDistributedLock(lockKey, requestId string) (bool, error) { | |||
luaScript := ` | |||
if redis.call("get",KEYS[1]) == ARGV[1] | |||
then | |||
return redis.call("del",KEYS[1]) | |||
else | |||
return 0 | |||
end` | |||
do, err := cache.Do("eval", luaScript, 1, lockKey, requestId) | |||
fmt.Println(reflect.TypeOf(do)) | |||
fmt.Println(do) | |||
if zhios_day_luck_draw_utils.AnyToInt64(do) == 1 { | |||
return true, err | |||
} else { | |||
return false, err | |||
} | |||
} | |||
func GetDistributedLockRequestId(prefix string) string { | |||
return prefix + zhios_day_luck_draw_utils.IntToStr(rand.Intn(100000000)) | |||
} | |||
// HandleDistributedLock 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁 | |||
func HandleDistributedLock(masterId, uid, requestIdPrefix string) (cb func(), err error) { | |||
// 获取余额更新锁 | |||
balanceLockKey := fmt.Sprintf(md.UserVirtualAmountUpdateLock, masterId, uid) | |||
requestId := GetDistributedLockRequestId(requestIdPrefix) | |||
balanceLockOk := TryGetDistributedLock(balanceLockKey, requestId, true) | |||
if !balanceLockOk { | |||
return nil, errors.New("系统繁忙,请稍后再试") | |||
} | |||
cb = func() { | |||
_, _ = ReleaseDistributedLock(balanceLockKey, requestId) | |||
} | |||
return cb, nil | |||
} |
@@ -0,0 +1,24 @@ | |||
package svc | |||
import ( | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | |||
"errors" | |||
"fmt" | |||
) | |||
// HandleBalanceDistributedLockForAmount 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁 | |||
func HandleBalanceDistributedLockForAmount(masterId, uid, requestIdPrefix string) (cb func(), err error) { | |||
// 获取余额更新锁 | |||
balanceLockKey := fmt.Sprintf(md.UserFinValidUpdateLock, masterId, uid) | |||
requestId := GetDistributedLockRequestId(requestIdPrefix) | |||
balanceLockOk := TryGetDistributedLock(balanceLockKey, requestId, true) | |||
if !balanceLockOk { | |||
return nil, errors.New("系统繁忙,请稍后再试") | |||
} | |||
cb = func() { | |||
_, _ = ReleaseDistributedLock(balanceLockKey, requestId) | |||
} | |||
return cb, nil | |||
} |