-
Notifications
You must be signed in to change notification settings - Fork 71
Dual-Stack AO2 Client to handle both TCP and Websocket connections seemlessly #696
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f4aee75
90533e9
95d29c1
3feba26
1bb37ce
866c43e
17a77ef
60e3aee
04e9e15
7e8701b
06c32fd
ef1acd2
f87b187
520a284
8fb120b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| [0] | ||
| name=Default Local Server | ||
| address=127.0.0.1 | ||
| port=27016 | ||
| protocol=tcp |
This file was deleted.
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -6,7 +6,7 @@ | |||
|
|
||||
| #include <QDnsLookup> | ||||
| #include <QNetworkAccessManager> | ||||
| #include <QTcpSocket> | ||||
| #include <QtWebSockets/QWebSocket> | ||||
oldmud0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
| #include <QTime> | ||||
| #include <QTimer> | ||||
|
|
||||
|
|
@@ -21,16 +21,20 @@ enum MSDocumentType { | |||
| class NetworkManager : public QObject { | ||||
| Q_OBJECT | ||||
|
|
||||
| public: | ||||
| explicit NetworkManager(AOApplication *parent); | ||||
| ~NetworkManager() = default; | ||||
|
|
||||
| private: | ||||
| AOApplication *ao_app; | ||||
| QNetworkAccessManager *http; | ||||
| QTcpSocket *server_socket; | ||||
|
|
||||
| union { | ||||
| QWebSocket *ws; | ||||
| QTcpSocket *tcp; | ||||
| } server_socket; | ||||
| connection_type active_connection_type; | ||||
| bool connected = false; | ||||
|
|
||||
| QTimer *heartbeat_timer; | ||||
|
|
||||
| const QString DEFAULT_MS_BASEURL = "https://servers.aceattorneyonline.com"; | ||||
| const QString DEFAULT_MS_BASEURL = "http://servers.aceattorneyonline.com"; | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: member variable 'DEFAULT_MS_BASEURL' has public visibility [misc-non-private-member-variables-in-classes] const QString DEFAULT_MS_BASEURL = "http://servers.aceattorneyonline.com";
^ |
||||
| QString ms_baseurl = DEFAULT_MS_BASEURL; | ||||
|
|
||||
| const int heartbeat_interval = 60 * 5 * 1000; | ||||
|
|
@@ -40,12 +44,17 @@ class NetworkManager : public QObject { | |||
|
|
||||
| unsigned int s_decryptor = 5; | ||||
|
|
||||
| public: | ||||
| explicit NetworkManager(AOApplication *parent); | ||||
| ~NetworkManager() = default; | ||||
|
|
||||
| void connect_to_server(server_type p_server); | ||||
| void disconnect_from_server(); | ||||
|
|
||||
| public slots: | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: redundant access specifier has the same accessibility as the previous access specifier [readability-redundant-access-specifiers]
Suggested change
include/networkmanager.h:46: previously declared here public:
^ |
||||
| void get_server_list(const std::function<void()> &cb); | ||||
| void ship_server_packet(QString p_packet); | ||||
| void handle_server_packet(); | ||||
| void handle_server_packet(const QString& p_data); | ||||
|
|
||||
| void request_document(MSDocumentType document_type, | ||||
| const std::function<void(QString)> &cb); | ||||
|
|
||||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] server_socket.tcp = new QTcpSocket(this);
^ |
||||||||||||
|
|
||||||||||||
| connect(server_socket.tcp, &QAbstractSocket::connected, this, [] { | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] connect(server_socket.tcp, &QAbstractSocket::connected, this, [] {
^ |
||||||||||||
| qDebug() << "established connection to server"; | ||||||||||||
| }); | ||||||||||||
| connect(server_socket.tcp, &QIODevice::readyRead, this, [this] { | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] connect(server_socket.tcp, &QIODevice::readyRead, this, [this] {
^ |
||||||||||||
| handle_server_packet(QString::fromUtf8(server_socket.tcp->readAll())); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] handle_server_packet(QString::fromUtf8(server_socket.tcp->readAll()));
^ |
||||||||||||
| }); | ||||||||||||
| connect(server_socket.tcp, &QAbstractSocket::disconnected, ao_app, | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] connect(server_socket.tcp, &QAbstractSocket::disconnected, ao_app,
^ |
||||||||||||
| &AOApplication::server_disconnected); | ||||||||||||
| connect(server_socket.tcp, &QAbstractSocket::errorOccurred, this, [this] { | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] connect(server_socket.tcp, &QAbstractSocket::errorOccurred, this, [this] {
^ |
||||||||||||
| qCritical() << "TCP socket error:" << server_socket.tcp->errorString(); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] qCritical() << "TCP socket error:" << server_socket.tcp->errorString();
^ |
||||||||||||
| }); | ||||||||||||
|
|
||||||||||||
| server_socket.tcp->connectToHost(p_server.ip, p_server.port); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] 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); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] server_socket.ws = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);
^ |
||||||||||||
|
|
||||||||||||
| connect(server_socket.ws, &QWebSocket::connected, this, [] { | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] connect(server_socket.ws, &QWebSocket::connected, this, [] {
^ |
||||||||||||
| qDebug() << "established connection to server"; | ||||||||||||
| }); | ||||||||||||
| connect(server_socket.ws, &QWebSocket::textMessageReceived, this, | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] connect(server_socket.ws, &QWebSocket::textMessageReceived, this,
^ |
||||||||||||
| &NetworkManager::handle_server_packet); | ||||||||||||
| connect(server_socket.ws, &QWebSocket::disconnected, ao_app, | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] connect(server_socket.ws, &QWebSocket::disconnected, ao_app,
^ |
||||||||||||
| &AOApplication::server_disconnected); | ||||||||||||
| connect(server_socket.ws, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] connect(server_socket.ws, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error),
^ |
||||||||||||
| this, [this] { | ||||||||||||
| qCritical() << "WebSockets error:" << server_socket.ws->errorString(); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] 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); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] server_socket.ws->open(req);
^ |
||||||||||||
| break; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| connected = true; | ||||||||||||
| active_connection_type = p_server.socket_type; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| void NetworkManager::disconnect_from_server() | ||||||||||||
| { | ||||||||||||
| if (!connected) | ||||||||||||
| return; | ||||||||||||
|
Comment on lines
+193
to
+194
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: statement should be inside braces [readability-braces-around-statements]
Suggested change
|
||||||||||||
|
|
||||||||||||
| switch (active_connection_type) { | ||||||||||||
| case TCP: | ||||||||||||
| server_socket.tcp->close(); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] server_socket.tcp->close();
^ |
||||||||||||
| server_socket.tcp->deleteLater(); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] server_socket.tcp->deleteLater();
^ |
||||||||||||
| break; | ||||||||||||
| case WEBSOCKETS: | ||||||||||||
| server_socket.ws->close(QWebSocketProtocol::CloseCodeGoingAway); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] server_socket.ws->close(QWebSocketProtocol::CloseCodeGoingAway);
^ |
||||||||||||
| server_socket.ws->deleteLater(); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] 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()); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] server_socket.tcp->write(p_packet.toUtf8());
^ |
||||||||||||
| break; | ||||||||||||
| case WEBSOCKETS: | ||||||||||||
| server_socket.ws->sendTextMessage(p_packet); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access] 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; | ||||||||||||
|
|
||||||||||||
Uh oh!
There was an error while loading. Please reload this page.