You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
3.3 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package cachecurd
import (
"context"
"joybuywork/internal/app"
"joybuywork/internal/repository/dao"
"joybuywork/internal/repository/model"
"joybuywork/internal/repository/mtype"
"joybuywork/internal/utils/lockdo"
"fmt"
"time"
grds "github.com/go-redis/redis/v8"
"gorm.io/gen"
)
type RankOption func(rank *Ranker)
func SetChildBuild(cpnId int64, childType int8) RankOption {
return func(rank *Ranker) {
rank.build = &RankBuild{
CpnId: cpnId,
ChildType: childType,
}
}
}
func SetRankExp(exp time.Duration) RankOption {
return func(rank *Ranker) {
rank.exp = exp
}
}
type Ranker struct {
ctx context.Context
cli *grds.Client
key string
build *RankBuild
exp time.Duration
}
type RankBuild struct {
CpnId int64
ChildType int8
}
func NewRanker(ctx context.Context, key string, opts ...RankOption) (*Ranker, error) {
rank := &Ranker{
ctx: ctx,
cli: app.Redis.Cache,
key: key,
exp: time.Hour * 24,
}
for _, opt := range opts {
opt(rank)
}
err := rank.Build()
if err != nil {
return nil, err
}
return rank, nil
}
func (s *Ranker) Build() (err error) {
if s.build == nil {
return
}
if s.build.ChildType == mtype.FissionCampaignChildTypeInvite {
return s.invite(s.build)
}
return
}
type RankMember struct {
UserId string
Score float64
}
// GetRank 获取排名数据
func (s *Ranker) GetRank(num int64) (members []*RankMember, err error) {
data, err := s.cli.ZRevRangeWithScores(s.ctx, s.key, 0, num-1).Result()
if err != nil {
return
}
members = make([]*RankMember, len(data))
for i, v := range data {
members[i] = &RankMember{
UserId: fmt.Sprintf("%v", v.Member),
Score: v.Score,
}
}
return
}
// InitMember 初始化一个用户
func (s *Ranker) InitMember(member string, asc int64) (err error) {
return s.SetMembers([]*grds.Z{{
Score: 1 + s.timeAsc(asc),
Member: member,
}})
}
// SetMembers 设置用户
func (s *Ranker) SetMembers(members []*grds.Z) (err error) {
return s.cli.ZAdd(s.ctx, s.key, members...).Err()
}
// GetMemberRank 获取用户当前排名,如果返回9,是第10名的意思
func (s *Ranker) GetMemberRank(member string) (rank int64, err error) {
return s.cli.ZRevRank(s.ctx, s.key, member).Result()
}
// Incr 追加分数
func (s *Ranker) Incr(member string) (err error) {
return s.IncrBy(1, member)
}
// IncrBy 追加特定分数
func (s *Ranker) IncrBy(increment float64, member string) (err error) {
return s.cli.ZIncrBy(s.ctx, s.key, increment, member).Err()
}
// 子活动排行榜初始化
func (s *Ranker) invite(build *RankBuild) (err error) {
return lockdo.ExistDo(s.ctx, s.key, func(exist bool) (err error) {
if exist {
return
}
m := dao.FissionChildUser
var list []*model.FissionChildUser
err = m.WithContext(s.ctx).Where(m.CampaignID.Eq(build.CpnId), m.InviteNum.Gt(0)).FindInBatches(&list, 200, func(tx gen.Dao, batch int) error {
var members = make([]*grds.Z, 0, len(list))
for _, v := range list {
members = append(members, &grds.Z{
Score: float64(v.InviteNum) + s.timeAsc(v.CreatedAt),
Member: fmt.Sprint(v.UserID),
})
}
return s.SetMembers(members)
})
s.setExp()
return
})
}
func (s *Ranker) setExp() {
s.cli.Expire(s.ctx, s.key, s.exp)
}
func (s *Ranker) timeAsc(asc int64) float64 {
return 1 - float64(asc)/1e13
}