package main import ( "context" "embed" "fmt" "log" "net/http" "os" "os/signal" "syscall" "time" "vision-tool/internal/config" "vision-tool/internal/database" "vision-tool/internal/router" ) //go:embed web var webFS embed.FS func main() { // 1. 加载配置(config.yaml,可被环境变量覆盖) cfg, err := config.Load("config.yaml") if err != nil { log.Fatalf("加载配置失败: %v", err) } // 2. 初始化数据库(首次启动自动写入进入密钥) db, err := database.Init(&cfg.Database, cfg.Auth.AccessKey) if err != nil { log.Fatalf("初始化数据库失败: %v", err) } // 3. 构建路由(分层依赖注入) r := router.Setup(cfg, db, webFS) // 4. 启动 HTTP 服务 srv := &http.Server{ Addr: fmt.Sprintf(":%d", cfg.Server.Port), Handler: r, } go func() { log.Printf("vision-tool 已启动: http://localhost:%d", cfg.Server.Port) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("服务启动失败: %v", err) } }() // 5. 优雅关闭 quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("正在关闭服务...") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Printf("关闭异常: %v", err) } if sqlDB, err := db.DB(); err == nil { sqlDB.Close() } log.Println("服务已退出") }