Merge pull request #152 from Salanto/http-advertiser2

Implement HTTP server advertiser
This commit is contained in:
scatterflower 2021-07-12 15:23:24 -05:00 committed by GitHub
commit 99c2ed8755
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 293 additions and 2 deletions

View File

@ -60,6 +60,18 @@ message_floodguard=250
; The URL of the server's remote repository, sent to the client during their initial handshake. Used by WebAO users for custom content.
asset_url=
[ModernAdvertiser]
; Options for the HTTP based Masterserver.
; Whether or not the server should appear on the master server.
advertise=false
; Wether the advertiser prints additional debug info
debug=false
; The IP address of the master server. Unless something happens to the default one, you shouldn't change this.
ms_ip=https://ms3.oldmud0.workers.dev/servers
[Dice]
; The maximum number of sides dice can be rolled with.
max_value=100

View File

@ -45,7 +45,8 @@ SOURCES += \
src/server.cpp \
src/testimony_recorder.cpp \
src/ws_client.cpp \
src/ws_proxy.cpp
src/ws_proxy.cpp \
src/http_advertiser.cpp
HEADERS += include/advertiser.h \
include/aoclient.h \
@ -58,4 +59,5 @@ HEADERS += include/advertiser.h \
include/logger.h \
include/server.h \
include/ws_client.h \
include/ws_proxy.h
include/ws_proxy.h \
include/http_advertiser.h

View File

