#pragma once // Running a console command that arrived over MQTT, and building its answer. // // The command goes through exactly the function a typed one does - the caller // passes it in - on the control thread, so its lock-outs, refusals and output // are the console's. What this adds is what a remote caller needs and a person // at the console does not: // - the answer: every line the command logged while it ran, and the most // severe level among them, sent back on CommandReply; // - a retained message is never run - it would re-run on every reconnect; // - a repeated id (QoS 1 may deliver twice) is answered again, not re-run; // - an audit line in the log for every remote command, before it runs; // - for a command whose answer comes back later from the firmware (`gimbal // dump`), the reply waits for that answer - see Await. #include "fgc/IControlChannel.h" #include #include #include #include #include #include #include namespace fgc { // What a command's answer still waits for once the command has returned: the // firmware answers `gimbal dump` on the serial thread, a moment later. While // waiting, lines from any thread that contain one of `collect` join the reply, // and the first that contains one of `ends` completes it. struct Await { std::vector collect; std::vector ends; long long timeout_ms = 5000; }; class RemoteCommandRunner { public: using Handler = std::function; // Run `rc` through `handle` (the console's command handler). Returns the // reply to publish - or nothing yet, when `await` is given and the command // did not warn: then the reply comes from poll(). Must be called on the // thread that runs the commands: of what is logged while `handle` runs, only // the calling thread's lines count as this command's output. std::optional run(const RemoteCommand& rc, const Handler& handle, const Await* await = nullptr, long long now_ms = 0); // A reply is still waiting for its answer; run nothing else until poll() // has returned it, so replies keep the order of their commands. bool waiting() const { return pending_ != nullptr; } // The waiting reply, once its answer has arrived or the wait timed out. std::optional poll(long long now_ms); // How many ids are remembered for de-duplication. static constexpr size_t kRememberIds = 64; struct Capture; // the tap's buffer; defined in RemoteCommands.cpp private: CommandReply finish(const RemoteCommand& rc, Capture& cap); struct Pending; std::shared_ptr pending_; std::deque> recent_; // id -> reply, newest last }; } // namespace fgc