Allow the execution of multiple commands after the IRC connection

fix #3275
This commit is contained in:
louiz’
2018-03-18 02:31:18 +01:00
parent ad7aa5b709
commit 577984faf2
10 changed files with 159 additions and 20 deletions
+4
View File
@@ -13,6 +13,10 @@ struct Column
T value{};
};
struct ForeignKey: Column<std::size_t> {
static constexpr auto name = "fk_";
};
struct Id: Column<std::size_t> {
static constexpr std::size_t unset_value = static_cast<std::size_t>(-1);
static constexpr auto name = "id_";
+29
View File
@@ -21,6 +21,7 @@ Database::GlobalOptionsTable Database::global_options("globaloptions_");
Database::IrcServerOptionsTable Database::irc_server_options("ircserveroptions_");
Database::IrcChannelOptionsTable Database::irc_channel_options("ircchanneloptions_");
Database::RosterTable Database::roster("roster");
Database::AfterConnectionCommandsTable Database::after_connection_commands("after_connection_commands_");
std::map<Database::CacheKey, Database::EncodingIn::real_type> Database::encoding_in_cache{};
Database::GlobalPersistent::GlobalPersistent():
@@ -53,6 +54,8 @@ void Database::open(const std::string& filename)
Database::irc_channel_options.upgrade(*Database::db);
Database::roster.create(*Database::db);
Database::roster.upgrade(*Database::db);
Database::after_connection_commands.create(*Database::db);
Database::after_connection_commands.upgrade(*Database::db);
create_index<Database::Owner, Database::IrcChanName, Database::IrcServerName>(*Database::db, "archive_index", Database::muc_log_lines.get_name());
}
@@ -88,6 +91,32 @@ Database::IrcServerOptions Database::get_irc_server_options(const std::string& o
return options;
}
Database::AfterConnectionCommands Database::get_after_connection_commands(const IrcServerOptions& server_options)
{
const auto id = server_options.col<Id>();
if (id == Id::unset_value)
return {};
auto request = Database::after_connection_commands.select();
request.where() << ForeignKey{} << "=" << id;
return request.execute(*Database::db);
}
void Database::set_after_connection_commands(const Database::IrcServerOptions& server_options, Database::AfterConnectionCommands& commands)
{
const auto id = server_options.col<Id>();
if (id == Id::unset_value)
return ;
auto query = Database::after_connection_commands.del();
query.where() << ForeignKey{} << "=" << id;
query.execute(*Database::db);
for (auto& command: commands)
{
command.col<ForeignKey>() = server_options.col<Id>();
command.save(Database::db);
}
}
Database::IrcChannelOptions Database::get_irc_channel_options(const std::string& owner, const std::string& server, const std::string& channel)
{
auto request = Database::irc_channel_options.select();
+9 -1
View File
@@ -92,7 +92,7 @@ class Database
using GlobalOptionsTable = Table<Id, Owner, MaxHistoryLength, RecordHistory, GlobalPersistent>;
using GlobalOptions = GlobalOptionsTable::RowType;
using IrcServerOptionsTable = Table<Id, Owner, Server, Pass, AfterConnectionCommand, TlsPorts, Ports, Username, Realname, VerifyCert, TrustedFingerprint, EncodingOut, EncodingIn, MaxHistoryLength, Address>;
using IrcServerOptionsTable = Table<Id, Owner, Server, Pass, TlsPorts, Ports, Username, Realname, VerifyCert, TrustedFingerprint, EncodingOut, EncodingIn, MaxHistoryLength, Address>;
using IrcServerOptions = IrcServerOptionsTable::RowType;
using IrcChannelOptionsTable = Table<Id, Owner, Server, Channel, EncodingOut, EncodingIn, MaxHistoryLength, Persistent, RecordHistoryOptional>;
@@ -101,6 +101,9 @@ class Database
using RosterTable = Table<LocalJid, RemoteJid>;
using RosterItem = RosterTable::RowType;
using AfterConnectionCommandsTable = Table<Id, ForeignKey, AfterConnectionCommand>;
using AfterConnectionCommands = std::vector<AfterConnectionCommandsTable::RowType>;
Database() = default;
~Database() = default;
@@ -121,6 +124,9 @@ class Database
static IrcChannelOptions get_irc_channel_options_with_server_and_global_default(const std::string& owner,
const std::string& server,
const std::string& channel);
static AfterConnectionCommands get_after_connection_commands(const IrcServerOptions& server_options);
static void set_after_connection_commands(const IrcServerOptions& server_options, AfterConnectionCommands& commands);
/**
* Get all the lines between (optional) start and end dates, with a (optional) limit.
* If after_id is set, only the records after it will be returned.
@@ -158,6 +164,8 @@ class Database
static IrcServerOptionsTable irc_server_options;
static IrcChannelOptionsTable irc_channel_options;
static RosterTable roster;
static AfterConnectionCommandsTable after_connection_commands;
static std::unique_ptr<DatabaseEngine> db;
/**
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include <database/query.hpp>
#include <database/engine.hpp>
class DeleteQuery: public Query
{
public:
DeleteQuery(const std::string& name):
Query("DELETE")
{
this->body += " from " + name;
}
DeleteQuery& where()
{
this->body += " WHERE ";
return *this;
};
void execute(DatabaseEngine& db)
{
auto statement = db.prepare(this->body);
if (!statement)
return;
#ifdef DEBUG_SQL_QUERIES
const auto timer = this->log_and_time();
#endif
statement->bind(std::move(this->params));
if (statement->step() != StepResult::Done)
log_error("Failed to execute DELETE command");
}
};
+7
View File
@@ -3,6 +3,7 @@
#include <database/engine.hpp>
#include <database/select_query.hpp>
#include <database/delete_query.hpp>
#include <database/row.hpp>
#include <algorithm>
@@ -85,6 +86,12 @@ class Table
return select;
}
auto del()
{
DeleteQuery query(this->name);
return query;
}
const std::string& get_name() const
{
return this->name;
+3 -2
View File
@@ -889,8 +889,9 @@ void IrcClient::on_welcome_message(const IrcMessage& message)
#ifdef USE_DATABASE
auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(),
this->get_hostname());
if (!options.col<Database::AfterConnectionCommand>().empty())
this->send_raw(options.col<Database::AfterConnectionCommand>());
const auto commands = Database::get_after_connection_commands(options);
for (const auto& command: commands)
this->send_raw(command.col<Database::AfterConnectionCommand>());
#endif
// Install a repeated events to regularly send a PING
TimedEventsManager::instance().add_event(TimedEvent(240s, std::bind(&IrcClient::send_ping_command, this),
+20 -8
View File
@@ -219,6 +219,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
server_domain = target.local;
auto options = Database::get_irc_server_options(owner.local + "@" + owner.domain,
server_domain);
auto commands = Database::get_after_connection_commands(options);
XmlSubNode x(command_node, "jabber:x:data:x");
x["type"] = "form";
@@ -307,14 +308,14 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
{
XmlSubNode after_cnt_cmd(x, "field");
after_cnt_cmd["var"] = "after_connect_command";
after_cnt_cmd["type"] = "text-single";
after_cnt_cmd["desc"] = "Custom IRC command sent after the connection is established with the server.";
after_cnt_cmd["label"] = "After-connection IRC command";
if (!options.col<Database::AfterConnectionCommand>().empty())
after_cnt_cmd["var"] = "after_connect_commands";
after_cnt_cmd["type"] = "text-multi";
after_cnt_cmd["desc"] = "Custom IRC commands sent after the connection is established with the server.";
after_cnt_cmd["label"] = "After-connection IRC commands";
for (const auto& command: commands)
{
XmlSubNode after_cnt_cmd_value(after_cnt_cmd, "value");
after_cnt_cmd_value.set_inner(options.col<Database::AfterConnectionCommand>());
after_cnt_cmd_value.set_inner(command.col<Database::AfterConnectionCommand>());
}
}
@@ -384,6 +385,8 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
server_domain = target.local;
auto options = Database::get_irc_server_options(owner.local + "@" + owner.domain,
server_domain);
auto commands = Database::get_after_connection_commands(options);
for (const XmlNode* field: x->get_children("field", "jabber:x:data"))
{
const XmlNode* value = field->get_child("value", "jabber:x:data");
@@ -427,8 +430,16 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
else if (field->get_tag("var") == "pass" && value)
options.col<Database::Pass>() = value->get_inner();
else if (field->get_tag("var") == "after_connect_command" && value)
options.col<Database::AfterConnectionCommand>() = value->get_inner();
else if (field->get_tag("var") == "after_connect_commands")
{
commands.clear();
for (const auto& val: values)
{
auto command = Database::after_connection_commands.row();
command.col<Database::AfterConnectionCommand>() = val->get_inner();
commands.push_back(std::move(command));
}
}
else if (field->get_tag("var") == "username" && value)
{
@@ -450,6 +461,7 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
}
Database::invalidate_encoding_in_cache();
options.save(Database::db);
Database::set_after_connection_commands(options, commands);
command_node.delete_all_children();
XmlSubNode note(command_node, "note");