活动模块,计划任务模块 加入第三方

This commit is contained in:
ayflying
2025-02-28 12:12:03 +08:00
parent 6d2b68a202
commit e9540d0971
103 changed files with 4258 additions and 74 deletions

View File

@@ -0,0 +1,266 @@
package gameAct
import (
"fmt"
"github.com/ayflying/utility_go/aycache"
"github.com/ayflying/utility_go/internal/game/act"
"github.com/ayflying/utility_go/internal/model/do"
"github.com/ayflying/utility_go/internal/model/entity"
"github.com/ayflying/utility_go/service2"
"github.com/ayflying/utility_go/tools"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
"strconv"
"strings"
"time"
)
var (
ctx = gctx.New()
Name = "game_act"
ActList = gset.New(true)
)
type sGameAct struct {
}
func new() *sGameAct {
return &sGameAct{}
}
func init() {
service2.RegisterGameAct(new())
}
// Info 获取活动信息
//
// @Description: 根据用户ID和活动ID获取活动信息
// @receiver s *sGameAct: 代表活动操作的结构体实例
// @param uid int64: 用户ID
// @param actId int: 活动ID
// @return data *v1.Act: 返回活动信息结构体指针
// @return err error: 返回错误信息
func (s *sGameAct) Info(uid int64, actId int) (data *g.Var, err error) {
if uid == 0 || actId == 0 {
g.Log().Error(ctx, "当前参数为空")
return
}
// 构造缓存键名
keyCache := fmt.Sprintf("act:%v:%v", actId, uid)
// 尝试从Redis缓存中获取活动信息
get, err := g.Redis().Get(ctx, keyCache)
if !get.IsEmpty() {
// 如果缓存中存在将数据扫描到data结构体中并返回
data = get
return
}
// 从数据库中查询活动信息
getDb, err := g.Model(Name).Where(do.GameAct{
Uid: uid,
ActId: actId,
}).Fields("action").OrderDesc("updated_at").Value()
getDb.Scan(&data)
if data == nil || data.IsEmpty() {
return
}
// 将查询到的活动信息保存到Redis缓存中
_, err = g.Redis().Set(ctx, keyCache, data)
var ActUidUpdateTimeCacheKey = fmt.Sprintf("act:update:%d", uid)
aycache.New("redis").Set(ctx, ActUidUpdateTimeCacheKey, uid, time.Hour*24*3)
return
}
// Set 将指定用户的活动信息存储到Redis缓存中。
//
// @Description:
// @receiver s *sGameAct: 表示sGameAct类型的实例。
// @param uid int64: 用户的唯一标识。
// @param actId int: 活动的唯一标识。
// @param data interface{}: 要存储的活动信息数据。
// @return err error: 返回错误信息如果操作成功则返回nil。
func (s *sGameAct) Set(uid int64, actId int, data interface{}) (err error) {
if uid == 0 || actId == 0 {
g.Log().Error(ctx, "当前参数为空")
return
}
// 构造缓存键名
keyCache := fmt.Sprintf("act:%v:%v", actId, uid)
if data == nil {
_, err = g.Redis().Del(ctx, keyCache)
return
}
// 将活动信息保存到Redis缓存并将用户ID添加到活动索引集合中
_, err = g.Redis().Set(ctx, keyCache, data)
//插入集合
ActList.Add(actId)
return
}
func (s *sGameAct) Saves() (err error) {
//遍历执行
ActList.Iterator(func(i interface{}) bool {
err = s.Save(i.(int))
return true
})
return
}
func (s *sGameAct) Save(actId int) (err error) {
cacheKey := fmt.Sprintf("act:%v:*", actId)
//获取当前用户的key值
//keys, err := utils.RedisScan(cacheKey)
//if len(keys) > 10000 {
// keys = keys[:10000]
//}
//循环获取缓存数据
err = tools.Redis.RedisScanV2(cacheKey, func(keys []string) (err error) {
var add []interface{}
var delKey []string
for _, cacheKey = range keys {
result := strings.Split(cacheKey, ":")
actId, err = strconv.Atoi(result[1])
var uid int64
uid, err = strconv.ParseInt(result[2], 10, 64)
if err != nil {
continue
}
cacheGet, _ := g.Redis().Get(ctx, cacheKey)
//最后删除key
delKey = append(delKey, cacheKey)
if uid == 0 {
//跳过为空的用户缓存
continue
}
if cacheGet.IsEmpty() {
//空数据也不巴保存
continue
}
var ActUidUpdateTimeCacheKey = fmt.Sprintf("act:update:%d", uid)
//如果有活跃,跳过持久化
if getBool, _ := aycache.New("redis").Contains(ctx, ActUidUpdateTimeCacheKey); getBool {
continue
}
////如果1天没有活跃跳过
//user, _ := service.MemberUser().Info(uid)
//if user.UpdatedAt.Seconds < gtime.Now().Add(consts.ActSaveTime).Unix() {
// continue
//}
//获取数据库数据
var data *entity.GameAct
// 从数据库中查询活动信息
err = g.Model(Name).Where(do.GameAct{
Uid: uid,
ActId: actId,
}).Fields("uid,act_id").Scan(&data)
if err != nil {
g.Log().Debugf(ctx, "当前数据错误: %v", cacheKey)
continue
}
actionData := cacheGet.String()
if data == nil {
//data =
add = append(add, &do.GameAct{
ActId: actId,
Uid: uid,
Action: actionData,
})
} else {
//覆盖数据
data.Action = actionData
add = append(add, data)
}
}
//批量写入数据库
if len(add) > 0 {
dbRes, err2 := g.Model(Name).Batch(30).Data(add).Save()
add = make([]interface{}, 0)
if err2 != nil {
g.Log().Error(ctx, err2)
return
}
for _, v := range delKey {
_, err2 = g.Redis().Del(ctx, v)
if err2 != nil {
g.Log().Error(ctx, err2)
return
}
}
delKey = make([]string, 0)
count, _ := dbRes.RowsAffected()
g.Log().Debugf(ctx, "当前 %v 写入数据库: %v 条", actId, count)
}
if err != nil {
g.Log().Error(ctx, "当前临时数据入库失败: %v", err)
}
return err
})
return
}
// 清空GetRedDot缓存
func (s *sGameAct) RefreshGetRedDotCache(uid int64) {
//cacheKey2 := fmt.Sprintf("gameAct:GetRedDot:%d", uid)
cacheKey := fmt.Sprintf("gameAct:GetRedDot:%s:%d", gtime.Now().Format("Ymd"), uid)
act.Cache.Remove(gctx.New(), cacheKey)
}
//
//func (s *sGameAct) GetRedDot(uid int64) (res map[string]int32, err error) {
// cacheKey := fmt.Sprintf("gameAct:GetRedDot:%s:%d", gtime.Now().Format("Ymd"), uid)
// if get, _ := act.Cache.Get(ctx, cacheKey); !get.IsEmpty() {
// err = get.Scan(&res)
// return
// }
//
// res = make(map[string]int32)
//
// //res["notice_count"] = 0
// //获取所有帖子红点
// for _, v := range communityNotice.Types {
// res[fmt.Sprintf("notice_%d", v)], err = service.CommunityNotice().Ping(uid, noticeV1.NoticeType(v))
// }
//
// //邮件红点
// res["mail_count"], err = service.GameMail().RedDot(uid)
//
// //act1可领取数量
// res["act1_count"], err = act1.New().RedDot(uid)
//
// //act2可领取数量
// res["act2_count"], err = act2.New().RedDot(uid)
//
// //成就红点
// res["act4_count"], err = act4.New().RedDot(uid)
//
// //广告点击
// res["act6_count"], err = act6.New().RedDot(uid)
//
// for k, v := range act.RedDotList {
// res[k] = v(uid)
// }
//
// aycache.New().Set(ctx, cacheKey, res, time.Hour)
// return
//}

