#pragma once #include "irc_command.hpp" #include "ircmsg.hpp" #include "snote.hpp" #include #include #include #include #include class Connection : public std::enable_shared_from_this { private: boost::asio::ip::tcp::socket stream_; boost::asio::steady_timer watchdog_timer_; std::list write_strings_; bool write_posted_; // Set true when watchdog triggers. // Set false when message received. bool stalled_; // AUTHENTICATE support std::string authenticate_buffer_; auto write_buffers() -> void; auto dispatch_line(char *line) -> void; static constexpr std::chrono::seconds watchdog_duration = std::chrono::seconds{30}; auto watchdog() -> void; auto watchdog_activity() -> void; /// Write bytes into the socket. Messages should be properly newline terminated. auto write_line(std::string message) -> void; /// Build and send well-formed IRC message from individual parameters auto write_irc(std::string) -> void; auto write_irc(std::string, std::string_view) -> void; template auto write_irc(std::string front, std::string_view next, Args... rest) -> void; public: Connection(boost::asio::io_context &io); boost::signals2::signal sig_connect; boost::signals2::signal sig_disconnect; boost::signals2::signal sig_ircmsg; boost::signals2::signal sig_snote; boost::signals2::signal sig_authenticate; auto get_executor() -> boost::asio::any_io_executor { return stream_.get_executor(); } auto connect( boost::asio::io_context &io, std::string host, std::string port ) -> boost::asio::awaitable; auto close() -> void; auto on_authenticate(std::string_view) -> void; auto send_ping(std::string_view) -> void; auto send_pong(std::string_view) -> void; auto send_pass(std::string_view) -> void; auto send_user(std::string_view, std::string_view) -> void; auto send_nick(std::string_view) -> void; auto send_cap_ls() -> void; auto send_cap_end() -> void; auto send_cap_req(std::string_view) -> void; auto send_privmsg(std::string_view, std::string_view) -> void; auto send_notice(std::string_view, std::string_view) -> void; auto send_authenticate(std::string_view message) -> void; auto send_authenticate_encoded(std::string_view message) -> void; auto send_authenticate_abort() -> void; }; template auto Connection::write_irc(std::string front, std::string_view next, Args... rest) -> void { const auto is_invalid = [](const char x) -> bool { return x == '\0' || x == '\r' || x == '\n' || x == ' '; }; if (next.empty() || next.front() == ':' || next.end() != std::find_if(next.begin(), next.end(), is_invalid)) { throw std::runtime_error{"bad irc argument"}; } front += " "; front += next; write_irc(std::move(front), rest...); }