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
This commit is contained in:
Leifa 2024-07-09 13:07:30 +02:00 committed by GitHub
parent 662d4781d2
commit efd2571459
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 252 additions and 450 deletions

View File

@ -78,12 +78,8 @@ add_executable(Attorney_Online
src/lobby.cpp src/lobby.cpp
src/lobby.h src/lobby.h
src/main.cpp src/main.cpp
src/net/netconnection.cpp src/network/websocketconnection.cpp
src/net/netconnection.h src/network/websocketconnection.h
src/net/nettcpconnection.cpp
src/net/nettcpconnection.h
src/net/netwebsocketconnection.cpp
src/net/netwebsocketconnection.h
src/networkmanager.cpp src/networkmanager.cpp
src/networkmanager.h src/networkmanager.h
src/options.cpp src/options.cpp
@ -103,6 +99,7 @@ add_executable(Attorney_Online
src/widgets/server_editor_dialog.h src/widgets/server_editor_dialog.h
data.qrc data.qrc
src/screenslidetimer.h src/screenslidetimer.cpp 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") set_target_properties(Attorney_Online PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")

View File

@ -78,34 +78,13 @@
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Protocol:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="protocol">
<item>
<property name="text">
<string>TCP</string>
</property>
</item>
<item>
<property name="text">
<string>WEBSOCKET</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Description:</string> <string>Description:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="3" column="1">
<widget class="QPlainTextEdit" name="description"> <widget class="QPlainTextEdit" name="description">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">

View File

@ -316,8 +316,14 @@ QScrollBar:horizontall {
<item row="1" column="0"> <item row="1" column="0">
<widget class="QTreeWidget" name="serverlist_tree"> <widget class="QTreeWidget" name="serverlist_tree">
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">background-color: rgba(140, 140, 140, 255); <string notr="true">QHeaderView, QTreeView {
color: rgb(255, 255, 255);</string> background-color: rgba(140, 140, 140, 255);
color: rgb(255, 255, 255);
}
QToolTip {
color: black;
}</string>
</property> </property>
<property name="textElideMode"> <property name="textElideMode">
<enum>Qt::ElideNone</enum> <enum>Qt::ElideNone</enum>
@ -330,7 +336,7 @@ color: rgb(255, 255, 255);</string>
<string>#</string> <string>#</string>
</property> </property>
<property name="textAlignment"> <property name="textAlignment">
<set>AlignTrailing|AlignVCenter</set> <set>AlignLeading|AlignVCenter</set>
</property> </property>
</column> </column>
<column> <column>
@ -369,7 +375,11 @@ color: rgb(255, 255, 255);</string>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">background-color: rgba(140, 140, 140, 255); <string notr="true">background-color: rgba(140, 140, 140, 255);
color: rgb(255, 255, 255);</string> color: rgb(255, 255, 255);
QToolTip {
color: black;
};</string>
</property> </property>
<property name="textElideMode"> <property name="textElideMode">
<enum>Qt::ElideNone</enum> <enum>Qt::ElideNone</enum>

View File

@ -5,25 +5,6 @@
#include <optional> #include <optional>
enum ServerConnectionType
{
TcpServerConnection,
WebSocketServerConnection,
};
static const QMap<QString, ServerConnectionType> 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 struct CharacterSlot
{ {
QString name; QString name;

View File

@ -9,8 +9,8 @@ DemoServer::DemoServer(QObject *parent)
timer->setTimerType(Qt::PreciseTimer); timer->setTimerType(Qt::PreciseTimer);
timer->setSingleShot(true); timer->setSingleShot(true);
tcp_server = new QTcpServer(this); server = new QWebSocketServer(tr("DemoServer"), QWebSocketServer::NonSecureMode, this);
connect(tcp_server, &QTcpServer::newConnection, this, &DemoServer::accept_connection); connect(server, &QWebSocketServer::newConnection, this, &DemoServer::accept_connection);
connect(timer, &QTimer::timeout, this, &DemoServer::playback); connect(timer, &QTimer::timeout, this, &DemoServer::playback);
} }
@ -30,22 +30,22 @@ void DemoServer::start_server()
{ {
return; return;
} }
if (!tcp_server->listen(QHostAddress::LocalHost, 0)) if (!server->listen(QHostAddress::LocalHost, 0))
{ {
qCritical() << "Could not start demo playback server..."; qCritical() << "Could not start demo playback server...";
qDebug() << tcp_server->errorString(); qDebug() << server->errorString();
return; return;
} }
this->m_port = tcp_server->serverPort(); this->m_port = server->serverPort();
qInfo() << "Demo server started at port" << m_port; qInfo() << "Demo server started at port" << m_port;
m_server_started = true; m_server_started = true;
} }
void DemoServer::destroy_connection() void DemoServer::destroy_connection()
{ {
QTcpSocket *temp_socket = tcp_server->nextPendingConnection(); QWebSocket *temp_socket = server->nextPendingConnection();
connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater); temp_socket->close();
temp_socket->disconnectFromHost(); temp_socket->deleteLater();
return; return;
} }
@ -80,22 +80,20 @@ void DemoServer::accept_connection()
{ {
// Client is already connected... // Client is already connected...
qWarning() << "Multiple connections to demo server disallowed."; qWarning() << "Multiple connections to demo server disallowed.";
QTcpSocket *temp_socket = tcp_server->nextPendingConnection(); QWebSocket *temp_socket = server->nextPendingConnection();
connect(temp_socket, &QAbstractSocket::disconnected, temp_socket, &QObject::deleteLater); temp_socket->close();
temp_socket->disconnectFromHost(); temp_socket->deleteLater();
return; return;
} }
client_sock = tcp_server->nextPendingConnection(); client_sock = server->nextPendingConnection();
connect(client_sock, &QAbstractSocket::disconnected, this, &DemoServer::client_disconnect); connect(client_sock, &QWebSocket::disconnected, this, &DemoServer::client_disconnect);
connect(client_sock, &QAbstractSocket::readyRead, this, &DemoServer::recv_data); connect(client_sock, &QWebSocket::textMessageReceived, this, &DemoServer::recv_data);
client_sock->write("decryptor#NOENCRYPT#%"); 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 = message.split("%", Qt::SkipEmptyParts);
const QStringList packet_list = in_data.split("%", Qt::SkipEmptyParts);
for (const QString &packet : packet_list) for (const QString &packet : packet_list)
{ {
QStringList f_contents; QStringList f_contents;
@ -145,39 +143,35 @@ void DemoServer::handle_packet(AOPacket p_packet)
if (header == "HI") if (header == "HI")
{ {
client_sock->write("ID#0#DEMOINTERNAL#0#%"); client_sock->sendTextMessage("ID#0#DEMOINTERNAL#0#%");
} }
else if (header == "ID") 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"}; 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->sendTextMessage("PN#0#1#%");
client_sock->write("FL#"); client_sock->sendTextMessage("FL#" + feature_list.join('#') + "#%");
client_sock->write(feature_list.join('#').toUtf8());
client_sock->write("#%");
} }
else if (header == "askchaa") else if (header == "askchaa")
{ {
client_sock->write("SI#"); client_sock->sendTextMessage("SI#" + QString::number(num_chars) + "#0#1#%");
client_sock->write(QString::number(num_chars).toUtf8());
client_sock->write("#0#1#%");
} }
else if (header == "RC") else if (header == "RC")
{ {
client_sock->write(sc_packet.toUtf8()); client_sock->sendTextMessage(sc_packet.toUtf8());
} }
else if (header == "RM") else if (header == "RM")
{ {
client_sock->write("SM#%"); client_sock->sendTextMessage("SM#%");
} }
else if (header == "RD") else if (header == "RD")
{ {
client_sock->write("DONE#%"); client_sock->sendTextMessage("DONE#%");
} }
else if (header == "CC") 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#%"; 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") else if (header == "CT")
{ {
@ -190,7 +184,7 @@ void DemoServer::handle_packet(AOPacket p_packet)
} }
load_demo(path); load_demo(path);
QString packet = "CT#DEMO#" + tr("Demo file loaded. Send /play or > in OOC to begin playback.") + "#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());
reset_state(); reset_state();
} }
else if (contents[1].startsWith("/play") || contents[1] == ">") else if (contents[1].startsWith("/play") || contents[1] == ">")
@ -199,7 +193,7 @@ void DemoServer::handle_packet(AOPacket p_packet)
{ {
timer->start(); timer->start();
QString packet = "CT#DEMO#" + tr("Resuming playback.") + "#1#%"; QString packet = "CT#DEMO#" + tr("Resuming playback.") + "#1#%";
client_sock->write(packet.toUtf8()); client_sock->sendTextMessage(packet.toUtf8());
} }
else else
{ {
@ -216,7 +210,7 @@ void DemoServer::handle_packet(AOPacket p_packet)
timer->stop(); timer->stop();
timer->setInterval(timeleft); timer->setInterval(timeleft);
QString packet = "CT#DEMO#" + tr("Pausing playback.") + "#1#%"; 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")) else if (contents[1].startsWith("/max_wait"))
{ {
@ -232,38 +226,32 @@ void DemoServer::handle_packet(AOPacket p_packet)
p_max_wait = -1; p_max_wait = -1;
} }
m_max_wait = p_max_wait; m_max_wait = p_max_wait;
QString packet = "CT#DEMO#" + tr("Setting max_wait to") + " "; QString packet = "CT#DEMO#" + tr("Setting max_wait to") + " " + QString::number(m_max_wait) + " " + tr("milliseconds.") + "#1#%";
client_sock->write(packet.toUtf8()); client_sock->sendTextMessage(packet);
client_sock->write(QString::number(m_max_wait).toUtf8());
packet = " " + tr("milliseconds.") + "#1#%";
client_sock->write(packet.toUtf8());
} }
else else
{ {
QString packet = "CT#DEMO#" + tr("Not a valid integer!") + "#1#%"; QString packet = "CT#DEMO#" + tr("Not a valid integer!") + "#1#%";
client_sock->write(packet.toUtf8()); client_sock->sendTextMessage(packet.toUtf8());
} }
} }
else else
{ {
QString packet = "CT#DEMO#" + tr("Current max_wait is") + " "; QString packet = "CT#DEMO#" + tr("Current max_wait is") + " " + QString::number(m_max_wait) + tr("milliseconds.") + "#1#%";
client_sock->write(packet.toUtf8()); client_sock->sendTextMessage(packet.toUtf8());
client_sock->write(QString::number(m_max_wait).toUtf8());
packet = " " + tr("milliseconds.") + "#1#%";
client_sock->write(packet.toUtf8());
} }
} }
else if (contents[1].startsWith("/reload")) else if (contents[1].startsWith("/reload"))
{ {
load_demo(p_path); load_demo(p_path);
QString packet = "CT#DEMO#" + tr("Current demo file reloaded. Send /play or > in OOC to begin playback.") + "#1#%"; 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(); reset_state();
} }
else if (contents[1].startsWith("/min_wait")) 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#%"; 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")) else if (contents[1].startsWith("/debug"))
{ {
@ -276,31 +264,31 @@ void DemoServer::handle_packet(AOPacket p_packet)
{ {
debug_mode = toggle == 1; debug_mode = toggle == 1;
QString packet = "CT#DEMO#" + tr("Setting debug mode to %1").arg(static_cast<int>(debug_mode)) + "#1#%"; QString packet = "CT#DEMO#" + tr("Setting debug mode to %1").arg(static_cast<int>(debug_mode)) + "#1#%";
client_sock->write(packet.toUtf8()); client_sock->sendTextMessage(packet.toUtf8());
// Debug mode disabled? // Debug mode disabled?
if (!debug_mode) if (!debug_mode)
{ {
// Reset the timer // Reset the timer
client_sock->write("TI#4#1#0#%"); client_sock->sendTextMessage("TI#4#1#0#%");
client_sock->write("TI#4#3#0#%"); client_sock->sendTextMessage("TI#4#3#0#%");
} }
} }
else else
{ {
QString packet = "CT#DEMO#" + tr("Valid values are 1 or 0!") + "#1#%"; QString packet = "CT#DEMO#" + tr("Valid values are 1 or 0!") + "#1#%";
client_sock->write(packet.toUtf8()); client_sock->sendTextMessage(packet.toUtf8());
} }
} }
else 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#%"; 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")) else if (contents[1].startsWith("/help"))
{ {
QString packet = "CT#DEMO#" + tr("Available commands:\nload, reload, play, pause, max_wait, debug, help") + "#1#%"; 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() void DemoServer::reset_state()
{ {
// Reset evidence list // Reset evidence list
client_sock->write("LE##%"); client_sock->sendTextMessage("LE##%");
// Reset timers // Reset timers
client_sock->write("TI#0#1#0#%"); client_sock->sendTextMessage("TI#0#1#0#%");
client_sock->write("TI#0#3#0#%"); client_sock->sendTextMessage("TI#0#3#0#%");
client_sock->write("TI#1#1#0#%"); client_sock->sendTextMessage("TI#1#1#0#%");
client_sock->write("TI#1#3#0#%"); client_sock->sendTextMessage("TI#1#3#0#%");
client_sock->write("TI#2#1#0#%"); client_sock->sendTextMessage("TI#2#1#0#%");
client_sock->write("TI#2#3#0#%"); client_sock->sendTextMessage("TI#2#3#0#%");
client_sock->write("TI#3#1#0#%"); client_sock->sendTextMessage("TI#3#1#0#%");
client_sock->write("TI#3#3#0#%"); client_sock->sendTextMessage("TI#3#3#0#%");
client_sock->write("TI#4#1#0#%"); client_sock->sendTextMessage("TI#4#1#0#%");
client_sock->write("TI#4#3#0#%"); client_sock->sendTextMessage("TI#4#3#0#%");
// Set the BG to default (also breaks up the message queue) // 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 // Stop the wait packet timer
timer->stop(); timer->stop();
@ -432,7 +420,7 @@ void DemoServer::playback()
while (!current_packet.startsWith("wait#")) while (!current_packet.startsWith("wait#"))
{ {
client_sock->write(current_packet.toUtf8()); client_sock->sendTextMessage(current_packet.toUtf8());
if (demo_data.isEmpty()) if (demo_data.isEmpty())
{ {
break; break;
@ -478,15 +466,15 @@ void DemoServer::playback()
timer->start(duration); timer->start(duration);
if (debug_mode) if (debug_mode)
{ {
client_sock->write("TI#4#2#%"); client_sock->sendTextMessage("TI#4#2#%");
QString debug_timer = "TI#4#0#" + QString::number(duration) + "#%"; QString debug_timer = "TI#4#0#" + QString::number(duration) + "#%";
client_sock->write(debug_timer.toUtf8()); client_sock->sendTextMessage(debug_timer.toUtf8());
} }
} }
else 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#%"; 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); timer->setInterval(0);
} }
} }

View File

@ -7,9 +7,9 @@
#include <QMessageBox> #include <QMessageBox>
#include <QObject> #include <QObject>
#include <QQueue> #include <QQueue>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTimer> #include <QTimer>
#include <QWebSocket>
#include <QWebSocketServer>
class DemoServer : public QObject class DemoServer : public QObject
{ {
@ -27,8 +27,8 @@ private:
int m_port = 0; int m_port = 0;
int m_max_wait = -1; int m_max_wait = -1;
QTcpServer *tcp_server; QWebSocketServer *server;
QTcpSocket *client_sock = nullptr; QWebSocket *client_sock = nullptr;
bool client_connected = false; bool client_connected = false;
bool partial_packet = false; bool partial_packet = false;
bool debug_mode = false; bool debug_mode = false;
@ -48,7 +48,7 @@ private:
private Q_SLOTS: private Q_SLOTS:
void accept_connection(); void accept_connection();
void destroy_connection(); void destroy_connection();
void recv_data(); void recv_data(const QString &in_data);
void client_disconnect(); void client_disconnect();
void playback(); void playback();

View File

@ -238,8 +238,7 @@ void Lobby::on_add_server_to_fave_released()
void Lobby::on_edit_favorite_released() void Lobby::on_edit_favorite_released()
{ {
const int index = get_selected_server(); const int index = get_selected_server();
ServerEditorDialog dialog; ServerEditorDialog dialog(Options::getInstance().favorites().at(index));
dialog.loadServerInfo(Options::getInstance().favorites().at(index));
if (dialog.exec()) if (dialog.exec())
{ {
Options::getInstance().updateFavorite(dialog.currentServerInfo(), index); 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()); 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(); ao_app->demo_server->start_server();
ServerInfo demo_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(); demo_server.port = ao_app->demo_server->port();
ao_app->demo_server->set_demo_file(l_filepath); ao_app->demo_server->set_demo_file(l_filepath);
net_manager->connect_to_server(demo_server); net_manager->connect_to_server(demo_server);
@ -462,7 +461,22 @@ void Lobby::list_servers()
{ {
QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_serverlist_tree); QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_serverlist_tree);
treeItem->setData(0, Qt::DisplayRole, i); 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++; i++;
} }
ui_serverlist_tree->setSortingEnabled(true); ui_serverlist_tree->setSortingEnabled(true);
@ -480,7 +494,22 @@ void Lobby::list_favorites()
{ {
QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_favorites_tree); QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_favorites_tree);
treeItem->setData(0, Qt::DisplayRole, i); 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++; i++;
} }
ui_favorites_tree->setSortingEnabled(true); ui_favorites_tree->setSortingEnabled(true);

View File

@ -1,5 +0,0 @@
#include "netconnection.h"
NetConnection::NetConnection(QObject *parent)
: QObject(parent)
{}

View File

@ -1,28 +0,0 @@
#pragma once
#include "aopacket.h"
#include "datatypes.h"
#include <QObject>
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);
};

View File

@ -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<QAbstractSocket::SocketError>::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));
}
}

