blob: eb9a40345c1c4fa3ef12b146f92964f081d91923 [file] [log] [blame]
Tyler Chatowa79419d2020-08-12 20:12:11 -07001#include "starter_rpc_lib.h"
2
3#include "aos/events/shm_event_loop.h"
4#include "aos/flatbuffer_merge.h"
5
6namespace aos {
7namespace starter {
8
9const aos::starter::ApplicationStatus *FindApplicationStatus(
10 const aos::starter::Status &status, std::string_view name) {
11 if (!status.has_statuses()) {
12 return nullptr;
13 }
14
15 auto statuses = status.statuses();
16
17 auto search =
18 std::find_if(statuses->begin(), statuses->end(),
19 [name](const aos::starter::ApplicationStatus *app_status) {
20 return app_status->has_name() &&
21 app_status->name()->string_view() == name;
22 });
23 if (search == statuses->end()) {
24 return nullptr;
25 }
26 return *search;
27}
28
milind upadhyay4272f382021-04-07 18:03:08 -070029std::string_view FindApplication(const std::string_view &name,
30 const aos::Configuration *config) {
31 std::string_view app_name = name;
32 for (const auto app : *config->applications()) {
Milind Upadhyay7641ce82021-04-10 14:15:28 -070033 if (app->has_executable_name() &&
milind upadhyay4272f382021-04-07 18:03:08 -070034 app->executable_name()->string_view() == name) {
35 app_name = app->name()->string_view();
36 break;
37 }
38 }
39 return app_name;
40}
41
Tyler Chatowa79419d2020-08-12 20:12:11 -070042bool SendCommandBlocking(aos::starter::Command command, std::string_view name,
43 const aos::Configuration *config,
44 std::chrono::milliseconds timeout) {
Austin Schuhe4b748a2021-10-16 14:19:58 -070045 return SendCommandBlocking(
46 std::vector<std::pair<aos::starter::Command, std::string_view>>{
47 {command, name}},
48 config, timeout);
49}
50
51bool SendCommandBlocking(
52 std::vector<std::pair<aos::starter::Command, std::string_view>> commands,
53 const aos::Configuration *config, std::chrono::milliseconds timeout) {
Tyler Chatowa79419d2020-08-12 20:12:11 -070054 aos::ShmEventLoop event_loop(config);
55 event_loop.SkipAosLog();
56
57 ::aos::Sender<aos::starter::StarterRpc> cmd_sender =
58 event_loop.MakeSender<aos::starter::StarterRpc>("/aos");
59
Austin Schuhe4b748a2021-10-16 14:19:58 -070060 // Wait until event loop starts to send all commands so the watcher is ready
61 event_loop.OnRun([&cmd_sender, &commands] {
62 for (const std::pair<aos::starter::Command, std::string_view>
63 &command_pair : commands) {
64 const aos::starter::Command command = command_pair.first;
65 const std::string_view name = command_pair.second;
66 aos::Sender<aos::starter::StarterRpc>::Builder builder =
67 cmd_sender.MakeBuilder();
Tyler Chatowa79419d2020-08-12 20:12:11 -070068
Austin Schuhe4b748a2021-10-16 14:19:58 -070069 auto name_str = builder.fbb()->CreateString(name);
Tyler Chatowa79419d2020-08-12 20:12:11 -070070
Austin Schuhe4b748a2021-10-16 14:19:58 -070071 aos::starter::StarterRpc::Builder cmd_builder =
72 builder.MakeBuilder<aos::starter::StarterRpc>();
Tyler Chatowa79419d2020-08-12 20:12:11 -070073
Austin Schuhe4b748a2021-10-16 14:19:58 -070074 cmd_builder.add_name(name_str);
75 cmd_builder.add_command(command);
Tyler Chatowa79419d2020-08-12 20:12:11 -070076
Austin Schuhe4b748a2021-10-16 14:19:58 -070077 builder.Send(cmd_builder.Finish());
78 }
Tyler Chatowa79419d2020-08-12 20:12:11 -070079 });
80
81 // If still waiting after timeout milliseconds, exit the loop
82 event_loop.AddTimer([&event_loop] { event_loop.Exit(); })
83 ->Setup(event_loop.monotonic_now() + timeout);
84
Austin Schuhe4b748a2021-10-16 14:19:58 -070085 // Fetch the last list of statuses. The id field changes every time the
86 // application restarts. By detecting when the application is running with a
87 // different ID, we can detect restarts.
Tyler Chatowa79419d2020-08-12 20:12:11 -070088 auto initial_status_fetcher =
89 event_loop.MakeFetcher<aos::starter::Status>("/aos");
90 initial_status_fetcher.Fetch();
Tyler Chatowa79419d2020-08-12 20:12:11 -070091
Austin Schuhe4b748a2021-10-16 14:19:58 -070092 std::vector<std::optional<uint64_t>> initial_ids;
Tyler Chatowa79419d2020-08-12 20:12:11 -070093
Austin Schuhe4b748a2021-10-16 14:19:58 -070094 for (const std::pair<aos::starter::Command, std::string_view> &command_pair :
95 commands) {
96 const std::string_view name = command_pair.second;
97 auto initial_status =
98 initial_status_fetcher.get()
99 ? FindApplicationStatus(*initial_status_fetcher, name)
100 : nullptr;
101
102 initial_ids.emplace_back(
103 (initial_status != nullptr && initial_status->has_id())
104 ? std::make_optional(initial_status->id())
105 : std::nullopt);
106 }
107
108 std::vector<bool> successes(commands.size(), false);
Tyler Chatowa79419d2020-08-12 20:12:11 -0700109 bool success = false;
Austin Schuhe4b748a2021-10-16 14:19:58 -0700110 event_loop.MakeWatcher("/aos", [&event_loop, &commands, &initial_ids, &success,
111 &successes](
112 const aos::starter::Status &status) {
113 size_t index = 0;
114 for (const std::pair<aos::starter::Command, std::string_view>
115 &command_pair : commands) {
116 const aos::starter::Command command = command_pair.first;
117 const std::string_view name = command_pair.second;
Tyler Chatowa79419d2020-08-12 20:12:11 -0700118
Austin Schuhe4b748a2021-10-16 14:19:58 -0700119 const aos::starter::ApplicationStatus *app_status =
120 FindApplicationStatus(status, name);
Tyler Chatowa79419d2020-08-12 20:12:11 -0700121
Austin Schuhe4b748a2021-10-16 14:19:58 -0700122 const std::optional<aos::starter::State> state =
123 (app_status != nullptr && app_status->has_state())
124 ? std::make_optional(app_status->state())
125 : std::nullopt;
126
127 switch (command) {
128 case aos::starter::Command::START: {
129 if (state == aos::starter::State::RUNNING) {
130 successes[index] = true;
Tyler Chatowa79419d2020-08-12 20:12:11 -0700131 }
Austin Schuhe4b748a2021-10-16 14:19:58 -0700132 break;
Tyler Chatowa79419d2020-08-12 20:12:11 -0700133 }
Austin Schuhe4b748a2021-10-16 14:19:58 -0700134 case aos::starter::Command::STOP: {
135 if (state == aos::starter::State::STOPPED) {
136 successes[index] = true;
137 }
138 break;
139 }
140 case aos::starter::Command::RESTART: {
141 if (state == aos::starter::State::RUNNING && app_status->has_id() &&
142 app_status->id() != initial_ids[index]) {
143 successes[index] = true;
144 }
145 break;
146 }
147 }
148 ++index;
149 }
150
151 // Wait until all applications are ready.
152 if (std::count(successes.begin(), successes.end(), true) ==
153 static_cast<ssize_t>(successes.size())) {
154 event_loop.Exit();
155 success = true;
156 }
157 });
Tyler Chatowa79419d2020-08-12 20:12:11 -0700158
159 event_loop.Run();
160
161 return success;
162}
163
164const FlatbufferDetachedBuffer<aos::starter::ApplicationStatus> GetStatus(
165 std::string_view name, const Configuration *config) {
166 ShmEventLoop event_loop(config);
167 event_loop.SkipAosLog();
168
169 auto status_fetcher = event_loop.MakeFetcher<aos::starter::Status>("/aos");
170 status_fetcher.Fetch();
Milind Upadhyay49174a72021-04-10 16:24:57 -0700171 auto status = status_fetcher.get()
172 ? FindApplicationStatus(*status_fetcher, name)
173 : nullptr;
Tyler Chatowa79419d2020-08-12 20:12:11 -0700174 return status ? aos::CopyFlatBuffer(status)
175 : FlatbufferDetachedBuffer<
176 aos::starter::ApplicationStatus>::Empty();
177}
178
milind upadhyay4272f382021-04-07 18:03:08 -0700179std::optional<const aos::FlatbufferVector<aos::starter::Status>>
180GetStarterStatus(const aos::Configuration *config) {
Philipp Schrader08537492021-01-23 16:17:55 -0800181 ShmEventLoop event_loop(config);
182 event_loop.SkipAosLog();
183
184 auto status_fetcher = event_loop.MakeFetcher<aos::starter::Status>("/aos");
185 status_fetcher.Fetch();
Milind Upadhyay49174a72021-04-10 16:24:57 -0700186 return (status_fetcher.get()
187 ? std::make_optional(status_fetcher.CopyFlatBuffer())
188 : std::nullopt);
Philipp Schrader08537492021-01-23 16:17:55 -0800189}
190
Tyler Chatowa79419d2020-08-12 20:12:11 -0700191} // namespace starter
192} // namespace aos