10
internal/logic/logic.go Normal file
View File

@@ -0,0 +1,10 @@
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package logic
import (
_ "github.com/ayflying/utility_go/internal/logic/gameAct"
_ "github.com/ayflying/utility_go/internal/logic/systemCron"
)

View File

@@ -0,0 +1,71 @@
package systemCron
import (
"encoding/json"
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/gclient"
"github.com/gogf/gf/v2/os/gtime"
)
type Status struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
Status int `json:"status"`
} `json:"data"`
}
func (s *sSystemCron) Guardian(DingTalkWebHook string) {
var list []struct {
Name string
Address string
}
cfg, _ := g.Cfg().Get(ctx, "serverList")
cfg.Scan(&list)
for _, v := range list {
get, err := g.Client().Discovery(nil).Get(ctx, v.Address+"/callback/status")
defer get.Close()
if err != nil {
s.DingTalk(DingTalkWebHook, fmt.Sprintf("监控报警:服务端访问失败 (%v 服务器),err=%v", v.Name, err))
} else if get.StatusCode != 200 {
s.DingTalk(DingTalkWebHook, fmt.Sprintf("监控报警:服务端访问失败 (%v 服务器),code=%v,err=%v", v.Name, get.StatusCode, err))
} else {
var ststus Status
err = json.Unmarshal(get.ReadAll(), &ststus)
if ststus.Code != 0 {
s.DingTalk(DingTalkWebHook, fmt.Sprintf("监控报警:服务端访问失败 (%v 服务器),msg=%v", v.Name, ststus.Message))
}
}
}
}
// DingTalk 发送钉钉消息
//
// @Description: 向指定的钉钉机器人发送消息。
// @receiver s: 系统定时任务结构体指针。
// @param value: 要发送的消息内容。
func (s *sSystemCron) DingTalk(DingTalkWebHook string, value string) (res *gclient.Response) {
// 从配置中获取发送者名称
name, _ := g.Cfg().Get(ctx, "name")
// 定义钉钉机器人发送消息的URL其中access_token为固定值
url := DingTalkWebHook
url += "&timestamp=" + gtime.Now().TimestampMilliStr()
// 使用goroutine异步发送消息
var post = g.Map{
"msgtype": "text",
"text": g.Map{
"content": "通知姬 " + name.String() + "\n" + value + "\n" + gtime.Now().String(),
},
}
// 构建发送的消息体,包含消息类型和内容
res, err := g.Client().Discovery(nil).ContentJson().Post(ctx, url, post)
if err != nil {
g.Log().Info(ctx, err)
}
return
}

