163 lines
3.3 KiB
Go
163 lines
3.3 KiB
Go
package main
|
||
|
||
import (
|
||
"context"
|
||
"flag"
|
||
"log"
|
||
"net/http"
|
||
"os"
|
||
"os/signal"
|
||
"syscall"
|
||
"time"
|
||
|
||
"jwts/auth"
|
||
"jwts/captcha"
|
||
"jwts/client"
|
||
"jwts/config"
|
||
grpcClient "jwts/grpc"
|
||
"jwts/parser"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
func main() {
|
||
mode := flag.String("mode", "http", "运行模式: http 或 grpc")
|
||
grpcAddr := flag.String("grpc-addr", "localhost:50051", "gRPC 服务器地址")
|
||
flag.Parse()
|
||
|
||
if *mode == "grpc" {
|
||
runGRPCClient(*grpcAddr)
|
||
} else {
|
||
runHTTPServer()
|
||
}
|
||
}
|
||
|
||
// runGRPCClient 运行 gRPC 客户端模式
|
||
func runGRPCClient(serverAddr string) {
|
||
runnerID := os.Getenv("RUNNER_ID")
|
||
if runnerID == "" {
|
||
hostname, _ := os.Hostname()
|
||
runnerID = "runner-" + hostname
|
||
}
|
||
|
||
version := os.Getenv("RUNNER_VERSION")
|
||
if version == "" {
|
||
version = "1.0.0"
|
||
}
|
||
|
||
log.Printf("启动 gRPC 客户端, Runner ID: %s, 版本: %s", runnerID, version)
|
||
|
||
client := grpcClient.NewClient(serverAddr, runnerID, version)
|
||
handler := grpcClient.NewTaskHandler()
|
||
client.SetHandler(handler)
|
||
|
||
ctx, cancel := context.WithCancel(context.Background())
|
||
defer cancel()
|
||
|
||
// 处理信号
|
||
sigChan := make(chan os.Signal, 1)
|
||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||
|
||
if err := client.Connect(ctx); err != nil {
|
||
log.Printf("连接失败: %v", err)
|
||
os.Exit(1)
|
||
}
|
||
|
||
go func() {
|
||
<-sigChan
|
||
log.Println("正在关闭...")
|
||
client.Close()
|
||
cancel()
|
||
}()
|
||
|
||
// 启动心跳
|
||
go client.HeartbeatLoop(ctx, 30*time.Second)
|
||
|
||
// 运行主循环
|
||
if err := client.Run(ctx); err != nil {
|
||
log.Printf("客户端错误: %v", err)
|
||
}
|
||
}
|
||
|
||
// runHTTPServer 运行 HTTP 服务器模式
|
||
func runHTTPServer() {
|
||
// 初始化客户端
|
||
client.InitClient()
|
||
|
||
r := gin.Default()
|
||
|
||
// 健康检查接口
|
||
r.GET("/ping", func(c *gin.Context) {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"message": "pong",
|
||
})
|
||
})
|
||
|
||
// 任务处理接口
|
||
r.POST("/task", func(c *gin.Context) {
|
||
// 这里可以根据请求体参数决定执行什么任务
|
||
// 目前默认执行原有的登录和获取课表逻辑
|
||
if config.Username == "" || config.Password == "" {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": "环境变量未设置"})
|
||
return
|
||
}
|
||
|
||
// 执行任务
|
||
err := runTask()
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{"message": "任务执行成功"})
|
||
})
|
||
|
||
// 启动服务
|
||
log.Println("Server starting on :8080")
|
||
if err := r.Run(":8080"); err != nil {
|
||
log.Fatalf("Failed to run server: %v", err)
|
||
}
|
||
}
|
||
|
||
func runTask() error {
|
||
// 步骤1: 获取初始Cookie
|
||
err := client.GetInitialCookies()
|
||
if err != nil {
|
||
log.Printf("获取Cookie失败: %v", err)
|
||
return err
|
||
}
|
||
|
||
// 重试登录
|
||
maxRetries := 3
|
||
for attempt := 1; attempt <= maxRetries; attempt++ {
|
||
log.Printf("尝试登录 (第%d次)...", attempt)
|
||
|
||
// 获取并识别验证码
|
||
captchaCode, err := captcha.GetAndRecognize(client.Client)
|
||
if err != nil {
|
||
log.Printf(" 验证码获取失败: %v", err)
|
||
continue
|
||
}
|
||
|
||
// 登录
|
||
success, err := auth.Login(captchaCode)
|
||
if err != nil {
|
||
log.Printf(" 登录失败: %v", err)
|
||
continue
|
||
}
|
||
|
||
if success {
|
||
// 获取课表
|
||
_, err = parser.FetchSchedule(client.Client)
|
||
if err != nil {
|
||
log.Printf("获取课表失败: %v", err)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
log.Println(" 登录失败,3秒后重试...")
|
||
}
|
||
|
||
return nil
|
||
}
|