module; #include #include #include #include export module ttwhy:io; namespace ttwhy::io { export template auto handle_signals(Stream & stream) -> asio::awaitable { auto executor = co_await asio::this_coro::executor; auto signals = asio::signal_set{executor, SIGINT, SIGTERM}; auto [error, signal] = co_await signals.async_wait(asio::as_tuple(asio::use_awaitable)); if (!error) { auto message = std::format("Received signal {}, exiting ...\n", signal); co_await asio::async_write(stream, asio::buffer(message), asio::use_awaitable); } co_return error; } export template auto read(InputStream & input_stream, ErrorStream & error_stream) -> asio::awaitable> { auto data = std::string{15, '\0'}; auto [error, read] = co_await input_stream.async_read_some(asio::buffer(data), asio::as_tuple(asio::use_awaitable)); if (error) { auto message = std::format("{}, exiting ...\n", error.message()); co_await asio::async_write(error_stream, asio::buffer(message), asio::use_awaitable); co_return std::unexpected{error}; } data.resize(read); co_return data; } export template auto write(std::string const & string, OutputStream & output_stream, ErrorStream & error_stream) -> asio::awaitable { auto [error, written] = co_await asio::async_write(output_stream, asio::buffer(string), asio::as_tuple(asio::use_awaitable)); if (error) { auto message = std::format("{}, exiting ...\n", error.message()); co_await asio::async_write(error_stream, asio::buffer(message), asio::use_awaitable); } co_return error; } export template auto echo(InputStream & input_stream, OutputStream & output_stream, ErrorStream & error_stream) -> asio::awaitable { while (true) { auto input = co_await read(input_stream, error_stream); if (!input.has_value()) { co_return input.error(); } auto write_error = co_await write(input.value(), output_stream, error_stream); if (write_error) { co_return write_error; } } } } // namespace ttwhy::io