blob: 7b86c0ae35a8ec3661c882817d9b37fa996cf2ff [file] [log] [blame]
#include "starter_rpc_lib.h"
#include "aos/events/shm_event_loop.h"
#include "aos/flatbuffer_merge.h"
namespace aos {
namespace starter {
const aos::starter::ApplicationStatus *FindApplicationStatus(
const aos::starter::Status &status, std::string_view name) {
if (!status.has_statuses()) {
return nullptr;
}
auto statuses = status.statuses();
auto search =
std::find_if(statuses->begin(), statuses->end(),
[name](const aos::starter::ApplicationStatus *app_status) {
return app_status->has_name() &&
app_status->name()->string_view() == name;
});
if (search == statuses->end()) {
return nullptr;
}
return *search;
}
std::string_view FindApplication(const std::string_view &name,
const aos::Configuration *config) {
std::string_view app_name = name;
for (const auto app : *config->applications()) {
if (app->has_executable_name() &&
app->executable_name()->string_view() == name) {
app_name = app->name()->string_view();
break;
}
}
return app_name;
}
bool SendCommandBlocking(aos::starter::Command command, std::string_view name,
const aos::Configuration *config,
std::chrono::milliseconds timeout) {
aos::ShmEventLoop event_loop(config);
event_loop.SkipAosLog();
::aos::Sender<aos::starter::StarterRpc> cmd_sender =
event_loop.MakeSender<aos::starter::StarterRpc>("/aos");
// Wait until event loop starts to send command so watcher is ready
event_loop.OnRun([&cmd_sender, command, name] {
aos::Sender<aos::starter::StarterRpc>::Builder builder =
cmd_sender.MakeBuilder();
auto name_str = builder.fbb()->CreateString(name);
aos::starter::StarterRpc::Builder cmd_builder =
builder.MakeBuilder<aos::starter::StarterRpc>();
cmd_builder.add_name(name_str);
cmd_builder.add_command(command);
builder.Send(cmd_builder.Finish());
});
// If still waiting after timeout milliseconds, exit the loop
event_loop.AddTimer([&event_loop] { event_loop.Exit(); })
->Setup(event_loop.monotonic_now() + timeout);
// Fetch the last list of statuses to compare the requested application's id
// against for commands such as restart.
auto initial_status_fetcher =
event_loop.MakeFetcher<aos::starter::Status>("/aos");
initial_status_fetcher.Fetch();
auto initial_status =
initial_status_fetcher.get()
? FindApplicationStatus(*initial_status_fetcher, name)
: nullptr;
const std::optional<uint64_t> initial_id =
(initial_status != nullptr && initial_status->has_id())
? std::make_optional(initial_status->id())
: std::nullopt;
bool success = false;
event_loop.MakeWatcher(
"/aos", [&event_loop, command, name, initial_id,
&success](const aos::starter::Status &status) {
const aos::starter::ApplicationStatus *app_status =
FindApplicationStatus(status, name);
const std::optional<aos::starter::State> state =
(app_status != nullptr && app_status->has_state())
? std::make_optional(app_status->state())
: std::nullopt;
switch (command) {
case aos::starter::Command::START: {
if (state == aos::starter::State::RUNNING) {
success = true;
event_loop.Exit();
}
break;
}
case aos::starter::Command::STOP: {
if (state == aos::starter::State::STOPPED) {
success = true;
event_loop.Exit();
}
break;
}
case aos::starter::Command::RESTART: {
if (state == aos::starter::State::RUNNING && app_status->has_id() &&
app_status->id() != initial_id) {
success = true;
event_loop.Exit();
}
break;
}
}
});
event_loop.Run();
return success;
}
const FlatbufferDetachedBuffer<aos::starter::ApplicationStatus> GetStatus(
std::string_view name, const Configuration *config) {
ShmEventLoop event_loop(config);
event_loop.SkipAosLog();
auto status_fetcher = event_loop.MakeFetcher<aos::starter::Status>("/aos");
status_fetcher.Fetch();
auto status = status_fetcher.get()
? FindApplicationStatus(*status_fetcher, name)
: nullptr;
return status ? aos::CopyFlatBuffer(status)
: FlatbufferDetachedBuffer<
aos::starter::ApplicationStatus>::Empty();
}
std::optional<const aos::FlatbufferVector<aos::starter::Status>>
GetStarterStatus(const aos::Configuration *config) {
ShmEventLoop event_loop(config);
event_loop.SkipAosLog();
auto status_fetcher = event_loop.MakeFetcher<aos::starter::Status>("/aos");
status_fetcher.Fetch();
return (status_fetcher.get()
? std::make_optional(status_fetcher.CopyFlatBuffer())
: std::nullopt);
}
} // namespace starter
} // namespace aos