module; #include #include #include // IWYU pragma: keep #include #include #include export module ttwhy:io; import ttwhy.scanners; namespace ttwhy::io { export template auto handle_signals(Stream & stream, TerminalAttributes & attributes) -> asio::awaitable { auto executor = co_await asio::this_coro::executor; auto signals = asio::signal_set{executor, SIGINT, SIGTERM}; signals.add(SIGTSTP); signals.add(SIGCONT); while (true) { auto [error, signal] = co_await signals.async_wait(asio::as_tuple(asio::use_awaitable)); if (error) { co_return error; } switch (signal) { case SIGINT: case SIGTERM: { auto message = std::format("Received signal {}, exiting ...\n", signal); co_await asio::async_write(stream, asio::buffer(message), asio::use_awaitable); co_return asio::error_code{}; } case SIGTSTP: { attributes.canonical_mode(true).echo(true); ::raise(SIGSTOP); break; } case SIGCONT: { attributes.canonical_mode(false).echo(false); break; } } if (!error) { } } } export template auto read_events(InputStream & stream, AppRouter & router) -> asio::awaitable { using namespace asio::experimental::awaitable_operators; using namespace std::chrono_literals; auto executor = co_await asio::this_coro::executor; auto timer = asio::steady_timer{executor}; auto queue = std::vector{}; queue.reserve(16); auto sink = [&queue](auto const & event) { queue.push_back(event); }; auto scanner = scanners::ansi{sink}; auto raw_buffer = std::array{}; while (true) { auto error = asio::error_code{}; auto bytes_read = std::size_t{}; if (scanner.is_pending()) { timer.expires_after(50ms); auto result = co_await (stream.async_read_some(asio::buffer(raw_buffer), asio::as_tuple(asio::use_awaitable)) || timer.async_wait(asio::as_tuple(asio::use_awaitable))); if (result.index() == 0) { std::tie(error, bytes_read) = std::get<0>(result); } else { scanner.timeout(); for (auto const & event : queue) { co_await router.process(event); } queue.clear(); continue; } } else { std::tie(error, bytes_read) = co_await stream.async_read_some(asio::buffer(raw_buffer), asio::as_tuple(asio::use_awaitable)); } if (error) { if (error == asio::error::interrupted) { continue; } co_return; } auto const byte_span = std::span{raw_buffer.data(), bytes_read}; scanner.process(byte_span); for (auto const & event : queue) { co_await router.process(event); } queue.clear(); } } } // namespace ttwhy::io