View File

@@ -0,0 +1,5 @@
package systemCron
func (s *sSystemCron) ReadLog() {
}

View File

@@ -0,0 +1,305 @@
package systemCron
import (
"context"
"github.com/ayflying/utility_go/api/system/v1"
"github.com/ayflying/utility_go/service2"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcron"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtimer"
"sync"
"time"
)
var (
ctx = gctx.New()
)
// sSystemCron 结构体定义了系统定时任务的秒计时器。
// 它包含了不同时间周期的任务,如秒、分钟、小时、天、周、月、年以及特定的工作日任务。
type sSystemCron struct {
//互斥锁
Lock sync.Mutex
// 每秒执行的任务
SecondlyTask []func() error
// 每分钟执行的任务
MinutelyTask []func() error
// 每小时执行的任务
HourlyTask []func() error
// 每天执行的任务
DailyTask []func() error
// 每周执行的任务
WeeklyTask []func() error
// 每月执行的任务
MonthlyTask []func() error
// 每年执行的任务
YearlyTask []func() error
// 每周一执行的任务
MondayTask []func() error
// 每周二执行的任务
TuesdayTask []func() error
// 每周三执行的任务
WednesdayTask []func() error
// 每周四执行的任务
ThursdayTask []func() error
// 每周五执行的任务
FridayTask []func() error
// 每周六执行的任务
SaturdayTask []func() error
// 每周日执行的任务
SundayTask []func() error
}
func New() *sSystemCron {
return &sSystemCron{}
}
func init() {
service2.RegisterSystemCron(New())
}
// AddCron 添加一个定时任务到相应的调度列表中。
//
// @Description: 根据指定的类型将函数添加到不同的任务列表中,以供后续执行。
// @receiver s: sSystemCron的实例代表一个调度系统。
// @param typ: 任务的类型,决定该任务将被添加到哪个列表中。对应不同的时间间隔。
// @param _func: 要添加的任务函数该函数执行时应该返回一个error。
func (s *sSystemCron) AddCron(typ v1.CronType, _func func() error) {
//加锁
s.Lock.Lock()
defer s.Lock.Unlock()
switch typ {
case v1.CronType_SECOND:
s.SecondlyTask = append(s.SecondlyTask, _func) // 将函数添加到每秒执行的任务列表中
case v1.CronType_MINUTE:
s.MinutelyTask = append(s.MinutelyTask, _func) // 将函数添加到每分钟执行的任务列表中
case v1.CronType_HOUR:
s.HourlyTask = append(s.HourlyTask, _func) // 将函数添加到每小时执行的任务列表中
case v1.CronType_DAILY:
s.DailyTask = append(s.DailyTask, _func) // 将函数添加到每日执行的任务列表中
case v1.CronType_WEEK:
s.WeeklyTask = append(s.WeeklyTask, _func) // 将函数添加到每周执行的任务列表中
case v1.CronType_MONTH:
s.MonthlyTask = append(s.MonthlyTask, _func) // 将函数添加到每月执行的任务列表中
case v1.CronType_YEAR:
s.YearlyTask = append(s.YearlyTask, _func) // 将函数添加到每年执行的任务列表中
case v1.CronType_MONDAY:
s.MondayTask = append(s.MondayTask, _func) // 将函数添加到每周一执行的任务列表中
case v1.CronType_TUESDAY:
s.TuesdayTask = append(s.TuesdayTask, _func) // 将函数添加到每周二的任务列表中
case v1.CronType_WEDNESDAY:
s.WednesdayTask = append(s.WednesdayTask, _func) // 将函数添加到每周三执行的任务列表中
case v1.CronType_THURSDAY:
s.ThursdayTask = append(s.ThursdayTask, _func) // 将函数添加到每周四执行的任务列表中
case v1.CronType_FRIDAY:
s.FridayTask = append(s.FridayTask, _func) // 将函数添加到每周五执行的任务列表中
case v1.CronType_SATURDAY:
s.SaturdayTask = append(s.SaturdayTask, _func) // 将函数添加到每周六执行的任务列表中
case v1.CronType_SUNDAY:
s.SundayTask = append(s.SundayTask, _func) // 将函数添加到每周日的任务列表中
}
}
// StartCron 开始计划任务执行
//
// @Description:
// @receiver s
// @return err
func (s *sSystemCron) StartCron() (err error) {
g.Log().Debug(ctx, "启动计划任务定时器详情")
//每秒任务
gtimer.SetInterval(ctx, time.Second, func(ctx context.Context) {
//g.Log().Debug(ctx, "每秒定时器")
err = s.secondlyTask()
})
//每分钟任务
_, err = gcron.AddSingleton(ctx, "0 * * * * *", func(ctx context.Context) {
//g.Log().Debug(ctx, "每分钟定时器")
err = s.minutelyTask()
})
//每小时任务
_, err = gcron.AddSingleton(ctx, "0 0 * * * *", func(ctx context.Context) {
g.Log().Debug(ctx, "每小时定时器")
err = s.hourlyTask()
})
//每天任务
_, err = gcron.AddSingleton(ctx, "0 0 0 * * *", func(ctx context.Context) {
g.Log().Debug(ctx, "每日定时器")
err = s.dailyTask()
})
//每周任务
_, err = gcron.AddSingleton(ctx, "0 0 0 * * 1", func(ctx context.Context) {
g.Log().Debug(ctx, "每周一定时器")
err = s.weeklyTask(1)
})
//每周二任务
_, err = gcron.AddSingleton(ctx, "0 0 0 * * 2", func(ctx context.Context) {
g.Log().Debug(ctx, "每周二定时器")
err = s.weeklyTask(2)
})
//周三任务
_, err = gcron.AddSingleton(ctx, "0 0 0 * * 3", func(ctx context.Context) {
g.Log().Debug(ctx, "周三定时器")
err = s.weeklyTask(3)
})
//周四任务
_, err = gcron.AddSingleton(ctx, "0 0 0 * * 4", func(ctx context.Context) {
g.Log().Debug(ctx, "周四定时器")
err = s.weeklyTask(4)
})
//周五任务
_, err = gcron.AddSingleton(ctx, "0 0 0 * * 5", func(ctx context.Context) {
g.Log().Debug(ctx, "周五定时器")
err = s.fridayTask()
})
//周六任务
_, err = gcron.AddSingleton(ctx, "0 0 0 * * 6", func(ctx context.Context) {
g.Log().Debug(ctx, "周六定时器")
err = s.weeklyTask(6)
})
//周日任务
_, err = gcron.AddSingleton(ctx, "0 0 0 * * 0", func(ctx context.Context) {
g.Log().Debug(ctx, "周日定时器")
err = s.weeklyTask(7)
})
//每月任务
_, err = gcron.AddSingleton(ctx, "0 0 0 1 * *", func(ctx context.Context) {
g.Log().Debug(ctx, "每月定时器")
err = s.monthlyTask()
})
_, err = gcron.AddSingleton(ctx, "0 0 0 1 1 *", func(ctx context.Context) {
g.Log().Debug(ctx, "每年定时器")
err = s.monthlyTask()
})
return
}
// 每妙任务
func (s *sSystemCron) secondlyTask() (err error) {
if len(s.SecondlyTask) == 0 {
return
}
for _, _func := range s.SecondlyTask {
err = _func()
if err != nil {
g.Log().Error(ctx, err)
}
}
return
}
// 每分钟任务
func (s *sSystemCron) minutelyTask() (err error) {
if len(s.MinutelyTask) == 0 {
return
}
for _, _func := range s.MinutelyTask {
err = _func()
if err != nil {
g.Log().Error(ctx, err)
}
}
return
}
// 每小时任务
func (s *sSystemCron) hourlyTask() (err error) {
if len(s.HourlyTask) == 0 {
return
}
for _, _func := range s.HourlyTask {
err = _func()
if err != nil {
g.Log().Error(ctx, err)
}
}
return
}
// 每天任务
func (s *sSystemCron) dailyTask() (err error) {
if len(s.DailyTask) == 0 {
return
}
for _, _func := range s.DailyTask {
err = _func()
if err != nil {
g.Log().Error(ctx, err)
}
}
return
}
// 每周任务
func (s *sSystemCron) weeklyTask(day int) (err error) {
var arr []func() error
switch day {
case 1:
arr = s.MondayTask
case 2:
arr = s.TuesdayTask
case 3:
arr = s.WednesdayTask
case 4:
arr = s.ThursdayTask
case 5:
arr = s.FridayTask
case 6:
arr = s.SaturdayTask
case 7:
arr = s.SundayTask
default:
arr = s.WeeklyTask
return
}
if len(arr) == 0 {
return
}
for _, _func := range arr {
err = _func()
if err != nil {
g.Log().Error(ctx, err)
}
}
return
}
// 周五任务
func (s *sSystemCron) fridayTask() (err error) {
if len(s.FridayTask) == 0 {
return
}
for _, _func := range s.FridayTask {
err = _func()
if err != nil {
g.Log().Error(ctx, err)
}
}
return
}
// 每月任务
func (s *sSystemCron) monthlyTask() (err error) {
if len(s.MonthlyTask) == 0 {
return
}
for _, _func := range s.MonthlyTask {
err = _func()
if err != nil {
g.Log().Error(ctx, err)
}
}
return
}