所有学习任务创建共享一个state
This commit is contained in:
johlanse 2022-11-06 15:01:22 +08:00
parent 4d7b8586b6
commit 1de1c28652
10 changed files with 146 additions and 124 deletions

View File

@ -35,7 +35,7 @@ func study() *grumble.Command {
Name: "study", Name: "study",
Aliases: []string{"study"}, Aliases: []string{"study"},
Help: "study xxqg", Help: "study xxqg",
LongHelp: "study the xxqg", LongHelp: "对选定序号的用户进行学习",
Args: func(a *grumble.Args) { Args: func(a *grumble.Args) {
a.Int("index", "the index user") a.Int("index", "the index user")
}, },
@ -75,7 +75,7 @@ func addUser() *grumble.Command {
Name: "add user", Name: "add user",
Aliases: []string{"add"}, Aliases: []string{"add"},
Help: "add a user", Help: "add a user",
LongHelp: "add a user", LongHelp: "添加一个用户",
Run: func(c *grumble.Context) error { Run: func(c *grumble.Context) error {
core := &lib.Core{ core := &lib.Core{
Push: push.GetPush(conf.GetConfig()), Push: push.GetPush(conf.GetConfig()),
@ -96,7 +96,7 @@ func getUser() *grumble.Command {
Help: "get all user", Help: "get all user",
LongHelp: "input the user,can get all user", LongHelp: "input the user,can get all user",
HelpGroup: "", HelpGroup: "",
Usage: "get all user", Usage: "获取用户列表",
Run: func(c *grumble.Context) error { Run: func(c *grumble.Context) error {
users, err := model.Query() users, err := model.Query()
if err != nil { if err != nil {

47
lib/lib.go Normal file
View File

@ -0,0 +1,47 @@
package lib
import (
"fmt"
"time"
"github.com/sirupsen/logrus"
"github.com/johlanse/study_xxqg/conf"
"github.com/johlanse/study_xxqg/model"
)
func Study(core2 *Core, u *model.User) {
config := conf.GetConfig()
defer func() {
err := recover()
if err != nil {
logrus.Errorln("学习过程异常")
logrus.Errorln(err)
}
}()
startTime := time.Now()
core2.LearnArticle(u)
core2.LearnVideo(u)
core2.LearnVideo(u)
if config.Model == 2 {
core2.RespondDaily(u, "daily")
} else if config.Model == 3 {
core2.RespondDaily(u, "daily")
core2.RespondDaily(u, "weekly")
core2.RespondDaily(u, "special")
}
endTime := time.Now()
score, err := GetUserScore(u.ToCookies())
if err != nil {
logrus.Errorln("获取成绩失败")
logrus.Debugln(err.Error())
return
}
score, _ = GetUserScore(u.ToCookies())
message := fmt.Sprintf("%v 学习完成,用时%.1f分钟\n%v", u.Nick, endTime.Sub(startTime).Minutes(), FormatScoreShort(score))
core2.Push(u.PushId, "flush", message)
}

33
lib/state/state.go Normal file
View File

@ -0,0 +1,33 @@
package state
import (
"sync"
"github.com/johlanse/study_xxqg/lib"
)
var (
state = sync.Map{}
)
func Add(uid string, core *lib.Core) {
state.Store(uid, core)
}
func IsStudy(uid string) bool {
_, ok := state.Load(uid)
return ok
}
func Delete(uid string) {
state.Delete(uid)
}
func Get(uid string) *lib.Core {
value, _ := state.Load(uid)
return value.(*lib.Core)
}
func Range(fun func(key, value interface{}) bool) {
state.Range(fun)
}

83
main.go
View File

@ -26,6 +26,7 @@ import (
"github.com/johlanse/study_xxqg/cli" "github.com/johlanse/study_xxqg/cli"
"github.com/johlanse/study_xxqg/conf" "github.com/johlanse/study_xxqg/conf"
"github.com/johlanse/study_xxqg/lib/state"
"github.com/johlanse/study_xxqg/utils" "github.com/johlanse/study_xxqg/utils"
// "github.com/johlanse/study_xxqg/gui" // "github.com/johlanse/study_xxqg/gui"
"github.com/johlanse/study_xxqg/lib" "github.com/johlanse/study_xxqg/lib"
@ -211,7 +212,7 @@ func main() {
} }
c2.Run() c2.Run()
} }
inittask() initTask()
model.SetPush(getPush) model.SetPush(getPush)
if now { if now {
do() do()
@ -244,65 +245,53 @@ func do() {
} }
c.Init() c.Init()
defer c.Quit() defer c.Quit()
study(c, newUser) lib.Study(c, newUser)
}(user) }(user)
} }
s := &sync.WaitGroup{} s := &sync.WaitGroup{}
// 如果为定时模式则直接循环所以用户依次运行 // 如果为定时模式则直接循环所以用户依次运行
for _, u := range users { if config.PoolSize == 1 {
core := &lib.Core{ShowBrowser: config.ShowBrowser, Push: getPush} for _, user := range users {
core.Init() if state.IsStudy(user.UID) {
t := &Task{ log.Infoln("检测到该用户已在学习中!")
Core: core, continue
User: u, } else {
wg: s, core := &lib.Core{ShowBrowser: config.ShowBrowser, Push: getPush}
core.Init()
state.Add(user.UID, core)
lib.Study(core, user)
core.Quit()
state.Delete(user.UID)
}
} }
run(t) } else {
s.Add(1) for _, u := range users {
if state.IsStudy(u.UID) {
log.Infoln("检测到该用户已在学习中!")
continue
} else {
core := &lib.Core{ShowBrowser: config.ShowBrowser, Push: getPush}
core.Init()
t := &Task{
Core: core,
User: u,
wg: s,
}
run(t)
s.Add(1)
}
}
s.Wait()
} }
s.Wait()
log.Infoln("定时任务执行完成") log.Infoln("定时任务执行完成")
return return
} }
func study(core2 *lib.Core, u *model.User) {
defer func() {
err := recover()
if err != nil {
log.Errorln("学习过程异常")
log.Errorln(err)
}
}()
startTime := time.Now()
core2.LearnArticle(u)
core2.LearnVideo(u)
core2.LearnVideo(u)
if config.Model == 2 {
core2.RespondDaily(u, "daily")
} else if config.Model == 3 {
core2.RespondDaily(u, "daily")
core2.RespondDaily(u, "weekly")
core2.RespondDaily(u, "special")
}
endTime := time.Now()
score, err := lib.GetUserScore(u.ToCookies())
if err != nil {
log.Errorln("获取成绩失败")
log.Debugln(err.Error())
return
}
score, _ = lib.GetUserScore(u.ToCookies())
message := fmt.Sprintf("%v 学习完成,用时%.1f分钟\n%v", u.Nick, endTime.Sub(startTime).Minutes(), lib.FormatScoreShort(score))
core2.Push(u.PushId, "flush", message)
}
func runBack() { func runBack() {
cmd, err := xdaemon.Background(os.Stdout, false) cmd, err := xdaemon.Background(os.Stdout, false)
if err != nil { if err != nil {

View File

@ -22,6 +22,7 @@ func init() {
log.Errorln("用户数据库打开失败请检查config目录权限") log.Errorln("用户数据库打开失败请检查config目录权限")
log.Panicln(err.Error()) log.Panicln(err.Error())
} }
db.SetMaxOpenConns(1)
_, _ = db.Exec(`create table user _, _ = db.Exec(`create table user
( (
@ -57,6 +58,7 @@ func initQuestionDb() {
log.Errorln("题目数据库打开失败请检查QuestionDB是否存在") log.Errorln("题目数据库打开失败请检查QuestionDB是否存在")
log.Panicln(err.Error()) log.Panicln(err.Error())
} }
db1.SetMaxOpenConns(1)
}) })
} }

View File

@ -12,11 +12,11 @@ import (
"time" "time"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/johlanse/study_xxqg/conf" "github.com/johlanse/study_xxqg/conf"
"github.com/johlanse/study_xxqg/lib" "github.com/johlanse/study_xxqg/lib"
"github.com/johlanse/study_xxqg/lib/state"
"github.com/johlanse/study_xxqg/model" "github.com/johlanse/study_xxqg/model"
"github.com/johlanse/study_xxqg/utils" "github.com/johlanse/study_xxqg/utils"
"github.com/johlanse/study_xxqg/utils/update" "github.com/johlanse/study_xxqg/utils/update"
@ -24,7 +24,6 @@ import (
var ( var (
handles sync.Map handles sync.Map
datas sync.Map
tgPush func(id string, kind string, message string) tgPush func(id string, kind string, message string)
) )
@ -403,10 +402,10 @@ func studyAll(bot *Telegram, from int64, args []string) {
timer := time.After(time.Minute * 30) timer := time.After(time.Minute * 30)
c := make(chan int, 1) c := make(chan int, 1)
go func() { go func() {
u := uuid.New().String()
bot.SendMsg(from, "已创建运行实例:"+u) bot.SendMsg(from, "已创建运行实例:"+user.UID)
datas.Store(u, &core) state.Add(user.UID, &core)
defer datas.Delete(u) defer state.Delete(user.UID)
core.Init() core.Init()
defer core.Quit() defer core.Quit()
core.LearnArticle(user) core.LearnArticle(user)
@ -551,10 +550,9 @@ func study(bot *Telegram, from int64, args []string) {
timer := time.After(time.Minute * 30) timer := time.After(time.Minute * 30)
c := make(chan int, 1) c := make(chan int, 1)
go func() { go func() {
u := uuid.New().String() bot.SendMsg(from, "已创建运行实例:"+user.UID)
bot.SendMsg(from, "已创建运行实例:"+u) state.Add(user.UID, &core)
datas.Store(u, &core) defer state.Delete(user.UID)
defer datas.Delete(u)
core.Init() core.Init()
defer core.Quit() defer core.Quit()
@ -614,14 +612,14 @@ func getScores(bot *Telegram, from int64, args []string) {
func quit(bot *Telegram, from int64, args []string) { func quit(bot *Telegram, from int64, args []string) {
if len(args) < 1 { if len(args) < 1 {
datas.Range(func(key, value interface{}) bool { state.Range(func(key, value interface{}) bool {
bot.SendMsg(from, "已退出运行实例"+key.(string)) bot.SendMsg(from, "已退出运行实例"+key.(string))
core := value.(*lib.Core) core := value.(*lib.Core)
core.Quit() core.Quit()
return true return true
}) })
} else { } else {
datas.Range(func(key, value interface{}) bool { state.Range(func(key, value interface{}) bool {
if key.(string) == args[0] { if key.(string) == args[0] {
core := value.(*lib.Core) core := value.(*lib.Core)
core.Quit() core.Quit()

View File

@ -15,6 +15,7 @@ import (
"github.com/johlanse/study_xxqg/conf" "github.com/johlanse/study_xxqg/conf"
"github.com/johlanse/study_xxqg/lib" "github.com/johlanse/study_xxqg/lib"
"github.com/johlanse/study_xxqg/lib/state"
"github.com/johlanse/study_xxqg/model" "github.com/johlanse/study_xxqg/model"
"github.com/johlanse/study_xxqg/utils" "github.com/johlanse/study_xxqg/utils"
"github.com/johlanse/study_xxqg/utils/update" "github.com/johlanse/study_xxqg/utils/update"
@ -23,7 +24,6 @@ import (
var ( var (
wx *mp.WeiXin wx *mp.WeiXin
lastNonce = "" lastNonce = ""
datas1 sync.Map
wxPush func(id, kind, message string) wxPush func(id, kind, message string)
) )
@ -580,12 +580,11 @@ func handleStartStudy(id string, msg string) {
core.Init() core.Init()
defer core.Quit() defer core.Quit()
for i, user := range users { for i, user := range users {
_, ok := datas1.Load(user.UID) if state.IsStudy(user.UID) {
if ok { log.Infoln("该用户已经在学习中了,跳过学习")
log.Warningln("用户" + user.Nick + "已经在学习中了,跳过该用户")
continue continue
} else { } else {
datas1.Store(user.UID, "") state.Add(user.UID, core)
} }
sendMsg(id, fmt.Sprintf("开始学习第%d个用户用户名%v", i+1, user.Nick)) sendMsg(id, fmt.Sprintf("开始学习第%d个用户用户名%v", i+1, user.Nick))
core.LearnArticle(user) core.LearnArticle(user)
@ -597,7 +596,7 @@ func handleStartStudy(id string, msg string) {
core.RespondDaily(user, "special") core.RespondDaily(user, "special")
} }
datas1.Delete(user.UID) state.Delete(user.UID)
score, _ := lib.GetUserScore(user.ToCookies()) score, _ := lib.GetUserScore(user.ToCookies())
sendMsg(id, fmt.Sprintf("第%d个用户%v学习完成学习积分\n%v", i+1, user.Nick, lib.FormatScore(score))) sendMsg(id, fmt.Sprintf("第%d个用户%v学习完成学习积分\n%v", i+1, user.Nick, lib.FormatScore(score)))
} }

43
run.go
View File

@ -1,14 +1,13 @@
package main package main
import ( import (
"fmt"
"sync" "sync"
"time"
"github.com/panjf2000/ants/v2" "github.com/panjf2000/ants/v2"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/johlanse/study_xxqg/lib" "github.com/johlanse/study_xxqg/lib"
"github.com/johlanse/study_xxqg/lib/state"
"github.com/johlanse/study_xxqg/model" "github.com/johlanse/study_xxqg/model"
) )
@ -26,47 +25,15 @@ func run(task *Task) {
pool.Invoke(task) pool.Invoke(task)
} }
func inittask() { func initTask() {
study := func(core2 *lib.Core, u *model.User) {
defer func() {
err := recover()
if err != nil {
log.Errorln("学习过程异常")
log.Errorln(err)
}
}()
startTime := time.Now()
core2.LearnArticle(u)
core2.LearnVideo(u)
core2.LearnVideo(u)
if config.Model == 2 {
core2.RespondDaily(u, "daily")
} else if config.Model == 3 {
core2.RespondDaily(u, "daily")
core2.RespondDaily(u, "weekly")
core2.RespondDaily(u, "special")
}
endTime := time.Now()
score, err := lib.GetUserScore(u.ToCookies())
if err != nil {
log.Errorln("获取成绩失败")
log.Debugln(err.Error())
return
}
score, _ = lib.GetUserScore(u.ToCookies())
message := fmt.Sprintf("%v 学习完成,用时%.1f分钟\n%v", u.Nick, endTime.Sub(startTime).Minutes(), lib.FormatScoreShort(score))
core2.Push(u.PushId, "flush", message)
}
pool1, err := ants.NewPoolWithFunc(config.PoolSize, func(i2 interface{}) { pool1, err := ants.NewPoolWithFunc(config.PoolSize, func(i2 interface{}) {
task := i2.(*Task) task := i2.(*Task)
log.Infoln("开始执行" + task.User.Nick) log.Infoln("开始执行" + task.User.Nick)
study(task.Core, task.User) state.Add(task.User.UID, task.Core)
lib.Study(task.Core, task.User)
defer task.Core.Quit() defer task.Core.Quit()
defer state.Delete(task.User.UID)
task.wg.Done() task.wg.Done()
}) })
if err != nil { if err != nil {

View File

@ -135,7 +135,7 @@ func Time2Stamp() int64 {
/*时间戳->字符串*/ /*时间戳->字符串*/
func Stamp2Str(stamp int64) string { func Stamp2Str(stamp int64) string {
timeLayout := "2006-01-02 15:04:05" timeLayout := "2006-01-02 15:04:05"
str := time.Unix(stamp/1000, 0).Format(timeLayout) str := time.Unix(stamp, 0).Format(timeLayout)
return str return str
} }

View File

@ -8,7 +8,6 @@ import (
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
"net/url" "net/url"
"sync"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -16,15 +15,12 @@ import (
"github.com/johlanse/study_xxqg/conf" "github.com/johlanse/study_xxqg/conf"
"github.com/johlanse/study_xxqg/lib" "github.com/johlanse/study_xxqg/lib"
"github.com/johlanse/study_xxqg/lib/state"
"github.com/johlanse/study_xxqg/model" "github.com/johlanse/study_xxqg/model"
"github.com/johlanse/study_xxqg/push" "github.com/johlanse/study_xxqg/push"
"github.com/johlanse/study_xxqg/utils" "github.com/johlanse/study_xxqg/utils"
) )
var (
state = sync.Map{}
)
// checkToken // checkToken
/* @Description: /* @Description:
* @return gin.HandlerFunc * @return gin.HandlerFunc
@ -250,17 +246,12 @@ func getUsers() gin.HandlerFunc {
var datas []map[string]interface{} var datas []map[string]interface{}
for _, user := range users { for _, user := range users {
var isStudy = false
_, ok := state.Load(user.UID)
if ok {
isStudy = true
}
datas = append(datas, map[string]interface{}{ datas = append(datas, map[string]interface{}{
"nick": user.Nick, "nick": user.Nick,
"uid": user.UID, "uid": user.UID,
"token": user.Token, "token": user.Token,
"login_time": user.LoginTime, "login_time": user.LoginTime,
"is_study": isStudy, "is_study": state.IsStudy(user.UID),
}) })
} }
ctx.JSON(200, Resp{ ctx.JSON(200, Resp{
@ -316,7 +307,7 @@ func study() gin.HandlerFunc {
Push: push.GetPush(conf.GetConfig()), Push: push.GetPush(conf.GetConfig()),
} }
core.Init() core.Init()
state.Store(uid, core) state.Add(user.UID, core)
config := conf.GetConfig() config := conf.GetConfig()
go func() { go func() {
core.LearnArticle(user) core.LearnArticle(user)
@ -343,11 +334,7 @@ func study() gin.HandlerFunc {
func stopStudy() gin.HandlerFunc { func stopStudy() gin.HandlerFunc {
return func(ctx *gin.Context) { return func(ctx *gin.Context) {
uid := ctx.Query("uid") uid := ctx.Query("uid")
value, ok := state.Load(uid) core := state.Get(uid)
if !ok {
return
}
core := value.(*lib.Core)
core.Quit() core.Quit()
ctx.JSON(200, Resp{ ctx.JSON(200, Resp{
Code: 200, Code: 200,