aboutsummaryrefslogtreecommitdiff
path: root/src/networkmanager.cpp
diff options
context:
space:
mode:
authorSalanto <62221668+Salanto@users.noreply.github.com>2022-06-06 10:14:44 -0700
committerGitHub <noreply@github.com>2022-06-06 19:14:44 +0200
commitf0a5e48f5ca6834c0f24b167c904a030894f706e (patch)
tree0e7ae1497d0164e3a1a3c1d61a88e4f719beb5b5 /src/networkmanager.cpp
parentc4f459b6cce6382cbd7c1960a6738a5a8a45ab8c (diff)
Dual-Stack AO2 Client to handle both TCP and Websocket connections seemlessly (#696)
* Replace TCP Serversocket with Websocket * Have TCP sockets live harmoniously with WS "like 5 lines" yeah probably lost a bet. * Update .gitlab-ci.yml * hack to fix favorites * Add support for websockets in the favorites list (serverlist.txt) Make "add_favorite_server" remember the socket type * Preserve old serverlist style This will keep new entries compatible with 2.9 and prior clients. Makes parsing the list easier too. * Add lookup table and correct write code to use lowercase * I have no idea what a lookup table is, but this looks close enough * Fix lookup table * Otherwise backend selection behaviour is inverted * clang-tidy had one job * Yet it did not do it. Co-authored-by: oldmud0 <oldmud0@users.noreply.github.com> * const p_data * Switch serverlist.txt to an ini format * Fixes an Omni bug where : would split the servername * Utilises internally QSettings properly for low parsing effort and clear structure * Automatically migrates the legacy serverlist.txt to favorite_servers.ini * Pleases my OCD * Replace sample serverlist. Co-authored-by: oldmud0 <oldmud0@users.noreply.github.com> Co-authored-by: stonedDiscord <Tukz@gmx.de> Co-authored-by: Alex Noir <Varsash@gmail.com>
Diffstat (limited to 'src/networkmanager.cpp')
-rw-r--r--src/networkmanager.cpp108
1 files changed, 92 insertions, 16 deletions
diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp
index 4c823852..8f419fce 100644
--- a/src/networkmanager.cpp
+++ b/src/networkmanager.cpp
@@ -4,6 +4,7 @@
#include "debug_functions.h"
#include "lobby.h"
+#include <QAbstractSocket>
#include <QJsonArray>
#include <QJsonDocument>
#include <QNetworkReply>
@@ -12,15 +13,9 @@ NetworkManager::NetworkManager(AOApplication *parent) : QObject(parent)
{
ao_app = parent;
- server_socket = new QTcpSocket(this);
http = new QNetworkAccessManager(this);
heartbeat_timer = new QTimer(this);
- connect(server_socket, &QTcpSocket::readyRead, this,
- &NetworkManager::handle_server_packet);
- connect(server_socket, &QTcpSocket::disconnected, ao_app,
- &AOApplication::server_disconnected);
-
QString master_config =
ao_app->configini->value("master", "").value<QString>();
if (!master_config.isEmpty() && QUrl(master_config).scheme().startsWith("http")) {
@@ -60,10 +55,18 @@ void NetworkManager::ms_request_finished(QNetworkReply *reply,
const auto entry = entryRef.toObject();
server_type server;
server.ip = entry["ip"].toString();
- server.port = entry["port"].toInt();
server.name = entry["name"].toString();
server.desc = entry["description"].toString(tr("No description provided."));
- server_list.append(server);
+ if (entry["ws_port"].isDouble()) {
+ server.socket_type = WEBSOCKETS;
+ server.port = entry["ws_port"].toInt();
+ } else {
+ server.socket_type = TCP;
+ server.port = entry["port"].toInt();
+ }
+ if (server.port != 0) {
+ server_list.append(server);
+ }
}
ao_app->set_server_list(server_list);
@@ -128,26 +131,99 @@ void NetworkManager::request_document(MSDocumentType document_type,
void NetworkManager::connect_to_server(server_type p_server)
{
- server_socket->close();
- server_socket->abort();
+ disconnect_from_server();
qInfo().nospace().noquote() << "connecting to " << p_server.ip << ":"
<< p_server.port;
- server_socket->connectToHost(p_server.ip, p_server.port);
+ switch (p_server.socket_type) {
+ default:
+ p_server.socket_type = TCP;
+ [[fallthrough]];
+ case TCP:
+ qInfo() << "using TCP backend";
+ server_socket.tcp = new QTcpSocket(this);
+
+ connect(server_socket.tcp, &QAbstractSocket::connected, this, [] {
+ qDebug() << "established connection to server";
+ });
+ connect(server_socket.tcp, &QIODevice::readyRead, this, [this] {
+ handle_server_packet(QString::fromUtf8(server_socket.tcp->readAll()));
+ });
+ connect(server_socket.tcp, &QAbstractSocket::disconnected, ao_app,
+ &AOApplication::server_disconnected);
+ connect(server_socket.tcp, &QAbstractSocket::errorOccurred, this, [this] {
+ qCritical() << "TCP socket error:" << server_socket.tcp->errorString();
+ });
+
+ server_socket.tcp->connectToHost(p_server.ip, p_server.port);
+ break;
+ case WEBSOCKETS:
+ qInfo() << "using WebSockets backend";
+ server_socket.ws = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);
+
+ connect(server_socket.ws, &QWebSocket::connected, this, [] {
+ qDebug() << "established connection to server";
+ });
+ connect(server_socket.ws, &QWebSocket::textMessageReceived, this,
+ &NetworkManager::handle_server_packet);
+ connect(server_socket.ws, &QWebSocket::disconnected, ao_app,
+ &AOApplication::server_disconnected);
+ connect(server_socket.ws, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error),
+ this, [this] {
+ qCritical() << "WebSockets error:" << server_socket.ws->errorString();
+ });
+
+ QUrl url;
+ url.setScheme("ws");
+ url.setHost(p_server.ip);
+ url.setPort(p_server.port);
+ QNetworkRequest req(url);
+ req.setHeader(QNetworkRequest::UserAgentHeader, get_user_agent());
+ server_socket.ws->open(req);
+ break;
+ }
+
+ connected = true;
+ active_connection_type = p_server.socket_type;
+}
+
+void NetworkManager::disconnect_from_server()
+{
+ if (!connected)
+ return;
+
+ switch (active_connection_type) {
+ case TCP:
+ server_socket.tcp->close();
+ server_socket.tcp->deleteLater();
+ break;
+ case WEBSOCKETS:
+ server_socket.ws->close(QWebSocketProtocol::CloseCodeGoingAway);
+ server_socket.ws->deleteLater();
+ break;
+ }
+
+ connected = false;
}
void NetworkManager::ship_server_packet(QString p_packet)
{
- server_socket->write(p_packet.toUtf8());
+ switch (active_connection_type) {
+ case TCP:
+ server_socket.tcp->write(p_packet.toUtf8());
+ break;
+ case WEBSOCKETS:
+ server_socket.ws->sendTextMessage(p_packet);
+ break;
+ }
}
-void NetworkManager::handle_server_packet()
+void NetworkManager::handle_server_packet(const QString& p_data)
{
- QByteArray buffer = server_socket->readAll();
- QString in_data = QString::fromUtf8(buffer, buffer.size());
+ QString in_data = p_data;
- if (!in_data.endsWith("%")) {
+ if (!p_data.endsWith("%")) {
partial_packet = true;
temp_packet += in_data;
return;