From 3cb37e33a29fa8a704b2abba4a0ab1b32112a7f2 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Tue, 18 Jun 2024 12:12:08 +0200 Subject: [PATCH] detect disconnect and reconnect (channels still missing) --- plugins/plugin_ircclient.cpp | 3 +- src/solanaceae/ircclient/ircclient.cpp | 163 ++++++++++++++++--------- src/solanaceae/ircclient/ircclient.hpp | 14 ++- 3 files changed, 116 insertions(+), 64 deletions(-) diff --git a/plugins/plugin_ircclient.cpp b/plugins/plugin_ircclient.cpp index a675937..c50d9a2 100644 --- a/plugins/plugin_ircclient.cpp +++ b/plugins/plugin_ircclient.cpp @@ -63,8 +63,7 @@ SOLANA_PLUGIN_EXPORT void solana_plugin_stop(void) { } SOLANA_PLUGIN_EXPORT float solana_plugin_tick(float delta) { - (void)delta; - g_ircc->iterate(); // TODO: return interval, respect dcc etc + g_ircc->iterate(delta); // TODO: return interval, respect dcc etc return 1.f; // expect atleast once per sec } diff --git a/src/solanaceae/ircclient/ircclient.cpp b/src/solanaceae/ircclient/ircclient.cpp index 1637de1..7b7eae7 100644 --- a/src/solanaceae/ircclient/ircclient.cpp +++ b/src/solanaceae/ircclient/ircclient.cpp @@ -26,6 +26,7 @@ void IRCClient1::on_event_numeric(irc_session_t* session, unsigned int event, co auto ircc = static_cast(irc_get_ctx(session)); ircc->dispatch(IRCClient_Event::NUMERIC, IRCClient::Events::Numeric{event, origin, params_view}); + ircc->_event_fired = true; } IRCClient1::IRCClient1( @@ -77,7 +78,105 @@ IRCClient1::IRCClient1( irc_option_set(_irc_session, LIBIRC_OPTION_STRIPNICKS); irc_option_set(_irc_session, LIBIRC_OPTION_SSL_NO_VERIFY); // why + connectSession(); +} +IRCClient1::~IRCClient1(void) { + irc_destroy_session(_irc_session); +} + +// tmp +void IRCClient1::run(void) { + if (irc_run(_irc_session) != 0) { + std::cerr << "error failed to run: " << irc_strerror(irc_errno(_irc_session)) << "\n"; + } +} + +float IRCClient1::iterate(float delta) { + //if ( session->state != LIBIRC_STATE_CONNECTING ) + //{ + //session->lasterror = LIBIRC_ERR_STATE; + //return 1; + //} + + if (!irc_is_connected(_irc_session)) { + if (_try_connecting_state) { + // try to connect, every 20sec + _try_connecting_cooldown -= delta; + if (_try_connecting_cooldown <= 0.f) { + std::cerr << "IRCC: trying to connect\n"; + connectSession(); + } + } else { + std::cerr << "IRCC error: not connected, trying to reconnect\n"; + connectSession(); // potentially enters trying phase + } + return 0.5f; + } + + _event_fired = false; + + struct timeval tv; + fd_set in_set, out_set; + int maxfd = 0; + + //tv.tv_usec = 20000; // 20ms + tv.tv_usec = 1000; // 1ms + tv.tv_sec = 0; + + // Init sets + FD_ZERO(&in_set); + FD_ZERO(&out_set); + + if (irc_add_select_descriptors(_irc_session, &in_set, &out_set, &maxfd) != 0) { + std::cerr << "IRCC error: adding select descriptors\n"; + } + + if (select(maxfd + 1, &in_set, &out_set, 0, &tv) < 0) { + std::cerr << "IRCC error: select returned error\n"; +#if 0 + if (socket_error() == EINTR) { + //continue; + return; + } +#endif + + //session->lasterror = LIBIRC_ERR_TERMINATED; + //return 1; + return 0.1f; + } + + if (irc_process_select_descriptors(_irc_session, &in_set, &out_set) != 0) { + std::cerr << "IRCC error: processing socket select\n"; + //return 1; + } + + // TODO: handle dcc + if (_event_fired) { + return 0.1f; + } else { + return 1.f; + } +} + +irc_session_t* IRCClient1::getSession(void) { + return _irc_session; +} + +const std::string_view IRCClient1::getServerName(void) const { + return _server_name; +} + +void IRCClient1::connectSession(void) { + _try_connecting_state = true; + _try_connecting_cooldown = 20.f; + + // reset connection + // only closes potentially open sockets and sets state to init + // nothing else is touched + irc_disconnect(_irc_session); + + // TODO: do we need to set this every time? if (!_conf.has_string("IRCClient", "server")) { std::cerr << "IRCC error: no irc server in config!!\n"; throw std::runtime_error("missing server in config"); @@ -111,70 +210,14 @@ IRCClient1::IRCClient1( } if (irc_connect(_irc_session, server.c_str(), port, nullptr, nick.c_str(), username.c_str(), realname.c_str()) != 0) { - std::cerr << "error failed to connect: (" << irc_errno(_irc_session) << ") " << irc_strerror(irc_errno(_irc_session)) << "\n"; - throw std::runtime_error("failed to connect to irc"); - } -} + std::cerr << "IRCC error: failed to connect: (" << irc_errno(_irc_session) << ") " << irc_strerror(irc_errno(_irc_session)) << "\n"; -IRCClient1::~IRCClient1(void) { - irc_destroy_session(_irc_session); -} + irc_disconnect(_irc_session); -// tmp -void IRCClient1::run(void) { - if (irc_run(_irc_session) != 0) { - std::cerr << "error failed to run: " << irc_strerror(irc_errno(_irc_session)) << "\n"; - } -} - -void IRCClient1::iterate(void) { - //if ( session->state != LIBIRC_STATE_CONNECTING ) - //{ - //session->lasterror = LIBIRC_ERR_STATE; - //return 1; - //} - - if (!irc_is_connected(_irc_session)) { + //throw std::runtime_error("failed to connect to irc"); return; } - struct timeval tv; - fd_set in_set, out_set; - int maxfd = 0; - - //tv.tv_usec = 20000; // 20ms - tv.tv_usec = 1000; // 1ms - tv.tv_sec = 0; - - // Init sets - FD_ZERO (&in_set); - FD_ZERO (&out_set); - - irc_add_select_descriptors(_irc_session, &in_set, &out_set, &maxfd); - - if (select(maxfd + 1, &in_set, &out_set, 0, &tv) < 0) - { -#if 0 - if (socket_error() == EINTR) { - //continue; - return; - } -#endif - - //session->lasterror = LIBIRC_ERR_TERMINATED; - //return 1; - return; - } - - if (irc_process_select_descriptors(_irc_session, &in_set, &out_set)) { - //return 1; - } + _try_connecting_state = false; } -irc_session_t* IRCClient1::getSession(void) { - return _irc_session; -} - -const std::string_view IRCClient1::getServerName(void) const { - return _server_name; -} diff --git a/src/solanaceae/ircclient/ircclient.hpp b/src/solanaceae/ircclient/ircclient.hpp index 96fc20e..afcfc23 100644 --- a/src/solanaceae/ircclient/ircclient.hpp +++ b/src/solanaceae/ircclient/ircclient.hpp @@ -170,7 +170,11 @@ using IRCClientEventProviderI = EventProviderI; class IRCClient1 : public IRCClientEventProviderI { ConfigModelI& _conf; - irc_session_t* _irc_session = nullptr; + irc_session_t* _irc_session {nullptr}; + bool _try_connecting_state {false}; + float _try_connecting_cooldown {0.f}; + + bool _event_fired {false}; std::string _server_name; // name of the irc network this iirc is connected to @@ -181,9 +185,10 @@ class IRCClient1 : public IRCClientEventProviderI { ~IRCClient1(void); + // tmp void run(void); - void iterate(void); + float iterate(float delta); // raw access irc_session_t* getSession(void); @@ -193,6 +198,10 @@ class IRCClient1 : public IRCClientEventProviderI { // join void join(std::string_view channel); + private: + // connects an already existing session + void connectSession(void); + private: // callbacks for libircclient static void on_event_numeric(irc_session_t* session, unsigned int event, const char* origin, const char** params, unsigned int count); @@ -220,6 +229,7 @@ class IRCClient1 : public IRCClientEventProviderI { assert(ircc != nullptr); ircc->dispatch(event_type_enum, EventType{origin, params_view}); + ircc->_event_fired = true; } };