From efd2571459924f40718130f7edd28a72a76b12d7 Mon Sep 17 00:00:00 2001 From: Leifa <26681464+TrickyLeifa@users.noreply.github.com> Date: Tue, 9 Jul 2024 13:07:30 +0200 Subject: [PATCH] Remove TCP entry point (#1007) * Remove TCP entry point Resolve #987 * Remove TCP entry point * Servers that do not support WebSocket will be marked as `Legacy` * Removal of TCP connection from the master will follow later. * Tweaked error message --- CMakeLists.txt | 9 +- data/ui/favorite_server_dialog.ui | 23 +--- data/ui/lobby.ui | 18 ++- src/datatypes.h | 19 --- src/demoserver.cpp | 128 ++++++++---------- src/demoserver.h | 10 +- src/lobby.cpp | 39 +++++- src/net/netconnection.cpp | 5 - src/net/netconnection.h | 28 ---- src/net/nettcpconnection.cpp | 102 -------------- src/net/nettcpconnection.h | 31 ----- src/net/netwebsocketconnection.h | 32 ----- src/network/serverinfo.cpp | 6 + src/network/serverinfo.h | 15 ++ .../websocketconnection.cpp} | 36 ++--- src/network/websocketconnection.h | 43 ++++++ src/networkmanager.cpp | 35 ++--- src/networkmanager.h | 4 +- src/options.cpp | 46 +++---- src/options.h | 3 +- src/packet_distribution.cpp | 4 +- src/widgets/direct_connect_dialog.cpp | 12 +- src/widgets/server_editor_dialog.cpp | 49 +++---- src/widgets/server_editor_dialog.h | 5 +- 24 files changed, 252 insertions(+), 450 deletions(-) delete mode 100644 src/net/netconnection.cpp delete mode 100644 src/net/netconnection.h delete mode 100644 src/net/nettcpconnection.cpp delete mode 100644 src/net/nettcpconnection.h delete mode 100644 src/net/netwebsocketconnection.h create mode 100644 src/network/serverinfo.cpp create mode 100644 src/network/serverinfo.h rename src/{net/netwebsocketconnection.cpp => network/websocketconnection.cpp} (55%) create mode 100644 src/network/websocketconnection.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8488259..2e5b24e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,12 +78,8 @@ add_executable(Attorney_Online src/lobby.cpp src/lobby.h src/main.cpp - src/net/netconnection.cpp - src/net/netconnection.h - src/net/nettcpconnection.cpp - src/net/nettcpconnection.h - src/net/netwebsocketconnection.cpp - src/net/netwebsocketconnection.h + src/network/websocketconnection.cpp + src/network/websocketconnection.h src/networkmanager.cpp src/networkmanager.h src/options.cpp @@ -103,6 +99,7 @@ add_executable(Attorney_Online src/widgets/server_editor_dialog.h data.qrc src/screenslidetimer.h src/screenslidetimer.cpp + src/network/serverinfo.h src/network/serverinfo.cpp ) set_target_properties(Attorney_Online PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin") diff --git a/data/ui/favorite_server_dialog.ui b/data/ui/favorite_server_dialog.ui index f0f60cb..b90514d 100644 --- a/data/ui/favorite_server_dialog.ui +++ b/data/ui/favorite_server_dialog.ui @@ -78,34 +78,13 @@ - - - Protocol: - - - - - - - - TCP - - - - - WEBSOCKET - - - - - Description: - + diff --git a/data/ui/lobby.ui b/data/ui/lobby.ui index ceb85ff..fcc364e 100644 --- a/data/ui/lobby.ui +++ b/data/ui/lobby.ui @@ -316,8 +316,14 @@ QScrollBar:horizontall { - background-color: rgba(140, 140, 140, 255); -color: rgb(255, 255, 255); + QHeaderView, QTreeView { +background-color: rgba(140, 140, 140, 255); +color: rgb(255, 255, 255); +} + +QToolTip { +color: black; +} Qt::ElideNone @@ -330,7 +336,7 @@ color: rgb(255, 255, 255); # - AlignTrailing|AlignVCenter + AlignLeading|AlignVCenter @@ -369,7 +375,11 @@ color: rgb(255, 255, 255); background-color: rgba(140, 140, 140, 255); -color: rgb(255, 255, 255); +color: rgb(255, 255, 255); + +QToolTip { + color: black; +}; Qt::ElideNone diff --git a/src/datatypes.h b/src/datatypes.h index 97fa8c7..b87744c 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -5,25 +5,6 @@ #include -enum ServerConnectionType -{ - TcpServerConnection, - WebSocketServerConnection, -}; - -static const QMap SERVER_CONNECTION_TYPE_STRING_MAP = {{"tcp", ServerConnectionType::TcpServerConnection}, {"ws", ServerConnectionType::WebSocketServerConnection}}; - -struct ServerInfo -{ - QString name; - QString description; - QString ip; - int port; - ServerConnectionType socket_type; - - inline QString toString() { return QString("%1 (<%2>%3:%4)").arg(name, SERVER_CONNECTION_TYPE_STRING_MAP.key(socket_type), ip, QString::number(port)); } -}; - struct CharacterSlot { QString name; diff --git a/src/demoserver.cpp b/src/demoserver.cpp index bc7cc4b..93eaad5 100644 --- a/src/demoserver.cpp +++ b/src/demoserver.cpp @@ -9,8 +9,8 @@ DemoServer::DemoServer(QObject *parent) timer->setTimerType(Qt::PreciseTimer); timer->setSingleShot(true); - tcp_server = new QTcpServer(this); - connect(tcp_server, &QTcpServer::newConnection, this, &DemoServer::accept_connection); + server = new QWebSocketServer(tr("DemoServer"), QWebSocketServer::NonSecureMode, this); + connect(server, &QWebSocketServer::newConnection, this, &DemoServer::accept_connection); connect(timer, &QTimer::timeout, this, &DemoServer::playback); } @@ -30,22 +30,22 @@ void DemoServer::start_server() { return; } - if (!tcp_server->listen(QHostAddress::LocalHost, 0)) + if (!server->listen(QHostAddress::LocalHost, 0)) { qCritical() << "Could not start demo playback server..."; - qDebug() << tcp_server->errorString(); + qDebug() << server->errorString(); return; } - this->m_port = tcp_server->serverPort(); + this->m_port = server->serverPort(); qInfo() << "Demo server started at port" << m_port; m_server_started = true; } void DemoServer::destroy_connection() { - QTcpSocket *temp_socket = tcp_server->nextPendingConnection(); - connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater); - temp_socket->disconnectFromHost(); + QWebSocket *temp_socket = server->nextPendingConnection(); + temp_socket->close(); + temp_socket->deleteLater(); return; } @@ -80,22 +80,20 @@ void DemoServer::accept_connection() { // Client is already connected... qWarning() << "Multiple connections to demo server disallowed."; - QTcpSocket *temp_socket = tcp_server->nextPendingConnection(); - connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater); - temp_socket->disconnectFromHost(); + QWebSocket *temp_socket = server->nextPendingConnection(); + temp_socket->close(); + temp_socket->deleteLater(); return; } - client_sock = tcp_server->nextPendingConnection(); - connect(client_sock, &QAbstractSocket::disconnected, this, &DemoServer::client_disconnect); - connect(client_sock, &QAbstractSocket::readyRead, this, &DemoServer::recv_data); - client_sock->write("decryptor#NOENCRYPT#%"); + client_sock = server->nextPendingConnection(); + connect(client_sock, &QWebSocket::disconnected, this, &DemoServer::client_disconnect); + connect(client_sock, &QWebSocket::textMessageReceived, this, &DemoServer::recv_data); + client_sock->sendTextMessage("decryptor#NOENCRYPT#%"); } -void DemoServer::recv_data() +void DemoServer::recv_data(const QString &message) { - QString in_data = QString::fromUtf8(client_sock->readAll()); - - const QStringList packet_list = in_data.split("%", Qt::SkipEmptyParts); + const QStringList packet_list = message.split("%", Qt::SkipEmptyParts); for (const QString &packet : packet_list) { QStringList f_contents; @@ -145,39 +143,35 @@ void DemoServer::handle_packet(AOPacket p_packet) if (header == "HI") { - client_sock->write("ID#0#DEMOINTERNAL#0#%"); + client_sock->sendTextMessage("ID#0#DEMOINTERNAL#0#%"); } else if (header == "ID") { QStringList feature_list = {"noencryption", "yellowtext", "prezoom", "flipping", "customobjections", "fastloading", "deskmod", "evidence", "cccc_ic_support", "arup", "casing_alerts", "modcall_reason", "looping_sfx", "additive", "effects", "y_offset", "expanded_desk_mods"}; - client_sock->write("PN#0#1#%"); - client_sock->write("FL#"); - client_sock->write(feature_list.join('#').toUtf8()); - client_sock->write("#%"); + client_sock->sendTextMessage("PN#0#1#%"); + client_sock->sendTextMessage("FL#" + feature_list.join('#') + "#%"); } else if (header == "askchaa") { - client_sock->write("SI#"); - client_sock->write(QString::number(num_chars).toUtf8()); - client_sock->write("#0#1#%"); + client_sock->sendTextMessage("SI#" + QString::number(num_chars) + "#0#1#%"); } else if (header == "RC") { - client_sock->write(sc_packet.toUtf8()); + client_sock->sendTextMessage(sc_packet.toUtf8()); } else if (header == "RM") { - client_sock->write("SM#%"); + client_sock->sendTextMessage("SM#%"); } else if (header == "RD") { - client_sock->write("DONE#%"); + client_sock->sendTextMessage("DONE#%"); } else if (header == "CC") { - client_sock->write("PV#0#CID#-1#%"); + client_sock->sendTextMessage("PV#0#CID#-1#%"); QString packet = "CT#DEMO#" + tr("Demo file loaded. Send /play or > in OOC to begin playback.") + "#1#%"; - client_sock->write(packet.toUtf8()); + client_sock->sendTextMessage(packet.toUtf8()); } else if (header == "CT") { @@ -190,7 +184,7 @@ void DemoServer::handle_packet(AOPacket p_packet) } load_demo(path); QString packet = "CT#DEMO#" + tr("Demo file loaded. Send /play or > in OOC to begin playback.") + "#1#%"; - client_sock->write(packet.toUtf8()); + client_sock->sendTextMessage(packet.toUtf8()); reset_state(); } else if (contents[1].startsWith("/play") || contents[1] == ">") @@ -199,7 +193,7 @@ void DemoServer::handle_packet(AOPacket p_packet) { timer->start(); QString packet = "CT#DEMO#" + tr("Resuming playback.") + "#1#%"; - client_sock->write(packet.toUtf8()); + client_sock->sendTextMessage(packet.toUtf8()); } else { @@ -216,7 +210,7 @@ void DemoServer::handle_packet(AOPacket p_packet) timer->stop(); timer->setInterval(timeleft); QString packet = "CT#DEMO#" + tr("Pausing playback.") + "#1#%"; - client_sock->write(packet.toUtf8()); + client_sock->sendTextMessage(packet.toUtf8()); } else if (contents[1].startsWith("/max_wait")) { @@ -232,38 +226,32 @@ void DemoServer::handle_packet(AOPacket p_packet) p_max_wait = -1; } m_max_wait = p_max_wait; - QString packet = "CT#DEMO#" + tr("Setting max_wait to") + " "; - client_sock->write(packet.toUtf8()); - client_sock->write(QString::number(m_max_wait).toUtf8()); - packet = " " + tr("milliseconds.") + "#1#%"; - client_sock->write(packet.toUtf8()); + QString packet = "CT#DEMO#" + tr("Setting max_wait to") + " " + QString::number(m_max_wait) + " " + tr("milliseconds.") + "#1#%"; + client_sock->sendTextMessage(packet); } else { QString packet = "CT#DEMO#" + tr("Not a valid integer!") + "#1#%"; - client_sock->write(packet.toUtf8()); + client_sock->sendTextMessage(packet.toUtf8()); } } else { - QString packet = "CT#DEMO#" + tr("Current max_wait is") + " "; - client_sock->write(packet.toUtf8()); - client_sock->write(QString::number(m_max_wait).toUtf8()); - packet = " " + tr("milliseconds.") + "#1#%"; - client_sock->write(packet.toUtf8()); + QString packet = "CT#DEMO#" + tr("Current max_wait is") + " " + QString::number(m_max_wait) + tr("milliseconds.") + "#1#%"; + client_sock->sendTextMessage(packet.toUtf8()); } } else if (contents[1].startsWith("/reload")) { load_demo(p_path); QString packet = "CT#DEMO#" + tr("Current demo file reloaded. Send /play or > in OOC to begin playback.") + "#1#%"; - client_sock->write(packet.toUtf8()); + client_sock->sendTextMessage(packet.toUtf8()); reset_state(); } else if (contents[1].startsWith("/min_wait")) { QString packet = "CT#DEMO#" + tr("min_wait is deprecated. Use the client Settings for minimum wait instead!") + "#1#%"; - client_sock->write(packet.toUtf8()); + client_sock->sendTextMessage(packet.toUtf8()); } else if (contents[1].startsWith("/debug")) { @@ -276,31 +264,31 @@ void DemoServer::handle_packet(AOPacket p_packet) { debug_mode = toggle == 1; QString packet = "CT#DEMO#" + tr("Setting debug mode to %1").arg(static_cast(debug_mode)) + "#1#%"; - client_sock->write(packet.toUtf8()); + client_sock->sendTextMessage(packet.toUtf8()); // Debug mode disabled? if (!debug_mode) { // Reset the timer - client_sock->write("TI#4#1#0#%"); - client_sock->write("TI#4#3#0#%"); + client_sock->sendTextMessage("TI#4#1#0#%"); + client_sock->sendTextMessage("TI#4#3#0#%"); } } else { QString packet = "CT#DEMO#" + tr("Valid values are 1 or 0!") + "#1#%"; - client_sock->write(packet.toUtf8()); + client_sock->sendTextMessage(packet.toUtf8()); } } else { QString packet = "CT#DEMO#" + tr("Set debug mode using /debug 1 to enable, and /debug 0 to disable, which will use the fifth timer (TI#4) to show the remaining time until next demo line.") + "#1#%"; - client_sock->write(packet.toUtf8()); + client_sock->sendTextMessage(packet.toUtf8()); } } else if (contents[1].startsWith("/help")) { QString packet = "CT#DEMO#" + tr("Available commands:\nload, reload, play, pause, max_wait, debug, help") + "#1#%"; - client_sock->write(packet.toUtf8()); + client_sock->sendTextMessage(packet.toUtf8()); } } } @@ -395,22 +383,22 @@ void DemoServer::load_demo(QString filename) void DemoServer::reset_state() { // Reset evidence list - client_sock->write("LE##%"); + client_sock->sendTextMessage("LE##%"); // Reset timers - client_sock->write("TI#0#1#0#%"); - client_sock->write("TI#0#3#0#%"); - client_sock->write("TI#1#1#0#%"); - client_sock->write("TI#1#3#0#%"); - client_sock->write("TI#2#1#0#%"); - client_sock->write("TI#2#3#0#%"); - client_sock->write("TI#3#1#0#%"); - client_sock->write("TI#3#3#0#%"); - client_sock->write("TI#4#1#0#%"); - client_sock->write("TI#4#3#0#%"); + client_sock->sendTextMessage("TI#0#1#0#%"); + client_sock->sendTextMessage("TI#0#3#0#%"); + client_sock->sendTextMessage("TI#1#1#0#%"); + client_sock->sendTextMessage("TI#1#3#0#%"); + client_sock->sendTextMessage("TI#2#1#0#%"); + client_sock->sendTextMessage("TI#2#3#0#%"); + client_sock->sendTextMessage("TI#3#1#0#%"); + client_sock->sendTextMessage("TI#3#3#0#%"); + client_sock->sendTextMessage("TI#4#1#0#%"); + client_sock->sendTextMessage("TI#4#3#0#%"); // Set the BG to default (also breaks up the message queue) - client_sock->write("BN#default#wit#%"); + client_sock->sendTextMessage("BN#default#wit#%"); // Stop the wait packet timer timer->stop(); @@ -432,7 +420,7 @@ void DemoServer::playback() while (!current_packet.startsWith("wait#")) { - client_sock->write(current_packet.toUtf8()); + client_sock->sendTextMessage(current_packet.toUtf8()); if (demo_data.isEmpty()) { break; @@ -478,15 +466,15 @@ void DemoServer::playback() timer->start(duration); if (debug_mode) { - client_sock->write("TI#4#2#%"); + client_sock->sendTextMessage("TI#4#2#%"); QString debug_timer = "TI#4#0#" + QString::number(duration) + "#%"; - client_sock->write(debug_timer.toUtf8()); + client_sock->sendTextMessage(debug_timer.toUtf8()); } } else { QString end_packet = "CT#DEMO#" + tr("Reached the end of the demo file. Send /play or > in OOC to restart, or /load to open a new file.") + "#1#%"; - client_sock->write(end_packet.toUtf8()); + client_sock->sendTextMessage(end_packet.toUtf8()); timer->setInterval(0); } } diff --git a/src/demoserver.h b/src/demoserver.h index f52fbc7..025ffe3 100644 --- a/src/demoserver.h +++ b/src/demoserver.h @@ -7,9 +7,9 @@ #include #include #include -#include -#include #include +#include +#include class DemoServer : public QObject { @@ -27,8 +27,8 @@ private: int m_port = 0; int m_max_wait = -1; - QTcpServer *tcp_server; - QTcpSocket *client_sock = nullptr; + QWebSocketServer *server; + QWebSocket *client_sock = nullptr; bool client_connected = false; bool partial_packet = false; bool debug_mode = false; @@ -48,7 +48,7 @@ private: private Q_SLOTS: void accept_connection(); void destroy_connection(); - void recv_data(); + void recv_data(const QString &in_data); void client_disconnect(); void playback(); diff --git a/src/lobby.cpp b/src/lobby.cpp index aba9f60..9918ca3 100644 --- a/src/lobby.cpp +++ b/src/lobby.cpp @@ -238,8 +238,7 @@ void Lobby::on_add_server_to_fave_released() void Lobby::on_edit_favorite_released() { const int index = get_selected_server(); - ServerEditorDialog dialog; - dialog.loadServerInfo(Options::getInstance().favorites().at(index)); + ServerEditorDialog dialog(Options::getInstance().favorites().at(index)); if (dialog.exec()) { Options::getInstance().updateFavorite(dialog.currentServerInfo(), index); @@ -428,7 +427,7 @@ void Lobby::on_demo_clicked(QTreeWidgetItem *item, int column) QString l_filepath = (get_app_path() + "/logs/%1/%2").arg(item->data(0, Qt::DisplayRole).toString(), item->data(1, Qt::DisplayRole).toString()); ao_app->demo_server->start_server(); ServerInfo demo_server; - demo_server.ip = "127.0.0.1"; + demo_server.address = "127.0.0.1"; demo_server.port = ao_app->demo_server->port(); ao_app->demo_server->set_demo_file(l_filepath); net_manager->connect_to_server(demo_server); @@ -462,7 +461,22 @@ void Lobby::list_servers() { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_serverlist_tree); treeItem->setData(0, Qt::DisplayRole, i); - treeItem->setText(1, i_server.name); + + if (i_server.legacy) + { + treeItem->setText(1, "(Legacy) " + i_server.name); + treeItem->setBackground(0, Qt::darkRed); + treeItem->setBackground(1, Qt::darkRed); + + QString tooltip = tr("Unable to connect to server. Server is missing WebSocket support."); + treeItem->setToolTip(0, tooltip); + treeItem->setToolTip(1, tooltip); + } + else + { + treeItem->setText(1, i_server.name); + } + i++; } ui_serverlist_tree->setSortingEnabled(true); @@ -480,7 +494,22 @@ void Lobby::list_favorites() { QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_favorites_tree); treeItem->setData(0, Qt::DisplayRole, i); - treeItem->setText(1, i_server.name); + + if (i_server.legacy) + { + treeItem->setText(1, "(Legacy) " + i_server.name); + treeItem->setBackground(0, Qt::darkRed); + treeItem->setBackground(1, Qt::darkRed); + + QString tooltip = tr("Unable to connect to server. Server is missing WebSocket support."); + treeItem->setToolTip(0, tooltip); + treeItem->setToolTip(1, tooltip); + } + else + { + treeItem->setText(1, i_server.name); + } + i++; } ui_favorites_tree->setSortingEnabled(true); diff --git a/src/net/netconnection.cpp b/src/net/netconnection.cpp deleted file mode 100644 index 63ca706..0000000 --- a/src/net/netconnection.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "netconnection.h" - -NetConnection::NetConnection(QObject *parent) - : QObject(parent) -{} diff --git a/src/net/netconnection.h b/src/net/netconnection.h deleted file mode 100644 index 0b5d6be..0000000 --- a/src/net/netconnection.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "aopacket.h" -#include "datatypes.h" - -#include - -class NetConnection : public QObject -{ - Q_OBJECT - -public: - explicit NetConnection(QObject *parent = nullptr); - - virtual bool isConnected() = 0; - - virtual void connectToServer(ServerInfo &server) = 0; - virtual void disconnectFromServer() = 0; - - virtual void sendPacket(AOPacket packet) = 0; - -Q_SIGNALS: - void connectedToServer(); - void disconnectedFromServer(); - void errorOccurred(QString error); - - void receivedPacket(AOPacket packet); -}; diff --git a/src/net/nettcpconnection.cpp b/src/net/nettcpconnection.cpp deleted file mode 100644 index 2bc52b7..0000000 --- a/src/net/nettcpconnection.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "nettcpconnection.h" - -NetTcpConnection::NetTcpConnection(QObject *parent) - : NetConnection(parent) - , m_socket(new QTcpSocket(this)) - , m_last_state(QAbstractSocket::UnconnectedState) -{ -#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) - connect(m_socket, QOverload::of(&QAbstractSocket::error), this, &NetTcpConnection::onErrorOccurred); -#else - connect(m_socket, &QTcpSocket::errorOccurred, this, &NetTcpConnection::onErrorOccurred); -#endif - connect(m_socket, &QTcpSocket::stateChanged, this, &NetTcpConnection::onStateChanged); - connect(m_socket, &QTcpSocket::readyRead, this, &NetTcpConnection::onReadyRead); -} - -NetTcpConnection::~NetTcpConnection() -{ - m_socket->disconnect(this); - disconnectFromServer(); -} - -bool NetTcpConnection::isConnected() -{ - return m_last_state == QAbstractSocket::ConnectedState; -} - -void NetTcpConnection::connectToServer(ServerInfo &server) -{ - disconnectedFromServer(); - m_socket->connectToHost(server.ip, server.port); -} - -void NetTcpConnection::disconnectFromServer() -{ - m_socket->abort(); -} - -void NetTcpConnection::sendPacket(AOPacket packet) -{ - if (!isConnected()) - { - qWarning().noquote() << QObject::tr("Cannot send packet, not connected to server"); - return; - } - m_socket->write(packet.toString(true).toUtf8()); -} - -void NetTcpConnection::onErrorOccurred() -{ - Q_EMIT errorOccurred(m_socket->errorString()); -} - -void NetTcpConnection::onStateChanged(QAbstractSocket::SocketState state) -{ - m_last_state = state; - switch (state) - { - default: - break; - - case QAbstractSocket::ConnectedState: - m_cached_data.clear(); - Q_EMIT connectedToServer(); - break; - - case QAbstractSocket::UnconnectedState: - Q_EMIT disconnectFromServer(); - break; - } -} - -void NetTcpConnection::onReadyRead() -{ - m_cached_data += QString::fromUtf8(m_socket->readAll()); - if (!m_cached_data.endsWith('%')) - { - return; - } - - QStringList raw_packet_list = m_cached_data.split('%', Qt::SkipEmptyParts); - m_cached_data.clear(); - for (QString raw_packet : raw_packet_list) - { - if (!raw_packet.endsWith('#')) - { - Q_EMIT errorOccurred(QObject::tr("Malformed packet received %1").arg(raw_packet)); - continue; - } - raw_packet.chop(1); - - QStringList raw_content = raw_packet.split('#'); - - const QString header = raw_content.takeFirst(); - for (QString &data : raw_content) - { - data = AOPacket::decode(data); - } - - Q_EMIT receivedPacket(AOPacket(header, raw_content)); - } -} diff --git a/src/net/nettcpconnection.h b/src/net/nettcpconnection.h deleted file mode 100644 index 40dae19..0000000 --- a/src/net/nettcpconnection.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "aopacket.h" -#include "datatypes.h" -#include "netconnection.h" - -#include - -class NetTcpConnection : public NetConnection -{ -public: - NetTcpConnection(QObject *parent = nullptr); - virtual ~NetTcpConnection(); - - bool isConnected() override; - - void connectToServer(ServerInfo &server) override; - void disconnectFromServer() override; - - void sendPacket(AOPacket packet) override; - -private: - QTcpSocket *m_socket; - QAbstractSocket::SocketState m_last_state; - QString m_cached_data; - -private Q_SLOTS: - void onErrorOccurred(); - void onStateChanged(QAbstractSocket::SocketState state); - void onReadyRead(); -}; diff --git a/src/net/netwebsocketconnection.h b/src/net/netwebsocketconnection.h deleted file mode 100644 index 26f41a6..0000000 --- a/src/net/netwebsocketconnection.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "netconnection.h" - -class NetworkManager; - -#include - -class NetWebSocketConnection : public NetConnection -{ -public: - NetWebSocketConnection(NetworkManager *networkManager); - virtual ~NetWebSocketConnection(); - - bool isConnected() override; - - void connectToServer(ServerInfo &server) override; - void disconnectFromServer() override; - - void sendPacket(AOPacket packet) override; - -private: - NetworkManager *m_network_manager; - - QWebSocket *m_socket; - QAbstractSocket::SocketState m_last_state; - -private Q_SLOTS: - void onError(); - void onStateChanged(QAbstractSocket::SocketState state); - void onTextMessageReceived(QString message); -}; diff --git a/src/network/serverinfo.cpp b/src/network/serverinfo.cpp new file mode 100644 index 0000000..1762866 --- /dev/null +++ b/src/network/serverinfo.cpp @@ -0,0 +1,6 @@ +#include "serverinfo.h" + +QString ServerInfo::toString() const +{ + return QString("%1 (%2:%3)").arg(name.isEmpty() ? QStringLiteral("Unnamed Server") : name).arg(address).arg(port); +} diff --git a/src/network/serverinfo.h b/src/network/serverinfo.h new file mode 100644 index 0000000..1f13e3e --- /dev/null +++ b/src/network/serverinfo.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +class ServerInfo +{ +public: + QString name; + QString description; + QString address; + quint16 port = 0; + bool legacy = false; + + QString toString() const; +}; diff --git a/src/net/netwebsocketconnection.cpp b/src/network/websocketconnection.cpp similarity index 55% rename from src/net/netwebsocketconnection.cpp rename to src/network/websocketconnection.cpp index 91fc526..133eae1 100644 --- a/src/net/netwebsocketconnection.cpp +++ b/src/network/websocketconnection.cpp @@ -1,48 +1,48 @@ -#include "netwebsocketconnection.h" +#include "websocketconnection.h" -#include "networkmanager.h" +#include "aoapplication.h" #include #include -NetWebSocketConnection::NetWebSocketConnection(NetworkManager *networkManager) - : NetConnection(networkManager) - , m_network_manager(networkManager) +WebSocketConnection::WebSocketConnection(AOApplication *ao_app, QObject *parent) + : QObject(parent) + , ao_app(ao_app) , m_socket(new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this)) , m_last_state(QAbstractSocket::UnconnectedState) { - connect(m_socket, QOverload::of(&QWebSocket::error), this, &NetWebSocketConnection::onError); - connect(m_socket, &QWebSocket::stateChanged, this, &NetWebSocketConnection::onStateChanged); - connect(m_socket, &QWebSocket::textMessageReceived, this, &NetWebSocketConnection::onTextMessageReceived); + connect(m_socket, QOverload::of(&QWebSocket::error), this, &WebSocketConnection::onError); + connect(m_socket, &QWebSocket::stateChanged, this, &WebSocketConnection::onStateChanged); + connect(m_socket, &QWebSocket::textMessageReceived, this, &WebSocketConnection::onTextMessageReceived); } -NetWebSocketConnection::~NetWebSocketConnection() +WebSocketConnection::~WebSocketConnection() { m_socket->disconnect(this); disconnectFromServer(); } -bool NetWebSocketConnection::isConnected() +bool WebSocketConnection::isConnected() { return m_last_state == QAbstractSocket::ConnectedState; } -void NetWebSocketConnection::connectToServer(ServerInfo &server) +void WebSocketConnection::connectToServer(const ServerInfo &server) { disconnectFromServer(); QUrl url; url.setScheme("ws"); - url.setHost(server.ip); + url.setHost(server.address); url.setPort(server.port); QNetworkRequest req(url); - req.setHeader(QNetworkRequest::UserAgentHeader, m_network_manager->get_user_agent()); + req.setHeader(QNetworkRequest::UserAgentHeader, QStringLiteral("AttorneyOnline/%1 (Desktop)").arg(ao_app->get_version_string())); m_socket->open(req); } -void NetWebSocketConnection::disconnectFromServer() +void WebSocketConnection::disconnectFromServer() { if (isConnected()) { @@ -50,17 +50,17 @@ void NetWebSocketConnection::disconnectFromServer() } } -void NetWebSocketConnection::sendPacket(AOPacket packet) +void WebSocketConnection::sendPacket(AOPacket packet) { m_socket->sendTextMessage(packet.toString(true)); } -void NetWebSocketConnection::onError() +void WebSocketConnection::onError() { Q_EMIT errorOccurred(m_socket->errorString()); } -void NetWebSocketConnection::onStateChanged(QAbstractSocket::SocketState state) +void WebSocketConnection::onStateChanged(QAbstractSocket::SocketState state) { m_last_state = state; switch (state) @@ -78,7 +78,7 @@ void NetWebSocketConnection::onStateChanged(QAbstractSocket::SocketState state) } } -void NetWebSocketConnection::onTextMessageReceived(QString message) +void WebSocketConnection::onTextMessageReceived(QString message) { if (!message.endsWith("#%")) { diff --git a/src/network/websocketconnection.h b/src/network/websocketconnection.h new file mode 100644 index 0000000..9df9a49 --- /dev/null +++ b/src/network/websocketconnection.h @@ -0,0 +1,43 @@ +#pragma once + +#include "aopacket.h" +#include "serverinfo.h" + +#include +#include + +class AOApplication; + +class WebSocketConnection : public QObject +{ + Q_OBJECT + +public: + explicit WebSocketConnection(AOApplication *ao_app, QObject *parent = nullptr); + virtual ~WebSocketConnection(); + + bool isConnected(); + + void connectToServer(const ServerInfo &server); + void disconnectFromServer(); + + void sendPacket(AOPacket packet); + +Q_SIGNALS: + void connectedToServer(); + void disconnectedFromServer(); + void errorOccurred(QString error); + + void receivedPacket(AOPacket packet); + +private: + AOApplication *ao_app; + + QWebSocket *m_socket; + QAbstractSocket::SocketState m_last_state; + +private Q_SLOTS: + void onError(); + void onStateChanged(QAbstractSocket::SocketState state); + void onTextMessageReceived(QString message); +}; diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp index b574b63..fc30060 100644 --- a/src/networkmanager.cpp +++ b/src/networkmanager.cpp @@ -3,8 +3,6 @@ #include "datatypes.h" #include "debug_functions.h" #include "lobby.h" -#include "net/nettcpconnection.h" -#include "net/netwebsocketconnection.h" #include "options.h" #include @@ -59,19 +57,19 @@ void NetworkManager::ms_request_finished(QNetworkReply *reply) { const auto entry = entryRef.toObject(); ServerInfo server; - server.ip = entry["ip"].toString(); + server.address = entry["ip"].toString(); server.name = entry["name"].toString(); server.description = entry["description"].toString(tr("No description provided.")); - if (entry["ws_port"].isDouble()) + if (entry.contains("ws_port")) { - server.socket_type = WebSocketServerConnection; server.port = entry["ws_port"].toInt(); } else { - server.socket_type = TcpServerConnection; server.port = entry["port"].toInt(); + server.legacy = true; } + if (server.port != 0) { server_list.append(server); @@ -149,27 +147,12 @@ void NetworkManager::connect_to_server(ServerInfo server) disconnect_from_server(); qInfo().noquote() << QObject::tr("Connecting to %1").arg(server.toString()); - switch (server.socket_type) - { - default: - server.socket_type = TcpServerConnection; - [[fallthrough]]; + m_connection = new WebSocketConnection(ao_app, this); - case TcpServerConnection: - qInfo() << "Using TCP backend."; - m_connection = new NetTcpConnection(this); - break; - - case WebSocketServerConnection: - qInfo() << "Using WebSockets backend."; - m_connection = new NetWebSocketConnection(this); - break; - } - - connect(m_connection, &NetConnection::connectedToServer, this, [] { qInfo() << "Established connection to server."; }); - connect(m_connection, &NetConnection::disconnectedFromServer, ao_app, &AOApplication::server_disconnected); - connect(m_connection, &NetConnection::errorOccurred, this, [](QString error) { qCritical() << "Connection error:" << error; }); - connect(m_connection, &NetConnection::receivedPacket, this, &NetworkManager::handle_server_packet); + connect(m_connection, &WebSocketConnection::connectedToServer, this, [] { qInfo() << "Established connection to server."; }); + connect(m_connection, &WebSocketConnection::disconnectedFromServer, ao_app, &AOApplication::server_disconnected); + connect(m_connection, &WebSocketConnection::errorOccurred, this, [](QString error) { qCritical() << "Connection error:" << error; }); + connect(m_connection, &WebSocketConnection::receivedPacket, this, &NetworkManager::handle_server_packet); m_connection->connectToServer(server); } diff --git a/src/networkmanager.h b/src/networkmanager.h index 4ec539f..8f2d8d4 100644 --- a/src/networkmanager.h +++ b/src/networkmanager.h @@ -2,7 +2,7 @@ #include "aoapplication.h" #include "aopacket.h" -#include "net/netconnection.h" +#include "network/websocketconnection.h" #include #include @@ -50,7 +50,7 @@ private: AOApplication *ao_app; QNetworkAccessManager *http; - NetConnection *m_connection = nullptr; + WebSocketConnection *m_connection = nullptr; QTimer *heartbeat_timer; diff --git a/src/options.cpp b/src/options.cpp index d06c5e4..9145aa4 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -668,11 +668,19 @@ QVector Options::favorites() { ServerInfo f_server; favorite.beginGroup(group); - f_server.ip = favorite.value("address", "127.0.0.1").toString(); + f_server.address = favorite.value("address", "127.0.0.1").toString(); f_server.port = favorite.value("port", 27016).toInt(); f_server.name = favorite.value("name", "Missing Name").toString(); f_server.description = favorite.value("desc", "No description").toString(); - f_server.socket_type = SERVER_CONNECTION_TYPE_STRING_MAP.value(favorite.value("protocol", "tcp").toString()); + if (favorite.contains("protocol")) + { + f_server.legacy = favorite.value("protocol").toString() == "tcp"; + } + else + { + f_server.legacy = favorite.value("legacy", false).toBool(); + } + serverlist.append(std::move(f_server)); favorite.endGroup(); } @@ -688,18 +696,10 @@ void Options::setFavorites(QVector value) auto fav_server = value.at(i); favorite.beginGroup(QString::number(i)); favorite.setValue("name", fav_server.name); - favorite.setValue("address", fav_server.ip); + favorite.setValue("address", fav_server.address); favorite.setValue("port", fav_server.port); favorite.setValue("desc", fav_server.description); - - if (fav_server.socket_type == TcpServerConnection) - { - favorite.setValue("protocol", "tcp"); - } - else - { - favorite.setValue("protocol", "ws"); - } + favorite.setValue("legacy", fav_server.legacy); favorite.endGroup(); } favorite.sync(); @@ -717,17 +717,10 @@ void Options::addFavorite(ServerInfo server) int index = favorites().size(); favorite.beginGroup(QString::number(index)); favorite.setValue("name", server.name); - favorite.setValue("address", server.ip); + favorite.setValue("address", server.address); favorite.setValue("port", server.port); favorite.setValue("desc", server.description); - if (server.socket_type == TcpServerConnection) - { - favorite.setValue("protocol", "tcp"); - } - else - { - favorite.setValue("protocol", "ws"); - } + favorite.setValue("legacy", server.legacy); favorite.endGroup(); favorite.sync(); } @@ -736,17 +729,10 @@ void Options::updateFavorite(ServerInfo server, int index) { favorite.beginGroup(QString::number(index)); favorite.setValue("name", server.name); - favorite.setValue("address", server.ip); + favorite.setValue("address", server.address); favorite.setValue("port", server.port); favorite.setValue("desc", server.description); - if (server.socket_type == TcpServerConnection) - { - favorite.setValue("protocol", "tcp"); - } - else - { - favorite.setValue("protocol", "ws"); - } + favorite.setValue("legacy", server.legacy); favorite.endGroup(); favorite.sync(); } diff --git a/src/options.h b/src/options.h index 1ea7621..4ccc301 100644 --- a/src/options.h +++ b/src/options.h @@ -1,8 +1,9 @@ #pragma once +#include "network/serverinfo.h" + #include #include -#include class Options { diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index 8b86b34..f440a0c 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -132,7 +132,7 @@ void AOApplication::server_packet_received(AOPacket packet) { auto info = server_list.at(selected_server); server_name = info.name; - server_address = QString("%1:%2").arg(info.ip, QString::number(info.port)); + server_address = QString("%1:%2").arg(info.address, QString::number(info.port)); window_title = server_name; } break; @@ -144,7 +144,7 @@ void AOApplication::server_packet_received(AOPacket packet) { auto info = favorite_list.at(selected_server); server_name = info.name; - server_address = QString("%1:%2").arg(info.ip, QString::number(info.port)); + server_address = QString("%1:%2").arg(info.address, QString::number(info.port)); window_title = server_name; } } diff --git a/src/widgets/direct_connect_dialog.cpp b/src/widgets/direct_connect_dialog.cpp index db4cde6..6a09b77 100644 --- a/src/widgets/direct_connect_dialog.cpp +++ b/src/widgets/direct_connect_dialog.cpp @@ -50,27 +50,29 @@ void DirectConnectDialog::onConnectPressed() QString l_hostname = ui_direct_hostname_edit->text(); if (!SCHEME_PATTERN.match(l_hostname).hasMatch()) { - l_hostname = "tcp://" % l_hostname; + l_hostname = "ws://" % l_hostname; } + QUrl l_url(l_hostname); if (!l_url.isValid()) { call_error(tr("Invalid URL.")); return; } - if (!SERVER_CONNECTION_TYPE_STRING_MAP.contains(l_url.scheme())) + + if (l_url.scheme() != "ws") { - call_error(tr("Scheme not recognized. Must be either of the following: ") % QStringList::fromVector(SERVER_CONNECTION_TYPE_STRING_MAP.keys().toVector()).join(", ")); + call_error(tr("Invalid URL scheme. Only ws:// is supported.")); return; } + if (l_url.port() == -1) { call_error(tr("Invalid server port.")); return; } ServerInfo l_server; - l_server.socket_type = SERVER_CONNECTION_TYPE_STRING_MAP[l_url.scheme()]; - l_server.ip = l_url.host(); + l_server.address = l_url.host(); l_server.port = l_url.port(); l_server.name = "Direct Connection"; diff --git a/src/widgets/server_editor_dialog.cpp b/src/widgets/server_editor_dialog.cpp index 386950e..150a435 100644 --- a/src/widgets/server_editor_dialog.cpp +++ b/src/widgets/server_editor_dialog.cpp @@ -1,6 +1,7 @@ #include "server_editor_dialog.h" #include "datatypes.h" +#include "debug_functions.h" #include "gui_utils.h" #include "options.h" @@ -30,7 +31,6 @@ ServerEditorDialog::ServerEditorDialog(QWidget *parent) FROM_UI(QLineEdit, name); FROM_UI(QLineEdit, hostname); FROM_UI(QSpinBox, port); - FROM_UI(QComboBox, protocol); FROM_UI(QPlainTextEdit, description); FROM_UI(QDialogButtonBox, button_box); @@ -43,52 +43,35 @@ ServerEditorDialog::ServerEditorDialog(QWidget *parent) connect(ui_button_box, &QDialogButtonBox::rejected, this, &ServerEditorDialog::reject); } +ServerEditorDialog::ServerEditorDialog(const ServerInfo &server, QWidget *parent) + : ServerEditorDialog(parent) +{ + ui_name->setText(server.name); + ui_hostname->setText(server.address); + ui_port->setValue(server.port); + ui_description->setPlainText(server.description); +} + ServerInfo ServerEditorDialog::currentServerInfo() const { ServerInfo server; server.name = ui_name->text(); - server.ip = ui_hostname->text(); + server.address = ui_hostname->text(); server.port = ui_port->value(); server.description = ui_description->toPlainText(); - server.socket_type = ServerConnectionType(ui_protocol->currentIndex()); return server; } -void ServerEditorDialog::loadServerInfo(ServerInfo server) -{ - ui_name->setText(server.name); - ui_hostname->setText(server.ip); - ui_port->setValue(server.port); - ui_description->setPlainText(server.description); - ui_protocol->setCurrentIndex(server.socket_type); -} - void ServerEditorDialog::parseLegacyEntry() { QStringList entry = ui_legacy_edit->text().split(":"); - ServerInfo l_server_entry; - if (entry.isEmpty()) + if (entry.size() < 3) { - qDebug() << "Legacy entry empty."; + call_error("Invalid legacy server entry"); return; } - int item_count = entry.size(); - if (item_count >= 3) - { - ui_hostname->setText(entry.at(0)); - ui_port->setValue(entry.at(1).toInt()); - ui_name->setText(entry.at(2)); - if (item_count >= 4) - { - if (entry.at(3) == "ws") - { - ui_protocol->setCurrentIndex(1); - } - else - { - ui_protocol->setCurrentIndex(0); - } - } - } + ui_hostname->setText(entry.at(0)); + ui_port->setValue(entry.at(1).toInt()); + ui_name->setText(entry.at(2)); } diff --git a/src/widgets/server_editor_dialog.h b/src/widgets/server_editor_dialog.h index 1ceb352..a8844d4 100644 --- a/src/widgets/server_editor_dialog.h +++ b/src/widgets/server_editor_dialog.h @@ -1,6 +1,6 @@ #pragma once -#include "datatypes.h" +#include "network/serverinfo.h" #include #include @@ -21,8 +21,6 @@ public: ServerInfo currentServerInfo() const; - void loadServerInfo(ServerInfo server); - private: static const QString UI_FILE_PATH; @@ -31,7 +29,6 @@ private: QLineEdit *ui_name; QLineEdit *ui_hostname; QSpinBox *ui_port; - QComboBox *ui_protocol; QPlainTextEdit *ui_description; QDialogButtonBox *ui_button_box;