feat: 添加定时系统
- 实现定时任务
This commit is contained in:
3
go.mod
3
go.mod
@@ -18,6 +18,7 @@ require (
|
||||
github.com/bytedance/sonic/loader v0.5.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
|
||||
github.com/gin-contrib/cors v1.7.6 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
@@ -34,6 +35,8 @@ require (
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/quic-go/qpack v0.6.0 // indirect
|
||||
github.com/quic-go/quic-go v0.59.0 // indirect
|
||||
github.com/robfig/cron v1.2.0 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.3.1 // indirect
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
|
||||
|
||||
6
go.sum
6
go.sum
@@ -15,6 +15,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
|
||||
github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gin-contrib/cors v1.7.6 h1:3gQ8GMzs1Ylpf70y8bMw4fVpycXIeX1ZemuSQIsnQQY=
|
||||
github.com/gin-contrib/cors v1.7.6/go.mod h1:Ulcl+xN4jel9t1Ry8vqph23a60FwH9xVLd+3ykmTjOk=
|
||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||
github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
|
||||
@@ -60,6 +62,10 @@ github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
|
||||
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
||||
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
||||
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ckwk
|
||||
|
||||
import (
|
||||
"ckwk/internal/conf"
|
||||
"ckwk/pkg/common"
|
||||
"ckwk/pkg/log"
|
||||
"ckwk/pkg/request"
|
||||
@@ -97,7 +98,7 @@ func (wk *WK) Code() (string, error) {
|
||||
"png_fix": "false",
|
||||
}).
|
||||
SetResult(&result).
|
||||
Post("http://localhost:8000/ocr")
|
||||
Post(fmt.Sprintf("%s/ocr", conf.DdddOCR))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("获取验证码验证结果失败: %w", err)
|
||||
}
|
||||
|
||||
@@ -115,3 +115,44 @@ func (m *SessionManager) KeepAlive(ctx context.Context, id string, wk *WK) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *SessionManager) ClearAll() {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
for sessionID, item := range m.sessions {
|
||||
// 停止 KeepAlive
|
||||
if item.cancel != nil {
|
||||
item.cancel()
|
||||
}
|
||||
|
||||
userKey := item.Instance.Host + ":" + item.Instance.Username
|
||||
delete(m.userToSession, userKey)
|
||||
delete(m.sessions, sessionID)
|
||||
|
||||
log.Info("清理 Session", zap.String("id", sessionID))
|
||||
}
|
||||
|
||||
log.Info("所有 Session 已清空")
|
||||
}
|
||||
|
||||
func (m *SessionManager) ClearExpired(d time.Duration) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
|
||||
for sessionID, item := range m.sessions {
|
||||
if now.Sub(item.LastValue) > d {
|
||||
if item.cancel != nil {
|
||||
item.cancel()
|
||||
}
|
||||
|
||||
userKey := item.Instance.Host + ":" + item.Instance.Username
|
||||
delete(m.userToSession, userKey)
|
||||
delete(m.sessions, sessionID)
|
||||
|
||||
log.Info("清理过期 Session", zap.String("id", sessionID))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
5
internal/conf/const.go
Normal file
5
internal/conf/const.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package conf
|
||||
|
||||
const (
|
||||
DdddOCR = "https://ocr.kmux.cn"
|
||||
)
|
||||
@@ -28,12 +28,17 @@ func (h *WKHandler) Login(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
log.Debug("请求数据", zap.Any("req", req))
|
||||
var cookies = []*http.Cookie{
|
||||
var cookies []*http.Cookie
|
||||
if req.Token != "" {
|
||||
cookies = []*http.Cookie{
|
||||
{
|
||||
Name: "token",
|
||||
Value: req.Token,
|
||||
Path: "/"},
|
||||
}
|
||||
} else {
|
||||
cookies = []*http.Cookie{}
|
||||
}
|
||||
wk := ckwk.NewWK(req.Username, req.Password, req.Host, cookies)
|
||||
if wk == nil {
|
||||
ctx.JSON(200, dto.Error(-1, "登录失败:请提供账号密码或有效的 Token,并确保 Host 正确"))
|
||||
@@ -171,3 +176,16 @@ func (h *WKHandler) AllRecord(ctx *gin.Context) {
|
||||
"page_info": pageInfo,
|
||||
}))
|
||||
}
|
||||
|
||||
func (h *WKHandler) Host(ctx *gin.Context) {
|
||||
ctx.JSON(200, dto.Success(map[string]any{
|
||||
"list": []map[string]any{
|
||||
{"host": "cqcst.leykeji.com", "name": "劳动课程测评考试平台"},
|
||||
{"host": "cqcst.zjxkeji.com", "name": "公益课程平台"},
|
||||
{"host": "cqcst.suwankj.com", "name": "在线课程测评考试平台"},
|
||||
{"host": "cqcst.yuruixxkj.com", "name": "在线测评考试平台"},
|
||||
// {"host": "cqcst.yuncanjykeji.com", "name": "劳动课程测评考试平台"},
|
||||
// {"host": "cqcst.yuruixxkj.com", "name": "公益课程平台"},
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -3,22 +3,33 @@ package router
|
||||
import (
|
||||
"ckwk/internal/handler"
|
||||
"ckwk/internal/middleware"
|
||||
"ckwk/internal/schedule"
|
||||
"time"
|
||||
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SetupRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
r.Use(cors.New(cors.Config{
|
||||
AllowOrigins: []string{"*://*", "http://localhost:5173"},
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "PATCH"},
|
||||
AllowHeaders: []string{"*", "X-Session-Id"},
|
||||
ExposeHeaders: []string{"Content-Length"},
|
||||
AllowCredentials: true,
|
||||
MaxAge: 12 * time.Hour,
|
||||
}))
|
||||
wkHandler := handler.NewWKHandler()
|
||||
sessionMiddleware := middleware.SessionMiddleware(wkHandler.Session)
|
||||
schedule.StartCron(wkHandler.Session)
|
||||
|
||||
api := r.Group("/api")
|
||||
{
|
||||
api.POST("/login", wkHandler.Login)
|
||||
v1 := api.Group("/v1", sessionMiddleware)
|
||||
v1 := api.Group("/v1")
|
||||
{
|
||||
v1.POST("/online", wkHandler.Online)
|
||||
v1.POST("/logout", wkHandler.Logout)
|
||||
v1.GET("/host", wkHandler.Host)
|
||||
}
|
||||
|
||||
v2 := api.Group("/v2", sessionMiddleware)
|
||||
|
||||
32
internal/schedule/schedule.go
Normal file
32
internal/schedule/schedule.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package schedule
|
||||
|
||||
import (
|
||||
"ckwk/internal/ckwk"
|
||||
"ckwk/pkg/log"
|
||||
"time"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func StartCron(m *ckwk.SessionManager) {
|
||||
loc, _ := time.LoadLocation("Asia/Singapore")
|
||||
|
||||
c := cron.New(
|
||||
cron.WithLocation(loc),
|
||||
)
|
||||
|
||||
// 每天 6 点执行
|
||||
_, err := c.AddFunc("0 2 * * *", func() {
|
||||
log.Info("开始定时清理 Session")
|
||||
m.ClearAll()
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Error("cron 添加任务失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
c.Start()
|
||||
}
|
||||
Reference in New Issue
Block a user