From a8ccbe77c1eb03b0695f9d0620354019d6bf905d Mon Sep 17 00:00:00 2001 From: oldmud0 Date: Sat, 4 Nov 2017 18:42:28 -0500 Subject: [PATCH] Don't do failover for Android, try reconnecting automatically once Issue: AOTextArea is supposed to have red text for errors, but it's not working --- .gitignore | 2 ++ aoapplication.cpp | 23 +++++++++---- aoapplication.h | 2 +- aotextarea.cpp | 82 +++++++++++----------------------------------- aotextarea.h | 6 ++++ lobby.cpp | 8 ++++- lobby.h | 1 + networkmanager.cpp | 65 +++++++++++++++++++++++++++++++++--- networkmanager.h | 22 +++++++++++-- 9 files changed, 132 insertions(+), 79 deletions(-) diff --git a/.gitignore b/.gitignore index 12b1c86..9a949cb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ *.so base_override.h +base-full/ +bass.lib diff --git a/aoapplication.cpp b/aoapplication.cpp index 8ee33b0..4362902 100644 --- a/aoapplication.cpp +++ b/aoapplication.cpp @@ -12,7 +12,8 @@ AOApplication::AOApplication(int &argc, char **argv) : QApplication(argc, argv) { net_manager = new NetworkManager(this); - QObject::connect(net_manager, SIGNAL(ms_connect_finished(bool)), SLOT(ms_connect_finished(bool))); + QObject::connect(net_manager, SIGNAL(ms_connect_finished(bool, bool)), + SLOT(ms_connect_finished(bool, bool))); } AOApplication::~AOApplication() @@ -136,7 +137,7 @@ void AOApplication::loading_cancelled() w_lobby->hide_loading_overlay(); } -void AOApplication::ms_connect_finished(bool connected) +void AOApplication::ms_connect_finished(bool connected, bool will_retry) { if (connected) { @@ -145,10 +146,18 @@ void AOApplication::ms_connect_finished(bool connected) } else { - call_error("There was an error connecting to the master server.\n" - "We deploy multiple master servers to mitigate any possible downtime," - "but the client appears to have exhausted all possible methods of finding" - "and connecting to one.\n" - "Please check your Internet connection and firewall, and please try again."); + if (will_retry) + { + w_lobby->append_error("Error connecting to master server. Will try again in " + + QString::number(net_manager->ms_reconnect_delay_ms / 1000.f) + " seconds."); + } + else + { + call_error("There was an error connecting to the master server.\n" + "We deploy multiple master servers to mitigate any possible downtime, " + "but the client appears to have exhausted all possible methods of finding " + "and connecting to one.\n" + "Please check your Internet connection and firewall, and please try again."); + } } } diff --git a/aoapplication.h b/aoapplication.h index 28d176d..d9737f6 100644 --- a/aoapplication.h +++ b/aoapplication.h @@ -147,7 +147,7 @@ private: QVector favorite_list; private slots: - void ms_connect_finished(bool connected); + void ms_connect_finished(bool connected, bool will_retry); public slots: void server_disconnected(); diff --git a/aotextarea.cpp b/aotextarea.cpp index d28ae4f..7c9e160 100644 --- a/aotextarea.cpp +++ b/aotextarea.cpp @@ -7,7 +7,7 @@ AOTextArea::AOTextArea(QWidget *p_parent) : QTextBrowser(p_parent) { - + this->setStyleSheet(".error {color: #0f0}"); } void AOTextArea::append_chatmessage(QString p_name, QString p_message) @@ -21,81 +21,37 @@ void AOTextArea::append_chatmessage(QString p_name, QString p_message) this->append(""); this->insertHtml("" + p_name.toHtmlEscaped() + ": "); - //QRegExp regExp("((([A-Za-z]{3,9}:(?:\\/\\/)?)(?:[\\-;:&=\\+\\$,\\w]+@)?[A-Za-z0-9\\.\\-]+|(?:www\\.|[\\-;:&=\\+\\$,\\w]+@)[A-Za-z0-9\\.\\-]+)((?:\\/[\\+~%\\/\\.\\w\\-]*)?\\??(?:[\\-\\+=&;%@\\.\\w]*)#?(?:[\\.\\!\\/\\\\\\w]*))?)"); - - QRegExp omnis_dank_url_regex("\\b(https?://\\S+\\.\\S+)\\b"); - //cheap workarounds ahoy p_message += " "; QString result = p_message.toHtmlEscaped().replace("\n", "
").replace(omnis_dank_url_regex, "\\1" ); this->insertHtml(result); + this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); +} - /* - QRegExp rx("\\bhttp://\\S+"); +void AOTextArea::append_error(QString p_message) +{ + const QTextCursor old_cursor = this->textCursor(); + const int old_scrollbar_value = this->verticalScrollBar()->value(); + const bool is_scrolled_down = old_scrollbar_value == this->verticalScrollBar()->maximum(); - int first_index = rx.indexIn(p_message); + this->moveCursor(QTextCursor::End); - qDebug() << "number of rx indices: " << rx.captureCount(); + this->append(""); + this->insertHtml("
"); - if (first_index < 0) - { - this->insertPlainText(p_message); - qDebug() << "NO REGEX MATCHES"; - return; - } + p_message += " "; + QString result = p_message.replace("\n", "
").replace(omnis_dank_url_regex, "\\1" ); - //indices where we found a regex match - QVector rx_indices; - QStringList links = rx.capturedTexts(); + this->insertHtml(result); + this->insertHtml("
"); - qDebug() << "link size" << links.size(); - - rx_indices.append(first_index); - - - //start at one because first_index is already appended - for (int n_pos = 1 ; n_pos < rx.captureCount() ; ++n_pos) - rx_indices.append(rx.indexIn(p_message)); - - for (int msg_pos = 0 ; msg_pos < p_message.size() ; ++msg_pos) - { - int tag_index = rx_indices.indexOf(msg_pos); - if (tag_index < 0) - { - this->insertPlainText(p_message.at(msg_pos)); - continue; - } - - QString link = links.at(tag_index); - QString html_string = "" + link + ""; - qDebug() << "html: " << html_string; - - this->insertHtml(html_string); - - msg_pos += link.size() - 1; - - } - - */ - - /* - - QStringList word_list = p_message.split(" "); - - for (QString i_word : word_list) - { - if (i_word.startsWith("http")) - { - i_word.replace("\n", "").replace("\r", ""); - this->insertHtml("" + i_word + " "); - } - else - this->insertPlainText(i_word + " "); - } - */ + this->auto_scroll(old_cursor, old_scrollbar_value, is_scrolled_down); +} +void AOTextArea::auto_scroll(QTextCursor old_cursor, int old_scrollbar_value, bool is_scrolled_down) +{ if (old_cursor.hasSelection() || !is_scrolled_down) { // The user has selected text or scrolled away from the bottom: maintain position. diff --git a/aotextarea.h b/aotextarea.h index 420bced..32635fd 100644 --- a/aotextarea.h +++ b/aotextarea.h @@ -9,6 +9,12 @@ public: AOTextArea(QWidget *p_parent = nullptr); void append_chatmessage(QString p_name, QString p_message); + void append_error(QString p_message); + +private: + const QRegExp omnis_dank_url_regex = QRegExp("\\b(https?://\\S+\\.\\S+)\\b"); + + void auto_scroll(QTextCursor old_cursor, int scrollbar_value, bool is_scrolled_down); }; #endif // AOTEXTAREA_H diff --git a/lobby.cpp b/lobby.cpp index 2a7589f..91827e8 100644 --- a/lobby.cpp +++ b/lobby.cpp @@ -262,8 +262,9 @@ void Lobby::on_about_clicked() call_notice("Attorney Online 2 is built using Qt 5.7\n\n" "Lead development:\n" "OmniTroid\n\n" - "Supporting development:\n" "stonedDiscord\n" + "longbyte1\n" + "Supporting development:\n" "Fiercy\n\n" "UI design:\n" "Ruekasu\n" @@ -357,6 +358,11 @@ void Lobby::append_chatmessage(QString f_name, QString f_message) ui_chatbox->append_chatmessage(f_name, f_message); } +void Lobby::append_error(QString f_message) +{ + ui_chatbox->append_error(f_message); +} + void Lobby::set_player_count(int players_online, int max_players) { QString f_string = "Online: " + QString::number(players_online) + "/" + QString::number(max_players); diff --git a/lobby.h b/lobby.h index b2bfbef..2d3aee5 100644 --- a/lobby.h +++ b/lobby.h @@ -27,6 +27,7 @@ public: void list_servers(); void list_favorites(); void append_chatmessage(QString f_name, QString f_message); + void append_error(QString f_message); void set_player_count(int players_online, int max_players); void set_loading_text(QString p_text); void show_loading_overlay(){ui_loading_background->show();} diff --git a/networkmanager.cpp b/networkmanager.cpp index 3c59a82..5f2aac2 100644 --- a/networkmanager.cpp +++ b/networkmanager.cpp @@ -12,6 +12,10 @@ NetworkManager::NetworkManager(AOApplication *parent) : QObject(parent) ms_socket = new QTcpSocket(this); server_socket = new QTcpSocket(this); + ms_reconnect_timer = new QTimer(this); + ms_reconnect_timer->setSingleShot(true); + QObject::connect(ms_reconnect_timer, SIGNAL(timeout()), this, SLOT(retry_ms_connect())); + QObject::connect(ms_socket, SIGNAL(readyRead()), this, SLOT(handle_ms_packet())); QObject::connect(server_socket, SIGNAL(readyRead()), this, SLOT(handle_server_packet())); QObject::connect(server_socket, SIGNAL(disconnected()), ao_app, SLOT(server_disconnected())); @@ -27,7 +31,16 @@ void NetworkManager::connect_to_master() ms_socket->close(); ms_socket->abort(); +#ifdef MS_FAILOVER_SUPPORTED perform_srv_lookup(); +#else + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(on_ms_connect_error(QAbstractSocket::SocketError))); + + QObject::connect(ms_socket, SIGNAL(connected()), + this, SLOT(on_ms_nosrv_connect_success())); + ms_socket->connectToHost(ms_nosrv_hostname, ms_port); +#endif } void NetworkManager::connect_to_server(server_type p_server) @@ -40,7 +53,14 @@ void NetworkManager::connect_to_server(server_type p_server) void NetworkManager::ship_ms_packet(QString p_packet) { - ms_socket->write(p_packet.toUtf8()); + if (!ms_socket->isOpen()) + { + retry_ms_connect(); + } + else + { + ms_socket->write(p_packet.toUtf8()); + } } void NetworkManager::ship_server_packet(QString p_packet) @@ -82,9 +102,10 @@ void NetworkManager::handle_ms_packet() } } +#ifdef MS_FAILOVER_SUPPORTED void NetworkManager::perform_srv_lookup() { - ms_dns = new QDnsLookup(QDnsLookup::SRV, ms_hostname, this); + ms_dns = new QDnsLookup(QDnsLookup::SRV, ms_srv_hostname, this); connect(ms_dns, SIGNAL(finished()), this, SLOT(on_srv_lookup())); ms_dns->lookup(); @@ -127,7 +148,13 @@ void NetworkManager::on_srv_lookup() break; } } while (timer.elapsed() < timeout_milliseconds); // Very expensive spin-wait loop - it will bring CPU to 100%! - if (connected) break; + if (connected) + { + // Connect a one-shot signal in case the master server disconnects randomly + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + break; + } else { ms_socket->abort(); @@ -135,7 +162,37 @@ void NetworkManager::on_srv_lookup() } } } - emit ms_connect_finished(connected); + emit ms_connect_finished(connected, false); +} +#endif + +void NetworkManager::on_ms_nosrv_connect_success() +{ + emit ms_connect_finished(true, false); + + QObject::connect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); +} + +void NetworkManager::on_ms_socket_error(QAbstractSocket::SocketError error) +{ + qWarning() << "Master server socket error:" << ms_socket->errorString() + << "(" << error << ")"; + + // Disconnect the one-shot signal - this way, failover connect attempts + // don't trigger a full retry + QObject::disconnect(ms_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(on_ms_socket_error(QAbstractSocket::SocketError))); + + emit ms_connect_finished(false, true); + + ms_reconnect_timer->start(ms_reconnect_delay_ms); +} + +void NetworkManager::retry_ms_connect() +{ + if (!ms_reconnect_timer->isActive() && ms_socket->state() != QAbstractSocket::ConnectingState) + connect_to_master(); } void NetworkManager::handle_server_packet() diff --git a/networkmanager.h b/networkmanager.h index 4bfebc6..00a7a96 100644 --- a/networkmanager.h +++ b/networkmanager.h @@ -1,12 +1,20 @@ #ifndef NETWORKMANAGER_H #define NETWORKMANAGER_H +// Qt for Android has stubbed QDnsLookup. This is not documented in any part of their wiki. +// This prevents SRV lookup/failover behavior from functioning. +// https://bugreports.qt.io/browse/QTBUG-56143 +#ifndef ANDROID +#define MS_FAILOVER_SUPPORTED +#endif + #include "aopacket.h" #include "aoapplication.h" #include #include #include +#include class NetworkManager : public QObject { @@ -20,11 +28,16 @@ public: QTcpSocket *ms_socket; QTcpSocket *server_socket; QDnsLookup *ms_dns; + QTimer *ms_reconnect_timer; - QString ms_hostname = "_aoms._tcp.aceattorneyonline.com"; - int ms_port = 27016; + const QString ms_srv_hostname = "_aoms._tcp.aceattorneyonline.com"; + const QString ms_nosrv_hostname = "master.aceattorneyonline.com"; + + const int ms_port = 27016; const int timeout_milliseconds = 2000; + const int ms_reconnect_delay_ms = 5000; + bool ms_partial_packet = false; QString ms_temp_packet = ""; @@ -41,7 +54,7 @@ public slots: void ship_server_packet(QString p_packet); signals: - void ms_connect_finished(bool success); + void ms_connect_finished(bool success, bool will_retry); private: void perform_srv_lookup(); @@ -50,6 +63,9 @@ private slots: void on_srv_lookup(); void handle_ms_packet(); void handle_server_packet(); + void on_ms_nosrv_connect_success(); + void on_ms_socket_error(QAbstractSocket::SocketError error); + void retry_ms_connect(); }; #endif // NETWORKMANAGER_H