consolidate command interface
This commit is contained in:
parent
5aec8397bb
commit
5f2439e5af
@ -67,15 +67,15 @@ static auto start_irc(
|
||||
}
|
||||
}
|
||||
|
||||
client->sig_registered.connect([connection, webhook]() {
|
||||
webhook->set_connection(connection);
|
||||
client->sig_registered.connect([client, webhook]() {
|
||||
webhook->set_client(client);
|
||||
});
|
||||
|
||||
// On disconnect reconnect in 5 seconds
|
||||
// connection is captured in the disconnect handler so it can keep itself alive
|
||||
connection->sig_disconnect.connect(
|
||||
[&io, &settings, connection, webhook]() {
|
||||
webhook->clear_connection();
|
||||
webhook->clear_client();
|
||||
auto timer = std::make_shared<boost::asio::steady_timer>(io);
|
||||
timer->expires_after(5s);
|
||||
timer->async_wait([&io, &settings, timer, webhook](auto) { start_irc(io, settings, webhook); });
|
||||
|
312
driver/web.cpp
312
driver/web.cpp
@ -269,31 +269,32 @@ auto start_webhook(
|
||||
const char *webhook_settings_filename
|
||||
) -> std::shared_ptr<Webhooks>
|
||||
{
|
||||
std::ifstream webhook_settings_file{webhook_settings_filename};
|
||||
if (!webhook_settings_file)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Unable to open webhook settings file";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
auto webhook_settings = toml::parse(webhook_settings_file);
|
||||
WebhookSettings settings = WebhookSettings::from_toml(webhook_settings);
|
||||
BOOST_LOG_TRIVIAL(info) << "Webhook settings: " << settings.to_toml();
|
||||
auto webhook = std::make_shared<Webhooks>(std::move(settings), webhook_settings_filename);
|
||||
auto webhook = std::make_shared<Webhooks>(webhook_settings_filename);
|
||||
webhook->load_settings();
|
||||
boost::asio::co_spawn(io, spawn_webhook(io, webhook), report_error);
|
||||
return webhook;
|
||||
}
|
||||
|
||||
auto Webhooks::load_settings() -> void
|
||||
{
|
||||
std::ifstream webhook_settings_file{settings_filename_};
|
||||
if (!webhook_settings_file)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Unable to open webhook settings file";
|
||||
}
|
||||
auto webhook_settings = toml::parse(webhook_settings_file);
|
||||
settings_ = WebhookSettings::from_toml(webhook_settings);
|
||||
}
|
||||
|
||||
auto Webhooks::save_settings() const -> void
|
||||
{
|
||||
std::ofstream webhook_settings_file{settings_file};
|
||||
std::ofstream webhook_settings_file{settings_filename_};
|
||||
if (!webhook_settings_file)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Unable to open webhook settings file";
|
||||
return;
|
||||
}
|
||||
|
||||
webhook_settings_file << settings_.to_toml();
|
||||
webhook_settings_file << settings_.to_toml() << "\n";
|
||||
}
|
||||
|
||||
auto ProjectSettings::from_toml(const toml::table &v) -> ProjectSettings
|
||||
@ -412,9 +413,9 @@ auto WebhookSettings::to_toml() const -> toml::table
|
||||
// Either emit the event now or save it until a connection is set
|
||||
auto Webhooks::send_notice(std::string_view target, std::string message) -> void
|
||||
{
|
||||
if (connection_)
|
||||
if (client_)
|
||||
{
|
||||
connection_->send_notice(target, message);
|
||||
client_->get_connection().send_notice(target, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -422,19 +423,19 @@ auto Webhooks::send_notice(std::string_view target, std::string message) -> void
|
||||
}
|
||||
}
|
||||
|
||||
auto Webhooks::set_connection(std::shared_ptr<myirc::Connection> connection) -> void
|
||||
auto Webhooks::set_client(std::shared_ptr<myirc::Client> client) -> void
|
||||
{
|
||||
connection_ = std::move(connection);
|
||||
client_ = std::move(client);
|
||||
for (auto &&[target, message] : std::move(events_))
|
||||
{
|
||||
connection_->send_notice(target, message);
|
||||
client_->get_connection().send_notice(target, message);
|
||||
}
|
||||
events_.clear();
|
||||
}
|
||||
|
||||
auto Webhooks::clear_connection() -> void
|
||||
auto Webhooks::clear_client() -> void
|
||||
{
|
||||
connection_.reset();
|
||||
client_.reset();
|
||||
}
|
||||
|
||||
static auto reply_to(std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd, std::string message) -> void
|
||||
@ -460,171 +461,124 @@ static auto authorized_for_project(
|
||||
}
|
||||
|
||||
std::map<std::string, void (*)(std::shared_ptr<Webhooks>, const myirc::Bot::Command &)> webhook_commands{
|
||||
{"add-credential", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
if (cmd.oper.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
{"announce", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
std::istringstream iss{std::string{cmd.arguments}};
|
||||
std::string name, key;
|
||||
if (iss >> name >> key)
|
||||
{
|
||||
webhooks->settings_.credentials.insert_or_assign(name, key);
|
||||
webhooks->save_settings();
|
||||
reply_to(webhooks, cmd, "Added credential " + name);
|
||||
}
|
||||
}},
|
||||
{"drop-credential", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
if (cmd.oper.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::istringstream iss{std::string{cmd.arguments}};
|
||||
std::string name;
|
||||
if (iss >> name)
|
||||
{
|
||||
webhooks->settings_.credentials.erase(name);
|
||||
webhooks->save_settings();
|
||||
reply_to(webhooks, cmd, "Dropped credential " + name);
|
||||
}
|
||||
}},
|
||||
{"enable-project", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
std::istringstream iss{std::string{cmd.arguments}};
|
||||
std::string name;
|
||||
if (iss >> name)
|
||||
std::string name, mode;
|
||||
if (iss >> name >> mode)
|
||||
{
|
||||
auto &project = webhooks->settings_.projects.at(name);
|
||||
if (not authorized_for_project(cmd, project, cmd.account))
|
||||
{
|
||||
return;
|
||||
}
|
||||
project.enabled = true;
|
||||
webhooks->save_settings();
|
||||
reply_to(webhooks, cmd, "Enabled project " + name);
|
||||
}
|
||||
}},
|
||||
{"disable-project", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
std::istringstream iss{std::string{cmd.arguments}};
|
||||
std::string name;
|
||||
if (iss >> name)
|
||||
{
|
||||
auto &project = webhooks->settings_.projects.at(name);
|
||||
if (not authorized_for_project(cmd, project, cmd.account))
|
||||
{
|
||||
return;
|
||||
}
|
||||
project.enabled = false;
|
||||
webhooks->save_settings();
|
||||
reply_to(webhooks, cmd, "Disabled project " + name);
|
||||
}
|
||||
}},
|
||||
{"add-events", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
std::istringstream iss{std::string{cmd.arguments}};
|
||||
std::string name;
|
||||
if (iss >> name)
|
||||
{
|
||||
auto &project = webhooks->settings_.projects.at(name);
|
||||
if (not authorized_for_project(cmd, project, cmd.account))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned n_added = 0, n_skipped = 0, n_unknown = 0;
|
||||
while (iss >> name) {
|
||||
if (formatters.contains(name)) {
|
||||
const auto [_, added] = project.events.insert(name);
|
||||
if (added) { n_added++; } else { n_skipped++; }
|
||||
} else {
|
||||
n_unknown++;
|
||||
}
|
||||
}
|
||||
|
||||
webhooks->save_settings();
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "Events updated.";
|
||||
if (n_added) { ss << " added: " << n_added; }
|
||||
if (n_skipped) { ss << " skipped: " << n_skipped; }
|
||||
if (n_unknown) { ss << " unknown: " << n_unknown; }
|
||||
reply_to(webhooks, cmd, ss.str());
|
||||
}
|
||||
}},
|
||||
{"drop-events", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
std::istringstream iss{std::string{cmd.arguments}};
|
||||
std::string name;
|
||||
if (iss >> name)
|
||||
{
|
||||
auto &project = webhooks->settings_.projects.at(name);
|
||||
if (not authorized_for_project(cmd, project, cmd.account))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned n_removed = 0, n_skipped = 0, n_unknown = 0;
|
||||
while (iss >> name) {
|
||||
if (formatters.contains(name)) {
|
||||
const auto removed = project.events.erase(name);
|
||||
if (removed) { n_removed++; } else { n_skipped++; }
|
||||
} else {
|
||||
n_unknown++;
|
||||
}
|
||||
}
|
||||
|
||||
webhooks->save_settings();
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "Events updated.";
|
||||
if (n_removed) { ss << " removed: " << n_removed; }
|
||||
if (n_skipped) { ss << " skipped: " << n_skipped; }
|
||||
if (n_unknown) { ss << " unknown: " << n_unknown; }
|
||||
reply_to(webhooks, cmd, ss.str());
|
||||
}
|
||||
}},
|
||||
{"add-access", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
if (cmd.oper.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::istringstream iss{std::string{cmd.arguments}};
|
||||
std::string name, account;
|
||||
if (iss >> name >> account)
|
||||
{
|
||||
auto &project = webhooks->settings_.projects.at(name);
|
||||
if (not authorized_for_project(cmd, project, cmd.account))
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto [_, inserted] = project.authorized_accounts.insert(account);
|
||||
if (inserted) {
|
||||
webhooks->save_settings();
|
||||
reply_to(webhooks, cmd, "Access added");
|
||||
}
|
||||
else
|
||||
{
|
||||
reply_to(webhooks, cmd, "Access already set");
|
||||
}
|
||||
}
|
||||
}},
|
||||
{"drop-access", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
if (cmd.oper.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::istringstream iss{std::string{cmd.arguments}};
|
||||
std::string name, account;
|
||||
if (iss >> name >> account)
|
||||
{
|
||||
auto &project = webhooks->settings_.projects.at(name);
|
||||
auto removed = project.authorized_accounts.erase(account);
|
||||
if (removed) {
|
||||
webhooks->save_settings();
|
||||
reply_to(webhooks, cmd, "Access dropped");
|
||||
if (mode == "on") {
|
||||
project.enabled = true;
|
||||
reply_to(webhooks, cmd, "Enabled project " + name);
|
||||
} else if (mode == "off") {
|
||||
project.enabled = false;
|
||||
reply_to(webhooks, cmd, "Disabled project " + name);
|
||||
} else {
|
||||
reply_to(webhooks, cmd, "Access not found");
|
||||
return;
|
||||
}
|
||||
webhooks->save_settings();
|
||||
}
|
||||
}},
|
||||
{"set-channel", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
{"event", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
std::istringstream iss{std::string{cmd.arguments}};
|
||||
std::string name, mode;
|
||||
if (iss >> name >> mode)
|
||||
{
|
||||
auto &project = webhooks->settings_.projects.at(name);
|
||||
if (not authorized_for_project(cmd, project, cmd.account))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == "list") {
|
||||
std::stringstream ss;
|
||||
ss << "Events for " << name << ":";
|
||||
for (auto &&event : project.events) {
|
||||
ss << " " << event;
|
||||
}
|
||||
reply_to(webhooks, cmd, ss.str());
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned n_added = 0, n_removed = 0, n_skipped = 0, n_unknown = 0;
|
||||
if (mode == "add") {
|
||||
while (iss >> name) {
|
||||
if (formatters.contains(name)) {
|
||||
const auto [_, added] = project.events.insert(name);
|
||||
if (added) { n_added++; } else { n_skipped++; }
|
||||
} else {
|
||||
n_unknown++;
|
||||
}
|
||||
}
|
||||
} else if (mode == "del") {
|
||||
while (iss >> name) {
|
||||
if (formatters.contains(name)) {
|
||||
const auto removed = project.events.erase(name);
|
||||
if (removed) { n_removed++; } else { n_skipped++; }
|
||||
} else {
|
||||
n_unknown++;
|
||||
}
|
||||
}
|
||||
}
|
||||
webhooks->save_settings();
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "Events updated:";
|
||||
if (n_added) { ss << " added " << n_added; }
|
||||
if (n_removed) { ss << " removed " << n_removed; }
|
||||
if (n_skipped) { ss << " skipped " << n_skipped; }
|
||||
if (n_unknown) { ss << " unknown " << n_unknown; }
|
||||
reply_to(webhooks, cmd, ss.str());
|
||||
}
|
||||
}},
|
||||
{"auth", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
if (cmd.oper.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::istringstream iss{std::string{cmd.arguments}};
|
||||
std::string name, mode;
|
||||
if (iss >> name >> mode)
|
||||
{
|
||||
auto &project = webhooks->settings_.projects.at(name);
|
||||
|
||||
if (mode == "list") {
|
||||
std::stringstream ss;
|
||||
ss << "Authorized accounts:";
|
||||
for (auto &&event : project.authorized_accounts) {
|
||||
ss << " " << event;
|
||||
}
|
||||
reply_to(webhooks, cmd, ss.str());
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned n_added = 0, n_removed = 0, n_skipped = 0;
|
||||
if (mode == "add") {
|
||||
while (iss >> name) {
|
||||
const auto [_, added] = project.authorized_accounts.insert(name);
|
||||
if (added) { n_added++; } else { n_skipped++; }
|
||||
}
|
||||
} else if (mode == "del") {
|
||||
while (iss >> name) {
|
||||
const auto removed = project.authorized_accounts.erase(name);
|
||||
if (removed) { n_removed++; } else { n_skipped++; }
|
||||
}
|
||||
}
|
||||
webhooks->save_settings();
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "Authorized accounts updated:";
|
||||
if (n_added) { ss << " added " << n_added; }
|
||||
if (n_removed) { ss << " removed " << n_removed; }
|
||||
if (n_skipped) { ss << " skipped " << n_skipped; }
|
||||
reply_to(webhooks, cmd, ss.str());
|
||||
}
|
||||
}},
|
||||
{"setchannel", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
if (cmd.oper.empty())
|
||||
{
|
||||
return;
|
||||
@ -639,4 +593,12 @@ std::map<std::string, void (*)(std::shared_ptr<Webhooks>, const myirc::Bot::Comm
|
||||
reply_to(webhooks, cmd, "Channel assigned");
|
||||
}
|
||||
}},
|
||||
{"rehash", [](std::shared_ptr<Webhooks> webhooks, const myirc::Bot::Command &cmd) {
|
||||
if (cmd.oper.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
webhooks->load_settings();
|
||||
reply_to(webhooks, cmd, "Rehashed");
|
||||
}},
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <myirc/bot.hpp>
|
||||
#include <myirc/connection.hpp>
|
||||
#include <myirc/client.hpp>
|
||||
|
||||
#include <toml++/toml.hpp>
|
||||
|
||||
@ -49,27 +49,27 @@ struct WebhookSettings {
|
||||
|
||||
class Webhooks {
|
||||
// IRC connection to announce on; could be empty
|
||||
std::shared_ptr<myirc::Connection> connection_;
|
||||
std::shared_ptr<myirc::Client> client_;
|
||||
|
||||
// Buffered events in case connection was inactive when event was received
|
||||
std::vector<std::pair<std::string, std::string>> events_;
|
||||
|
||||
const char * settings_file;
|
||||
const char * settings_filename_;
|
||||
|
||||
public:
|
||||
WebhookSettings settings_;
|
||||
|
||||
Webhooks(WebhookSettings settings, const char * settings_file)
|
||||
: settings_(std::move(settings))
|
||||
, settings_file(settings_file)
|
||||
Webhooks(const char * settings_filename)
|
||||
: settings_filename_{settings_filename}
|
||||
{
|
||||
}
|
||||
|
||||
// Either emit the event now or save it until a connection is set
|
||||
auto send_notice(std::string_view, std::string) -> void;
|
||||
auto set_connection(std::shared_ptr<myirc::Connection> connection) -> void;
|
||||
auto clear_connection() -> void;
|
||||
auto set_client(std::shared_ptr<myirc::Client> client) -> void;
|
||||
auto clear_client() -> void;
|
||||
auto save_settings() const -> void;
|
||||
auto load_settings() -> void;
|
||||
};
|
||||
|
||||
auto start_webhook(boost::asio::io_context &io, const char *) -> std::shared_ptr<Webhooks>;
|
||||
|
Loading…
x
Reference in New Issue
Block a user