Discord webhook refactor
Completely refactors the Discord class, breaking it up into separate functions and slots, removing circular dependencies, and replacing most pointers with const references.
This commit is contained in:
parent
4c32cf86cc
commit
4f7d5cd045
@ -28,7 +28,7 @@ max_dice=100
|
||||
|
||||
[Discord]
|
||||
webhook_enabled=false
|
||||
webhook_url=Your webhook url here.
|
||||
webhook_url=
|
||||
webhook_sendfile=false
|
||||
webhook_content=
|
||||
|
||||
|
@ -20,48 +20,104 @@
|
||||
|
||||
#include <QtNetwork>
|
||||
#include <QCoreApplication>
|
||||
#include "server.h"
|
||||
|
||||
class Server;
|
||||
|
||||
/**
|
||||
* @brief A class for handling all Discord webhook requests.
|
||||
*/
|
||||
class Discord : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Creates an instance of the Discord class.
|
||||
* @brief Constructor for the Discord object
|
||||
*
|
||||
* @param p_server A pointer to the Server instance Discord is constructed by.
|
||||
* @param f_webhook_url The URL to send webhook POST requests to.
|
||||
* @param f_webhook_content The content to include in the webhook POST request.
|
||||
* @param f_webhook_sendfile Whether or not to send a file containing area logs with the webhook POST request.
|
||||
* @param parent Qt-based parent, passed along to inherited constructor from QObject.
|
||||
*/
|
||||
Discord(Server* p_server, QObject* parent = nullptr)
|
||||
: QObject(parent), server(p_server) {
|
||||
};
|
||||
Discord(const QUrl& f_webhook_url, const QString& f_webhook_content, const bool& f_webhook_sendfile, QObject* parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Deconstructor for the Discord class.
|
||||
*
|
||||
* @details Marks the nam to be deleted later.
|
||||
*/
|
||||
~Discord();
|
||||
|
||||
/**
|
||||
* @brief Sends a webhook POST request with the given JSON document.
|
||||
*
|
||||
* @param f_json The JSON document to send.
|
||||
*/
|
||||
void postJsonWebhook(const QJsonDocument& f_json);
|
||||
|
||||
/**
|
||||
* @brief Sends a webhook POST request with the given QHttpMultiPart.
|
||||
*
|
||||
* @param f_multipart The QHttpMultiPart to send.
|
||||
*/
|
||||
void postMultipartWebhook(QHttpMultiPart& f_multipart);
|
||||
|
||||
/**
|
||||
* @brief Constructs a new JSON document for modcalls.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @return A JSON document for the modcall.
|
||||
*/
|
||||
QJsonDocument constructModcallJson(const QString& f_name, const QString& f_area, const QString& f_reason) const;
|
||||
|
||||
/**
|
||||
* @brief Constructs a new QHttpMultiPart document for log files.
|
||||
*
|
||||
* @param f_buffer The area's log buffer.
|
||||
*
|
||||
* @return A QHttpMultiPart containing the log file.
|
||||
*/
|
||||
QHttpMultiPart* constructLogMultipart(const QQueue<QString>& f_buffer) const;
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* @brief Sends a modcall to a discord webhook.
|
||||
* @brief Handles a modcall webhook request.
|
||||
*
|
||||
* @param name The character or OOC name of the client who sent the modcall.
|
||||
* @param area The area name of the area the modcall was sent from.
|
||||
* @param reason The reason the client specified for the modcall.
|
||||
* @param current_area The index of the area the modcall is made.
|
||||
* @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 postModcallWebhook(QString name, QString reason, int current_area);
|
||||
|
||||
/**
|
||||
* @brief Sends the reply to the POST request sent by Discord::postModcallWebhook.
|
||||
*/
|
||||
void onFinish(QNetworkReply *reply);
|
||||
void onModcallWebhookRequested(const QString& f_name, const QString& f_area, const QString& f_reason, const QQueue<QString>& f_buffer);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief The QNetworkAccessManager for webhooks.
|
||||
*/
|
||||
QNetworkAccessManager* m_nam;
|
||||
|
||||
/**
|
||||
* @brief A pointer to the Server.
|
||||
* @brief The QNetworkRequest for webhooks.
|
||||
*/
|
||||
Server* server;
|
||||
QNetworkRequest m_request;
|
||||
|
||||
/**
|
||||
* @brief The content to include in the webhook POST request.
|
||||
*/
|
||||
const QString& m_webhook_content;
|
||||
|
||||
/**
|
||||
* @brief Whether or not to send a file containing area logs with the webhook POST request.
|
||||
*/
|
||||
const bool& m_webhook_sendfile;
|
||||
|
||||
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
|
||||
|
@ -38,7 +38,6 @@
|
||||
class AOClient;
|
||||
class DBManager;
|
||||
class AreaData;
|
||||
class Discord;
|
||||
|
||||
/**
|
||||
* @brief The class that represents the actual server as it is.
|
||||
@ -242,7 +241,7 @@ class Server : public QObject {
|
||||
/**
|
||||
* @brief Requires an https Webhook link, including both ID and Token in the link.
|
||||
*/
|
||||
QString webhook_url;
|
||||
QUrl webhook_url;
|
||||
|
||||
/**
|
||||
* @brief If the modcall buffer is sent as a file.
|
||||
@ -392,11 +391,12 @@ class Server : public QObject {
|
||||
/**
|
||||
* @brief Sends a modcall webhook request, emitted by AOClient::pktModcall.
|
||||
*
|
||||
* @param name The character or OOC name of the client who sent the modcall.
|
||||
* @param reason The reason the client specified for the modcall.
|
||||
* @param current_area Integer ID of the area the modcall is made.
|
||||
* @param f_name The character or OOC name of the client who sent the modcall.
|
||||
* @param f_area The name of the area the modcall was sent from.
|
||||
* @param f_reason The reason the client specified for the modcall.
|
||||
* @param f_buffer The area's log buffer.
|
||||
*/
|
||||
void webhookRequest(QString name, QString reason, int current_area);
|
||||
void modcallWebhookRequest(const QString& f_name, const QString& f_area, const QString& f_reason, const QQueue<QString>& f_buffer);
|
||||
|
||||
private:
|
||||
/**
|
||||
@ -411,6 +411,11 @@ class Server : public QObject {
|
||||
*/
|
||||
QTcpServer* server;
|
||||
|
||||
/**
|
||||
* @brief Handles Discord webhooks.
|
||||
*/
|
||||
Discord* discord;
|
||||
|
||||
/**
|
||||
* @brief The port through which the server will accept TCP connections.
|
||||
*/
|
||||
@ -420,11 +425,6 @@ class Server : public QObject {
|
||||
* @brief The port through which the server will accept WebSocket connections.
|
||||
*/
|
||||
int ws_port;
|
||||
|
||||
/**
|
||||
* @brief Handles discord webhooks.
|
||||
*/
|
||||
Discord* discord;
|
||||
};
|
||||
|
||||
#endif // SERVER_H
|
||||
|
@ -17,59 +17,94 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "include/discord.h"
|
||||
|
||||
void Discord::postModcallWebhook(QString name, QString reason, int current_area)
|
||||
Discord::Discord(const QUrl &f_webhook_url, const QString &f_webhook_content, const bool &f_webhook_sendfile, QObject* parent) :
|
||||
QObject(parent),
|
||||
m_webhook_content(f_webhook_content),
|
||||
m_webhook_sendfile(f_webhook_sendfile)
|
||||
{
|
||||
if (!QUrl (server->webhook_url).isValid()) {
|
||||
qWarning() << "Invalid webhook url!";
|
||||
if (!QUrl(f_webhook_url).isValid())
|
||||
qWarning("Invalid webhook URL!");
|
||||
m_nam = new QNetworkAccessManager();
|
||||
connect(m_nam, &QNetworkAccessManager::finished,
|
||||
this, &Discord::onReplyFinished);
|
||||
m_request.setUrl(f_webhook_url);
|
||||
}
|
||||
|
||||
void Discord::onModcallWebhookRequested(const QString &f_name, const QString &f_area, const QString &f_reason, const QQueue<QString> &f_buffer)
|
||||
{
|
||||
QJsonDocument l_json = constructModcallJson(f_name, f_area, f_reason);
|
||||
postJsonWebhook(l_json);
|
||||
|
||||
if (m_webhook_sendfile) {
|
||||
QHttpMultiPart *l_multipart = constructLogMultipart(f_buffer);
|
||||
postMultipartWebhook(*l_multipart);
|
||||
}
|
||||
}
|
||||
|
||||
QJsonDocument Discord::constructModcallJson(const QString &f_name, const QString &f_area, const QString &f_reason) const
|
||||
{
|
||||
QJsonObject l_json;
|
||||
QJsonArray l_array;
|
||||
QJsonObject l_object {
|
||||
{"color", "13312842"},
|
||||
{"title", f_name + " filed a modcall in " + f_area},
|
||||
{"description", f_reason}
|
||||
};
|
||||
l_array.append(l_object);
|
||||
l_json["embeds"] = l_array;
|
||||
if (!m_webhook_content.isEmpty())
|
||||
l_json["content"] = m_webhook_content;
|
||||
|
||||
return QJsonDocument(l_json);
|
||||
}
|
||||
|
||||
QHttpMultiPart* Discord::constructLogMultipart(const QQueue<QString> &f_buffer) const
|
||||
{
|
||||
QHttpMultiPart* l_multipart = new QHttpMultiPart();
|
||||
QHttpPart l_file;
|
||||
l_file.setRawHeader(QByteArray("Content-Disposition"), QByteArray("form-data; name=\"file\"; filename=\"log.txt\""));
|
||||
l_file.setRawHeader(QByteArray("Content-Type"), QByteArray("plain/text"));
|
||||
QString l_log;
|
||||
for (QString log_entry : f_buffer) {
|
||||
l_log.append(log_entry + "\n");
|
||||
}
|
||||
l_file.setBody(l_log.toUtf8());
|
||||
l_multipart->append(l_file);
|
||||
return l_multipart;
|
||||
}
|
||||
|
||||
void Discord::postJsonWebhook(const QJsonDocument &f_json)
|
||||
{
|
||||
if (!QUrl(m_request.url()).isValid()) {
|
||||
qWarning("Invalid webhook URL!");
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkRequest request(QUrl (server->webhook_url));
|
||||
QNetworkAccessManager* nam = new QNetworkAccessManager();
|
||||
connect(nam, &QNetworkAccessManager::finished,
|
||||
this, &Discord::onFinish);
|
||||
|
||||
// This is the kind of garbage Qt makes me write.
|
||||
// I am so tired. Qt has broken me.
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
QJsonObject json;
|
||||
QJsonArray jsonArray;
|
||||
QJsonObject jsonObject {
|
||||
{"color", "13312842"},
|
||||
{"title", name + " filed a modcall in " + server->areas[current_area]->name()},
|
||||
{"description", reason}
|
||||
};
|
||||
jsonArray.append(jsonObject);
|
||||
json["embeds"] = jsonArray;
|
||||
if (!server->webhook_content.isEmpty())
|
||||
json["content"] = server->webhook_content;
|
||||
|
||||
nam->post(request, QJsonDocument(json).toJson());
|
||||
|
||||
if (server->webhook_sendfile) {
|
||||
QHttpMultiPart* construct = new QHttpMultiPart();
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + construct->boundary());
|
||||
|
||||
//This cost me two days of my life. Thanks Qt and Discord. You have broken me.
|
||||
QHttpPart file;
|
||||
file.setRawHeader(QByteArray("Content-Disposition"), QByteArray("form-data; name=\"file\"; filename=\"log.txt\""));
|
||||
file.setRawHeader(QByteArray("Content-Type"), QByteArray("plain/text"));
|
||||
QQueue<QString> buffer = server->areas[current_area]->buffer(); // I feel no shame for doing this
|
||||
QString log;
|
||||
while (!buffer.isEmpty()) {
|
||||
log.append(buffer.dequeue() + "\n");
|
||||
}
|
||||
file.setBody(log.toUtf8());
|
||||
construct->append(file);
|
||||
|
||||
nam->post(request, construct);
|
||||
}
|
||||
m_request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
m_nam->post(m_request, f_json.toJson());
|
||||
}
|
||||
|
||||
void Discord::onFinish(QNetworkReply *reply)
|
||||
void Discord::postMultipartWebhook(QHttpMultiPart &f_multipart)
|
||||
{
|
||||
QByteArray data = reply->readAll();
|
||||
QString str_reply = data;
|
||||
qDebug() << str_reply;
|
||||
if (!QUrl(m_request.url()).isValid()) {
|
||||
qWarning("Invalid webhook URL!");
|
||||
f_multipart.deleteLater();
|
||||
return;
|
||||
}
|
||||
m_request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + f_multipart.boundary());
|
||||
QNetworkReply* l_reply = m_nam->post(m_request, &f_multipart);
|
||||
f_multipart.setParent(l_reply);
|
||||
}
|
||||
|
||||
void Discord::onReplyFinished(QNetworkReply *f_reply)
|
||||
{
|
||||
auto l_data = f_reply->readAll();
|
||||
f_reply->deleteLater();
|
||||
#ifdef DISCORD_DEBUG
|
||||
QDebug() << l_data;
|
||||
#endif
|
||||
}
|
||||
|
||||
Discord::~Discord()
|
||||
{
|
||||
m_nam->deleteLater();
|
||||
}
|
||||
|
@ -353,7 +353,7 @@ void AOClient::pktModCall(AreaData* area, int argc, QStringList argv, AOPacket p
|
||||
if (ooc_name.isEmpty())
|
||||
name = current_char;
|
||||
|
||||
server->webhookRequest(name, packet.contents[0], current_area);
|
||||
emit server->modcallWebhookRequest(name, server->areas[current_area]->name(), packet.contents[0], area->buffer());
|
||||
}
|
||||
|
||||
area->flushLogs();
|
||||
|
@ -53,14 +53,13 @@ void Server::start()
|
||||
|
||||
loadServerConfig();
|
||||
loadCommandConfig();
|
||||
|
||||
if (webhook_enabled) {
|
||||
discord = new Discord(this, this);
|
||||
connect(this, &Server::webhookRequest,
|
||||
discord, &Discord::postModcallWebhook);
|
||||
|
||||
}
|
||||
|
||||
if (webhook_enabled) {
|
||||
discord = new Discord(webhook_url, webhook_content, webhook_sendfile, this);
|
||||
connect(this, &Server::modcallWebhookRequest,
|
||||
discord, &Discord::onModcallWebhookRequested);
|
||||
}
|
||||
|
||||
proxy = new WSProxy(port, ws_port, this);
|
||||
if(ws_port != -1)
|
||||
proxy->start();
|
||||
@ -309,7 +308,9 @@ void Server::loadServerConfig()
|
||||
//Load discord webhook
|
||||
config.beginGroup("Discord");
|
||||
webhook_enabled = config.value("webhook_enabled", "false").toBool();
|
||||
webhook_url = config.value("webhook_url", "Your webhook url here.").toString();
|
||||
webhook_url = config.value("webhook_url", "").toUrl();
|
||||
if (!webhook_url.isValid())
|
||||
webhook_url = NULL;
|
||||
webhook_sendfile = config.value("webhook_sendfile", false).toBool();
|
||||
webhook_content = config.value("webhook_content", "").toString();
|
||||
config.endGroup();
|
||||
@ -346,6 +347,7 @@ Server::~Server()
|
||||
}
|
||||
server->deleteLater();
|
||||
proxy->deleteLater();
|
||||
discord->deleteLater();
|
||||
|
||||
delete db_manager;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user