Smail/backend/internal/app/app.go
smail 218337d8b5
Some checks are pending
Security Checks / security (push) Waiting to run
修复主程序查询版本时误启动服务的问题
2026-09-26 02:12:07 +08:00

91 lines
2.8 KiB
Go

package app
import (
"fmt"
"os"
"git.pcux.cn/xuans/Smail/config"
"git.pcux.cn/xuans/Smail/internal/buildinfo"
"git.pcux.cn/xuans/Smail/listen/cron_server"
"git.pcux.cn/xuans/Smail/res_init"
"git.pcux.cn/xuans/Smail/services/runtimelog"
"git.pcux.cn/xuans/Smail/utils/runtimepath"
log "github.com/sirupsen/logrus"
)
// Run 启动 Smail 主服务。
func Run() (err error) {
// 版本查询必须先于部署初始化,不能触发配置迁移、日志写入或服务监听。
if len(os.Args) == 2 && (os.Args[1] == `--version` || os.Args[1] == `version`) {
_, err := fmt.Fprintln(os.Stdout, buildinfo.Current().Version)
return err
}
if err := config.InitializeDeployment(config.ROOT_PATH); err != nil {
return err
}
if err := runtimepath.CheckReady(config.ROOT_PATH); err != nil {
return err
}
if err := config.MigrateLegacySSLStorage(config.ROOT_PATH); err != nil {
return fmt.Errorf("迁移证书存储失败,原文件已保留: %w", err)
}
if err := config.Init(); err != nil {
return err
}
runtimeLogs, err := runtimelog.Start(config.ROOT_PATH)
if err != nil {
return fmt.Errorf("启动运行日志失败: %w", err)
}
defer finishRuntimeLogs(runtimeLogs, &err)
config.MaintainManagedSSLHistory()
build := buildinfo.Current()
if build.Version == "dev" {
build.Version = "TestVersion"
}
log.WithFields(log.Fields{"action": "启动主服务", "object": "Smail", "result": "started"}).Infof("服务启动,版本:%s", build.Version)
// 启动定时任务。
go cron_server.Start()
// 启动核心服务。
if err := res_init.Init(build.Version); err != nil {
return err
}
log.WithFields(log.Fields{"action": "停止主服务", "object": "Smail", "result": "success"}).Info("主服务已停止")
return nil
}
// finishRuntimeLogs 在关闭日志文件前记录返回错误或异常,避免致命错误只留在控制台。
func finishRuntimeLogs(writer *runtimelog.Writer, runErr *error) {
if recovered := recover(); recovered != nil {
*runErr = fmt.Errorf("服务启动异常: %v", recovered)
}
if *runErr != nil {
log.WithError(*runErr).WithFields(log.Fields{"action": "运行主服务", "object": "Smail", "result": "failure"}).Error("服务因致命错误停止")
}
if err := writer.Close(); err != nil {
log.WithError(err).Error("关闭运行日志失败")
}
}
// RunAndExit 执行主服务并在发生致命错误时退出。
func RunAndExit() {
if err := Run(); err != nil {
log.WithError(err).Error("Server stopped because of a fatal error")
os.Exit(1)
}
}
// RecoverPanic 将启动过程中的 panic 转换为可记录的错误。
func RecoverPanic(run func() error) (err error) {
defer func() {
if recovered := recover(); recovered != nil {
err = fmt.Errorf("server initialization panic: %v", recovered)
}
}()
return run()
}