View File

@ -1,31 +0,0 @@
#pragma once
#include "aopacket.h"
#include "datatypes.h"
#include "netconnection.h"
#include <QTcpSocket>
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();
};

View File

@ -1,32 +0,0 @@
#pragma once
#include "netconnection.h"
class NetworkManager;
#include <QWebSocket>
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);
};

View File

@ -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);
}

15
src/network/serverinfo.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include <QString>
class ServerInfo
{
public:
QString name;
QString description;
QString address;
quint16 port = 0;
bool legacy = false;
QString toString() const;
};

View File

@ -1,48 +1,48 @@
#include "netwebsocketconnection.h" #include "websocketconnection.h"
#include "networkmanager.h" #include "aoapplication.h"
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QUrl> #include <QUrl>
NetWebSocketConnection::NetWebSocketConnection(NetworkManager *networkManager) WebSocketConnection::WebSocketConnection(AOApplication *ao_app, QObject *parent)
: NetConnection(networkManager) : QObject(parent)
, m_network_manager(networkManager) , ao_app(ao_app)
, m_socket(new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this)) , m_socket(new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this))
, m_last_state(QAbstractSocket::UnconnectedState) , m_last_state(QAbstractSocket::UnconnectedState)
{ {
connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, &NetWebSocketConnection::onError); connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, &WebSocketConnection::onError);
connect(m_socket, &QWebSocket::stateChanged, this, &NetWebSocketConnection::onStateChanged); connect(m_socket, &QWebSocket::stateChanged, this, &WebSocketConnection::onStateChanged);
connect(m_socket, &QWebSocket::textMessageReceived, this, &NetWebSocketConnection::onTextMessageReceived); connect(m_socket, &QWebSocket::textMessageReceived, this, &WebSocketConnection::onTextMessageReceived);
} }
NetWebSocketConnection::~NetWebSocketConnection() WebSocketConnection::~WebSocketConnection()
{ {
m_socket->disconnect(this); m_socket->disconnect(this);
disconnectFromServer(); disconnectFromServer();
} }
bool NetWebSocketConnection::isConnected() bool WebSocketConnection::isConnected()
{ {
return m_last_state == QAbstractSocket::ConnectedState; return m_last_state == QAbstractSocket::ConnectedState;
} }
void NetWebSocketConnection::connectToServer(ServerInfo &server) void WebSocketConnection::connectToServer(const ServerInfo &server)
{ {
disconnectFromServer(); disconnectFromServer();
QUrl url; QUrl url;
url.setScheme("ws"); url.setScheme("ws");
url.setHost(server.ip); url.setHost(server.address);
url.setPort(server.port); url.setPort(server.port);
QNetworkRequest req(url); 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); m_socket->open(req);
} }
void NetWebSocketConnection::disconnectFromServer() void WebSocketConnection::disconnectFromServer()
{ {
if (isConnected()) 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)); m_socket->sendTextMessage(packet.toString(true));
} }
void NetWebSocketConnection::onError() void WebSocketConnection::onError()
{ {
Q_EMIT errorOccurred(m_socket->errorString()); Q_EMIT errorOccurred(m_socket->errorString());
} }
void NetWebSocketConnection::onStateChanged(QAbstractSocket::SocketState state) void WebSocketConnection::onStateChanged(QAbstractSocket::SocketState state)
{ {
m_last_state = state; m_last_state = state;
switch (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("#%")) if (!message.endsWith("#%"))
{ {

View File

@ -0,0 +1,43 @@
#pragma once
#include "aopacket.h"
#include "serverinfo.h"
#include <QObject>
#include <QWebSocket>
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);
};

View File

@ -3,8 +3,6 @@
#include "datatypes.h" #include "datatypes.h"
#include "debug_functions.h" #include "debug_functions.h"
#include "lobby.h" #include "lobby.h"
#include "net/nettcpconnection.h"
#include "net/netwebsocketconnection.h"
#include "options.h" #include "options.h"
#include <QAbstractSocket> #include <QAbstractSocket>
@ -59,19 +57,19 @@ void NetworkManager::ms_request_finished(QNetworkReply *reply)
{ {
const auto entry = entryRef.toObject(); const auto entry = entryRef.toObject();
ServerInfo server; ServerInfo server;
server.ip = entry["ip"].toString(); server.address = entry["ip"].toString();
server.name = entry["name"].toString(); server.name = entry["name"].toString();
server.description = entry["description"].toString(tr("No description provided.")); 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(); server.port = entry["ws_port"].toInt();
} }
else else
{ {
server.socket_type = TcpServerConnection;
server.port = entry["port"].toInt(); server.port = entry["port"].toInt();
server.legacy = true;
} }
if (server.port != 0) if (server.port != 0)
{ {
server_list.append(server); server_list.append(server);
@ -149,27 +147,12 @@ void NetworkManager::connect_to_server(ServerInfo server)
disconnect_from_server(); disconnect_from_server();
qInfo().noquote() << QObject::tr("Connecting to %1").arg(server.toString()); qInfo().noquote() << QObject::tr("Connecting to %1").arg(server.toString());
switch (server.socket_type) m_connection = new WebSocketConnection(ao_app, this);
{
default:
server.socket_type = TcpServerConnection;
[[fallthrough]];
case TcpServerConnection: connect(m_connection, &WebSocketConnection::connectedToServer, this, [] { qInfo() << "Established connection to server."; });
qInfo() << "Using TCP backend."; connect(m_connection, &WebSocketConnection::disconnectedFromServer, ao_app, &AOApplication::server_disconnected);
m_connection = new NetTcpConnection(this); connect(m_connection, &WebSocketConnection::errorOccurred, this, [](QString error) { qCritical() << "Connection error:" << error; });
break; connect(m_connection, &WebSocketConnection::receivedPacket, this, &NetworkManager::handle_server_packet);
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);
m_connection->connectToServer(server); m_connection->connectToServer(server);
} }

View File

@ -2,7 +2,7 @@
#include "aoapplication.h" #include "aoapplication.h"
#include "aopacket.h" #include "aopacket.h"
#include "net/netconnection.h" #include "network/websocketconnection.h"
#include <QDnsLookup> #include <QDnsLookup>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
@ -50,7 +50,7 @@ private:
AOApplication *ao_app; AOApplication *ao_app;
QNetworkAccessManager *http; QNetworkAccessManager *http;
NetConnection *m_connection = nullptr; WebSocketConnection *m_connection = nullptr;
QTimer *heartbeat_timer; QTimer *heartbeat_timer;

View File

@ -668,11 +668,19 @@ QVector<ServerInfo> Options::favorites()
{ {
ServerInfo f_server; ServerInfo f_server;
favorite.beginGroup(group); 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.port = favorite.value("port", 27016).toInt();
f_server.name = favorite.value("name", "Missing Name").toString(); f_server.name = favorite.value("name", "Missing Name").toString();
f_server.description = favorite.value("desc", "No description").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)); serverlist.append(std::move(f_server));
favorite.endGroup(); favorite.endGroup();
} }
@ -688,18 +696,10 @@ void Options::setFavorites(QVector<ServerInfo> value)
auto fav_server = value.at(i); auto fav_server = value.at(i);
favorite.beginGroup(QString::number(i)); favorite.beginGroup(QString::number(i));
favorite.setValue("name", fav_server.name); 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("port", fav_server.port);
favorite.setValue("desc", fav_server.description); favorite.setValue("desc", fav_server.description);
favorite.setValue("legacy", fav_server.legacy);
if (fav_server.socket_type == TcpServerConnection)
{
favorite.setValue("protocol", "tcp");
}
else
{
favorite.setValue("protocol", "ws");
}
favorite.endGroup(); favorite.endGroup();
} }
favorite.sync(); favorite.sync();
@ -717,17 +717,10 @@ void Options::addFavorite(ServerInfo server)
int index = favorites().size(); int index = favorites().size();
favorite.beginGroup(QString::number(index)); favorite.beginGroup(QString::number(index));
favorite.setValue("name", server.name); favorite.setValue("name", server.name);
favorite.setValue("address", server.ip); favorite.setValue("address", server.address);
favorite.setValue("port", server.port); favorite.setValue("port", server.port);
favorite.setValue("desc", server.description); favorite.setValue("desc", server.description);
if (server.socket_type == TcpServerConnection) favorite.setValue("legacy", server.legacy);
{
favorite.setValue("protocol", "tcp");
}
else
{
favorite.setValue("protocol", "ws");
}
favorite.endGroup(); favorite.endGroup();
favorite.sync(); favorite.sync();
} }
@ -736,17 +729,10 @@ void Options::updateFavorite(ServerInfo server, int index)
{ {
favorite.beginGroup(QString::number(index)); favorite.beginGroup(QString::number(index));
favorite.setValue("name", server.name); favorite.setValue("name", server.name);
favorite.setValue("address", server.ip); favorite.setValue("address", server.address);
favorite.setValue("port", server.port); favorite.setValue("port", server.port);
favorite.setValue("desc", server.description); favorite.setValue("desc", server.description);
if (server.socket_type == TcpServerConnection) favorite.setValue("legacy", server.legacy);
{
favorite.setValue("protocol", "tcp");
}
else
{
favorite.setValue("protocol", "ws");
}
favorite.endGroup(); favorite.endGroup();
favorite.sync(); favorite.sync();
} }

