72 lines
2.8 KiB
C++
72 lines
2.8 KiB
C++
#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 <deque>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
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<std::string> collect;
|
|
std::vector<std::string> ends;
|
|
long long timeout_ms = 5000;
|
|
};
|
|
|
|
class RemoteCommandRunner {
|
|
public:
|
|
using Handler = std::function<void(const std::string& line)>;
|
|
|
|
// 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<CommandReply> 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<CommandReply> 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> pending_;
|
|
std::deque<std::pair<std::string, CommandReply>> recent_; // id -> reply, newest last
|
|
};
|
|
|
|
} // namespace fgc
|