xbot/snote_thread.cpp

154 lines
4.5 KiB
C++
Raw Normal View History

2023-11-25 20:09:20 -08:00
#include "snote_thread.hpp"
#include "irc_parse_thread.hpp"
#include "connection.hpp"
#include <cstring>
2023-11-26 21:16:56 -08:00
#include <cstdlib>
#include <stdexcept>
#include <utility>
#include <regex>
2023-11-25 20:09:20 -08:00
2023-11-26 21:16:56 -08:00
namespace {
2023-11-25 20:09:20 -08:00
2023-11-26 21:16:56 -08:00
struct SnotePattern
2023-11-25 20:09:20 -08:00
{
2023-11-26 21:16:56 -08:00
SnotePattern(SnoteTag tag, char const* expression, unsigned flags = 0)
: tag{tag}
, expression{expression}
, regex{expression, std::regex_constants::ECMAScript | std::regex_constants::optimize}
{
}
SnoteTag tag;
char const* expression;
std::regex regex;
};
SnotePattern const patterns[] =
{
{SnoteTag::ClientConnecting,
R"(^Client connecting: ([^ ]+) \(([^@ ]+)@([^) ]+)\) \[(.*)\] \{([^ ]*)\} <([^ ]*)> \[(.*)\]$)"},
{SnoteTag::ClientExiting,
R"(^Client exiting: ([^ ]+) \(([^@ ]+)@([^) ]+)\) \[(.*)\] \[(.*)\]$)"},
2023-11-27 14:12:20 -08:00
{SnoteTag::RejectingKlined,
R"(^Rejecting K-Lined user ([^ ]+)\[([^@]+)@([^\]]+)\] \[([^\] ]+)\] \((.*)\)$)"},
{SnoteTag::NickChange,
R"(^Nick change: From ([^ ]+) to ([^ ]+) \[([^@]+)@([^ ]+)\]$)"},
{SnoteTag::CreateChannel,
R"(^([^ ]+) is creating new channel ([^ ]+)$)"},
{SnoteTag::TemporaryKlineExpired,
R"(^Temporary K-line for \[([^ ]+)\] expired$)"},
{SnoteTag::DisconnectingKlined,
R"(^Disconnecting K-Lined user ([^ ]+)\[([^@]+)@([^ ]+)\] \((.*)\)$)"},
2023-11-26 21:16:56 -08:00
};
2023-11-27 14:12:20 -08:00
auto setup_database() -> hs_database_t*
2023-11-26 21:16:56 -08:00
{
2023-11-27 14:12:20 -08:00
auto const n = std::size(patterns);
2023-11-26 21:16:56 -08:00
std::vector<char const*> expressions;
2023-11-27 14:12:20 -08:00
std::vector<unsigned> flags(n, 0);
2023-11-26 21:16:56 -08:00
std::vector<unsigned> ids;
expressions.reserve(std::size(patterns));
ids.reserve(std::size(patterns));
2023-11-27 14:12:20 -08:00
for (std::size_t i = 0; i < n; i++)
2023-11-26 21:16:56 -08:00
{
2023-11-27 14:12:20 -08:00
expressions.push_back(patterns[i].expression);
flags.push_back(0);
ids.push_back(i);
2023-11-26 21:16:56 -08:00
}
hs_database_t* db;
hs_compile_error *error;
2023-11-27 14:12:20 -08:00
hs_platform_info_t *platform = nullptr; // target current platform
switch (hs_compile_multi(expressions.data(), flags.data(), ids.data(), expressions.size(), HS_MODE_BLOCK, platform, &db, &error))
2023-11-26 21:16:56 -08:00
{
case HS_COMPILER_ERROR:
{
std::string msg = error->message;
hs_free_compile_error(error);
throw std::runtime_error{std::move(msg)};
}
case HS_SUCCESS:
break;
default:
abort();
}
2023-11-27 14:12:20 -08:00
return db;
2023-11-26 21:16:56 -08:00
}
} // namespace
auto SnoteThread::start(Connection& connection) -> std::shared_ptr<SnoteThread>
{
auto thread = std::make_shared<SnoteThread>();
2023-11-27 14:12:20 -08:00
thread->db_.reset(setup_database());
2023-11-26 21:16:56 -08:00
hs_scratch_t* scratch = nullptr;
if (HS_SUCCESS != hs_alloc_scratch(thread->db_.get(), &scratch))
{
abort();
}
2023-11-27 14:12:20 -08:00
thread->scratch_.reset(scratch);
2023-11-26 21:16:56 -08:00
2023-11-25 20:09:20 -08:00
static char const* const prefix = "*** Notice -- ";
2023-11-26 21:16:56 -08:00
connection.add_listener<IrcMsgEvent>([&connection, thread](IrcMsgEvent& event)
2023-11-25 20:09:20 -08:00
{
2023-11-26 15:14:07 -08:00
auto& args = event.irc.args;
if (IrcCommand::NOTICE == event.command
&& "*" == args[0]
&& args[1].starts_with(prefix))
2023-11-25 20:09:20 -08:00
{
event.handled_ = true;
2023-11-26 21:16:56 -08:00
auto message = args[1].substr(strlen(prefix));
unsigned int match_id = -1;
auto const scan_result = hs_scan(thread->db_.get(), message.data(), message.size(), 0, thread->scratch_.get(),
[](unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void *context) -> int
{
int* const match_id = static_cast<int*>(context);
*match_id = id;
return 1; // stop scanning
}
, &match_id);
if (scan_result != HS_SUCCESS && scan_result != HS_SCAN_TERMINATED)
{
abort();
}
2023-11-27 14:12:20 -08:00
if (match_id == -1)
{
std::cout << "Unknown snote: " << message << std::endl;
}
else
2023-11-26 21:16:56 -08:00
{
auto& pattern = patterns[match_id];
std::match_results<std::string_view::const_iterator> results;
if (not std::regex_match(message.begin(), message.end(), results, pattern.regex))
{
// something went wrong - hyperscan disagrees with std::regex
abort();
}
std::vector<std::string_view> parts;
for (auto const sub : results)
{
parts.push_back(std::string_view{sub.first, sub.second});
}
connection.make_event<SnoteEvent>(pattern.tag, std::move(parts));
}
2023-11-25 20:09:20 -08:00
}
});
2023-11-26 21:16:56 -08:00
return thread;
2023-11-25 20:09:20 -08:00
}