diff --git a/bin/config_sample/config.ini b/bin/config_sample/config.ini index 882106d..f89cfd9 100644 --- a/bin/config_sample/config.ini +++ b/bin/config_sample/config.ini @@ -82,36 +82,6 @@ max_value=100 ; The maximum number of dice that can be rolled at once. max_dice=100 -[Discord] -; Whether the discord webhook is enabled or not. -; The server will send messages to this webhook whenever a modcall is sent. -; Changing this requires a server restart. -webhook_enabled=false - -; The URL of the discord webhook to send messages to. Must contain the webhook ID and token. -webhook_modcall_url= - -; Whether to attach a file containing the area log when a modcall message is sent to the webhook. -webhook_modcall_sendfile=false - -; Additional text to send with the webhook message. Usually for adding tags for role. Ensure the format is <@&[RoleID]>. -webhook_content= - -; Enables the ban webhook. -webhook_ban_enabled = false - -; The URL of the ban discord webhook to send messages to. Must contain the webhook ID and token. -webhook_ban_url= - -; Enables Uptime Webhook. -webhook_uptime_enabled = false - -; The time between message posting. This time is in minutes, with a default of 60. -webhook_uptime_time = 60 - -; The URL of the uptime discord webhook to send messages to. Must contain the webhook ID and token. -webhook_uptime_url= - [Password] ; Whether or not to enforce password requirements. Only applicable under advanced authorization. password_requirements = true diff --git a/bin/config_sample/discord.ini b/bin/config_sample/discord.ini new file mode 100644 index 0000000..ce3a496 --- /dev/null +++ b/bin/config_sample/discord.ini @@ -0,0 +1,30 @@ +[Discord] +; Enables the Discord Webhook Integration +webhook_enabled=false + +; Enables the modcall webhook to post a message when a modcall is made. +webhook_modcall_enabled=false + +; The URL of the modcall webhook. Must contain the webhook ID and token. +webhook_modcall_url= + +; Optional text. Usually for adding tags for roles. Ensure the format is <@&[RoleID]>. +webhook_modcall_content= + +; Attaches a logfile of the area to the modcall webhook. +webhook_modcall_sendfile=false + +; Enables the ban webhook. +webhook_ban_enabled = false + +; The URL of the ban discord webhook to send messages to. Must contain the webhook ID and token. +webhook_ban_url= + +; Enables Uptime Webhook. +webhook_uptime_enabled = false + +; The time between message posting. Time is in minutes. +webhook_uptime_time = 60 + +; The URL of the Uptime Webhook. Must contain the webhook ID and token. +webhook_uptime_url= diff --git a/core/include/config_manager.h b/core/include/config_manager.h index 4103ff8..9af71b3 100644 --- a/core/include/config_manager.h +++ b/core/include/config_manager.h @@ -29,6 +29,7 @@ #include #include #include +#include /** * @brief The config file handler class. @@ -191,12 +192,19 @@ class ConfigManager { static int diceMaxDice(); /** - * @brief Returns true if the discord webhook is enabled. + * @brief Returns true if the discord webhook integration is enabled. * * @return See short description. */ static bool discordWebhookEnabled(); + /** + * @brief Returns true if the discord modcall webhook is enabled. + * + * @return See short description. + */ + static bool discordModcallWebhookEnabled(); + /** * @brief Returns the discord webhook URL. * @@ -348,6 +356,11 @@ class ConfigManager { */ static QUrl advertiserHTTPIP(); + /** + * @brief Returns the uptime of the server in miliseconds. + */ + static qint64 uptime(); + /** * @brief Sets the server's authorization type. * @@ -406,6 +419,16 @@ private: */ static QSettings* m_settings; + /** + * @brief Stores all discord webhook configuration values. + */ + static QSettings* m_discord; + + /** + * @brief Pointer to QElapsedTimer to track the uptime of the server. + */ + static QElapsedTimer* m_uptimeTimer; + /** * @brief Returns a stringlist with the contents of a .txt file from config/text/. * diff --git a/core/include/discord.h b/core/include/discord.h index 439e485..d9cc814 100644 --- a/core/include/discord.h +++ b/core/include/discord.h @@ -46,6 +46,67 @@ public: */ ~Discord(); + /** + * @brief Method to start the Uptime Webhook posting timer. + */ + void startUptimeTimer(); + + /** + * @brief Method to stop the Uptime Webhook posting timer. + */ + void stopUptimeTimer(); + + +public slots: + /** + * @brief Handles a modcall webhook request. + * + * @param f_name The name of the modcall sender. + * @param f_area The name of the area the modcall was sent from. + * @param f_reason The reason for the modcall. + * @param f_buffer The area's log buffer. + */ + void onModcallWebhookRequested(const QString& f_name, const QString& f_area, const QString& f_reason, const QQueue& f_buffer); + + /** + * @brief Handles a ban webhook request. + * + * @param f_ipid The IPID of the client. + * @param f_moderator The name of the moderator banning. + * @param f_duration The date the ban expires. + * @param f_reason The reason of the ban. + */ + void onBanWebhookRequested(const QString& f_ipid, const QString& f_moderator, const QString& f_duration, const QString& f_reason, const int& f_banID); + + /** + * @brief Handles a uptime webhook request. + */ + void onUptimeWebhookRequested(); + +private: + /** + * @brief The QNetworkAccessManager for webhooks. + */ + QNetworkAccessManager* m_nam; + + /** + * @brief The QNetworkRequest for webhooks. + */ + QNetworkRequest m_request; + + /** + * @brief Timer to post a message that the server is still alive. + */ + QTimer* m_uptimePostTimer; + +private slots: + /** + * @brief Handles a network reply from a webhook POST request. + * + * @param f_reply Pointer to the QNetworkReply created by the webhook POST request. + */ + void onReplyFinished(QNetworkReply* f_reply); + /** * @brief Sends a webhook POST request with the given JSON document. * @@ -98,67 +159,6 @@ public: * @return A QHttpMultiPart containing the log file. */ QHttpMultiPart* constructLogMultipart(const QQueue& f_buffer) const; - -public slots: - /** - * @brief Handles a modcall webhook request. - * - * @param f_name The name of the modcall sender. - * @param f_area The name of the area the modcall was sent from. - * @param f_reason The reason for the modcall. - * @param f_buffer The area's log buffer. - */ - void onModcallWebhookRequested(const QString& f_name, const QString& f_area, const QString& f_reason, const QQueue& f_buffer); - - /** - * @brief Handles a ban webhook request. - * - * @param f_ipid The IPID of the client. - * @param f_moderator The name of the moderator banning. - * @param f_duration The date the ban expires. - * @param f_reason The reason of the ban. - */ - void onBanWebhookRequested(const QString& f_ipid, const QString& f_moderator, const QString& f_duration, const QString& f_reason, const int& f_banID); - - /** - * @brief Handles a uptime webhook request. - */ - void onUptimeWebhookRequested(); - -private: - /** - * @brief The QNetworkAccessManager for webhooks. - */ - QNetworkAccessManager* m_nam; - - /** - * @brief The QNetworkRequest for webhooks. - */ - QNetworkRequest m_request; - - /** - * @brief Timer to post a message that the server is still alive. - */ - QTimer* m_uptimePostTimer; - - /** - * @brief Stores how long the interval between postings is. - **/ - int m_uptimeInterval; - - /** - * @brief Proof that Salanto does not know what he is doing. - * @details Counts how often the server alive counter has been posted. - */ - int m_uptimeCounter; - -private slots: - /** - * @brief Handles a network reply from a webhook POST request. - * - * @param f_reply Pointer to the QNetworkReply created by the webhook POST request. - */ - void onReplyFinished(QNetworkReply* f_reply); }; #endif // DISCORD_H diff --git a/core/include/server.h b/core/include/server.h index 8ebd5de..aefe125 100644 --- a/core/include/server.h +++ b/core/include/server.h @@ -228,6 +228,13 @@ class Server : public QObject { */ void allowMessage(); + /** + * @brief Method to construct and reconstruct Discord Webhook Integration. + * + * @details Constructs or rebuilds Discord Object during server startup and configuration reload. + */ + void handleDiscordIntegration(); + signals: /** @@ -260,7 +267,14 @@ class Server : public QObject { */ void modcallWebhookRequest(const QString& f_name, const QString& f_area, const QString& f_reason, const QQueue& f_buffer); - + /** + * @brief Sends a ban webhook request, emitted by AOClient::cmdBan + * @param f_ipid The IPID of the banned client. + * @param f_moderator The moderator who issued the ban. + * @param f_duration The duration of the ban in a human readable format. + * @param f_reason The reason for the ban. + * @param f_banID The ID of the issued ban. + */ void banWebhookRequest(const QString& f_ipid, const QString& f_moderator, const QString& f_duration, const QString& f_reason, const int& f_banID); private: diff --git a/core/src/commands/moderation.cpp b/core/src/commands/moderation.cpp index d4b0433..caea60a 100644 --- a/core/src/commands/moderation.cpp +++ b/core/src/commands/moderation.cpp @@ -417,6 +417,7 @@ void AOClient::cmdReload(int argc, QStringList argv) ConfigManager::reloadSettings(); emit server->reloadRequest(ConfigManager::serverName(), ConfigManager::serverDescription()); server->updateHTTPAdvertiserConfig(); + server->handleDiscordIntegration(); sendServerMessage("Reloaded configurations"); } diff --git a/core/src/config_manager.cpp b/core/src/config_manager.cpp index 36b4e2e..49e1401 100644 --- a/core/src/config_manager.cpp +++ b/core/src/config_manager.cpp @@ -18,7 +18,9 @@ #include "include/config_manager.h" QSettings* ConfigManager::m_settings = new QSettings("config/config.ini", QSettings::IniFormat); +QSettings* ConfigManager::m_discord = new QSettings("config/discord.ini", QSettings::IniFormat); ConfigManager::CommandSettings* ConfigManager::m_commands = new CommandSettings(); +QElapsedTimer* ConfigManager::m_uptimeTimer = new QElapsedTimer; bool ConfigManager::verifyServerConfig() { @@ -84,12 +86,15 @@ bool ConfigManager::verifyServerConfig() m_commands->reprimands = (loadConfigFile("reprimands")); m_commands->gimps = (loadConfigFile("gimp")); + m_uptimeTimer->start(); + return true; } void ConfigManager::reloadSettings() { m_settings->sync(); + m_discord->sync(); } QStringList ConfigManager::loadConfigFile(const QString filename) @@ -267,43 +272,48 @@ int ConfigManager::diceMaxDice() bool ConfigManager::discordWebhookEnabled() { - return m_settings->value("Discord/webhook_enabled", false).toBool(); + return m_discord->value("Discord/webhook_enabled", false).toBool(); +} + +bool ConfigManager::discordModcallWebhookEnabled() +{ + return m_discord->value("Discord/webhook_modcall_enabled", false).toBool(); } QString ConfigManager::discordModcallWebhookUrl() { - return m_settings->value("Discord/webhook_modcall_url", "").toString(); + return m_discord->value("Discord/webhook_modcall_url", "").toString(); } QString ConfigManager::discordWebhookContent() { - return m_settings->value("Discord/webhook_content", "").toString(); + return m_discord->value("Discord/webhook_content", "").toString(); } bool ConfigManager::discordModcallWebhookSendFile() { - return m_settings->value("Discord/webhook_modcall_sendfile", false).toBool(); + return m_discord->value("Discord/webhook_modcall_sendfile", false).toBool(); } bool ConfigManager::discordBanWebhookEnabled() { - return m_settings->value("Discord/webhook_ban_enabled", false).toBool(); + return m_discord->value("Discord/webhook_ban_enabled", false).toBool(); } QString ConfigManager::discordBanWebhookUrl() { - return m_settings->value("Discord/webhook_ban_url", "").toString(); + return m_discord->value("Discord/webhook_ban_url", "").toString(); } bool ConfigManager::discordUptimeEnabled() { - return m_settings->value("Discord/webhook_uptime_enabled","false").toBool(); + return m_discord->value("Discord/webhook_uptime_enabled","false").toBool(); } int ConfigManager::discordUptimeTime() { bool ok; - int l_aliveTime = m_settings->value("Discord/webhook_uptime_time","60").toInt(&ok); + int l_aliveTime = m_discord->value("Discord/webhook_uptime_time","60").toInt(&ok); if (!ok) { qWarning("alive_time is not an int"); l_aliveTime = 60; @@ -313,7 +323,7 @@ int ConfigManager::discordUptimeTime() QString ConfigManager::discordUptimeWebhookUrl() { - return m_settings->value("Discord/webhook_uptime_url", "").toString(); + return m_discord->value("Discord/webhook_uptime_url", "").toString(); } bool ConfigManager::passwordRequirements() @@ -414,6 +424,11 @@ QUrl ConfigManager::advertiserHTTPIP() return m_settings->value("ModernAdvertiser/ms_ip","").toUrl(); } +qint64 ConfigManager::uptime() +{ + return m_uptimeTimer->elapsed(); +} + void ConfigManager::setMotd(const QString f_motd) { m_settings->setValue("Options/motd", f_motd); diff --git a/core/src/discord.cpp b/core/src/discord.cpp index 8d52292..3fd8e94 100644 --- a/core/src/discord.cpp +++ b/core/src/discord.cpp @@ -24,16 +24,9 @@ Discord::Discord(QObject* parent) : connect(m_nam, &QNetworkAccessManager::finished, this, &Discord::onReplyFinished); - if (ConfigManager::discordUptimeEnabled()){ - m_uptimePostTimer = new QTimer; - m_uptimeInterval = ConfigManager::discordUptimeTime() * 60000; - m_uptimeCounter = 0; - - connect(m_uptimePostTimer, &QTimer::timeout, - this, &Discord::onUptimeWebhookRequested); - m_uptimePostTimer->start(m_uptimeInterval); - onUptimeWebhookRequested(); - } + m_uptimePostTimer = new QTimer; + connect(m_uptimePostTimer, &QTimer::timeout, + this, &Discord::onUptimeWebhookRequested); } void Discord::onModcallWebhookRequested(const QString &f_name, const QString &f_area, const QString &f_reason, const QQueue &f_buffer) @@ -57,7 +50,7 @@ void Discord::onBanWebhookRequested(const QString &f_ipid, const QString &f_mode void Discord::onUptimeWebhookRequested() { - ulong l_expiredTimeSeconds = (m_uptimeCounter * m_uptimeInterval) / 1000; + qint64 l_expiredTimeSeconds = ConfigManager::uptime() / 1000; int minutes = (l_expiredTimeSeconds / 60) % 60; int hours = (l_expiredTimeSeconds / (60 * 60)) % 24; int days = (l_expiredTimeSeconds / (60 * 60 * 24)) % 365; @@ -66,7 +59,6 @@ void Discord::onUptimeWebhookRequested() QString f_timeExpired = QString::number(days) + " days, " + QString::number(hours) + " hours and " + QString::number(minutes) + " minutes."; QJsonDocument l_json = constructUptimeJson(f_timeExpired); postJsonWebhook(l_json); - m_uptimeCounter++; } QJsonDocument Discord::constructModcallJson(const QString &f_name, const QString &f_area, const QString &f_reason) const @@ -107,8 +99,8 @@ QJsonDocument Discord::constructUptimeJson(const QString& f_timeExpired) QJsonArray l_array; QJsonObject l_object { {"color", "13312842"}, - {"title", "Your server is still running!"}, - {"description", "Hello World!\nYour server has been online for " + f_timeExpired} + {"title", "Your server is online!"}, + {"description", "Your server has been online for " + f_timeExpired} }; l_array.append(l_object); l_json["embeds"] = l_array; @@ -166,3 +158,14 @@ Discord::~Discord() { m_nam->deleteLater(); } + +void Discord::startUptimeTimer() +{ + m_uptimePostTimer->start(ConfigManager::discordUptimeTime() * 60000); + onUptimeWebhookRequested(); +} + +void Discord::stopUptimeTimer() +{ + m_uptimePostTimer->stop(); +} diff --git a/core/src/packets.cpp b/core/src/packets.cpp index 5e16d4f..5cab906 100644 --- a/core/src/packets.cpp +++ b/core/src/packets.cpp @@ -352,7 +352,7 @@ void AOClient::pktModCall(AreaData* area, int argc, QStringList argv, AOPacket p } area->log(current_char, ipid, packet); - if (ConfigManager::discordWebhookEnabled()) { + if (ConfigManager::discordModcallWebhookEnabled()) { QString name = ooc_name; if (ooc_name.isEmpty()) name = current_char; diff --git a/core/src/server.cpp b/core/src/server.cpp index 775ca69..6da6f31 100644 --- a/core/src/server.cpp +++ b/core/src/server.cpp @@ -52,13 +52,8 @@ void Server::start() qDebug() << "Server listening on" << port; } - if (ConfigManager::discordWebhookEnabled()) { - discord = new Discord(this); - connect(this, &Server::modcallWebhookRequest, - discord, &Discord::onModcallWebhookRequested); - connect(this, &Server::banWebhookRequest, - discord, &Discord::onBanWebhookRequested); - } + discord = new Discord(this); + handleDiscordIntegration(); if (ConfigManager::advertiseHTTPServer()) { httpAdvertiserTimer = new QTimer(this); @@ -289,6 +284,28 @@ void Server::allowMessage() can_send_ic_messages = true; } +void Server::handleDiscordIntegration() +{ + // Prevent double connecting by preemtively disconnecting them. + disconnect(this, nullptr, discord, nullptr); + + if (ConfigManager::discordWebhookEnabled()) { + if (ConfigManager::discordModcallWebhookEnabled()) + connect(this, &Server::modcallWebhookRequest, + discord, &Discord::onModcallWebhookRequested); + + if (ConfigManager::discordBanWebhookEnabled()) + connect(this, &Server::banWebhookRequest, + discord, &Discord::onBanWebhookRequested); + + if (ConfigManager::discordUptimeEnabled()) + discord->startUptimeTimer(); + else + discord->stopUptimeTimer(); + } + return; +} + Server::~Server() { for (AOClient* client : clients) {