Files
tyapi-server/internal/app/app.go

236 lines
5.8 KiB
Go

package app
import (
"fmt"
"os"
"os/signal"
"syscall"
"go.uber.org/zap"
"gorm.io/gorm"
"tyapi-server/internal/config"
"tyapi-server/internal/container"
"tyapi-server/internal/domains/user/entities"
)
// Application 应用程序结构
type Application struct {
container *container.Container
config *config.Config
logger *zap.Logger
}
// NewApplication 创建新的应用程序实例
func NewApplication() (*Application, error) {
// 加载配置
cfg, err := config.LoadConfig()
if err != nil {
return nil, fmt.Errorf("failed to load config: %w", err)
}
// 创建日志器
logger, err := createLogger(cfg)
if err != nil {
return nil, fmt.Errorf("failed to create logger: %w", err)
}
// 创建容器
cont := container.NewContainer()
return &Application{
container: cont,
config: cfg,
logger: logger,
}, nil
}
// Run 运行应用程序
func (a *Application) Run() error {
// 打印启动信息
a.printBanner()
// 启动容器
a.logger.Info("Starting application container...")
if err := a.container.Start(); err != nil {
a.logger.Error("Failed to start container", zap.Error(err))
return err
}
// 设置优雅关闭
a.setupGracefulShutdown()
a.logger.Info("Application started successfully",
zap.String("version", a.config.App.Version),
zap.String("environment", a.config.App.Env),
zap.String("port", a.config.Server.Port))
// 等待信号
return a.waitForShutdown()
}
// RunMigrations 运行数据库迁移
func (a *Application) RunMigrations() error {
a.logger.Info("Running database migrations...")
// 创建数据库连接
db, err := a.createDatabaseConnection()
if err != nil {
return fmt.Errorf("failed to create database connection: %w", err)
}
// 自动迁移
if err := a.autoMigrate(db); err != nil {
return fmt.Errorf("failed to run migrations: %w", err)
}
a.logger.Info("Database migrations completed successfully")
return nil
}
// printBanner 打印启动横幅
func (a *Application) printBanner() {
banner := fmt.Sprintf(`
╔══════════════════════════════════════════════════════════════╗
║ %s ║
║ Version: %s ║
║ Environment: %s ║
║ Port: %s ║
╚══════════════════════════════════════════════════════════════╝
`,
a.config.App.Name,
a.config.App.Version,
a.config.App.Env,
a.config.Server.Port,
)
fmt.Println(banner)
}
// setupGracefulShutdown 设置优雅关闭
func (a *Application) setupGracefulShutdown() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
a.logger.Info("Received shutdown signal, starting graceful shutdown...")
// 停止容器
if err := a.container.Stop(); err != nil {
a.logger.Error("Error during container shutdown", zap.Error(err))
}
a.logger.Info("Application shutdown completed")
os.Exit(0)
}()
}
// waitForShutdown 等待关闭信号
func (a *Application) waitForShutdown() error {
// 创建一个通道来等待关闭
done := make(chan bool, 1)
// 启动一个协程来监听信号
go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
<-c
done <- true
}()
// 等待关闭信号
<-done
return nil
}
// createDatabaseConnection 创建数据库连接
func (a *Application) createDatabaseConnection() (*gorm.DB, error) {
return container.NewDatabase(a.config, a.logger)
}
// autoMigrate 自动迁移
func (a *Application) autoMigrate(db *gorm.DB) error {
// 迁移用户相关表
return db.AutoMigrate(
&entities.User{},
// 后续可以添加其他实体
)
}
// createLogger 创建日志器
func createLogger(cfg *config.Config) (*zap.Logger, error) {
level, err := zap.ParseAtomicLevel(cfg.Logger.Level)
if err != nil {
level = zap.NewAtomicLevelAt(zap.InfoLevel)
}
config := zap.Config{
Level: level,
Development: cfg.App.IsDevelopment(),
Encoding: cfg.Logger.Format,
EncoderConfig: zap.NewProductionEncoderConfig(),
OutputPaths: []string{cfg.Logger.Output},
ErrorOutputPaths: []string{"stderr"},
}
if cfg.Logger.Format == "" {
config.Encoding = "json"
}
if cfg.Logger.Output == "" {
config.OutputPaths = []string{"stdout"}
}
return config.Build()
}
// GetConfig 获取配置
func (a *Application) GetConfig() *config.Config {
return a.config
}
// GetLogger 获取日志器
func (a *Application) GetLogger() *zap.Logger {
return a.logger
}
// HealthCheck 应用程序健康检查
func (a *Application) HealthCheck() error {
// 这里可以添加应用程序级别的健康检查逻辑
return nil
}
// GetVersion 获取版本信息
func (a *Application) GetVersion() map[string]string {
return map[string]string{
"name": a.config.App.Name,
"version": a.config.App.Version,
"environment": a.config.App.Env,
"go_version": "1.23.4+",
}
}
// RunCommand 运行特定命令
func (a *Application) RunCommand(command string, args ...string) error {
switch command {
case "migrate":
return a.RunMigrations()
case "version":
version := a.GetVersion()
fmt.Printf("Name: %s\n", version["name"])
fmt.Printf("Version: %s\n", version["version"])
fmt.Printf("Environment: %s\n", version["environment"])
fmt.Printf("Go Version: %s\n", version["go_version"])
return nil
case "health":
if err := a.HealthCheck(); err != nil {
fmt.Printf("Health check failed: %v\n", err)
return err
}
fmt.Println("Application is healthy")
return nil
default:
return fmt.Errorf("unknown command: %s", command)
}
}