Files
AntiCaptcha/cmd/server/main.go
T
admin 84cac4ea77
Build and Deploy / build (push) Failing after 1m51s
Build and Deploy / deploy (push) Has been skipped
fix: 安装后设置全局配置,提示重启容器
2026-07-16 19:00:10 +00:00

193 lines
5.1 KiB
Go

package main
import (
"crypto/rand"
"encoding/hex"
"fmt"
"log"
"anticaptcha/internal/captcha"
"anticaptcha/internal/config"
"anticaptcha/internal/database"
"anticaptcha/internal/handler"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
func main() {
// 检查是否已安装
if !config.IsInstalled() {
fmt.Println("系统未安装,请先访问 /install 进行安装配置")
}
// 加载配置
if err := config.Load(""); err != nil {
log.Printf("警告: %v", err)
}
// 初始化数据库
if config.Cfg != nil {
if err := database.Init(&config.Cfg.Database); err != nil {
log.Fatalf("数据库初始化失败: %v", err)
}
defer database.Close()
}
// 创建 Gin 引擎
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.Use(gin.Recovery())
// CORS 配置
r.Use(cors.New(cors.Config{
AllowAllOrigins: true,
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
}))
// 静态文件服务(前端)
r.Static("/assets", "./web/dist/assets")
r.NoRoute(func(c *gin.Context) {
c.File("./web/dist/index.html")
})
// API 路由
captchaHandler := handler.NewCaptchaHandler(captcha.NewHandler("./models"))
captchaHandler.RegisterRoutes(r.Group(""), true)
// 安装路由
r.POST("/api/install", handleInstall)
r.GET("/api/install/check", func(c *gin.Context) {
c.JSON(200, gin.H{"installed": config.IsInstalled()})
})
// 健康检查
r.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
// 启动服务
addr := ":6688"
if config.Cfg != nil {
addr = fmt.Sprintf("%s:%d", config.Cfg.Server.Host, config.Cfg.Server.Port)
}
fmt.Printf(`
╔════════════════════════════════════════════════════════════════╗
║ AntiCaptcha Server v1.0.0 ║
║ https://git.viaeon.com/admin/AntiCaptcha ║
╠════════════════════════════════════════════════════════════════╣
║ 服务已启动: http://%s ║
║ 默认账号: admin / admin ║
╚════════════════════════════════════════════════════════════════╝
`, addr)
if err := r.Run(addr); err != nil {
log.Fatalf("服务启动失败: %v", err)
}
}
func handleInstall(c *gin.Context) {
var req struct {
Database struct {
Type string `json:"type"`
Host string `json:"host"`
Port int `json:"port"`
User string `json:"user"`
Password string `json:"password"`
Database string `json:"database"`
SQLite struct {
Path string `json:"path"`
} `json:"sqlite"`
} `json:"database"`
Redis struct {
Enabled bool `json:"enabled"`
Host string `json:"host"`
Port int `json:"port"`
Password string `json:"password"`
DB int `json:"db"`
} `json:"redis"`
Admin struct {
Username string `json:"username"`
Password string `json:"password"`
} `json:"admin"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// 生成 JWT Secret
jwtSecret := generateRandomSecret()
// 构建配置
cfg := &config.Config{
Server: config.ServerConfig{
Host: "0.0.0.0",
Port: 6688,
Mode: "release",
},
Database: config.DatabaseConfig{
Type: req.Database.Type,
Host: req.Database.Host,
Port: req.Database.Port,
User: req.Database.User,
Password: req.Database.Password,
Database: req.Database.Database,
SQLite: config.SQLiteConfig{
Path: req.Database.SQLite.Path,
},
},
Redis: config.RedisConfig{
Enabled: req.Redis.Enabled,
Host: req.Redis.Host,
Port: req.Redis.Port,
Password: req.Redis.Password,
DB: req.Redis.DB,
},
JWT: config.JWTConfig{
Secret: jwtSecret,
ExpireTime: 1440,
},
Captcha: config.CaptchaConfig{
ModelPath: "./models",
},
}
// 保存配置
if err := config.Save(cfg); err != nil {
c.JSON(500, gin.H{"error": "保存配置失败: " + err.Error()})
return
}
// 设置全局配置
config.Cfg = cfg
// 初始化数据库
if err := database.Init(&cfg.Database); err != nil {
c.JSON(500, gin.H{"error": "数据库初始化失败: " + err.Error()})
return
}
// 创建管理员用户
if err := database.EnsureAdminUser(req.Admin.Username, req.Admin.Password); err != nil {
c.JSON(500, gin.H{"error": "创建管理员用户失败: " + err.Error()})
return
}
c.JSON(200, gin.H{
"message": "安装成功",
"restart": true,
"restartMsg": "请重启容器以完成安装",
})
}
func generateRandomSecret() string {
b := make([]byte, 32)
rand.Read(b)
return hex.EncodeToString(b)
}