From 7665f4c0f5446017a61a68bbd99429e5004f348e Mon Sep 17 00:00:00 2001 From: Eric Mertens Date: Wed, 22 Jan 2025 23:49:48 -0800 Subject: [PATCH] migrate to signals2 --- CMakeLists.txt | 22 ++++----- connection.cpp | 23 +++++++-- connection.hpp | 64 +++---------------------- irc_parse_thread.hpp => irc_command.hpp | 21 -------- irc_parse_thread.cpp | 37 -------------- main.cpp | 50 +++++++------------ ping_thread.cpp | 9 ++-- registration_thread.cpp | 33 +++++++------ registration_thread.hpp | 7 +-- self_thread.cpp | 20 ++++---- snote_thread.cpp | 25 ++++------ snote_thread.hpp | 12 ++--- watchdog_thread.cpp | 7 ++- 13 files changed, 100 insertions(+), 230 deletions(-) rename irc_parse_thread.hpp => irc_command.hpp (94%) delete mode 100644 irc_parse_thread.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d34cc3b..833499e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,13 +20,6 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(tomlplusplus) -FetchContent_Declare( - eventpp - GIT_REPOSITORY https://github.com/wqking/eventpp.git - GIT_TAG v0.1.3 -) -FetchContent_MakeAvailable(eventpp) - add_custom_command( OUTPUT irc_commands.inc COMMAND @@ -41,9 +34,14 @@ add_subdirectory(mybase64) add_executable(xbot main.cpp irc_commands.inc ircmsg.cpp settings.cpp connection.cpp - snote_thread.cpp watchdog_thread.cpp write_irc.cpp - ping_thread.cpp irc_parse_thread.cpp registration_thread.cpp - self_thread.cpp command_thread.cpp priv_thread.cpp - sasl_thread.cpp) + write_irc.cpp + registration_thread.cpp + ping_thread.cpp + snote_thread.cpp + self_thread.cpp + watchdog_thread.cpp +) +# command_thread.cpp priv_thread.cpp +# sasl_thread.cpp) target_include_directories(xbot PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(xbot PRIVATE Boost::log Boost::headers tomlplusplus_tomlplusplus eventpp PkgConfig::LIBHS mybase64) +target_link_libraries(xbot PRIVATE Boost::log Boost::headers tomlplusplus_tomlplusplus PkgConfig::LIBHS mybase64) diff --git a/connection.cpp b/connection.cpp index 709da2b..2c0b38c 100644 --- a/connection.cpp +++ b/connection.cpp @@ -4,6 +4,10 @@ #include +namespace { +#include "irc_commands.inc" +} // namespace + Connection::Connection(boost::asio::io_context & io) : stream_{io} , write_timer_{io, std::chrono::steady_clock::time_point::max()} @@ -72,7 +76,7 @@ auto Connection::connect( auto const endpoints = co_await resolver.async_resolve(host, port, boost::asio::use_awaitable); auto const endpoint = co_await boost::asio::async_connect(stream_, endpoints, boost::asio::use_awaitable); - make_event(); + sig_connect(); } self->writer(); @@ -86,11 +90,24 @@ auto Connection::connect( } buffer.add_bytes(n, [this](char * line) { BOOST_LOG_TRIVIAL(debug) << "RECV: " << line; - make_event(line); + + auto const msg = parse_irc_message(line); + auto const recognized = IrcCommandHash::in_word_set(msg.command.data(), msg.command.size()); + auto const command + = recognized + && recognized->min_args <= msg.args.size() + && recognized->max_args >= msg.args.size() + ? recognized->command : IrcCommand::UNKNOWN; + + if (IrcCommand::UNKNOWN == command) + { + BOOST_LOG_TRIVIAL(warning) << "Unrecognized command: " << msg.command << " " << msg.args.size(); + } + sig_ircmsg(command, msg); }); } - make_event(); + sig_disconnect(); } auto Connection::write_line(std::string message) -> void diff --git a/connection.hpp b/connection.hpp index 650f87b..f60e38c 100644 --- a/connection.hpp +++ b/connection.hpp @@ -3,10 +3,8 @@ #include "event.hpp" #include "settings.hpp" -#include -#include - #include +#include #include #include @@ -20,43 +18,16 @@ #include #include #include -#include -#include -struct ConnectEvent : Event -{ -}; - -struct DisconnectEvent : Event -{ -}; - -struct LineEvent : Event -{ - explicit LineEvent(char * line) : line{line} {} - char * line; -}; +#include "ircmsg.hpp" +#include "irc_command.hpp" class Connection : public std::enable_shared_from_this { - using EventDispatcher = eventpp::EventDispatcher; - -public: - template - class Handle - { - EventDispatcher::Handle handle; - Handle(EventDispatcher::Handle handle) : handle{handle} {} - public: - Handle() : handle{} {} - friend Connection; - }; - private: boost::asio::ip::tcp::socket stream_; boost::asio::steady_timer write_timer_; std::list write_strings_; - EventDispatcher dispatcher_; auto writer() -> void; auto writer_immediate() -> void; @@ -64,37 +35,14 @@ private: public: Connection(boost::asio::io_context & io); - template - auto add_listener(F f) -> Handle - { - return Handle{dispatcher_.appendListener( - typeid(T), - eventpp::argumentAdapter(f) - )}; - } - - template - auto remove_listener(Handle handle) -> void - { - dispatcher_.removeListener(typeid(T), handle.handle); - } - - template - auto dispatch(T& event) -> void - { - dispatcher_.dispatch(typeid(T), event); - } + boost::signals2::signal sig_connect; + boost::signals2::signal sig_disconnect; + boost::signals2::signal sig_ircmsg; auto get_executor() -> boost::asio::any_io_executor { return stream_.get_executor(); } - template - auto make_event(Args&& ... args) { - auto event = T{std::forward(args)...}; - dispatch(event); - } - /// Write bytes into the socket. Messages should be properly newline terminated. auto write_line(std::string message) -> void; diff --git a/irc_parse_thread.hpp b/irc_command.hpp similarity index 94% rename from irc_parse_thread.hpp rename to irc_command.hpp index 7d460ee..a2895db 100644 --- a/irc_parse_thread.hpp +++ b/irc_command.hpp @@ -1,12 +1,3 @@ -#pragma once - -#include "event.hpp" - -#include - -class Connection; -class IrcMsg; - enum class IrcCommand { UNKNOWN, @@ -284,15 +275,3 @@ enum class IrcCommand SETNAME, TOPIC, }; - -struct IrcMsgEvent : Event -{ - IrcMsgEvent(IrcCommand command, IrcMsg const& irc); - IrcCommand command; - IrcMsg const& irc; -}; - -struct IrcParseThread -{ - static auto start(Connection& connection) -> void; -}; diff --git a/irc_parse_thread.cpp b/irc_parse_thread.cpp deleted file mode 100644 index 539fa5c..0000000 --- a/irc_parse_thread.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "irc_parse_thread.hpp" - -#include "connection.hpp" -#include "ircmsg.hpp" - -#include - -#include - -namespace { - -#include "irc_commands.inc" - -} // namespace - -IrcMsgEvent::IrcMsgEvent(IrcCommand command, IrcMsg const& irc) -: command{command}, irc{irc} {} - -auto IrcParseThread::start(Connection& connection) -> void -{ - connection.add_listener([&connection](LineEvent const& event) - { - auto const msg = parse_irc_message(event.line); - auto const recognized = IrcCommandHash::in_word_set(msg.command.data(), msg.command.size()); - auto const command - = recognized - && recognized->min_args <= msg.args.size() - && recognized->max_args >= msg.args.size() - ? recognized->command : IrcCommand::UNKNOWN; - - if (IrcCommand::UNKNOWN == command) - { - BOOST_LOG_TRIVIAL(warning) << "Unrecognized command: " << msg.command << " " << msg.args.size(); - } - connection.make_event(command, msg); - }); -} diff --git a/main.cpp b/main.cpp index c70ae0b..5cbc5a2 100644 --- a/main.cpp +++ b/main.cpp @@ -6,15 +6,6 @@ #include "settings.hpp" #include "write_irc.hpp" -#include "command_thread.hpp" -#include "irc_parse_thread.hpp" -#include "ping_thread.hpp" -#include "registration_thread.hpp" -#include "self_thread.hpp" -#include "snote_thread.hpp" -#include "watchdog_thread.hpp" -#include "priv_thread.hpp" - #include #include @@ -34,46 +25,37 @@ #include #include -using namespace std::chrono_literals; +#include "ping_thread.hpp" +#include "registration_thread.hpp" +#include "self_thread.hpp" +#include "snote_thread.hpp" -auto echo_thread( - Connection& connection, - std::shared_ptr priv_thread) -> void -{ - connection.add_listener([&connection, priv_thread](CommandEvent& event) - { - if ("raw" == event.command && priv_thread->check_command(event, PrivThread::owner_priv)) - { - connection.write_line(std::string{event.arg}); - event.handled_ = true; - send_notice(connection, event.nick, "ack"); - } - }); -} +using namespace std::chrono_literals; auto start(boost::asio::io_context & io, Settings const& settings) -> void { auto const connection = std::make_shared(io); - WatchdogThread::start(*connection); - IrcParseThread::start(*connection); + RegistrationThread::start(*connection, settings.password, settings.username, settings.realname, settings.nickname); PingThread::start(*connection); SelfThread::start(*connection); - RegistrationThread::start(*connection, settings.password, settings.username, settings.realname, settings.nickname); - SnoteThread::start(*connection); + auto const snote_thread = SnoteThread::start(*connection); + +/* + WatchdogThread::start(*connection); + IrcParseThread::start(*connection); CommandThread::start(*connection); auto const priv_thread = PrivThread::start(*connection, "privs.toml"); echo_thread(*connection, priv_thread); -/* - connection->add_listener([](SnoteEvent& event) { - std::cout << "SNOTE " << static_cast(event.get_tag()) << std::endl; - for (auto c : event.get_results()) +*/ + snote_thread->sig_snote.connect([](auto tag, auto &match) { + std::cout << "SNOTE " << static_cast(tag) << std::endl; + for (auto c : match.get_results()) { std::cout << " " << std::string_view{c.first, c.second} << std::endl; } }); -*/ boost::asio::co_spawn( io, @@ -81,7 +63,7 @@ auto start(boost::asio::io_context & io, Settings const& settings) -> void [&io, &settings](std::exception_ptr e) { auto timer = std::make_shared(io); - + timer->expires_after(5s); timer->async_wait([&io, &settings, timer](auto) { start(io, settings); diff --git a/ping_thread.cpp b/ping_thread.cpp index a43cf0f..9268cee 100644 --- a/ping_thread.cpp +++ b/ping_thread.cpp @@ -1,19 +1,16 @@ #include "ping_thread.hpp" #include "connection.hpp" -#include "irc_parse_thread.hpp" #include "ircmsg.hpp" #include "write_irc.hpp" auto PingThread::start(Connection& connection) -> void { - connection.add_listener([&connection](IrcMsgEvent& event) + connection.sig_ircmsg.connect([&connection](auto cmd, auto& msg) { - auto& irc = event.irc; - if (IrcCommand::PING == event.command) + if (IrcCommand::PING == cmd) { - send_pong(connection, irc.args[0]); - event.handled_ = true; + send_pong(connection, msg.args[0]); } }); } diff --git a/registration_thread.cpp b/registration_thread.cpp index d8e0a08..4dd869b 100644 --- a/registration_thread.cpp +++ b/registration_thread.cpp @@ -1,7 +1,6 @@ #include "registration_thread.hpp" #include "connection.hpp" -#include "irc_parse_thread.hpp" #include "ircmsg.hpp" #include "write_irc.hpp" @@ -17,10 +16,10 @@ RegistrationThread::RegistrationThread( std::string nickname ) : connection_{connection} - , password_{password} - , username_{username} - , realname_{realname} - , nickname_{nickname} + , password_{std::move(password)} + , username_{std::move(username)} + , realname_{std::move(realname)} + , nickname_{std::move(nickname)} { } @@ -60,12 +59,12 @@ auto RegistrationThread::send_req() -> void outstanding.insert(cap); } } - + if (not outstanding.empty()) { request.pop_back(); send_cap_req(connection_, request); - + listen_for_cap_ack(); } else @@ -86,7 +85,7 @@ auto RegistrationThread::on_msg_cap_ack(IrcMsg const& msg) -> void ); if (outstanding.empty()) { - connection_.remove_listener(message_handle_); + message_handle_.disconnect(); send_cap_end(connection_); } } @@ -131,7 +130,7 @@ auto RegistrationThread::on_msg_cap_ls(IrcMsg const& msg) -> void if (last) { - connection_.remove_listener(message_handle_); + message_handle_.disconnect(); send_req(); } } @@ -148,9 +147,9 @@ auto RegistrationThread::start( thread->listen_for_cap_ls(); - thread->connect_handle_ = connection.add_listener([thread](ConnectEvent const&) + connection.sig_connect.connect_extended([thread](auto& handle) { - thread->connection_.remove_listener(thread->connect_handle_); + handle.disconnect(); thread->on_connect(); }); @@ -159,22 +158,22 @@ auto RegistrationThread::start( auto RegistrationThread::listen_for_cap_ack() -> void { - message_handle_ = connection_.add_listener([thread = shared_from_this()](IrcMsgEvent const& event) + message_handle_ = connection_.sig_ircmsg.connect([thread = shared_from_this()](IrcCommand cmd, IrcMsg const& msg) { - if (IrcCommand::CAP == event.command && event.irc.args.size() >= 2 && "*" == event.irc.args[0] && "ACK" == event.irc.args[1]) + if (IrcCommand::CAP == cmd && msg.args.size() >= 2 && "*" == msg.args[0] && "ACK" == msg.args[1]) { - thread->on_msg_cap_ack(event.irc); + thread->on_msg_cap_ack(msg); } }); } auto RegistrationThread::listen_for_cap_ls() -> void { - message_handle_ = connection_.add_listener([thread = shared_from_this()](IrcMsgEvent const& event) + message_handle_ = connection_.sig_ircmsg.connect([thread = shared_from_this()](IrcCommand cmd, IrcMsg const& msg) { - if (IrcCommand::CAP == event.command && event.irc.args.size() >= 2 && "*" == event.irc.args[0] && "LS" == event.irc.args[1]) + if (IrcCommand::CAP == cmd && msg.args.size() >= 2 && "*" == msg.args[0] && "LS" == msg.args[1]) { - thread->on_msg_cap_ls(event.irc); + thread->on_msg_cap_ls(msg); } }); } diff --git a/registration_thread.hpp b/registration_thread.hpp index e5d7492..99e2550 100644 --- a/registration_thread.hpp +++ b/registration_thread.hpp @@ -1,9 +1,6 @@ #pragma once -#include - #include "connection.hpp" -#include "irc_parse_thread.hpp" #include #include @@ -21,8 +18,8 @@ class RegistrationThread : public std::enable_shared_from_this caps; std::unordered_set outstanding; - Connection::Handle connect_handle_; - Connection::Handle message_handle_; + boost::signals2::connection connect_handle_; + boost::signals2::connection message_handle_; auto on_connect() -> void; auto send_req() -> void; diff --git a/self_thread.cpp b/self_thread.cpp index 2efcc18..6681ed0 100644 --- a/self_thread.cpp +++ b/self_thread.cpp @@ -1,8 +1,6 @@ #include "self_thread.hpp" #include "connection.hpp" -#include "ircmsg.hpp" -#include "irc_parse_thread.hpp" auto SelfThread::on_welcome(IrcMsg const& irc) -> void { @@ -84,40 +82,40 @@ auto SelfThread::start(Connection& connection) -> std::shared_ptr { auto thread = std::make_shared(connection); - connection.add_listener([thread](IrcMsgEvent& event) + connection.sig_ircmsg.connect([thread](auto cmd, auto& msg) { - switch (event.command) + switch (cmd) { // Learn nickname from 001 case IrcCommand::RPL_WELCOME: - thread->on_welcome(event.irc); + thread->on_welcome(msg); break; // Track changes to our nickname case IrcCommand::NICK: - thread->on_nick(event.irc); + thread->on_nick(msg); break; // Re-establish user modes case IrcCommand::RPL_UMODEIS: - thread->on_umodeis(event.irc); + thread->on_umodeis(msg); break; case IrcCommand::JOIN: - thread->on_join(event.irc); + thread->on_join(msg); break; case IrcCommand::KICK: - thread->on_kick(event.irc); + thread->on_kick(msg); break; case IrcCommand::PART: - thread->on_part(event.irc); + thread->on_part(msg); break; // Interpret self mode changes case IrcCommand::MODE: - thread->on_mode(event.irc); + thread->on_mode(msg); break; default: break; diff --git a/snote_thread.cpp b/snote_thread.cpp index 62fe077..7f4a894 100644 --- a/snote_thread.cpp +++ b/snote_thread.cpp @@ -1,7 +1,5 @@ #include "snote_thread.hpp" -#include "irc_parse_thread.hpp" -#include "ircmsg.hpp" #include "connection.hpp" #include "c_callback.hpp" @@ -74,7 +72,7 @@ SnotePattern static const patterns[] = {SnoteTag::TooManyGlobalConnections, R"(^Too many global connections for ([^ ]+)\[([^ ]+)@([^ ]+)\] \[(.*)\]$)"}, - + {SnoteTag::SetVhostOnMarkedAccount, "^\x02([^ ]+)\x02 set vhost ([^ ]+) on the \x02MARKED\x02 account ([^ ]+).$"}, }; @@ -130,14 +128,13 @@ auto SnoteThread::start(Connection& connection) -> std::shared_ptr thread->scratch_.reset(scratch); static char const* const prefix = "*** Notice -- "; - connection.add_listener([&connection, thread](IrcMsgEvent& event) + connection.sig_ircmsg.connect([&connection, thread](auto cmd, auto& msg) { - auto& args = event.irc.args; - if (IrcCommand::NOTICE == event.command && "*" == args[0] && args[1].starts_with(prefix)) + auto& args = msg.args; + if (IrcCommand::NOTICE == cmd && "*" == args[0] && args[1].starts_with(prefix)) { - event.handled_ = true; auto const message = args[1].substr(strlen(prefix)); - + unsigned match_id; auto cb = [&match_id](unsigned id, unsigned long long, unsigned long long, unsigned) -> int { @@ -159,11 +156,12 @@ auto SnoteThread::start(Connection& connection) -> std::shared_ptr case HS_SUCCESS: BOOST_LOG_TRIVIAL(warning) << "Unknown snote: " << message; break; - + case HS_SCAN_TERMINATED: { auto& pattern = patterns[match_id]; - connection.make_event(pattern.tag, pattern.regex, message); + auto match = SnoteMatch{pattern.regex, message}; + thread->sig_snote(pattern.tag, match); break; } @@ -176,12 +174,7 @@ auto SnoteThread::start(Connection& connection) -> std::shared_ptr return thread; } -auto SnoteEvent::get_tag() const -> SnoteTag -{ - return tag_; -} - -auto SnoteEvent::get_results() -> std::match_results const& +auto SnoteMatch::get_results() -> std::match_results const& { if (auto results = std::get_if<1>(&components_)) { return *results; diff --git a/snote_thread.hpp b/snote_thread.hpp index 63ed68c..a4045b4 100644 --- a/snote_thread.hpp +++ b/snote_thread.hpp @@ -1,6 +1,6 @@ #pragma once -#include "event.hpp" +#include #include #include @@ -30,15 +30,13 @@ enum class SnoteTag SetVhostOnMarkedAccount, }; -class SnoteEvent : public Event +class SnoteMatch { public: - SnoteEvent(SnoteTag tag, std::regex const& regex, std::string_view full) - : tag_{tag} - , components_{std::make_pair(std::ref(regex), full)} + SnoteMatch(std::regex const& regex, std::string_view full) + : components_{std::make_pair(std::ref(regex), full)} {} - auto get_tag() const -> SnoteTag; auto get_results() -> std::match_results const&; private: @@ -64,5 +62,7 @@ struct SnoteThread /// @brief HyperScan scratch space std::unique_ptr scratch_; + boost::signals2::signal sig_snote; + static auto start(Connection& connection) -> std::shared_ptr; }; diff --git a/watchdog_thread.cpp b/watchdog_thread.cpp index d8dd5fa..c22521f 100644 --- a/watchdog_thread.cpp +++ b/watchdog_thread.cpp @@ -1,7 +1,6 @@ #include "watchdog_thread.hpp" #include "connection.hpp" -#include "irc_parse_thread.hpp" #include "write_irc.hpp" #include @@ -65,15 +64,15 @@ auto WatchdogThread::on_disconnect() -> void auto WatchdogThread::start(Connection& connection) -> void { auto const thread = std::make_shared(connection); - connection.add_listener([thread](auto&) + connection.sig_connect.connect([thread]() { thread->on_connect(); }); - connection.add_listener([thread](auto&) + connection.sig_disconnect.connect([thread]() { thread->on_disconnect(); }); - connection.add_listener([thread](auto&) + connection.sig_ircmsg.connect([thread](auto, auto&) { thread->on_activity(); });