Skip to content

Commit cbb41b8

Browse files
SyntaxNyahclaude
andcommitted
Add TCP socket support for DRO servers
DRO servers only advertise a plain port (no ws_port/wss_port), so they were assigned protocol="tcp" but the WebSocket connection rejected the tcp:// URL scheme. This adds raw TCP transport via a new TcpConnection class so DRO servers can be connected to directly. - Add AOConnection abstract base class with shared signals/interface - Add TcpConnection using QTcpSocket with AO packet buffering/parsing - Refactor WebSocketConnection to inherit from AOConnection - NetworkManager picks TcpConnection or WebSocketConnection by protocol - Fix CMakeLists.txt include path for bass.h (moved to lib/bass/ in AttorneyOnline#1112) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 8f501e4 commit cbb41b8

10 files changed

Lines changed: 190 additions & 31 deletions

CMakeLists.txt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ set(CMAKE_AUTOUIC ON)
1212
set(CMAKE_INCLUDE_CURRENT_DIR ON)
1313

1414
option(AO_BUILD_TESTS "Build test programs" ON)
15-
option(AO_ENABLE_DISCORD_RPC "Enable Discord Rich Presence" ON)
15+
option(AO_ENABLE_DISCORD_RPC "Enable Discord Rich Presence" OFF)
1616

1717
find_package(QT NAMES Qt6)
1818
find_package(Qt6 REQUIRED COMPONENTS Core Gui Network Widgets Concurrent WebSockets UiTools)
@@ -64,8 +64,6 @@ qt_add_executable(Attorney_Online
6464
src/debug_functions.h
6565
src/demoserver.cpp
6666
src/demoserver.h
67-
src/discord_rich_presence.cpp
68-
src/discord_rich_presence.h
6967
src/emotes.cpp
7068
src/eventfilters.cpp
7169
src/eventfilters.h
@@ -103,8 +101,18 @@ qt_add_executable(Attorney_Online
103101
src/screenslidetimer.h src/screenslidetimer.cpp
104102
src/moderation_functions.h src/moderation_functions.cpp
105103
src/network/serverinfo.h src/network/serverinfo.cpp
104+
src/network/aoconnection.h src/network/aoconnection.cpp
105+
src/network/tcpconnection.h src/network/tcpconnection.cpp
106106
)
107107

108+
# Conditionally add Discord RPC sources
109+
if(AO_ENABLE_DISCORD_RPC)
110+
target_sources(Attorney_Online PRIVATE
111+
src/discord_rich_presence.cpp
112+
src/discord_rich_presence.h
113+
)
114+
endif()
115+
108116
set_target_properties(Attorney_Online PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")
109117

110118
if(WIN32)
@@ -115,7 +123,7 @@ if(WIN32)
115123
endif()
116124
endif()
117125

118-
target_include_directories(Attorney_Online PRIVATE src lib)
126+
target_include_directories(Attorney_Online PRIVATE src lib lib/bass)
119127
target_link_directories(Attorney_Online PRIVATE lib)
120128
target_link_libraries(Attorney_Online PRIVATE
121129
Qt${QT_VERSION_MAJOR}::Core
@@ -140,4 +148,4 @@ endif()
140148

141149
set_target_properties(Attorney_Online PROPERTIES
142150
LIBRARY_OUTPUT_DIRECTORY $<1:${CMAKE_CURRENT_LIST_DIR}/bin>
143-
RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_CURRENT_LIST_DIR}/bin>)
151+
RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_CURRENT_LIST_DIR}/bin>)

src/network/aoconnection.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include "aoconnection.h"
2+
3+
AOConnection::AOConnection(AOApplication *ao_app, QObject *parent)
4+
: QObject(parent)
5+
, ao_app(ao_app)
6+
{}