View File

@ -1,8 +1,9 @@
#pragma once #pragma once
#include "network/serverinfo.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QSettings> #include <QSettings>
#include <datatypes.h>
class Options class Options
{ {

View File

@ -132,7 +132,7 @@ void AOApplication::server_packet_received(AOPacket packet)
{ {
auto info = server_list.at(selected_server); auto info = server_list.at(selected_server);
server_name = info.name; 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; window_title = server_name;
} }
break; break;
@ -144,7 +144,7 @@ void AOApplication::server_packet_received(AOPacket packet)
{ {
auto info = favorite_list.at(selected_server); auto info = favorite_list.at(selected_server);
server_name = info.name; 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; window_title = server_name;
} }
} }

View File

@ -50,27 +50,29 @@ void DirectConnectDialog::onConnectPressed()
QString l_hostname = ui_direct_hostname_edit->text(); QString l_hostname = ui_direct_hostname_edit->text();
if (!SCHEME_PATTERN.match(l_hostname).hasMatch()) if (!SCHEME_PATTERN.match(l_hostname).hasMatch())
{ {
l_hostname = "tcp://" % l_hostname; l_hostname = "ws://" % l_hostname;
} }
QUrl l_url(l_hostname); QUrl l_url(l_hostname);
if (!l_url.isValid()) if (!l_url.isValid())
{ {
call_error(tr("Invalid URL.")); call_error(tr("Invalid URL."));
return; 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; return;
} }
if (l_url.port() == -1) if (l_url.port() == -1)
{ {
call_error(tr("Invalid server port.")); call_error(tr("Invalid server port."));
return; return;
} }
ServerInfo l_server; ServerInfo l_server;
l_server.socket_type = SERVER_CONNECTION_TYPE_STRING_MAP[l_url.scheme()]; l_server.address = l_url.host();
l_server.ip = l_url.host();
l_server.port = l_url.port(); l_server.port = l_url.port();
l_server.name = "Direct Connection"; l_server.name = "Direct Connection";

