Files
opsx-licence/backend/main.go
T
Logan.Li 83a3630404
CI / backend (push) Canceled after 0s
feat(settings): 运行配置中心——.env 业务参数统一到后台页面维护
- 新增 app_configs 表与 appconfig 注册表:读取优先级 页面 → .env → 默认,删除即回退
- 页面可配 7 项:支付回调基址、成功回跳、Webhook 密钥(加密入库)、未验签放行开关、CORS、可信代理、GeoIP 路径
- 引导密钥(JWT_SECRET / OPSLIC_MASTER_KEY / OFFLINE_LICENSE_SEED)与部署参数只读展示掩码+指纹,永不入库
- 校验:URL 格式、密钥长度≥16、CIDR、release 下禁止开启未验签回调;变更写审计日志
- 消费点改造:支付回调地址、Waffo 回跳、webhook 验签、可信代理、CORS、GeoIP 统一走配置中心
- 前端新增「审计与设置 → 运行配置」页(分组表格 + 来源标记 + 编辑弹窗 + 恢复默认)
- .env.example 补注释:哪些必须留在 .env、哪些已收敛到页面
2026-11-01 06:17:58 +08:00

93 lines
2.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"backend/config"
"backend/database"
"backend/internal/secretbox"
"backend/internal/service/appconfig"
licenseservice "backend/internal/service/license"
syncservice "backend/internal/service/sync"
"backend/router"
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
// 加载配置 // Logan.Li
cfg := config.Load()
// 机密字段主密钥:缺失/非法直接拒绝启动(fail-fast),避免带病运行 // Logan.Li
if err := secretbox.LoadMasterKey(); err != nil {
log.Fatal(err)
}
// 初始化数据库 // Logan.Li
db, err := database.Init(cfg)
if err != nil {
log.Fatal("数据库初始化失败:", err)
}
// 历史明文机密一次性加密回写(幂等;双节点需配置相同 OPSLIC_MASTER_KEY) // Logan.Li
if err := secretbox.MigratePlaintext(db); err != nil {
log.Fatal("机密字段迁移失败:", err)
}
// 运行配置中心:DB → 环境变量 → 默认值(须在路由注册前装载) // Logan.Li
if err := appconfig.Init(db); err != nil {
log.Fatal("运行配置初始化失败:", err)
}
// 跨域白名单以页面配置为准(后台改动需重启生效) // Logan.Li
if origins := appconfig.List("CORS_ORIGINS"); len(origins) > 0 {
cfg.CORSOrigins = origins
}
// 启动在线状态清扫(超时未心跳的激活记录置为离线) // Logan.Li
licenseservice.StartOnlineSweeper(db, cfg.OnlineTTLMinutes)
// 启动节点定时双向同步(宽松节奏,默认 10 分钟) // Logan.Li
syncservice.NewService(db, cfg).StartSyncLoop(cfg.SyncIntervalMinutes)
// 初始化路由 // Logan.Li
r := router.SetupRouter(db, cfg)
// 单二进制构建时提供嵌入的 Vue 前端;开发模式会自动跳过。 // Logan.Li
setupEmbeddedFrontend(r)
// 启动服务器 // Logan.Li
addr := ":" + cfg.Port
srv := &http.Server{
Addr: addr,
Handler: r,
}
// 优雅关机: 在独立 goroutine 中启动服务器 // Logan.Li
go func() {
log.Printf("服务器启动在 %s", addr)
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal("服务器启动失败:", err)
}
}()
// 等待中断信号 // Logan.Li
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("正在关闭服务器...")
// 设置 5 秒超时来关闭服务器 // Logan.Li
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal("服务器强制关闭:", err)
}
log.Println("服务器已优雅关闭")
}