src/network/aoconnection.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#pragma once
2+
3+
#include "aopacket.h"
4+
#include "serverinfo.h"
5+
6+
#include <QObject>
7+
8+
class AOApplication;
9+
10+
class AOConnection : public QObject
11+
{
12+
Q_OBJECT
13+
14+
public:
15+
explicit AOConnection(AOApplication *ao_app, QObject *parent = nullptr);
16+
virtual ~AOConnection() = default;
17+
18+
virtual bool isConnected() = 0;
19+
virtual void connectToServer(const ServerInfo &server) = 0;
20+
virtual void disconnectFromServer() = 0;
21+
virtual void sendPacket(AOPacket packet) = 0;
22+
23+
Q_SIGNALS:
24+
void connectedToServer();
25+
void disconnectedFromServer();
26+
void errorOccurred(QString error);
27+
void receivedPacket(AOPacket packet);
28+
29+
protected:
30+
AOApplication *ao_app;
31+
};

src/network/tcpconnection.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#include "tcpconnection.h"
2+
3+
#include "aopacket.h"
4+
5+
TcpConnection::TcpConnection(AOApplication *ao_app, QObject *parent)
6+
: AOConnection(ao_app, parent)
7+
, m_socket(new QTcpSocket(this))
8+
{
9+
connect(m_socket, &QTcpSocket::connected, this, &TcpConnection::onConnected);
10+
connect(m_socket, &QTcpSocket::disconnected, this, &TcpConnection::onDisconnected);
11+
connect(m_socket, &QAbstractSocket::errorOccurred, this, &TcpConnection::onError);
12+
connect(m_socket, &QTcpSocket::readyRead, this, &TcpConnection::onReadyRead);
13+
}
14+
15+
TcpConnection::~TcpConnection()
16+
{
17+
m_socket->disconnect(this);
18+
disconnectFromServer();
19+
}
20+
21+
bool TcpConnection::isConnected()
22+
{
23+
return m_socket->state() == QAbstractSocket::ConnectedState;
24+
}
25+
26+
void TcpConnection::connectToServer(const ServerInfo &server)
27+
{
28+
disconnectFromServer();
29+
m_buffer.clear();
30+
m_socket->connectToHost(server.address, server.port);
31+
}
32+
33+
void TcpConnection::disconnectFromServer()
34+
{
35+
if (isConnected())
36+
{
37+
m_socket->disconnectFromHost();
38+
}
39+
}
40+
41+
void TcpConnection::sendPacket(AOPacket packet)
42+
{
43+
m_socket->write(packet.toString(true).toUtf8());
44+
}
45+
46+
void TcpConnection::onConnected()
47+
{
48+
Q_EMIT connectedToServer();
49+
}
50+
51+
void TcpConnection::onDisconnected()
52+
{
53+
Q_EMIT disconnectedFromServer();
54+
}
55+
56+
void TcpConnection::onError(QAbstractSocket::SocketError error)
57+
{
58+
Q_UNUSED(error);
59+
Q_EMIT errorOccurred(m_socket->errorString());
60+
}
61+
62+
void TcpConnection::onReadyRead()
63+
{
64+
m_buffer += QString::fromUtf8(m_socket->readAll());
65+
66+
while (true)
67+
{
68+
int end = m_buffer.indexOf("#%");
69+
if (end == -1)
70+
{
71+
break;
72+
}
73+
74+
QString message = m_buffer.left(end);
75+
m_buffer = m_buffer.mid(end + 2);
76+
77+
QStringList raw_content = message.split('#');
78+
if (raw_content.isEmpty())
79+
{
80+
continue;
81+
}
82+
const QString header = raw_content.takeFirst();
83+
for (QString &data : raw_content)
84+
{
85+
data = AOPacket::decode(data);
86+
}
87+
88+
Q_EMIT receivedPacket(AOPacket(header, raw_content));
89+
}
90+
}

src/network/tcpconnection.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#pragma once
2+
3+
#include "aoconnection.h"
4+
5+
#include <QTcpSocket>
6+
7+
class TcpConnection : public AOConnection
8+
{
9+
Q_OBJECT
10+
11+
public:
12+
explicit TcpConnection(AOApplication *ao_app, QObject *parent = nullptr);
13+
~TcpConnection() override;
14+
15+
bool isConnected() override;
16+
void connectToServer(const ServerInfo &server) override;
17+
void disconnectFromServer() override;
18+
void sendPacket(AOPacket packet) override;
19+
20+
private:
21+
QTcpSocket *m_socket;
22+
QString m_buffer;
23+
24+
private Q_SLOTS:
25+
void onConnected();
26+
void onDisconnected();
27+
void onError(QAbstractSocket::SocketError error);
28+
void onReadyRead();
29+
};

