Compare commits
2 Commits
f59049187e
...
efb49b8708
Author | SHA1 | Date | |
---|---|---|---|
efb49b8708 | |||
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);
|
||||
|
169
self_thread.cpp
169
self_thread.cpp
@ -1,9 +1,87 @@
|
||||
#include "self_thread.hpp"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include "connection.hpp"
|
||||
#include "ircmsg.hpp"
|
||||
#include "irc_parse_thread.hpp"
|
||||
|
||||
auto SelfThread::on_welcome(IrcMsg const& irc) -> void
|
||||
{
|
||||
nickname_ = irc.args[0];
|
||||
}
|
||||
|
||||
auto SelfThread::on_nick(IrcMsg const& irc) -> void
|
||||
{
|
||||
if (is_my_mask(irc.source))
|
||||
{
|
||||
nickname_ = irc.args[0];
|
||||
}
|
||||
}
|
||||
|
||||
auto SelfThread::on_umodeis(IrcMsg const& irc) -> void
|
||||
{
|
||||
mode_ = irc.args[1];
|
||||
}
|
||||
|
||||
auto SelfThread::on_join(IrcMsg const& irc) -> void
|
||||
{
|
||||
if (is_my_mask(irc.source))
|
||||
{
|
||||
channels_.insert(std::string{irc.args[0]});
|
||||
}
|
||||
}
|
||||
|
||||
auto SelfThread::on_kick(IrcMsg const& irc) -> void
|
||||
{
|
||||
if (is_my_nick(irc.args[1]))
|
||||
{
|
||||
channels_.erase(std::string{irc.args[0]});
|
||||
}
|
||||
}
|
||||
|
||||
auto SelfThread::on_part(IrcMsg const& irc) -> void
|
||||
{
|
||||
if (is_my_mask(irc.source))
|
||||
{
|
||||
channels_.erase(std::string{irc.args[0]});
|
||||
}
|
||||
}
|
||||
|
||||
auto SelfThread::on_mode(IrcMsg const& irc) -> void
|
||||
{
|
||||
if (is_my_nick(irc.args[0]))
|
||||
{
|
||||
auto polarity = true;
|
||||
for (char const c : irc.args[1])
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '+':
|
||||
polarity = true;
|
||||
break;
|
||||
case '-':
|
||||
polarity = false;
|
||||
break;
|
||||
default:
|
||||
if (polarity)
|
||||
{
|
||||
mode_ += c;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const ix = mode_.find(c);
|
||||
if (ix != std::string::npos)
|
||||
{
|
||||
mode_.erase(ix, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto SelfThread::start(Connection& connection) -> std::shared_ptr<SelfThread>
|
||||
{
|
||||
auto thread = std::make_shared<SelfThread>(connection);
|
||||
@ -14,64 +92,65 @@ auto SelfThread::start(Connection& connection) -> std::shared_ptr<SelfThread>
|
||||
{
|
||||
// Learn nickname from 001
|
||||
case IrcCommand::RPL_WELCOME:
|
||||
thread->nickname_ = event.irc.args[0];
|
||||
thread->on_welcome(event.irc);
|
||||
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)
|
||||
)
|
||||
{
|
||||
thread->nickname_ = event.irc.args[0];
|
||||
}
|
||||
thread->on_nick(event.irc);
|
||||
break;
|
||||
}
|
||||
|
||||
// Re-establish user modes
|
||||
case IrcCommand::RPL_UMODEIS:
|
||||
thread->mode_ = event.irc.args[1];
|
||||
thread->on_umodeis(event.irc);
|
||||
break;
|
||||
|
||||
|
||||
case IrcCommand::JOIN:
|
||||
thread->on_join(event.irc);
|
||||
break;
|
||||
|
||||
case IrcCommand::KICK:
|
||||
thread->on_kick(event.irc);
|
||||
break;
|
||||
|
||||
case IrcCommand::PART:
|
||||
thread->on_part(event.irc);
|
||||
break;
|
||||
|
||||
// Interpret self mode changes
|
||||
case IrcCommand::MODE:
|
||||
if (2 == event.irc.args.size()
|
||||
&& thread->nickname_ == event.irc.args[0]
|
||||
)
|
||||
{
|
||||
auto polarity = true;
|
||||
for (char const c : event.irc.args[1])
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '+':
|
||||
polarity = true;
|
||||
break;
|
||||
case '-':
|
||||
polarity = false;
|
||||
break;
|
||||
default:
|
||||
if (polarity)
|
||||
{
|
||||
thread->mode_ += c;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const ix = thread->mode_.find(c);
|
||||
if (ix != std::string::npos)
|
||||
{
|
||||
thread->mode_.erase(ix, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
thread->on_mode(event.irc);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
});
|
||||
|
||||
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,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
struct Connection;
|
||||
struct IrcMsg;
|
||||
|
||||
/**
|
||||
* @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_;
|
||||
|
||||
auto on_welcome(IrcMsg const& irc) -> void;
|
||||
auto on_nick(IrcMsg const& irc) -> void;
|
||||
auto on_umodeis(IrcMsg const& irc) -> void;
|
||||
auto on_join(IrcMsg const& irc) -> void;
|
||||
auto on_kick(IrcMsg const& irc) -> void;
|
||||
auto on_part(IrcMsg const& irc) -> void;
|
||||
auto on_mode(IrcMsg const& irc) -> void;
|
||||
|
||||
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