upload all files

This commit is contained in:
2026-01-07 21:26:28 +08:00
parent 1d35a422ec
commit 6d7544e0a3
17 changed files with 2987 additions and 0 deletions

348
Modules/socketactions.cpp Normal file
View File

@@ -0,0 +1,348 @@
#include "socketactions.h"
#include "Logger.h"
#include <QCoreApplication>
#include <QNetworkInterface>
#include <QEventLoop>
#include <QMutexLocker>
#include <QAbstractSocket>
#include <QDateTime>
#include <string>
namespace sockAct {
struct SocketContext {
std::unique_ptr<QTcpSocket> socket;
QMutex sendMutex;
QMutex connectMutex;
bool isInitialized = false;
std::string lastError;
QHostAddress lastConnectedHost;
quint16 lastConnectedPort = 0;
qint64 lastSendTime = 0;
qint64 lastReceiveTime = 0;
int sendCount = 0;
int receiveCount = 0;
};
static SocketContext& context() { // Static context
static SocketContext ctx;
return ctx;
}
namespace {
bool ensureInitialized();
bool internalConnectToHost(const std::string& host, quint16 port, int timeoutMs);
std::string waitForResponse(int timeoutMs);
void logNetworkEvent(const std::string& message, LogLevel level);
void handleSocketError(QAbstractSocket::SocketError error);
void resetSocket();
QString toQString(const std::string& str);
std::string fromQString(const QString& str);
// Add UTF-8 encoding helper functions
QByteArray stringToUtf8Bytes(const std::string& str);
std::string bytesToUtf8String(const QByteArray& bytes);
}
bool sockInit() {
QMutexLocker locker(&context().connectMutex);
if (context().isInitialized) {
logNetworkEvent("[Socket] Initialization completed.", INFO);
return true;
}
if (!QNetworkInterface::allInterfaces().isEmpty()) { // Check Qt Network Module
logNetworkEvent("[Socket] Qt Networking module initializing completed.", INFO);
} else {
logNetworkEvent("[Socket] No avaliable network interfaces", WARNING);
}
context().isInitialized = true;
logNetworkEvent("[Socket] Initialization completed.", INFO);
return true;
}
bool connectToHost(const std::string& host, quint16 port, int timeoutMs) {
if (!ensureInitialized()) {
return false;
}
QMutexLocker locker(&context().connectMutex);
QString qhost = toQString(host);
if (context().socket &&
context().lastConnectedHost.toString() == qhost &&
context().lastConnectedPort == port) {
if (context().socket->state() == QAbstractSocket::ConnectedState) {
logNetworkEvent(std::string("[Socket] Connected to server: ") + host + ":" + std::to_string(port), INFO);
return true;
}
}
return internalConnectToHost(host, port, timeoutMs);
}
std::string tcpSend(const std::string& data, int timeoutMs) {
if (!ensureInitialized()) {
return std::string();
}
QMutexLocker locker(&context().sendMutex);
if (!context().socket || context().socket->state() != QAbstractSocket::ConnectedState) {
logNetworkEvent("[Socket] No connection avaliable, cannot send any data.", ERROR);
return std::string();
}
// Convert string to UTF-8 bytes for transmission
QByteArray sendData = stringToUtf8Bytes(data);
qint64 bytesWritten = context().socket->write(sendData); // Send data
context().lastSendTime = QDateTime::currentMSecsSinceEpoch();
context().sendCount++;
if (bytesWritten == -1) {
QString errorStr = context().socket->errorString();
logNetworkEvent("[Socket] Failed to send data: " + fromQString(errorStr), ERROR);
return std::string();
}
if (bytesWritten != sendData.size()) {
logNetworkEvent("[Socket] Data send not complete, expected to send " + std::to_string(sendData.size()) +
" bytes, " + std::to_string(bytesWritten) + " bytes sent", WARNING);
}
logNetworkEvent("[Socket] " + std::to_string(bytesWritten) + " bytes has been sent to sevrer", DEBUG);
std::string response = waitForResponse(timeoutMs);
return response;
}
void clearSocket() {
QMutexLocker locker1(&context().connectMutex);
QMutexLocker locker2(&context().sendMutex);
if (context().socket) {
std::string serverInfo;
if (!context().lastConnectedHost.isNull()) {
serverInfo = fromQString(context().lastConnectedHost.toString()) + ":" +
std::to_string(context().lastConnectedPort);
}
logNetworkEvent("[Socket] Disconnecting from server " + serverInfo + "...", INFO);
if (context().socket->state() != QAbstractSocket::UnconnectedState) {
context().socket->abort();
}
context().socket->disconnect();
// Reset connection info
context().lastConnectedHost.clear();
context().lastConnectedPort = 0;
context().lastSendTime = 0;
context().lastReceiveTime = 0;
context().sendCount = 0;
context().receiveCount = 0;
logNetworkEvent("[Socket] Disconnected.", INFO);
}
}
bool isConnected() {
if (!context().socket) {
return false;
}
return context().socket->state() == QAbstractSocket::ConnectedState;
}
std::string getLastError() {
return context().lastError;
}
// ==================== Internal methods ====================
namespace {
QString toQString(const std::string& str) {
return QString::fromStdString(str);
}
std::string fromQString(const QString& str) {
return str.toStdString();
}
// Convert string to UTF-8 bytes
QByteArray stringToUtf8Bytes(const std::string& str) {
// Use QString to convert to UTF-8
QString qstr = QString::fromStdString(str);
return qstr.toUtf8();
}
// Convert UTF-8 bytes to string
std::string bytesToUtf8String(const QByteArray& bytes) {
// Convert from UTF-8 bytes to QString, then to std::string
QString qstr = QString::fromUtf8(bytes);
return qstr.toStdString();
}
bool ensureInitialized() {
if (!context().isInitialized) {
logNetworkEvent("[Socket] Not initialized.", ERROR);
return false;
}
return true;
}
bool internalConnectToHost(const std::string& host, quint16 port, int timeoutMs) {
if (context().socket) {
context().socket->abort();
context().socket.reset();
}
context().socket.reset(new QTcpSocket());
QString qhost = toQString(host);
QObject::connect(context().socket.get(), &QTcpSocket::connected, [host, port]() {
logNetworkEvent("[Socket] Connected to server " + host + ":" + std::to_string(port), INFO);
});
QObject::connect(context().socket.get(), QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred),
[](QAbstractSocket::SocketError error) {
handleSocketError(error);
});
logNetworkEvent("[Socket] Connecting to server " + host + ":" + std::to_string(port) +
" (Timeout: " + std::to_string(timeoutMs) + "ms)...", INFO);
context().socket->connectToHost(qhost, port);
QElapsedTimer timer;
timer.start();
while (context().socket->state() == QAbstractSocket::ConnectingState) {
if (timer.elapsed() > timeoutMs) {
logNetworkEvent("[Socket] Connection to server " + host + ":" + std::to_string(port) + " timeout", WARNING);
context().socket->abort();
return false;
}
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
QThread::msleep(10);
}
if (context().socket->state() != QAbstractSocket::ConnectedState) {
QString errorStr = context().socket->errorString();
logNetworkEvent("[Sockct] Failed to connect to server " + host + ":" + std::to_string(port) +
" Reason: " + fromQString(errorStr), ERROR);
return false;
}
context().lastConnectedHost = context().socket->peerAddress();
context().lastConnectedPort = context().socket->peerPort();
return true;
}
std::string waitForResponse(int timeoutMs) {
if (!context().socket) {
return std::string();
}
QElapsedTimer timer;
timer.start();
while (context().socket->bytesAvailable() == 0) {
if (timer.elapsed() > timeoutMs) {
logNetworkEvent("[Socket] Timeout when waiting for reply (" + std::to_string(timeoutMs) + "ms)", WARNING);
return std::string();
}
if (!context().socket->waitForReadyRead(100)) {
if (context().socket->state() != QAbstractSocket::ConnectedState) {
logNetworkEvent("[Socket] Connection lost.", ERROR);
return std::string();
}
}
}
QByteArray responseData = context().socket->readAll();
context().lastReceiveTime = QDateTime::currentMSecsSinceEpoch();
context().receiveCount++;
// Convert UTF-8 bytes to string
std::string response = bytesToUtf8String(responseData);
int waitTime = timer.elapsed();
logNetworkEvent("[Socket] Reply from server " + std::to_string(responseData.size()) +
" bytes, Time: " + std::to_string(waitTime) + "ms", DEBUG);
return response;
}
void logNetworkEvent(const std::string& message, LogLevel level) {
postLog(message, static_cast<int>(level));
}
void handleSocketError(QAbstractSocket::SocketError error) {
std::string errorMsg;
LogLevel level = ERROR;
switch (error) {
case QAbstractSocket::ConnectionRefusedError:
errorMsg = "[Socket] Connection refused.";
break;
case QAbstractSocket::RemoteHostClosedError:
errorMsg = "[Socket] Remote server closed connection.";
level = WARNING;
break;
case QAbstractSocket::HostNotFoundError:
errorMsg = "[Socket] No host found.";
break;
case QAbstractSocket::SocketAccessError:
errorMsg = "[Socket] Access error.";
break;
case QAbstractSocket::SocketResourceError:
errorMsg = "[Socket] Resource error.";
level = WARNING;
break;
case QAbstractSocket::SocketTimeoutError:
errorMsg = "[Socket] Timeout.";
level = WARNING;
break;
case QAbstractSocket::NetworkError:
errorMsg = "[Socket] Network fatal.";
level = FATAL;
break;
case QAbstractSocket::SslHandshakeFailedError:
errorMsg = "[Socket] TLS handshake error.";
break;
default:
errorMsg = "[Socket] Unknown error.";
break;
}
if (context().socket) {
QString errorStr = context().socket->errorString();
errorMsg += ": " + fromQString(errorStr);
}
logNetworkEvent(errorMsg, level);
context().lastError = errorMsg;
}
void resetSocket() {
if (context().socket) {
context().socket->disconnect();
context().socket.reset();
}
context().lastError.clear();
}
}
} // namespace sockAct