1//! @file view.hpp
2//! @author ryftchen
3//! @brief The declarations (view) in the application module.
4//! @version 0.1.0
5//! @copyright Copyright (c) 2022-2026 ryftchen. All rights reserved.
6
7#pragma once
8
9#include "configure.hpp"
10
11#include "utility/include/fsm.hpp"
12#include "utility/include/socket.hpp"
13
14//! @brief The application module.
15namespace application // NOLINT(modernize-concat-nested-namespaces)
16{
17//! @brief View-server-related functions in the application module.
18namespace view
19{
20//! @brief Minimum port number.
21inline constexpr std::uint16_t minPortNumber = 1024;
22//! @brief Maximum port number.
23inline constexpr std::uint16_t maxPortNumber = 65535;
24
25//! @brief Simplified interface.
26namespace intf
27{
28//! @brief Connect from the client.
29//! @tparam Sock - type of client
30//! @param client - client to be connected
31template <typename Sock>
32void connectFromClient(std::shared_ptr<Sock>& client);
33//! @brief Forward message by client.
34//! @tparam Sock - type of client
35//! @param client - client to be used for forwarding
36//! @param inputs - input strings to be forwarded
37template <typename Sock>
38void forwardByClient(std::shared_ptr<Sock>& client, const std::vector<std::string>& inputs);
39
40template <>
41void connectFromClient(std::shared_ptr<utility::socket::TCPSocket>& client);
42template <>
43void connectFromClient(std::shared_ptr<utility::socket::UDPSocket>& client);
44template <>
45void forwardByClient(std::shared_ptr<utility::socket::TCPSocket>& client, const std::vector<std::string>& inputs);
46template <>
47void forwardByClient(std::shared_ptr<utility::socket::UDPSocket>& client, const std::vector<std::string>& inputs);
48} // namespace intf
49
50//! @brief Viewer.
51class View final : public utility::fsm::FSM<View>
52{
53public:
54 friend class FSM<View>;
55 //! @brief Destroy the View object.
56 ~View() = default;
57 //! @brief Construct a new View object.
58 View(const View&) = delete;
59 //! @brief Construct a new View object.
60 View(View&&) = delete;
61 //! @brief The operator (=) overloading of View class.
62 //! @return reference of the View object
63 View& operator=(const View&) = delete;
64 //! @brief The operator (=) overloading of View class.
65 //! @return reference of the View object
66 View& operator=(View&&) = delete;
67
68 //! @brief Instance name.
69 static constexpr std::string name{configure::field::viewer};
70 //! @brief Get the View instance.
71 //! @return reference of the View object
72 static std::shared_ptr<View> getInstance();
73 //! @brief Service for running.
74 void service();
75 //! @brief Enumerate specific states for FSM.
76 enum State : std::uint8_t
77 {
78 //! @brief Initial.
79 initial,
80 //! @brief Active.
81 active,
82 //! @brief Established.
83 established,
84 //! @brief Inactive.
85 inactive,
86 //! @brief Idle.
87 idle
88 };
89
90private:
91 //! @brief Construct a new View object.
92 View();
93
94 //! @brief TCP server host address.
95 const std::string tcpHost{configure::detail::tcpHost4Viewer()};
96 //! @brief TCP server port number.
97 const std::uint16_t tcpPort{static_cast<std::uint16_t>(configure::detail::tcpPort4Viewer())};
98 //! @brief UDP server host address.
99 const std::string udpHost{configure::detail::udpHost4Viewer()};
100 //! @brief UDP server port number.
101 const std::uint16_t udpPort{static_cast<std::uint16_t>(configure::detail::udpPort4Viewer())};
102 //! @brief Timeout period (ms) to waiting for the viewer to change to the target state.
103 const std::uint32_t timeoutPeriod{static_cast<std::uint32_t>(configure::detail::helperTimeout())};
104
105 //! @brief Alias for the option arguments.
106 using Args = std::vector<std::string>;
107 //! @brief Option attribute.
108 struct OptBase
109 {
110 //! @brief The option arguments.
111 const Args args;
112 };
113 //! @brief Option attribute for the depend option.
114 struct OptDepend : public OptBase
115 {
116 //! @brief The option name.
117 static constexpr const char* const name{"depend"};
118 //! @brief The option description.
119 static constexpr const char* const description{"list all associated libraries"};
120 };
121 //! @brief Option attribute for the execute option.
122 struct OptExecute : public OptBase
123 {
124 //! @brief The option name.
125 static constexpr const char* const name{"execute"};
126 //! @brief The option description.
127 static constexpr const char* const description{"enter bash commands in quotes [inputs: 'CMD']"};
128 };
129 //! @brief Option attribute for the journal option.
130 struct OptJournal : public OptBase
131 {
132 //! @brief The option name.
133 static constexpr const char* const name{"journal"};
134 //! @brief The option description.
135 static constexpr const char* const description{"view the log with highlights"};
136 };
137 //! @brief Option attribute for the monitor option.
138 struct OptMonitor : public OptBase
139 {
140 //! @brief The option name.
141 static constexpr const char* const name{"monitor"};
142 //! @brief The option description.
143 static constexpr const char* const description{"query process status and stacks [inputs: NUM]"};
144 };
145 //! @brief Option attribute for the profile option.
146 struct OptProfile : public OptBase
147 {
148 //! @brief The option name.
149 static constexpr const char* const name{"profile"};
150 //! @brief The option description.
151 static constexpr const char* const description{"display current configuration"};
152 };
153 friend std::map<std::string, std::string> obtainSupportedOptions();
154 //! @brief Maximum size of the shared memory buffer.
155 static constexpr std::size_t shmLimitSize{static_cast<std::size_t>(65536 * 10)};
156 //! @brief Memory that can be accessed by multiple programs simultaneously.
157 struct ShrMemBlock
158 {
159 //! @brief Data of the shared memory buffer.
160 alignas(64) char data[shmLimitSize];
161 //! @brief Size of the shared memory buffer.
162 alignas(64) std::size_t size;
163 //! @brief Flag for operable.
164 alignas(64) std::atomic_bool signal;
165 };
166
167 //! @brief Alias for the buffer.
168 using Buffer = std::array<char, 1024>;
169 //! @brief Build the response message.
170 //! @param reqPlaintext - plaintext of the request
171 //! @param respBuffer - buffer to store the response
172 //! @return length of the response message
173 static std::size_t buildResponse(const std::string& reqPlaintext, Buffer& respBuffer);
174 //! @brief Alias for the option type.
175 using OptionType = std::variant<OptBase, OptDepend, OptExecute, OptJournal, OptMonitor, OptProfile>;
176 //! @brief Extract the option from the request.
177 //! @param reqPlaintext - plaintext of the request
178 //! @return option type
179 static OptionType extractOption(const std::string& reqPlaintext);
180 //! @brief Split string by space.
181 //! @param str - target string
182 //! @return strings after split
183 static std::vector<std::string> splitString(const std::string& str);
184 //! @brief Build the TLV packet of the response message to acknowledge only.
185 //! @param buffer - TLV packet buffer
186 //! @return buffer length
187 static std::size_t buildAckTLVPacket(Buffer& buffer);
188 //! @brief Build the TLV packet of the response message to stop connection.
189 //! @param buffer - TLV packet buffer
190 //! @return buffer length
191 static std::size_t buildFinTLVPacket(Buffer& buffer);
192 //! @brief Build the TLV packet of the response message in a customized way.
193 //! @tparam Opt - type of option attribute
194 //! @param args - container of arguments
195 //! @param buffer - TLV packet buffer
196 //! @return buffer length
197 template <typename Opt>
198 requires std::derived_from<Opt, OptBase>
199 static std::size_t buildCustomTLVPacket(const Args& args, Buffer& buffer);
200 //! @brief Fill the shared memory.
201 //! @param contents - contents to be filled
202 //! @return shm id
203 static int fillSharedMemory(const std::string_view contents);
204 //! @brief Fetch the shared memory.
205 //! @param shmId - shm id
206 //! @param contents - contents to be fetched
207 static void fetchSharedMemory(const int shmId, std::string& contents);
208 //! @brief Print the shared memory.
209 //! @param shmId - shm id
210 //! @param withoutPaging - whether output without paging
211 static void printSharedMemory(const int shmId, const bool withoutPaging = true);
212 //! @brief Segmented output.
213 //! @param cache - output cache
214 static void segmentedOutput(const std::string& cache);
215 //! @brief Log context preview.
216 //! @return log context
217 static std::string logContextPreview();
218 //! @brief Status report preview.
219 //! @param frame - maximum frame
220 //! @return status report
221 static std::string statusReportPreview(const std::uint16_t frame);
222
223 //! @brief The server (TCP) of the permanent session.
224 std::shared_ptr<utility::socket::TCPServer> permSessServer;
225 //! @brief The server (UDP) of the temporary session.
226 std::shared_ptr<utility::socket::UDPServer> tempSessServer;
227 //! @brief Mutex for controlling daemon.
228 mutable std::mutex daemonMtx;
229 //! @brief The synchronization condition for daemon. Use with daemonMtx.
230 std::condition_variable daemonCond;
231 //! @brief Flag to indicate whether it is viewing.
232 std::atomic_bool isOngoing{false};
233 //! @brief Flag for rollback request.
234 std::atomic_bool inResetting{false};
235 //! @brief Mutex for controlling output.
236 mutable std::mutex outputMtx;
237 //! @brief The synchronization condition for output. Use with outputMtx.
238 std::condition_variable outputCond;
239 //! @brief Flag to indicate whether the output is complete.
240 std::atomic_bool outputCompleted{true};
241 //! @brief Renew the server.
242 //! @tparam Sock - type of server
243 template <typename Sock>
244 void renewServer();
245
246 template <typename Sock>
247 friend void intf::connectFromClient(std::shared_ptr<Sock>& client);
248 //! @brief Connect from the client. Simplified interface for external use.
249 //! @tparam Sock - type of client
250 //! @param client - client to be connected
251 template <typename Sock>
252 void onConnecting(std::shared_ptr<Sock>& client);
253 template <typename Sock>
254 friend void intf::forwardByClient(std::shared_ptr<Sock>& client, const std::vector<std::string>& inputs);
255 //! @brief Forward message by client. Simplified interface for external use.
256 //! @tparam Sock - type of client
257 //! @param client - client to be used for forwarding
258 //! @param inputs - input strings to be forwarded
259 template <typename Sock>
260 void onForwarding(std::shared_ptr<Sock>& client, const std::vector<std::string>& inputs);
261 //! @brief Parse the TLV packet of message.
262 //! @tparam Sock - type of client
263 //! @param client - client associated with parsing
264 //! @param bytes - message buffer
265 //! @param size - message length
266 template <typename Sock>
267 void parseTLVMessage(std::shared_ptr<Sock>& client, char* const bytes, const std::size_t size);
268 //! @brief Block the caller until the output task is marked as done.
269 void waitTaskDone();
270 //! @brief Notify that the output task has been completed and unblock any waiters.
271 void notifyTaskDone();
272 friend class configure::Controller<View>;
273 //! @brief Wait until the viewer reaches the target state. Access controller for external use.
274 //! @param state - target state
275 //! @param handling - handling if unexpected state
276 void syncWaitOr(const State state, const std::function<void()>& handling) const;
277 //! @brief Notify the viewer to change the state. Access controller for external use.
278 //! @param action - action to be executed
279 void syncNotifyVia(const std::function<void()>& action);
280 //! @brief Keep countdown if the viewer does not meet the condition in time. Access controller for external use.
281 //! @param condition - condition of countdown
282 //! @param handling - handling if timeout
283 void syncCountdownIf(const std::function<bool()>& condition, const std::function<void()>& handling) const;
284
285 //! @brief Check whether it is in the uninterrupted serving state.
286 //! @param state - target state
287 //! @return in the uninterrupted serving state or not
288 bool isInServingState(const State state) const;
289 //! @brief FSM event. Create server.
290 struct CreateServer
291 {
292 };
293 //! @brief FSM event. Destroy server.
294 struct DestroyServer
295 {
296 };
297 //! @brief FSM event. Go viewing.
298 struct GoViewing
299 {
300 };
301 //! @brief FSM event. NO viewing.
302 struct NoViewing
303 {
304 };
305 //! @brief FSM event. Standby.
306 struct Standby
307 {
308 };
309 //! @brief FSM event. Relaunch.
310 struct Relaunch
311 {
312 };
313 //! @brief Create the view server.
314 void createViewServer();
315 //! @brief Destroy the view server.
316 void destroyViewServer();
317 //! @brief Start viewing.
318 void startViewing();
319 //! @brief Stop viewing.
320 void stopViewing();
321 //! @brief Do toggle.
322 void doToggle();
323 //! @brief Do rollback.
324 void doRollback();
325 // clang-format off
326 //! @brief Alias for the transition table of the viewer.
327 using TransitionTable = Table
328 <
329 // +------ Source ------+---- Event ----+------ Target ------+--------- Action ---------+- Guard -+
330 // +--------------------+---------------+--------------------+--------------------------+---------+
331 Row< State::initial , CreateServer , State::active , &View::createViewServer >,
332 Row< State::active , GoViewing , State::established , &View::startViewing >,
333 Row< State::established , DestroyServer , State::active , &View::destroyViewServer >,
334 Row< State::active , NoViewing , State::inactive , &View::stopViewing >,
335 Row< State::initial , Standby , State::idle , &View::doToggle >,
336 Row< State::active , Standby , State::idle , &View::doToggle >,
337 Row< State::established , Standby , State::idle , &View::doToggle >,
338 Row< State::established , Relaunch , State::initial , &View::doRollback >,
339 Row< State::inactive , Relaunch , State::initial , &View::doRollback >,
340 Row< State::idle , Relaunch , State::initial , &View::doRollback >
341 // +--------------------+---------------+--------------------+--------------------------+---------+
342 >;
343 // clang-format on
344 //! @brief The notification loop.
345 void notificationLoop();
346 //! @brief Await notification to proceed.
347 void awaitNotification2Proceed();
348 //! @brief Await notification to retry.
349 //! @return whether retry is required or not
350 bool awaitNotification2Retry();
351
352protected:
353 friend std::ostream& operator<<(std::ostream& os, const State state);
354};
355
356extern auto obtainSupportedOptions() -> std::map<std::string, std::string>;
357extern std::string buildDisconnectRequest();
358extern void interactionLatency();
359} // namespace view
360} // namespace application
361