comments
This commit is contained in:
parent
f59049187e
commit
0aab173d94
@ -10,7 +10,7 @@ Connection::Connection(boost::asio::io_context & io)
|
||||
{
|
||||
}
|
||||
|
||||
auto Connection::writer_() -> void
|
||||
auto Connection::writer_immediate() -> void
|
||||
{
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
buffers.reserve(write_strings_.size());
|
||||
@ -45,14 +45,14 @@ auto Connection::writer() -> void
|
||||
{
|
||||
if (not self->write_strings_.empty())
|
||||
{
|
||||
self->writer_();
|
||||
self->writer_immediate();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
writer_();
|
||||
writer_immediate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ private:
|
||||
EventDispatcher dispatcher_;
|
||||
|
||||
auto writer() -> void;
|
||||
auto writer_() -> void;
|
||||
auto writer_immediate() -> void;
|
||||
|
||||
public:
|
||||
Connection(boost::asio::io_context & io);
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "self_thread.hpp"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include "connection.hpp"
|
||||
#include "ircmsg.hpp"
|
||||
#include "irc_parse_thread.hpp"
|
||||
@ -14,16 +16,23 @@ auto SelfThread::start(Connection& connection) -> std::shared_ptr<SelfThread>
|
||||
{
|
||||
// Learn nickname from 001
|
||||
case IrcCommand::RPL_WELCOME:
|
||||
if (event.irc.args.size() < 1)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << "RPL_WELCOME has too few arguments";
|
||||
break;
|
||||
}
|
||||
thread->nickname_ = event.irc.args[0];
|
||||
break;
|
||||
|
||||
// Track changes to our nickname
|
||||
case IrcCommand::NICK:
|
||||
{
|
||||
auto const bang = event.irc.source.find('!');
|
||||
if (bang != std::string::npos
|
||||
&& thread->nickname_ == event.irc.source.substr(0, bang)
|
||||
)
|
||||
if (event.irc.args.size() < 1) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "NICK has too few arguments";
|
||||
break;
|
||||
}
|
||||
|
||||
if (thread->is_my_mask(event.irc.source))
|
||||
{
|
||||
thread->nickname_ = event.irc.args[0];
|
||||
}
|
||||
@ -32,14 +41,64 @@ auto SelfThread::start(Connection& connection) -> std::shared_ptr<SelfThread>
|
||||
|
||||
// Re-establish user modes
|
||||
case IrcCommand::RPL_UMODEIS:
|
||||
if (event.irc.args.size() < 1)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << "RPL_UMODEIS has too few arguments";
|
||||
break;
|
||||
}
|
||||
|
||||
thread->mode_ = event.irc.args[1];
|
||||
break;
|
||||
|
||||
case IrcCommand::JOIN: {
|
||||
if (event.irc.args.size() < 1)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << "JOIN has too few arguments";
|
||||
break;
|
||||
}
|
||||
|
||||
if (thread->is_my_mask(event.irc.source))
|
||||
{
|
||||
thread->channels_.insert(std::string{event.irc.args[0]});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrcCommand::KICK: {
|
||||
if (event.irc.args.size() < 2)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << "PART has too few arguments";
|
||||
break;
|
||||
}
|
||||
|
||||
if (thread->is_my_nick(event.irc.args[1]))
|
||||
{
|
||||
thread->channels_.erase(std::string{event.irc.args[0]});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrcCommand::PART: {
|
||||
if (event.irc.args.size() < 1)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << "PART has too few arguments";
|
||||
break;
|
||||
}
|
||||
|
||||
if (thread->is_my_mask(event.irc.source))
|
||||
{
|
||||
thread->channels_.erase(std::string{event.irc.args[0]});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Interpret self mode changes
|
||||
case IrcCommand::MODE:
|
||||
if (2 == event.irc.args.size()
|
||||
&& thread->nickname_ == event.irc.args[0]
|
||||
)
|
||||
if (event.irc.args.size() < 2)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << "MODE has too few arguments";
|
||||
break;
|
||||
}
|
||||
|
||||
if (thread->is_my_nick(event.irc.args[0]))
|
||||
{
|
||||
auto polarity = true;
|
||||
for (char const c : event.irc.args[1])
|
||||
@ -75,3 +134,29 @@ auto SelfThread::start(Connection& connection) -> std::shared_ptr<SelfThread>
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
auto SelfThread::get_my_nickname() const -> std::string const&
|
||||
{
|
||||
return nickname_;
|
||||
}
|
||||
|
||||
auto SelfThread::get_my_mode() const -> std::string const&
|
||||
{
|
||||
return mode_;
|
||||
}
|
||||
|
||||
auto SelfThread::get_my_channels() const -> std::unordered_set<std::string> const&
|
||||
{
|
||||
return channels_;
|
||||
}
|
||||
|
||||
auto SelfThread::is_my_nick(std::string_view nick) const -> bool
|
||||
{
|
||||
return nick == nickname_;
|
||||
}
|
||||
|
||||
auto SelfThread::is_my_mask(std::string_view mask) const -> bool
|
||||
{
|
||||
auto const bang = mask.find('!');
|
||||
return bang != std::string_view::npos && nickname_ == mask.substr(0, bang);
|
||||
}
|
||||
|
@ -1,17 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
struct Connection;
|
||||
|
||||
/**
|
||||
* @brief Thread to track this connection's identity, and IRC state.
|
||||
*
|
||||
*/
|
||||
class SelfThread
|
||||
{
|
||||
Connection& connection_;
|
||||
std::string nickname_;
|
||||
std::string mode_;
|
||||
std::unordered_set<std::string> channels_;
|
||||
|
||||
public:
|
||||
SelfThread(Connection& connection) : connection_{connection} {}
|
||||
static auto start(Connection&) -> std::shared_ptr<SelfThread>;
|
||||
|
||||
auto get_my_nickname() const -> std::string const&;
|
||||
auto get_my_mode() const -> std::string const&;
|
||||
auto get_my_channels() const -> std::unordered_set<std::string> const&;
|
||||
|
||||
auto is_my_nick(std::string_view nick) const -> bool;
|
||||
auto is_my_mask(std::string_view nick) const -> bool;
|
||||
};
|
||||
|
@ -31,7 +31,7 @@ struct SnotePattern
|
||||
std::regex regex;
|
||||
};
|
||||
|
||||
SnotePattern const patterns[] =
|
||||
SnotePattern static const patterns[] =
|
||||
{
|
||||
{SnoteTag::ClientConnecting,
|
||||
R"(^Client connecting: ([^ ]+) \(([^@ ]+)@([^) ]+)\) \[(.*)\] \{([^ ]*)\} <([^ ]*)> \[(.*)\]$)"},
|
||||
@ -79,7 +79,7 @@ SnotePattern const patterns[] =
|
||||
"^\x02([^ ]+)\x02 set vhost ([^ ]+) on the \x02MARKED\x02 account ([^ ]+).$"},
|
||||
};
|
||||
|
||||
auto setup_database() -> hs_database_t*
|
||||
static auto setup_database() -> hs_database_t*
|
||||
{
|
||||
auto const n = std::size(patterns);
|
||||
std::vector<char const*> expressions;
|
||||
|
@ -58,7 +58,10 @@ struct SnoteThread
|
||||
auto operator()(hs_scratch * scratch) const -> void;
|
||||
};
|
||||
|
||||
/// @brief Database of server notice patterns
|
||||
std::unique_ptr<hs_database, DbDeleter> db_;
|
||||
|
||||
/// @brief HyperScan scratch space
|
||||
std::unique_ptr<hs_scratch, ScratchDeleter> scratch_;
|
||||
|
||||
static auto start(Connection& connection) -> std::shared_ptr<SnoteThread>;
|
||||
|
@ -9,24 +9,22 @@
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
WatchdogThread::WatchdogThread(Connection& connection)
|
||||
: connection_{connection}
|
||||
, timer_{connection.get_executor()}
|
||||
, tried_ping{false}
|
||||
, stalled_{false}
|
||||
{
|
||||
}
|
||||
|
||||
auto WatchdogThread::on_activity() -> void
|
||||
{
|
||||
tried_ping = false;
|
||||
timer_.expires_from_now(30s);
|
||||
stalled_ = false;
|
||||
timer_.expires_from_now(WatchdogThread::TIMEOUT);
|
||||
}
|
||||
|
||||
auto WatchdogThread::timeout_token()
|
||||
auto WatchdogThread::start_timer()
|
||||
{
|
||||
return [weak = weak_from_this()](auto const& error)
|
||||
timer_.async_wait([weak = weak_from_this()](auto const& error)
|
||||
{
|
||||
if (not error)
|
||||
{
|
||||
@ -35,28 +33,28 @@ auto WatchdogThread::timeout_token()
|
||||
self->on_timeout();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
auto WatchdogThread::on_timeout() -> void
|
||||
{
|
||||
if (tried_ping)
|
||||
if (stalled_)
|
||||
{
|
||||
connection_.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
send_ping(connection_, "watchdog");
|
||||
tried_ping = true;
|
||||
timer_.expires_from_now(30s);
|
||||
timer_.async_wait(timeout_token());
|
||||
stalled_ = true;
|
||||
timer_.expires_from_now(WatchdogThread::TIMEOUT);
|
||||
start_timer();
|
||||
}
|
||||
}
|
||||
|
||||
auto WatchdogThread::on_connect() -> void
|
||||
{
|
||||
on_activity();
|
||||
timer_.async_wait(timeout_token());
|
||||
start_timer();
|
||||
}
|
||||
|
||||
auto WatchdogThread::on_disconnect() -> void
|
||||
|
@ -2,20 +2,43 @@
|
||||
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
class Connection;
|
||||
|
||||
/**
|
||||
* @brief Watch for connection activity and disconnect on stall
|
||||
*
|
||||
* The thread will send a ping if no message is received in the
|
||||
* last TIMEOUT seconds. After another period of no messages
|
||||
* the thread will disconnect the connection.
|
||||
*
|
||||
*/
|
||||
class WatchdogThread : std::enable_shared_from_this<WatchdogThread>
|
||||
{
|
||||
Connection& connection_;
|
||||
boost::asio::steady_timer timer_;
|
||||
bool tried_ping;
|
||||
|
||||
/// @brief Set true and ping sent and false when reply received
|
||||
bool stalled_;
|
||||
|
||||
const std::chrono::steady_clock::duration TIMEOUT = std::chrono::seconds{30};
|
||||
|
||||
/// @brief Start the timer
|
||||
/// @return
|
||||
auto start_timer();
|
||||
|
||||
/// @brief
|
||||
auto on_activity() -> void;
|
||||
auto timeout_token();
|
||||
|
||||
/// @brief
|
||||
auto on_timeout() -> void;
|
||||
|
||||
/// @brief callback for ConnectEvent event
|
||||
auto on_connect() -> void;
|
||||
|
||||
/// @brief callback for DisconnectEvent event
|
||||
auto on_disconnect() -> void;
|
||||
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user