src/network/websocketconnection.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
#include <QUrl>
77

88
WebSocketConnection::WebSocketConnection(AOApplication *ao_app, QObject *parent)
9-
: QObject(parent)
10-
, ao_app(ao_app)
9+
: AOConnection(ao_app, parent)
1110
, m_socket(new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this))
1211
, m_last_state(QAbstractSocket::UnconnectedState)
1312
{

src/network/websocketconnection.h

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,25 @@
11
#pragma once
22

3-
#include "aopacket.h"
4-
#include "serverinfo.h"
3+
#include "aoconnection.h"
54

6-
#include <QObject>
75
#include <QWebSocket>
86

9-
class AOApplication;
10-
11-
class WebSocketConnection : public QObject
7+
class WebSocketConnection : public AOConnection
128
{
139
Q_OBJECT
1410

1511
public:
1612
explicit WebSocketConnection(AOApplication *ao_app, QObject *parent = nullptr);
17-
virtual ~WebSocketConnection();
18-
19-
bool isConnected();
13+
~WebSocketConnection() override;
2014

21-
void connectToServer(const ServerInfo &server);
22-
void disconnectFromServer();
15+
bool isConnected() override;
2316

24-
void sendPacket(AOPacket packet);
17+
void connectToServer(const ServerInfo &server) override;
18+
void disconnectFromServer() override;
2519

26-
Q_SIGNALS:
27-
void connectedToServer();
28-
void disconnectedFromServer();
29-
void errorOccurred(QString error);
30-
31-
void receivedPacket(AOPacket packet);
20+
void sendPacket(AOPacket packet) override;
3221

3322
private:
34-
AOApplication *ao_app;
35-
3623
QWebSocket *m_socket;
3724
QAbstractSocket::SocketState m_last_state;
3825

src/networkmanager.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include "datatypes.h"
44
#include "debug_functions.h"
55
#include "lobby.h"
6+
#include "network/tcpconnection.h"
7+
#include "network/websocketconnection.h"
68
#include "options.h"
79

810
#include <QAbstractSocket>
@@ -153,7 +155,14 @@ void NetworkManager::connect_to_server(ServerInfo server)
153155
disconnect_from_server();
154156

155157
qInfo().noquote() << QObject::tr("Connecting to %1").arg(server.toString());
156-
m_connection = new WebSocketConnection(ao_app, this);
158+
if (server.protocol == "tcp")
159+
{
160+
m_connection = new TcpConnection(ao_app, this);
161+
}
162+
else
163+
{
164+
m_connection = new WebSocketConnection(ao_app, this);
165+
}
157166

158167
connect(m_connection, &WebSocketConnection::connectedToServer, ao_app, &AOApplication::server_connected);
159168
connect(m_connection, &WebSocketConnection::disconnectedFromServer, ao_app, &AOApplication::server_disconnected);

src/networkmanager.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include "aoapplication.h"
44
#include "aopacket.h"
5-
#include "network/websocketconnection.h"
5+
#include "network/aoconnection.h"
66

77
#include <QDnsLookup>
88
#include <QNetworkAccessManager>
@@ -50,7 +50,7 @@ private Q_SLOTS:
5050
AOApplication *ao_app;
5151
QNetworkAccessManager *http;
5252

53-
WebSocketConnection *m_connection = nullptr;
53+
AOConnection *m_connection = nullptr;
5454

5555
QTimer *heartbeat_timer;
5656

test/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function(ao_declare_test test_id)
1212
message(STATUS "Adding test: ${test_id}")
1313
message(STATUS "Source files: ${ARGN}")
1414
add_executable(${test_id} ${ARGN})
15-
target_include_directories(${test_id} PRIVATE ../src src)
15+
target_include_directories(${test_id} PRIVATE ../src src ../lib/bass)
1616
target_link_directories(${test_id} PRIVATE ../lib)
1717
target_link_libraries(${test_id} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Test)
1818
add_test(NAME ${test_id} COMMAND ${test_id})

0 commit comments

Comments
 (0)