#pragma once #include "irc_thread.hpp" #include "ircmsg.hpp" #include "linebuffer.hpp" #include "settings.hpp" #include #include #include #include #include #include #include #include #include #include #include #include class Connection : public std::enable_shared_from_this { boost::asio::ip::tcp::socket stream_; boost::asio::steady_timer write_timer_; std::list write_strings_; std::vector> threads_; auto writer() -> void; auto writer_() -> void; template auto dispatch( IrcThread::callback_result (IrcThread::* method)(Args...), Args... args ) -> void { std::vector> work; work.swap(threads_); std::sort(work.begin(), work.end(), [](auto const& a, auto const& b) { return a->priority() < b->priority(); }); std::size_t const n = work.size(); for (std::size_t i = 0; i < n; i++) { auto const [thread_outcome, msg_outcome] = (work[i].get()->*method)(args...); if (thread_outcome == ThreadOutcome::Continue) { threads_.push_back(std::move(work[i])); } if (msg_outcome == EventOutcome::Consume) { std::move(work.begin() + i + 1, work.end(), std::back_inserter(threads_)); break; } } } public: Connection(boost::asio::io_context & io) : stream_{io} , write_timer_{io, std::chrono::steady_clock::time_point::max()} { } auto listen(std::unique_ptr thread) -> void { threads_.push_back(std::move(thread)); } auto write(std::string front, std::string_view last) -> void; template auto write(std::string front, std::string_view next, Args ...rest) -> void { auto const is_invalid = [](char x) -> bool { return x == '\0' || x == '\r' || x == '\n' || x == ' '; }; if (next.empty() || next.end() != std::find_if(next.begin(), next.end(), is_invalid)) { throw std::runtime_error{"bad irc argument"}; } front += " "; front += next; write(std::move(front), rest...); } auto write(std::string message) -> void; auto connect( boost::asio::io_context & io, Settings settings ) -> boost::asio::awaitable; };