File indexing completed on 2024-09-22 04:57:52
0001 /* 0002 SPDX-FileCopyrightText: 2018 Ivan Čukić <ivan.cukic(at)kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #ifndef VOY_TRASNPORT_ASIO_PROCESS_H 0008 #define VOY_TRASNPORT_ASIO_PROCESS_H 0009 0010 // STL 0011 #include <string> 0012 #include <iostream> 0013 0014 // Boost 0015 #include <boost/process.hpp> 0016 #include <boost/algorithm/cxx11/copy_if.hpp> 0017 #include <boost/asio/read_until.hpp> 0018 0019 // Self 0020 #include "../../utils.h" 0021 #include "service.h" 0022 0023 namespace voy::engine::asio { 0024 0025 using utils::non_copyable; 0026 0027 template <typename Handler> 0028 class process: non_copyable { 0029 public: 0030 template <typename Tuple, size_t ...Idx> 0031 auto make_process_impl(Tuple&& args, std::index_sequence<Idx...>) 0032 { 0033 // utils::print_types<Tuple>(); 0034 return boost::process::child(std::get<Idx>(std::move(args))..., boost::process::std_out > m_pipe); 0035 } 0036 0037 template <typename ...Args> 0038 decltype(auto) make_process(std::tuple<Args...> args) 0039 { 0040 return make_process_impl(std::move(args), 0041 std::index_sequence_for<Args...>()); 0042 } 0043 0044 0045 0046 template <typename ...Args> 0047 process(Handler handler, std::tuple<Args...> args) 0048 : m_handler{std::move(handler)} 0049 , m_pipe(service::instance()) 0050 , m_process{make_process(args)} 0051 // , m_process(args, boost::process::std_out > m_pipe) 0052 { 0053 read_next(); 0054 } 0055 0056 ~process() 0057 { 0058 } 0059 0060 process(process&& other) = delete; 0061 process& operator=(process&& other) = delete; 0062 0063 template <typename T> 0064 void notify(T&& value) 0065 { 0066 voy_fwd_invoke(m_handler, value); 0067 } 0068 0069 void init_handler() 0070 { 0071 m_handler.init(); 0072 } 0073 0074 void read_next() 0075 { 0076 boost::asio::async_read_until( 0077 m_pipe, m_buffer, "\n", 0078 [&] (boost::system::error_code ec, size_t count) { 0079 // std::cerr << "One read finished: " << ec.message() << " count:" << count << std::endl; 0080 0081 if (ec && !(ec.value() == boost::asio::error::eof)) { 0082 std::cerr << "Unknown error: " << ec.message() << std::endl; 0083 m_handler.notify_ended(); 0084 return; 0085 } 0086 0087 // std::string line; 0088 std::istream stream(&m_buffer); 0089 auto line_begin = std::istreambuf_iterator<char>(stream); 0090 const auto buffer_end = std::istreambuf_iterator<char>(); 0091 0092 // std::string s(line_begin, buffer_end); 0093 // std::cerr << "READ [" << s << "]\n"; 0094 0095 for (;;) { 0096 auto is_newline = [] (char c) { return c == '\n'; }; 0097 0098 std::string line; 0099 line.reserve(256); 0100 0101 auto [ next, output ] = boost::algorithm::copy_until( 0102 line_begin, buffer_end, 0103 std::back_inserter(line), 0104 is_newline); 0105 0106 line_begin = next; 0107 0108 if (buffer_end == line_begin) { 0109 m_previous_line = line; 0110 break; 0111 } 0112 0113 auto to_send = m_previous_line + line; 0114 std::invoke(m_handler, to_send); 0115 m_previous_line.clear(); 0116 0117 ++line_begin; 0118 0119 if (buffer_end == line_begin) { 0120 break; 0121 } 0122 } 0123 0124 if (!ec) { 0125 read_next(); 0126 0127 } else { 0128 std::invoke(m_handler, std::move(m_previous_line)); 0129 m_handler.notify_ended(); 0130 } 0131 }); 0132 } 0133 0134 private: 0135 Handler m_handler; 0136 boost::process::async_pipe m_pipe; 0137 boost::process::child m_process; 0138 boost::asio::streambuf m_buffer; 0139 std::string m_previous_line; 0140 }; 0141 0142 } // namespace voy::engine::asio 0143 0144 #endif // include guard 0145