xbot/connection.hpp

98 lines
2.5 KiB
C++
Raw Normal View History

2023-11-22 19:59:34 -08:00
#pragma once
#include "irc_thread.hpp"
#include "ircmsg.hpp"
#include "linebuffer.hpp"
#include "settings.hpp"
#include <boost/asio.hpp>
#include <chrono>
#include <coroutine>
#include <iostream>
#include <list>
#include <memory>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <variant>
#include <vector>
class Connection : public std::enable_shared_from_this<Connection>
{
boost::asio::ip::tcp::socket stream_;
boost::asio::steady_timer write_timer_;
std::list<std::string> write_strings_;
std::vector<std::unique_ptr<IrcThread>> threads_;
auto writer() -> void;
auto writer_() -> void;
template <typename... Args>
auto dispatch(
IrcThread::callback_result (IrcThread::* method)(Args...),
Args... args
) -> void
{
std::vector<std::unique_ptr<IrcThread>> work;
work.swap(threads_);
std::sort(work.begin(), work.end(), [](auto const& a, auto const& b) { return a->priority() < b->priority(); });
std::size_t const n = work.size();
for (std::size_t i = 0; i < n; i++)
{
auto const [thread_outcome, msg_outcome] = (work[i].get()->*method)(args...);
if (thread_outcome == ThreadOutcome::Continue)
{
threads_.push_back(std::move(work[i]));
}
if (msg_outcome == EventOutcome::Consume)
{
std::move(work.begin() + i + 1, work.end(), std::back_inserter(threads_));
break;
}
}
}
public:
Connection(boost::asio::io_context & io)
: stream_{io}
, write_timer_{io, std::chrono::steady_clock::time_point::max()}
{
}
auto listen(std::unique_ptr<IrcThread> thread) -> void
{
threads_.push_back(std::move(thread));
}
auto write(std::string front, std::string_view last) -> void;
template <typename... Args>
auto write(std::string front, std::string_view next, Args ...rest) -> void
{
auto const is_invalid = [](char x) -> bool {
return x == '\0' || x == '\r' || x == '\n' || x == ' ';
};
if (next.empty() || next.end() != std::find_if(next.begin(), next.end(), is_invalid))
{
throw std::runtime_error{"bad irc argument"};
}
front += " ";
front += next;
write(std::move(front), rest...);
}
auto write(std::string message) -> void;
auto connect(
boost::asio::io_context & io,
Settings settings
) -> boost::asio::awaitable<void>;
};