@ -302,6 +302,22 @@ class ConfigManager {
*/
static QStringList gimpList();
/**
* @brief Returns if the HTTP advertiser is constructed or not.
*/
static bool advertiseHTTPServer();
/**
* @brief Returns if the HTTP advertiser prints debug info to console.
*/
static bool advertiserHTTPDebug();
/**
* @brief Returns the IP or URL of the masterserver.
*/
static QUrl advertiserHTTPIP();
/**
* @brief Sets the server's authorization type.
*

View File

@ -0,0 +1,115 @@
//////////////////////////////////////////////////////////////////////////////////////
// akashi - a server for Attorney Online 2 //
// Copyright (C) 2020 scatterflower //
// //
// This program is free software: you can redistribute it and/or modify //
// it under the terms of the GNU Affero General Public License as //
// published by the Free Software Foundation, either version 3 of the //
// License, or (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU Affero General Public License for more details. //
// //
// You should have received a copy of the GNU Affero General Public License //
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
//////////////////////////////////////////////////////////////////////////////////////
#ifndef HTTP_ADVERTISER_H
#define HTTP_ADVERTISER_H
#include <QtNetwork>
#include <QObject>
//Don't question this. It needs to be here for some reason.
struct advertiser_config {
QString name;
QString description;
int port;
int ws_port;
int players;
QUrl masterserver;
bool debug;
};
/**
* @brief Represents the advertiser of the server. Sends current server information to masterserver.
*/
class HTTPAdvertiser : public QObject
{
Q_OBJECT
public:
/**
* @brief Constructor for the HTTP_Advertiser class.
*/
explicit HTTPAdvertiser();
/**
* @brief Deconstructor for the HTTP_Advertiser class. Yes, that's it. Can't say more about it.
*/
~HTTPAdvertiser();
public slots:
/**
* @brief Establishes a connection with masterserver to register or update the listing on the masterserver.
*/
void msAdvertiseServer();
/**
* @brief Reads the information send as a reply for further error handling.
* @param reply Response data from the masterserver. Information contained is send to the console if debug is enabled.
*/
void msRequestFinished(QNetworkReply *reply);
/**
* @brief Sets the values being advertised to masterserver.
* @param config Configuration struct for the advertiser. Always includes ALL settings.
*/
void setAdvertiserSettings(advertiser_config config);
private:
/**
* @brief Pointer to the network manager, necessary to execute POST requests to the masterserver.
*/
QNetworkAccessManager* m_manager;
/**
* @brief Name of the server send to the masterserver. Changing this will change the display name in the serverlist
*/
QString m_name;
/**
* @brief Description of the server that is displayed in the client when the server is selected.
*/
QString m_description;
/**
* @brief Client port for the AO2-Client.
*/
int m_port;
/**
* @brief Websocket proxy port for WebAO users.
*/
int m_ws_port;
/**
* @brief Maximum amount of clients that can be connected to the server.
*/
int m_players;
/**
* @brief URL of the masterserver that m_manager posts to. This is almost never changed.
*/
QUrl m_masterserver;
/**
* @brief Controls if network replies are printed to console. Should only be true if issues communicating with masterserver appear.
*/
bool m_debug;
};
#endif // HTTP_ADVERTISER_H

View File

@ -25,6 +25,7 @@
#include "include/db_manager.h"
#include "include/discord.h"
#include "include/config_manager.h"
#include "include/http_advertiser.h"
#include <QCoreApplication>
#include <QDebug>
@ -137,6 +138,11 @@ class Server : public QObject {
*/
int getCharID(QString char_name);
/**
* @brief Creates an HTTP advertiser config struct and emits it using server::reloadHTTPRequest.
*/
void reloadHTTPAdvertiserConfig();
/**
* @brief The collection of all currently connected clients.
*/
@ -227,6 +233,12 @@ class Server : public QObject {
*/
void reloadRequest(QString p_name, QString p_desc);
/**
* @brief Sends all necessary info for the new advertiser.
* @param Struct that contains all configuration for the advertiser
*/
void reloadHTTPRequest(struct advertiser_config config);
/**
* @brief Sends a modcall webhook request, emitted by AOClient::pktModcall.
*
@ -255,6 +267,16 @@ class Server : public QObject {
*/
Discord* discord;
/**
* @brief Handles HTTP server advertising.
*/
HTTPAdvertiser* httpAdvertiser;
/**
* @brief Advertises the server in a regular intervall.
*/
QTimer* httpAdvertiserTimer;
/**
* @brief The port through which the server will accept TCP connections.
*/

View File

@ -412,6 +412,7 @@ void AOClient::cmdReload(int argc, QStringList argv)
{
ConfigManager::reloadSettings();
emit server->reloadRequest(ConfigManager::serverName(), ConfigManager::serverDescription());
server->reloadHTTPAdvertiserConfig();
sendServerMessage("Reloaded configurations");
}

View File

@ -368,6 +368,21 @@ QStringList ConfigManager::gimpList()
return m_commands->gimps;
}
bool ConfigManager::advertiseHTTPServer()
{
return m_settings->value("ModernAdvertiser/advertise","true").toBool();
}
bool ConfigManager::advertiserHTTPDebug()
{
return m_settings->value("ModernAdvertiser/debug","true").toBool();
}
QUrl ConfigManager::advertiserHTTPIP()
{
return m_settings->value("ModernAdvertiser/ms_ip","").toUrl();
}
void ConfigManager::setMotd(const QString f_motd)
{
m_settings->setValue("Options/motd", f_motd);

View File

@ -0,0 +1,82 @@
#include "include/http_advertiser.h"
HTTPAdvertiser::HTTPAdvertiser()
{
m_manager = new QNetworkAccessManager();
connect(m_manager, &QNetworkAccessManager::finished,
this, &HTTPAdvertiser::msRequestFinished);
}
HTTPAdvertiser::~HTTPAdvertiser()
{
m_manager->deleteLater();
}
void HTTPAdvertiser::msAdvertiseServer()
{
if (m_masterserver.isValid()) {
QUrl url(m_masterserver);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QJsonObject json;
json["port"] = m_port;
if (m_ws_port != -1) {
json["ws_port"] = m_ws_port;
}
json["players"] = m_players;
json["name"] = m_name;
if (!m_description.isEmpty()) {
json["description"] = m_description;
}
m_manager->post(request, QJsonDocument(json).toJson());
if (m_debug)
qDebug().noquote() << "Advertised Server";
return;
}
if (m_debug)
qWarning().noquote() << "Unable to advertise. Masterserver URL '" + m_masterserver.toString() + "' is not valid.";
return;
}
void HTTPAdvertiser::msRequestFinished(QNetworkReply *reply)
{
if (m_debug) {
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200) {
qDebug().noquote() << "Succesfully advertised server.";
}
else {
QJsonDocument json = QJsonDocument::fromJson(reply->readAll());
if (json.isNull()) {
qCritical().noquote() << "Invalid JSON response from" << reply->url();
reply->deleteLater();
return;
}
qDebug().noquote() << "Got valid response from" << reply->url();
qDebug() << json;
}
}
reply->deleteLater();
}
void HTTPAdvertiser::setAdvertiserSettings(advertiser_config config)
{
m_name = config.name;
m_description = config.description;
m_port = config.port;
m_ws_port = config.ws_port;
m_players = config.players;
m_masterserver = config.masterserver;
m_debug = config.debug;
msAdvertiseServer();
}

View File

@ -29,6 +29,7 @@ Server::Server(int p_port, int p_ws_port, QObject* parent) :
timer = new QTimer();
db_manager = new DBManager();
}
void Server::start()
@ -57,6 +58,18 @@ void Server::start()
discord, &Discord::onModcallWebhookRequested);
}
if (ConfigManager::advertiseHTTPServer()) {
httpAdvertiserTimer = new QTimer(this);
httpAdvertiser = new HTTPAdvertiser();
connect(httpAdvertiserTimer, &QTimer::timeout,
httpAdvertiser, &HTTPAdvertiser::msAdvertiseServer);
connect(this, &Server::reloadHTTPRequest,
httpAdvertiser, &HTTPAdvertiser::setAdvertiserSettings);
reloadHTTPAdvertiserConfig();
httpAdvertiserTimer->start(300000);
}
proxy = new WSProxy(port, ws_port, this);
if(ws_port != -1)
proxy->start();
@ -242,6 +255,19 @@ int Server::getCharID(QString char_name)
return -1; // character does not exist
}
void Server::reloadHTTPAdvertiserConfig()
{
advertiser_config config;
config.name = ConfigManager::serverName();
config.description = ConfigManager::serverDescription();
config.port = ConfigManager::serverPort();
config.ws_port = ConfigManager::webaoPort();
config.players = ConfigManager::maxPlayers();
config.masterserver = ConfigManager::advertiserHTTPIP();
config.debug = ConfigManager::advertiserHTTPDebug();
emit reloadHTTPRequest(config);
}
void Server::allowMessage()
{
can_send_ic_messages = true;