package containers import ( "joybuywork/internal/app" "joybuywork/internal/consts" "joybuywork/internal/repository/cache" "joybuywork/internal/repository/dao" "joybuywork/internal/repository/model" "joybuywork/internal/repository/mtype" "joybuywork/internal/service/provider/players" "joybuywork/internal/service/provider/pusher" "joybuywork/internal/utils/logic" "fmt" "strconv" "strings" "sync" "time" "github.com/panjf2000/ants/v2" "gorm.io/gen" ) const ( faultTolerance = 900 ) type PushNotify struct { logic.Logic data map[int64]string } func (s *PushNotify) Run() error { return logic.Run(s) } func (s *PushNotify) Exec() (err error) { m := dao.FissionCampaign list, err := m.WithContext(s.Ctx).Where( m.StartTime.Gt(0), m.StartTime.Lte(time.Now().Unix()), m.Status.In(mtype.FissionCampaignStatusPub, mtype.FissionCampaignStatusPubPre), m.IsDel.Eq(mtype.No), ).Find() if err != nil { err = s.BE().MysqlError(err) return } if len(list) == 0 { return } wg := sync.WaitGroup{} defer wg.Wait() gp, _ := ants.NewPool(10) defer gp.Release() for _, v := range list { wg.Add(1) _ = gp.Submit(func() { defer wg.Done() defer app.TryCatch(s.Ctx, fmt.Sprintf("活动奖品补偿失败:cpnid:%d", v.ID)) pushM := dao.FissionCampaignPush pushs, err2 := pushM.WithContext(s.Ctx).Where(pushM.CampaignID.Eq(v.ID), pushM.Open.Eq(mtype.Yes)).Find() if err2 != nil { err = err2 return } if len(pushs) == 0 { return } for _, push := range pushs { switch push.Mark { case mtype.FissionCampaignPushMarkTaskReset: for _, cond := range push.GetCond() { err = s.taskReset(v, cond) if err != nil { return } } case mtype.FissionCampaignPushMarkOffline: for _, cond := range push.GetCond() { err = s.offline(v, cond) if err != nil { return } } case mtype.FissionCampaignPushMarkActive: for _, cond := range push.GetCond() { err = s.active(v, cond) if err != nil { return } } } } }) } return } // 日活 func (s *PushNotify) active(cpn *model.FissionCampaign, cond *mtype.PushCond) (err error) { hour, markCode, codeVal := s._getHourCond(cond) t := s._minTime().Add(-time.Duration(hour) * time.Hour) push, err := pusher.NewPusher(s.Ctx, cpn) if err != nil { return } m := dao.FissionUserActive var list []*model.FissionUserActive err = m.WithContext(s.Ctx). Where( m.CampaignID.Eq(cpn.ID), m.LastActive.Lte(t.Unix()), m.LastActive.Gt(t.Unix()-faultTolerance), ). FindInBatches(&list, 200, func(tx gen.Dao, batch int) error { var userLines []*pusher.UserLine for _, v := range list { userLines = append(userLines, &pusher.UserLine{ Id: v.UserID, DoneAt: v.LastActive, }) } return push.Active(t, markCode, codeVal, userLines) }) return } // 任务重制 func (s *PushNotify) taskReset(cpn *model.FissionCampaign, cond *mtype.PushCond) (err error) { switch cpn.FissionID { case consts.IdCash: return s._cashReset(cpn, cond) case consts.IdGold: return s._goldReset(cpn, cond) } return } func (s *PushNotify) _cashReset(cpn *model.FissionCampaign, cond *mtype.PushCond) (err error) { hour, markCode, codeVal := s._getHourCond(cond) t := s._minTime().Add(time.Duration(hour) * time.Hour) push, err := pusher.NewPusher(s.Ctx, cpn) if err != nil { return } m := dao.FissionCash var list []*model.FissionCash err = m.WithContext(s.Ctx). Where( m.CampaignID.Eq(cpn.ID), m.ExpiredIn.Lte(t.Unix()), m.ExpiredIn.Gt(t.Unix()-faultTolerance), ). FindInBatches(&list, 200, func(tx gen.Dao, batch int) error { var userLines []*pusher.UserLine for _, v := range list { userLines = append(userLines, &pusher.UserLine{ Id: v.UserID, DoneAt: v.ExpiredIn, }) } return push.TaskRest(t, markCode, codeVal, userLines) }) if err != nil { return } return } func (s *PushNotify) _goldReset(cpn *model.FissionCampaign, cond *mtype.PushCond) (err error) { hour, markCode, codeVal := s._getHourCond(cond) t := s._minTime().Add(time.Duration(hour) * time.Hour) push, err := pusher.NewPusher(s.Ctx, cpn) if err != nil { return } m := dao.FissionGold var list []*model.FissionGold err = m.WithContext(s.Ctx). Where( m.CampaignID.Eq(cpn.ID), m.ExpiredIn.Lte(t.Unix()), m.ExpiredIn.Gt(t.Unix()-faultTolerance), ). FindInBatches(&list, 200, func(tx gen.Dao, batch int) error { var userLines []*pusher.UserLine for _, v := range list { userLines = append(userLines, &pusher.UserLine{ Id: v.UserID, DoneAt: v.ExpiredIn, }) } return push.TaskRest(t, markCode, codeVal, userLines) }) if err != nil { return } return } // 离线 func (s *PushNotify) offline(cpn *model.FissionCampaign, cond *mtype.PushCond) (err error) { switch cpn.FissionID { case consts.IdKeep: return s._keepOffline(cpn, cond) } return } func (s *PushNotify) _keepOffline(cpn *model.FissionCampaign, cond *mtype.PushCond) (err error) { keep, err := cache.NewCampaignKeep(s.Ctx).FindByCampaignId(cpn.ID) if err != nil { err = s.BE().CacheError(err) return } if keep == nil || keep.MachineType != mtype.FissionCampaignKeepMachineTypeOffline { return } minute, markCode, codeVal := s._getMinCond(cond) tm := keep.OfflineMin + int32(minute) t := s._minTime().Add(-(time.Duration(tm)) * time.Minute) push, err := pusher.NewPusher(s.Ctx, cpn) if err != nil { return } m := dao.FissionKeep var list []*model.FissionKeep err = m.WithContext(s.Ctx). Where( m.CampaignID.Eq(cpn.ID), m.RewardID.Gt(0), m.RecordID.Eq(0), m.ReceiveOffline.Lte(t.Unix()), m.ReceiveOffline.Gt(t.Unix()-faultTolerance), ). FindInBatches(&list, 200, func(tx gen.Dao, batch int) error { var userLines []*pusher.UserLine var userIds []int64 for _, v := range list { userIds = append(userIds, v.UserID) } userM := s.GetDao().FissionUser users, _ := userM.WithContext(s.Ctx).Where(userM.ID.In(userIds...)).Find() var playerMap = make(map[int64]*players.KeepDog, len(users)) for _, user := range users { playerMap[user.ID], _ = players.NewKeepDog(s.Ctx, user, players.SetCpn(cpn)) } for _, v := range list { player, ok := playerMap[v.UserID] if !ok { continue } if ok, _ = player.OfflineLimit(); ok { continue } userLines = append(userLines, &pusher.UserLine{ Id: v.UserID, DoneAt: v.ReceiveOffline, }) } return push.Offline(t, markCode, codeVal, userLines) }) if err != nil { return } return } func (s *PushNotify) _getHourCond(cond *mtype.PushCond) (hour int, markCode, codeVal string) { if cond.Mark == "custom" { hour, _ = strconv.Atoi(cond.Val) } else { day := cond.Mark[strings.LastIndex(cond.Mark, "_")+1:] dayi, _ := strconv.Atoi(day) hour = dayi * 24 } return hour, cond.Mark, cond.Val } func (s *PushNotify) _getMinCond(cond *mtype.PushCond) (min int, markCode, codeVal string) { if cond.Mark == "custom" { min, _ = strconv.Atoi(cond.Val) } else { hour := cond.Mark[strings.LastIndex(cond.Mark, "_")+1:] houri, _ := strconv.Atoi(hour) min = houri * 60 } return min, cond.Mark, cond.Val } func (s *PushNotify) _minTime() time.Time { t, _ := time.ParseInLocation("2006-01-02 15:04", time.Now().Format("2006-01-02 15:04"), time.Local) return t }