2025-10-26 15:48:38 +08:00
|
|
|
|
package core
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2025-11-05 16:00:43 +08:00
|
|
|
|
"context"
|
2025-10-26 15:48:38 +08:00
|
|
|
|
"fmt"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/app/service"
|
|
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/app/webhook"
|
|
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/domain/device"
|
|
|
|
|
|
domain_notify "git.huangwc.com/pig/pig-farm-controller/internal/domain/notify"
|
|
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/domain/pig"
|
2025-11-02 18:16:44 +08:00
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/domain/plan"
|
2025-10-26 15:48:38 +08:00
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/domain/task"
|
|
|
|
|
|
"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/notify"
|
|
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
|
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/transport"
|
|
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/transport/lora"
|
2025-11-05 21:40:19 +08:00
|
|
|
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/utils/token"
|
2025-10-26 15:48:38 +08:00
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// Infrastructure 聚合了所有基础设施层的组件。
|
|
|
|
|
|
type Infrastructure struct {
|
2025-11-05 21:40:19 +08:00
|
|
|
|
storage database.Storage
|
|
|
|
|
|
repos *Repositories
|
|
|
|
|
|
lora *LoraComponents
|
|
|
|
|
|
notifyService domain_notify.Service
|
|
|
|
|
|
tokenGenerator token.Generator
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// initInfrastructure 初始化所有基础设施层组件。
|
2025-11-05 16:00:43 +08:00
|
|
|
|
func initInfrastructure(ctx context.Context, cfg *config.Config) (*Infrastructure, error) {
|
|
|
|
|
|
storage, err := initStorage(ctx, cfg.Database)
|
2025-10-26 15:48:38 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 23:00:07 +08:00
|
|
|
|
repos := initRepositories(ctx, storage.GetDB(ctx))
|
2025-10-26 15:48:38 +08:00
|
|
|
|
|
2025-11-05 16:00:43 +08:00
|
|
|
|
lora, err := initLora(ctx, cfg, repos)
|
2025-10-26 15:48:38 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 16:00:43 +08:00
|
|
|
|
notifyService, err := initNotifyService(ctx, cfg.Notify, repos.userRepo, repos.notificationRepo)
|
2025-10-26 15:48:38 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("初始化通知服务失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 21:40:19 +08:00
|
|
|
|
tokenGenerator := token.NewTokenGenerator([]byte(cfg.App.JWTSecret))
|
2025-10-26 15:48:38 +08:00
|
|
|
|
|
|
|
|
|
|
return &Infrastructure{
|
2025-11-05 21:40:19 +08:00
|
|
|
|
storage: storage,
|
|
|
|
|
|
repos: repos,
|
|
|
|
|
|
lora: lora,
|
|
|
|
|
|
notifyService: notifyService,
|
|
|
|
|
|
tokenGenerator: tokenGenerator,
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Repositories 聚合了所有的仓库实例。
|
|
|
|
|
|
type Repositories struct {
|
2025-11-02 19:59:13 +08:00
|
|
|
|
userRepo repository.UserRepository
|
|
|
|
|
|
deviceRepo repository.DeviceRepository
|
|
|
|
|
|
areaControllerRepo repository.AreaControllerRepository
|
|
|
|
|
|
deviceTemplateRepo repository.DeviceTemplateRepository
|
|
|
|
|
|
planRepo repository.PlanRepository
|
|
|
|
|
|
pendingTaskRepo repository.PendingTaskRepository
|
|
|
|
|
|
executionLogRepo repository.ExecutionLogRepository
|
|
|
|
|
|
sensorDataRepo repository.SensorDataRepository
|
|
|
|
|
|
deviceCommandLogRepo repository.DeviceCommandLogRepository
|
|
|
|
|
|
pendingCollectionRepo repository.PendingCollectionRepository
|
|
|
|
|
|
userActionLogRepo repository.UserActionLogRepository
|
|
|
|
|
|
pigBatchRepo repository.PigBatchRepository
|
|
|
|
|
|
pigBatchLogRepo repository.PigBatchLogRepository
|
|
|
|
|
|
pigFarmRepo repository.PigFarmRepository
|
|
|
|
|
|
pigPenRepo repository.PigPenRepository
|
|
|
|
|
|
pigTransferLogRepo repository.PigTransferLogRepository
|
|
|
|
|
|
pigTradeRepo repository.PigTradeRepository
|
|
|
|
|
|
pigSickPigLogRepo repository.PigSickLogRepository
|
|
|
|
|
|
medicationLogRepo repository.MedicationLogRepository
|
|
|
|
|
|
rawMaterialRepo repository.RawMaterialRepository
|
|
|
|
|
|
notificationRepo repository.NotificationRepository
|
2025-11-07 22:26:16 +08:00
|
|
|
|
alarmRepo repository.AlarmRepository
|
2025-11-02 19:59:13 +08:00
|
|
|
|
unitOfWork repository.UnitOfWork
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// initRepositories 初始化所有的仓库。
|
2025-11-05 16:00:43 +08:00
|
|
|
|
func initRepositories(ctx context.Context, db *gorm.DB) *Repositories {
|
|
|
|
|
|
baseCtx := context.Background()
|
2025-10-26 15:48:38 +08:00
|
|
|
|
return &Repositories{
|
2025-11-05 19:57:30 +08:00
|
|
|
|
userRepo: repository.NewGormUserRepository(logs.AddCompName(baseCtx, "UserRepo"), db),
|
|
|
|
|
|
deviceRepo: repository.NewGormDeviceRepository(logs.AddCompName(baseCtx, "DeviceRepo"), db),
|
|
|
|
|
|
areaControllerRepo: repository.NewGormAreaControllerRepository(logs.AddCompName(baseCtx, "AreaControllerRepo"), db),
|
|
|
|
|
|
deviceTemplateRepo: repository.NewGormDeviceTemplateRepository(logs.AddCompName(baseCtx, "DeviceTemplateRepo"), db),
|
|
|
|
|
|
planRepo: repository.NewGormPlanRepository(logs.AddCompName(baseCtx, "PlanRepo"), db),
|
|
|
|
|
|
pendingTaskRepo: repository.NewGormPendingTaskRepository(logs.AddCompName(baseCtx, "PendingTaskRepo"), db),
|
|
|
|
|
|
executionLogRepo: repository.NewGormExecutionLogRepository(logs.AddCompName(baseCtx, "ExecutionLogRepo"), db),
|
|
|
|
|
|
sensorDataRepo: repository.NewGormSensorDataRepository(logs.AddCompName(baseCtx, "SensorDataRepo"), db),
|
|
|
|
|
|
deviceCommandLogRepo: repository.NewGormDeviceCommandLogRepository(logs.AddCompName(baseCtx, "DeviceCommandLogRepo"), db),
|
|
|
|
|
|
pendingCollectionRepo: repository.NewGormPendingCollectionRepository(logs.AddCompName(baseCtx, "PendingCollectionRepo"), db),
|
|
|
|
|
|
userActionLogRepo: repository.NewGormUserActionLogRepository(logs.AddCompName(baseCtx, "UserActionLogRepo"), db),
|
|
|
|
|
|
pigBatchRepo: repository.NewGormPigBatchRepository(logs.AddCompName(baseCtx, "PigBatchRepo"), db),
|
|
|
|
|
|
pigBatchLogRepo: repository.NewGormPigBatchLogRepository(logs.AddCompName(baseCtx, "PigBatchLogRepo"), db),
|
|
|
|
|
|
pigFarmRepo: repository.NewGormPigFarmRepository(logs.AddCompName(baseCtx, "PigFarmRepo"), db),
|
|
|
|
|
|
pigPenRepo: repository.NewGormPigPenRepository(logs.AddCompName(baseCtx, "PigPenRepo"), db),
|
|
|
|
|
|
pigTransferLogRepo: repository.NewGormPigTransferLogRepository(logs.AddCompName(baseCtx, "PigTransferLogRepo"), db),
|
|
|
|
|
|
pigTradeRepo: repository.NewGormPigTradeRepository(logs.AddCompName(baseCtx, "PigTradeRepo"), db),
|
|
|
|
|
|
pigSickPigLogRepo: repository.NewGormPigSickLogRepository(logs.AddCompName(baseCtx, "PigSickPigLogRepo"), db),
|
|
|
|
|
|
medicationLogRepo: repository.NewGormMedicationLogRepository(logs.AddCompName(baseCtx, "MedicationLogRepo"), db),
|
|
|
|
|
|
rawMaterialRepo: repository.NewGormRawMaterialRepository(logs.AddCompName(baseCtx, "RawMaterialRepo"), db),
|
|
|
|
|
|
notificationRepo: repository.NewGormNotificationRepository(logs.AddCompName(baseCtx, "NotificationRepo"), db),
|
2025-11-07 22:26:16 +08:00
|
|
|
|
alarmRepo: repository.NewGormAlarmRepository(logs.AddCompName(baseCtx, "AlarmRepo"), db),
|
2025-11-05 19:57:30 +08:00
|
|
|
|
unitOfWork: repository.NewGormUnitOfWork(logs.AddCompName(baseCtx, "UnitOfWork"), db),
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DomainServices 聚合了所有的领域服务实例。
|
|
|
|
|
|
type DomainServices struct {
|
2025-11-02 19:59:13 +08:00
|
|
|
|
pigPenTransferManager pig.PigPenTransferManager
|
|
|
|
|
|
pigTradeManager pig.PigTradeManager
|
|
|
|
|
|
pigSickManager pig.SickPigManager
|
|
|
|
|
|
pigBatchDomain pig.PigBatchService
|
|
|
|
|
|
generalDeviceService device.Service
|
2025-11-02 18:16:44 +08:00
|
|
|
|
taskFactory plan.TaskFactory
|
2025-11-02 19:59:13 +08:00
|
|
|
|
planExecutionManager plan.ExecutionManager
|
|
|
|
|
|
analysisPlanTaskManager plan.AnalysisPlanTaskManager
|
2025-11-02 19:46:20 +08:00
|
|
|
|
planService plan.Service
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// initDomainServices 初始化所有的领域服务。
|
2025-11-05 16:00:43 +08:00
|
|
|
|
func initDomainServices(ctx context.Context, cfg *config.Config, infra *Infrastructure) *DomainServices {
|
|
|
|
|
|
baseCtx := context.Background()
|
|
|
|
|
|
|
2025-10-26 15:48:38 +08:00
|
|
|
|
// 猪群管理相关
|
2025-11-05 19:57:30 +08:00
|
|
|
|
pigPenTransferManager := pig.NewPigPenTransferManager(logs.AddCompName(baseCtx, "PigPenTransferManager"), infra.repos.pigPenRepo, infra.repos.pigTransferLogRepo, infra.repos.pigBatchRepo)
|
|
|
|
|
|
pigTradeManager := pig.NewPigTradeManager(logs.AddCompName(baseCtx, "PigTradeManager"), infra.repos.pigTradeRepo)
|
|
|
|
|
|
pigSickManager := pig.NewSickPigManager(logs.AddCompName(baseCtx, "PigSickManager"), infra.repos.pigSickPigLogRepo, infra.repos.medicationLogRepo)
|
2025-11-05 21:40:19 +08:00
|
|
|
|
pigBatchDomain := pig.NewPigBatchService(
|
|
|
|
|
|
logs.AddCompName(baseCtx, "PigBatchDomain"),
|
|
|
|
|
|
infra.repos.pigBatchRepo,
|
|
|
|
|
|
infra.repos.pigBatchLogRepo,
|
|
|
|
|
|
infra.repos.unitOfWork,
|
|
|
|
|
|
pigPenTransferManager,
|
|
|
|
|
|
pigTradeManager, pigSickManager,
|
|
|
|
|
|
)
|
2025-10-26 15:48:38 +08:00
|
|
|
|
|
|
|
|
|
|
// 通用设备服务
|
|
|
|
|
|
generalDeviceService := device.NewGeneralDeviceService(
|
2025-11-05 19:57:30 +08:00
|
|
|
|
logs.AddCompName(baseCtx, "GeneralDeviceService"),
|
2025-11-02 19:59:13 +08:00
|
|
|
|
infra.repos.deviceRepo,
|
|
|
|
|
|
infra.repos.deviceCommandLogRepo,
|
|
|
|
|
|
infra.repos.pendingCollectionRepo,
|
|
|
|
|
|
infra.lora.comm,
|
2025-10-26 15:48:38 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-10-29 15:30:16 +08:00
|
|
|
|
// 任务工厂
|
2025-11-05 16:00:43 +08:00
|
|
|
|
taskFactory := task.NewTaskFactory(logs.AddCompName(baseCtx, "TaskFactory"), infra.repos.sensorDataRepo, infra.repos.deviceRepo, generalDeviceService)
|
2025-10-26 15:48:38 +08:00
|
|
|
|
|
2025-11-02 19:46:20 +08:00
|
|
|
|
// 计划任务管理器
|
2025-11-05 19:57:30 +08:00
|
|
|
|
analysisPlanTaskManager := plan.NewAnalysisPlanTaskManager(logs.AddCompName(baseCtx, "AnalysisPlanTaskManager"), infra.repos.planRepo, infra.repos.pendingTaskRepo, infra.repos.executionLogRepo)
|
2025-11-02 19:46:20 +08:00
|
|
|
|
|
2025-10-26 15:48:38 +08:00
|
|
|
|
// 任务执行器
|
2025-11-02 18:16:44 +08:00
|
|
|
|
planExecutionManager := plan.NewPlanExecutionManager(
|
2025-11-05 19:57:30 +08:00
|
|
|
|
logs.AddCompName(baseCtx, "PlanExecutionManager"),
|
2025-11-02 19:59:13 +08:00
|
|
|
|
infra.repos.pendingTaskRepo,
|
|
|
|
|
|
infra.repos.executionLogRepo,
|
|
|
|
|
|
infra.repos.deviceRepo,
|
|
|
|
|
|
infra.repos.sensorDataRepo,
|
|
|
|
|
|
infra.repos.planRepo,
|
2025-10-26 15:48:38 +08:00
|
|
|
|
analysisPlanTaskManager,
|
2025-10-29 15:30:16 +08:00
|
|
|
|
taskFactory,
|
2025-10-26 15:48:38 +08:00
|
|
|
|
generalDeviceService,
|
|
|
|
|
|
time.Duration(cfg.Task.Interval)*time.Second,
|
|
|
|
|
|
cfg.Task.NumWorkers,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-11-02 19:46:20 +08:00
|
|
|
|
// 计划管理器
|
2025-11-03 16:29:57 +08:00
|
|
|
|
planService := plan.NewPlanService(
|
2025-11-05 19:57:30 +08:00
|
|
|
|
logs.AddCompName(baseCtx, "PlanService"),
|
2025-11-03 16:29:57 +08:00
|
|
|
|
planExecutionManager,
|
|
|
|
|
|
analysisPlanTaskManager,
|
|
|
|
|
|
infra.repos.planRepo,
|
|
|
|
|
|
infra.repos.deviceRepo,
|
|
|
|
|
|
infra.repos.unitOfWork,
|
|
|
|
|
|
taskFactory,
|
2025-11-05 19:57:30 +08:00
|
|
|
|
)
|
2025-11-02 19:46:20 +08:00
|
|
|
|
|
2025-10-26 15:48:38 +08:00
|
|
|
|
return &DomainServices{
|
2025-11-02 19:59:13 +08:00
|
|
|
|
pigPenTransferManager: pigPenTransferManager,
|
|
|
|
|
|
pigTradeManager: pigTradeManager,
|
|
|
|
|
|
pigSickManager: pigSickManager,
|
|
|
|
|
|
pigBatchDomain: pigBatchDomain,
|
|
|
|
|
|
generalDeviceService: generalDeviceService,
|
|
|
|
|
|
analysisPlanTaskManager: analysisPlanTaskManager,
|
2025-10-29 15:30:16 +08:00
|
|
|
|
taskFactory: taskFactory,
|
2025-11-02 19:59:13 +08:00
|
|
|
|
planExecutionManager: planExecutionManager,
|
2025-11-02 19:46:20 +08:00
|
|
|
|
planService: planService,
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AppServices 聚合了所有的应用服务实例。
|
|
|
|
|
|
type AppServices struct {
|
2025-11-02 19:59:13 +08:00
|
|
|
|
pigFarmService service.PigFarmService
|
|
|
|
|
|
pigBatchService service.PigBatchService
|
|
|
|
|
|
monitorService service.MonitorService
|
|
|
|
|
|
deviceService service.DeviceService
|
|
|
|
|
|
planService service.PlanService
|
|
|
|
|
|
userService service.UserService
|
2025-11-05 19:57:30 +08:00
|
|
|
|
auditService service.AuditService
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// initAppServices 初始化所有的应用服务。
|
2025-11-05 16:00:43 +08:00
|
|
|
|
func initAppServices(ctx context.Context, infra *Infrastructure, domainServices *DomainServices) *AppServices {
|
|
|
|
|
|
baseCtx := context.Background()
|
2025-11-05 19:57:30 +08:00
|
|
|
|
pigFarmService := service.NewPigFarmService(logs.AddCompName(baseCtx, "PigFarmService"), infra.repos.pigFarmRepo, infra.repos.pigPenRepo, infra.repos.pigBatchRepo, domainServices.pigBatchDomain, infra.repos.unitOfWork)
|
|
|
|
|
|
pigBatchService := service.NewPigBatchService(logs.AddCompName(baseCtx, "PigBatchService"), domainServices.pigBatchDomain)
|
2025-10-26 15:48:38 +08:00
|
|
|
|
monitorService := service.NewMonitorService(
|
2025-11-05 19:57:30 +08:00
|
|
|
|
logs.AddCompName(baseCtx, "MonitorService"),
|
2025-11-02 19:59:13 +08:00
|
|
|
|
infra.repos.sensorDataRepo,
|
|
|
|
|
|
infra.repos.deviceCommandLogRepo,
|
|
|
|
|
|
infra.repos.executionLogRepo,
|
|
|
|
|
|
infra.repos.planRepo,
|
|
|
|
|
|
infra.repos.pendingCollectionRepo,
|
|
|
|
|
|
infra.repos.userActionLogRepo,
|
|
|
|
|
|
infra.repos.rawMaterialRepo,
|
|
|
|
|
|
infra.repos.medicationLogRepo,
|
|
|
|
|
|
infra.repos.pigBatchRepo,
|
|
|
|
|
|
infra.repos.pigBatchLogRepo,
|
|
|
|
|
|
infra.repos.pigTransferLogRepo,
|
|
|
|
|
|
infra.repos.pigSickPigLogRepo,
|
|
|
|
|
|
infra.repos.pigTradeRepo,
|
|
|
|
|
|
infra.repos.notificationRepo,
|
2025-10-26 15:48:38 +08:00
|
|
|
|
)
|
2025-10-31 16:00:55 +08:00
|
|
|
|
deviceService := service.NewDeviceService(
|
2025-11-05 19:57:30 +08:00
|
|
|
|
logs.AddCompName(baseCtx, "DeviceService"),
|
2025-11-02 19:59:13 +08:00
|
|
|
|
infra.repos.deviceRepo,
|
|
|
|
|
|
infra.repos.areaControllerRepo,
|
|
|
|
|
|
infra.repos.deviceTemplateRepo,
|
|
|
|
|
|
domainServices.generalDeviceService,
|
2025-10-31 16:00:55 +08:00
|
|
|
|
)
|
2025-11-05 19:57:30 +08:00
|
|
|
|
auditService := service.NewAuditService(logs.AddCompName(baseCtx, "AuditService"), infra.repos.userActionLogRepo)
|
2025-11-05 16:00:43 +08:00
|
|
|
|
planService := service.NewPlanService(logs.AddCompName(baseCtx, "AppPlanService"), domainServices.planService)
|
2025-11-05 21:40:19 +08:00
|
|
|
|
userService := service.NewUserService(logs.AddCompName(baseCtx, "UserService"), infra.repos.userRepo, infra.tokenGenerator, infra.notifyService)
|
2025-10-26 15:48:38 +08:00
|
|
|
|
|
|
|
|
|
|
return &AppServices{
|
2025-11-02 19:59:13 +08:00
|
|
|
|
pigFarmService: pigFarmService,
|
|
|
|
|
|
pigBatchService: pigBatchService,
|
|
|
|
|
|
monitorService: monitorService,
|
|
|
|
|
|
deviceService: deviceService,
|
|
|
|
|
|
auditService: auditService,
|
|
|
|
|
|
planService: planService,
|
|
|
|
|
|
userService: userService,
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// LoraComponents 聚合了所有 LoRa 相关组件。
|
|
|
|
|
|
type LoraComponents struct {
|
2025-11-02 19:59:13 +08:00
|
|
|
|
listenHandler webhook.ListenHandler
|
|
|
|
|
|
comm transport.Communicator
|
|
|
|
|
|
loraListener transport.Listener
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// initLora 根据配置初始化 LoRa 相关组件。
|
|
|
|
|
|
func initLora(
|
2025-11-05 16:00:43 +08:00
|
|
|
|
ctx context.Context,
|
2025-10-26 15:48:38 +08:00
|
|
|
|
cfg *config.Config,
|
|
|
|
|
|
repos *Repositories,
|
|
|
|
|
|
) (*LoraComponents, error) {
|
|
|
|
|
|
var listenHandler webhook.ListenHandler
|
|
|
|
|
|
var comm transport.Communicator
|
|
|
|
|
|
var loraListener transport.Listener
|
2025-11-05 16:00:43 +08:00
|
|
|
|
baseCtx := context.Background()
|
2025-10-26 15:48:38 +08:00
|
|
|
|
|
2025-11-05 16:00:43 +08:00
|
|
|
|
logger := logs.GetLogger(ctx)
|
2025-10-26 15:48:38 +08:00
|
|
|
|
if cfg.Lora.Mode == config.LoraMode_LoRaWAN {
|
|
|
|
|
|
logger.Info("当前运行模式: lora_wan。初始化 ChirpStack 监听器和传输层。")
|
2025-11-05 16:00:43 +08:00
|
|
|
|
listenHandler = webhook.NewChirpStackListener(logs.AddCompName(baseCtx, "ChirpStackListener"), repos.sensorDataRepo, repos.deviceRepo, repos.areaControllerRepo, repos.deviceCommandLogRepo, repos.pendingCollectionRepo)
|
2025-11-05 23:00:07 +08:00
|
|
|
|
comm = lora.NewChirpStackTransport(logs.AddCompName(baseCtx, "ChirpStackTransport"), cfg.ChirpStack)
|
2025-11-05 16:00:43 +08:00
|
|
|
|
loraListener = lora.NewPlaceholderTransport(logs.AddCompName(baseCtx, "PlaceholderTransport"))
|
2025-10-26 15:48:38 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
logger.Info("当前运行模式: lora_mesh。初始化 LoRa Mesh 传输层和占位符监听器。")
|
2025-11-05 16:00:43 +08:00
|
|
|
|
listenHandler = webhook.NewPlaceholderListener(logs.AddCompName(baseCtx, "PlaceholderListener"))
|
2025-11-05 23:00:07 +08:00
|
|
|
|
tp, err := lora.NewLoRaMeshUartPassthroughTransport(logs.AddCompName(baseCtx, "LoRaMeshTransport"), cfg.LoraMesh, repos.areaControllerRepo, repos.pendingCollectionRepo, repos.deviceRepo, repos.sensorDataRepo)
|
2025-10-26 15:48:38 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("无法初始化 LoRa Mesh 模块: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
loraListener = tp
|
|
|
|
|
|
comm = tp
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &LoraComponents{
|
2025-11-02 19:59:13 +08:00
|
|
|
|
listenHandler: listenHandler,
|
|
|
|
|
|
comm: comm,
|
|
|
|
|
|
loraListener: loraListener,
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// initNotifyService 根据配置初始化并返回一个通知领域服务。
|
|
|
|
|
|
// 它确保至少有一个 LogNotifier 总是可用,并根据配置启用其他通知器。
|
|
|
|
|
|
func initNotifyService(
|
2025-11-05 16:00:43 +08:00
|
|
|
|
ctx context.Context,
|
2025-10-26 15:48:38 +08:00
|
|
|
|
cfg config.NotifyConfig,
|
|
|
|
|
|
userRepo repository.UserRepository,
|
|
|
|
|
|
notificationRepo repository.NotificationRepository,
|
|
|
|
|
|
) (domain_notify.Service, error) {
|
|
|
|
|
|
var availableNotifiers []notify.Notifier
|
2025-11-05 16:00:43 +08:00
|
|
|
|
logger := logs.GetLogger(ctx)
|
|
|
|
|
|
baseCtx := context.Background()
|
2025-10-26 15:48:38 +08:00
|
|
|
|
|
|
|
|
|
|
// 1. 总是创建 LogNotifier 作为所有告警的最终记录渠道
|
2025-11-05 16:00:43 +08:00
|
|
|
|
logNotifier := notify.NewLogNotifier(logs.AddCompName(baseCtx, "LogNotifier"))
|
2025-10-26 15:48:38 +08:00
|
|
|
|
availableNotifiers = append(availableNotifiers, logNotifier)
|
2025-11-05 16:00:43 +08:00
|
|
|
|
logger.Info("Log通知器已启用 (作为所有告警的最终记录渠道)")
|
2025-10-26 15:48:38 +08:00
|
|
|
|
|
|
|
|
|
|
// 2. 根据配置,按需创建并收集所有启用的其他 Notifier 实例
|
|
|
|
|
|
if cfg.SMTP.Enabled {
|
|
|
|
|
|
smtpNotifier := notify.NewSMTPNotifier(
|
2025-11-05 23:00:07 +08:00
|
|
|
|
logs.AddCompName(baseCtx, "SMTPNotifier"),
|
2025-10-26 15:48:38 +08:00
|
|
|
|
cfg.SMTP.Host,
|
|
|
|
|
|
cfg.SMTP.Port,
|
|
|
|
|
|
cfg.SMTP.Username,
|
|
|
|
|
|
cfg.SMTP.Password,
|
|
|
|
|
|
cfg.SMTP.Sender,
|
|
|
|
|
|
)
|
|
|
|
|
|
availableNotifiers = append(availableNotifiers, smtpNotifier)
|
2025-11-05 16:00:43 +08:00
|
|
|
|
logger.Info("SMTP通知器已启用")
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if cfg.WeChat.Enabled {
|
|
|
|
|
|
wechatNotifier := notify.NewWechatNotifier(
|
2025-11-05 23:00:07 +08:00
|
|
|
|
logs.AddCompName(baseCtx, "WechatNotifier"),
|
2025-10-26 15:48:38 +08:00
|
|
|
|
cfg.WeChat.CorpID,
|
|
|
|
|
|
cfg.WeChat.AgentID,
|
|
|
|
|
|
cfg.WeChat.Secret,
|
|
|
|
|
|
)
|
|
|
|
|
|
availableNotifiers = append(availableNotifiers, wechatNotifier)
|
2025-11-05 16:00:43 +08:00
|
|
|
|
logger.Info("企业微信通知器已启用")
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if cfg.Lark.Enabled {
|
|
|
|
|
|
larkNotifier := notify.NewLarkNotifier(
|
2025-11-05 23:00:07 +08:00
|
|
|
|
logs.AddCompName(baseCtx, "LarkNotifier"),
|
2025-10-26 15:48:38 +08:00
|
|
|
|
cfg.Lark.AppID,
|
|
|
|
|
|
cfg.Lark.AppSecret,
|
|
|
|
|
|
)
|
|
|
|
|
|
availableNotifiers = append(availableNotifiers, larkNotifier)
|
2025-11-05 16:00:43 +08:00
|
|
|
|
logger.Info("飞书通知器已启用")
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 动态确定首选通知器
|
|
|
|
|
|
var primaryNotifier notify.Notifier
|
2025-11-07 21:39:24 +08:00
|
|
|
|
primaryNotifierType := models.NotifierType(cfg.Primary)
|
2025-10-26 15:48:38 +08:00
|
|
|
|
|
|
|
|
|
|
// 检查用户指定的主渠道是否已启用
|
|
|
|
|
|
for _, n := range availableNotifiers {
|
|
|
|
|
|
if n.Type() == primaryNotifierType {
|
|
|
|
|
|
primaryNotifier = n
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果用户指定的主渠道未启用或未指定,则自动选择第一个可用的 (这将是 LogNotifier,如果其他都未启用)
|
|
|
|
|
|
if primaryNotifier == nil {
|
|
|
|
|
|
primaryNotifier = availableNotifiers[0] // 确保总能找到一个,因为 LogNotifier 总是存在的
|
2025-11-05 16:00:43 +08:00
|
|
|
|
logger.Warnf("配置的首选渠道 '%s' 未启用或未指定,已自动降级使用 '%s' 作为首选渠道。", cfg.Primary, primaryNotifier.Type())
|
2025-10-26 15:48:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 使用创建的 Notifier 列表和 notificationRepo 来组装领域服务
|
|
|
|
|
|
notifyService, err := domain_notify.NewFailoverService(
|
2025-11-05 16:00:43 +08:00
|
|
|
|
logs.AddCompName(baseCtx, "FailoverNotifyService"),
|
2025-10-26 15:48:38 +08:00
|
|
|
|
userRepo,
|
|
|
|
|
|
availableNotifiers,
|
|
|
|
|
|
primaryNotifier.Type(),
|
|
|
|
|
|
cfg.FailureThreshold,
|
|
|
|
|
|
notificationRepo,
|
|
|
|
|
|
)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("创建故障转移通知服务失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 16:00:43 +08:00
|
|
|
|
logger.Infof("通知服务初始化成功,首选渠道: %s, 故障阈值: %d", primaryNotifier.Type(), cfg.FailureThreshold)
|
2025-10-26 15:48:38 +08:00
|
|
|
|
return notifyService, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// initStorage 封装了数据库的初始化、连接和迁移逻辑。
|
2025-11-05 16:00:43 +08:00
|
|
|
|
func initStorage(ctx context.Context, cfg config.DatabaseConfig) (database.Storage, error) {
|
2025-10-26 15:48:38 +08:00
|
|
|
|
// 创建存储实例
|
2025-11-05 22:22:46 +08:00
|
|
|
|
storage := database.NewStorage(logs.AddCompName(context.Background(), "Storage"), cfg)
|
2025-11-05 23:00:07 +08:00
|
|
|
|
if err := storage.Connect(ctx); err != nil {
|
2025-10-26 15:48:38 +08:00
|
|
|
|
// 错误已在 Connect 内部被记录,这里只需包装并返回
|
|
|
|
|
|
return nil, fmt.Errorf("数据库连接失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 执行数据库迁移
|
2025-11-05 19:57:30 +08:00
|
|
|
|
if err := storage.Migrate(ctx, models.GetAllModels()...); err != nil {
|
2025-10-26 15:48:38 +08:00
|
|
|
|
return nil, fmt.Errorf("数据库迁移失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-05 16:00:43 +08:00
|
|
|
|
logs.GetLogger(ctx).Info("数据库初始化完成。")
|
2025-10-26 15:48:38 +08:00
|
|
|
|
return storage, nil
|
|
|
|
|
|
}
|