diff --git a/internal/core/application.go b/internal/core/application.go index 6216da6..0aacafe 100644 --- a/internal/core/application.go +++ b/internal/core/application.go @@ -8,8 +8,11 @@ import ( "syscall" "git.huangwc.com/pig/pig-farm-controller/internal/app/api" + "git.huangwc.com/pig/pig-farm-controller/internal/app/listener" + "git.huangwc.com/pig/pig-farm-controller/internal/app/listener/chirp_stack" "git.huangwc.com/pig/pig-farm-controller/internal/infra/config" "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" + "git.huangwc.com/pig/pig-farm-controller/internal/infra/transport/lora" ) // Application 是整个应用的核心,封装了所有组件和生命周期。 @@ -32,14 +35,11 @@ func NewApplication(configPath string) (*Application, error) { if err := cfg.Load(configPath); err != nil { return nil, fmt.Errorf("无法加载配置: %w", err) } - // 初始化全局日志记录器 logs.InitDefaultLogger(cfg.Log) - - // 为 Application 本身创建 Ctx selfCtx := logs.AddCompName(context.Background(), "Application") ctx := logs.AddFuncName(selfCtx, selfCtx, "NewApplication") - // 2. 初始化所有分层服务 + // 2. 初始化基础设施和领域服务 (此时它们是解耦的) infra, err := initInfrastructure(ctx, cfg) if err != nil { return nil, fmt.Errorf("初始化基础设施失败: %w", err) @@ -50,7 +50,31 @@ func NewApplication(configPath string) (*Application, error) { } appServices := initAppServices(ctx, infra, domain) - // 3. 初始化 API 入口点 + // 3. 【核心组装逻辑】创建应用层监听器并注入到基础设施层 + // 此时,所有依赖项(repos, domain services, comm)都已准备就绪 + upstreamHandler := listener.NewLoRaListener( + selfCtx, + infra.repos.areaControllerRepo, + infra.repos.pendingCollectionRepo, + infra.repos.deviceRepo, + infra.repos.sensorDataRepo, + infra.repos.deviceCommandLogRepo, + infra.repos.otaRepo, + infra.lora.comm, + ) + + // 根据 LoRa 模式完成最终的绑定 + if cfg.Lora.Mode == config.LoraMode_LoRaWAN { + // 对于 LoRaWAN,创建真正的 Webhook 处理器并替换掉占位符 + infra.lora.listenHandler = chirp_stack.NewChirpStackListener(selfCtx, upstreamHandler) + } else { + // 对于 LoRa Mesh,将处理器注入到已创建的 transport 实例中 + if tp, ok := infra.lora.loraListener.(*lora.LoRaMeshUartPassthroughTransport); ok { + tp.SetHandler(upstreamHandler) + } + } + + // 4. 初始化 API 入口点 (现在可以安全地传入 listenHandler) apiServer := api.NewAPI( cfg.Server, logs.AddCompName(context.Background(), "API"), @@ -73,10 +97,10 @@ func NewApplication(configPath string) (*Application, error) { appServices.recipeService, appServices.inventoryService, infra.tokenGenerator, - infra.lora.listenHandler, + infra.lora.listenHandler, // 此处传入的是最终组装好的 handler ) - // 4. 组装 Application 对象 + // 5. 组装 Application 对象 app := &Application{ cfgPath: configPath, Config: cfg, diff --git a/internal/core/component_initializers.go b/internal/core/component_initializers.go index db8b085..ba133bc 100644 --- a/internal/core/component_initializers.go +++ b/internal/core/component_initializers.go @@ -52,7 +52,7 @@ func initInfrastructure(ctx context.Context, cfg *config.Config) (*Infrastructur repos := initRepositories(ctx, storage.GetDB(ctx)) - lora, err := initLora(ctx, cfg, repos) + lora, err := initLora(ctx, cfg) if err != nil { return nil, err } @@ -399,10 +399,10 @@ type LoraComponents struct { } // initLora 根据配置初始化 LoRa 相关组件。 +// 此函数只负责创建和返回底层的传输和监听组件,不关心业务处理器的创建。 func initLora( ctx context.Context, cfg *config.Config, - repos *Repositories, ) (*LoraComponents, error) { var listenHandler listener.ListenHandler var comm transport.Communicator @@ -410,38 +410,28 @@ func initLora( baseCtx := context.Background() logger := logs.GetLogger(ctx) - // 1. 创建统一的业务处理器 (App层适配器) - // 它实现了 infra 层的 transport.UpstreamHandler 接口 - upstreamHandler := listener.NewLoRaListener( - baseCtx, - repos.areaControllerRepo, - repos.pendingCollectionRepo, - repos.deviceRepo, - repos.sensorDataRepo, - repos.deviceCommandLogRepo, - ) - - // 2. 根据配置初始化具体的传输层和监听器 + // 1. 根据配置初始化具体的传输层和监听器 if cfg.Lora.Mode == config.LoraMode_LoRaWAN { - logger.Info("当前运行模式: lora_wan。初始化 ChirpStack 监听器和传输层。") + logger.Info("当前运行模式: lora_wan。初始化 ChirpStack 传输层和占位符监听器。") - // 2a. 创建 ChirpStack 的 Webhook 监听器 (infra),并注入 App 层的业务处理器 - listenHandler = chirp_stack.NewChirpStackListener(baseCtx, upstreamHandler) - - // 2b. 创建 ChirpStack 的发送器 (infra) + // 1a. 创建 ChirpStack 的发送器 (infra) comm = lora.NewChirpStackTransport(logs.AddCompName(baseCtx, "ChirpStackTransport"), cfg.ChirpStack) - // 2c. LoRaWAN 模式下没有主动监听的 Listener,使用占位符 + // 1b. LoRaWAN 模式下没有主动监听的 Listener,使用占位符 loraListener = lora.NewPlaceholderTransport(logs.AddCompName(baseCtx, "PlaceholderTransport")) + // 1c. Webhook 监听器将在 Application 层组装时创建,此处使用占位符 + listenHandler = chirp_stack.NewPlaceholderListener(logs.AddCompName(baseCtx, "PlaceholderListener")) + } else { logger.Info("当前运行模式: lora_mesh。初始化 LoRa Mesh 传输层和占位符监听器。") - // 2a. LoRa Mesh 模式下没有 Webhook 监听器,使用占位符 + // 1a. LoRa Mesh 模式下没有 Webhook 监听器,使用占位符 listenHandler = chirp_stack.NewPlaceholderListener(logs.AddCompName(baseCtx, "PlaceholderListener")) - // 2b. 创建串口的传输工具 (infra),它同时实现了发送和监听,并注入 App 层的业务处理器 - tp, err := lora.NewLoRaMeshUartPassthroughTransport(baseCtx, cfg.LoraMesh, upstreamHandler) + // 1b. 创建串口的传输工具 (infra),它同时实现了发送和监听 + // 注意:此处传入 nil,业务处理器将在 Application 层组装时被注入 + tp, err := lora.NewLoRaMeshUartPassthroughTransport(baseCtx, cfg.LoraMesh, nil) if err != nil { return nil, fmt.Errorf("无法初始化 LoRa Mesh 模块: %w", err) } @@ -449,6 +439,7 @@ func initLora( comm = tp } + // 2. 返回只包含基础设施组件的 LoraComponents return &LoraComponents{ listenHandler: listenHandler, comm: comm, diff --git a/internal/infra/transport/lora/lora_mesh_uart_passthrough_transport.go b/internal/infra/transport/lora/lora_mesh_uart_passthrough_transport.go index 23cd7e6..88ae20a 100644 --- a/internal/infra/transport/lora/lora_mesh_uart_passthrough_transport.go +++ b/internal/infra/transport/lora/lora_mesh_uart_passthrough_transport.go @@ -109,6 +109,12 @@ func NewLoRaMeshUartPassthroughTransport( return t, nil } +// SetHandler 允许在创建实例后设置或更新上行处理器。 +// 这对于解决循环依赖至关重要。 +func (t *LoRaMeshUartPassthroughTransport) SetHandler(handler transport.UpstreamHandler) { + t.handler = handler +} + // Listen 启动后台监听协程(非阻塞) func (t *LoRaMeshUartPassthroughTransport) Listen(ctx context.Context) error { // 注意:这里的 loraCtx 是从 selfCtx 派生的,因为它代表了这个组件自身的生命周期