View File

@ -1,6 +1,7 @@
#include "server_editor_dialog.h" #include "server_editor_dialog.h"
#include "datatypes.h" #include "datatypes.h"
#include "debug_functions.h"
#include "gui_utils.h" #include "gui_utils.h"
#include "options.h" #include "options.h"
@ -30,7 +31,6 @@ ServerEditorDialog::ServerEditorDialog(QWidget *parent)
FROM_UI(QLineEdit, name); FROM_UI(QLineEdit, name);
FROM_UI(QLineEdit, hostname); FROM_UI(QLineEdit, hostname);
FROM_UI(QSpinBox, port); FROM_UI(QSpinBox, port);
FROM_UI(QComboBox, protocol);
FROM_UI(QPlainTextEdit, description); FROM_UI(QPlainTextEdit, description);
FROM_UI(QDialogButtonBox, button_box); FROM_UI(QDialogButtonBox, button_box);
@ -43,52 +43,35 @@ ServerEditorDialog::ServerEditorDialog(QWidget *parent)
connect(ui_button_box, &QDialogButtonBox::rejected, this, &ServerEditorDialog::reject); 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 ServerEditorDialog::currentServerInfo() const
{ {
ServerInfo server; ServerInfo server;
server.name = ui_name->text(); server.name = ui_name->text();
server.ip = ui_hostname->text(); server.address = ui_hostname->text();
server.port = ui_port->value(); server.port = ui_port->value();
server.description = ui_description->toPlainText(); server.description = ui_description->toPlainText();
server.socket_type = ServerConnectionType(ui_protocol->currentIndex());
return server; 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() void ServerEditorDialog::parseLegacyEntry()
{ {
QStringList entry = ui_legacy_edit->text().split(":"); QStringList entry = ui_legacy_edit->text().split(":");
ServerInfo l_server_entry; if (entry.size() < 3)
if (entry.isEmpty())
{ {
qDebug() << "Legacy entry empty."; call_error("Invalid legacy server entry");
return; return;
} }
int item_count = entry.size(); ui_hostname->setText(entry.at(0));
if (item_count >= 3) ui_port->setValue(entry.at(1).toInt());
{ ui_name->setText(entry.at(2));
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);
}
}
}
} }

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "datatypes.h" #include "network/serverinfo.h"
#include <QComboBox> #include <QComboBox>
#include <QDialog> #include <QDialog>
@ -21,8 +21,6 @@ public:
ServerInfo currentServerInfo() const; ServerInfo currentServerInfo() const;
void loadServerInfo(ServerInfo server);
private: private:
static const QString UI_FILE_PATH; static const QString UI_FILE_PATH;
@ -31,7 +29,6 @@ private:
QLineEdit *ui_name; QLineEdit *ui_name;
QLineEdit *ui_hostname; QLineEdit *ui_hostname;
QSpinBox *ui_port; QSpinBox *ui_port;
QComboBox *ui_protocol;
QPlainTextEdit *ui_description; QPlainTextEdit *ui_description;
QDialogButtonBox *ui_button_box; QDialogButtonBox *ui_button_box;