133 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package core
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"os/signal"
 | |
| 	"syscall"
 | |
| 
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/app/api"
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/app/service/token"
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/infra/config"
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/infra/database"
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
 | |
| 	"git.huangwc.com/pig/pig-farm-controller/internal/infra/task"
 | |
| )
 | |
| 
 | |
| // Application 是整个应用的核心,封装了所有组件和生命周期。
 | |
| type Application struct {
 | |
| 	Config   *config.Config
 | |
| 	Logger   *logs.Logger
 | |
| 	Storage  database.Storage
 | |
| 	Executor *task.Executor
 | |
| 	API      *api.API // 添加 API 对象
 | |
| }
 | |
| 
 | |
| // NewApplication 创建并初始化一个新的 Application 实例。
 | |
| // 这是应用的“组合根”,所有依赖都在这里被创建和注入。
 | |
| func NewApplication(configPath string) (*Application, error) {
 | |
| 	// 1. 加载配置
 | |
| 	cfg := config.NewConfig()
 | |
| 	if err := cfg.Load(configPath); err != nil {
 | |
| 		return nil, fmt.Errorf("无法加载配置: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// 2. 初始化日志记录器
 | |
| 	logger := logs.NewLogger(cfg.Log)
 | |
| 
 | |
| 	// 3. 初始化数据库存储
 | |
| 	storage, err := initStorage(cfg.Database, logger)
 | |
| 	if err != nil {
 | |
| 		return nil, err // 错误已在 initStorage 中被包装
 | |
| 	}
 | |
| 
 | |
| 	// 4. 初始化任务执行器
 | |
| 	executor := task.NewExecutor(cfg.Heartbeat.Concurrency, logger)
 | |
| 
 | |
| 	// 5. 初始化 Token 服务
 | |
| 	tokenService := token.NewTokenService([]byte(cfg.App.JWTSecret))
 | |
| 
 | |
| 	// 6. 初始化用户仓库
 | |
| 	userRepo := repository.NewGormUserRepository(storage.GetDB())
 | |
| 
 | |
| 	// 7. 初始化设备仓库
 | |
| 	deviceRepo := repository.NewGormDeviceRepository(storage.GetDB())
 | |
| 
 | |
| 	// 8. 初始化计划仓库
 | |
| 	planRepo := repository.NewGormPlanRepository(storage.GetDB())
 | |
| 
 | |
| 	// 9. 初始化 API 服务器
 | |
| 	apiServer := api.NewAPI(cfg.Server, logger, userRepo, deviceRepo, planRepo, tokenService)
 | |
| 
 | |
| 	// 10. 组装 Application 对象
 | |
| 	app := &Application{
 | |
| 		Config:   cfg,
 | |
| 		Logger:   logger,
 | |
| 		Storage:  storage,
 | |
| 		Executor: executor,
 | |
| 		API:      apiServer,
 | |
| 	}
 | |
| 
 | |
| 	return app, nil
 | |
| }
 | |
| 
 | |
| // Start 启动应用的所有组件并阻塞,直到接收到关闭信号。
 | |
| func (app *Application) Start() error {
 | |
| 	app.Logger.Info("应用启动中...")
 | |
| 
 | |
| 	// 启动任务执行器
 | |
| 	app.Executor.Start()
 | |
| 
 | |
| 	// 启动 API 服务器
 | |
| 	app.API.Start()
 | |
| 
 | |
| 	// 等待关闭信号
 | |
| 	quit := make(chan os.Signal, 1)
 | |
| 	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
 | |
| 	<-quit
 | |
| 
 | |
| 	// 接收到信号后,执行优雅关闭
 | |
| 	return app.Stop()
 | |
| }
 | |
| 
 | |
| // Stop 优雅地关闭应用的所有组件。
 | |
| func (app *Application) Stop() error {
 | |
| 	app.Logger.Info("应用关闭中...")
 | |
| 
 | |
| 	// 关闭 API 服务器
 | |
| 	app.API.Stop()
 | |
| 
 | |
| 	// 关闭任务执行器
 | |
| 	app.Executor.Stop()
 | |
| 
 | |
| 	// 断开数据库连接
 | |
| 	if err := app.Storage.Disconnect(); err != nil {
 | |
| 		app.Logger.Errorw("数据库连接断开失败", "error", err)
 | |
| 	}
 | |
| 
 | |
| 	// 刷新日志缓冲区
 | |
| 	_ = app.Logger.Sync()
 | |
| 
 | |
| 	app.Logger.Info("应用已成功关闭")
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // initStorage 封装了数据库的初始化、连接和迁移逻辑。
 | |
| func initStorage(cfg config.DatabaseConfig, logger *logs.Logger) (database.Storage, error) {
 | |
| 	// 创建存储实例
 | |
| 	storage := database.NewStorage(cfg, logger)
 | |
| 	if err := storage.Connect(); err != nil {
 | |
| 		// 错误已在 Connect 内部被记录,这里只需包装并返回
 | |
| 		return nil, fmt.Errorf("数据库连接失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// 执行数据库迁移
 | |
| 	if err := storage.Migrate(models.GetAllModels()...); err != nil {
 | |
| 		return nil, fmt.Errorf("数据库迁移失败: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	return storage, nil
 | |
| }
 |