#pragma once #include "fgc/ChannelHistory.h" #include "fgc/ChannelTopics.h" #include "fgc/IControlChannel.h" #include "fgc/Logger.h" #include #include namespace fgc { // No-op control channel for running without an MQTT broker. Publishes go // nowhere and poll() never supplies a control command, so the scheduler stays // in automatic-sweep mode (ControlCode 0). // // It still records what it was asked to send, using the same topic and payload // builders as the real channel, so the connectivity view works under --no-mqtt // and shows exactly what would have gone out. Every entry is Delivery::Dropped, // which is the truth: nothing was sent. class NullControlChannel : public IControlChannel { public: explicit NullControlChannel(std::string tower = "") : tower_(std::move(tower)) {} bool connect() override { return true; } void disconnect() override {} bool connected() const override { return true; } void publishStatus(int code) override { const std::string payload = std::to_string(code); history_.noteStatus(payload); LOG_TRACE_CAT(LogCat::Mqtt) << "PUB StatusCode " << code << " (null channel)"; drop(kTopicStatusCode, payload); } void publishCamEvent(const CamEvent& e) override { LOG_TRACE_CAT(LogCat::Mqtt) << "PUB CamEvent cam=" << e.camera << " hdg=" << e.heading_decideg << " t=" << e.timestamp_ms << " (null channel)"; drop(kTopicCamEvent, camEventJson(e)); } ControlCommand poll() override { return {}; } std::vector recentMessages() const override { return history_.recent(); } ChannelStats channelStats() const override { return history_.stats(); } private: void drop(const std::string& leaf, std::string payload) { history_.record(/*outbound=*/true, Delivery::Dropped, towerTopic(tower_, leaf), std::move(payload)); } std::string tower_; ChannelHistory history_; }; } // namespace fgc