GrabBag/App/BeltTearing/BeltTearingApp/Presenter/Src/BeltTearingPresenter.cpp

411 lines
13 KiB
C++
Raw Normal View History

#include "BeltTearingPresenter.h"
2025-09-18 23:49:32 +08:00
#include "IVrTCPClient.h"
#include "PathManager.h"
#include "VrLog.h"
#include <QDebug>
#include <QTimer>
#include <QMetaObject>
#include <QImage>
#include <QBuffer>
#include <QVariant>
#include <QSettings>
#include <QDir>
2025-08-31 21:08:28 +08:00
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include "widgets/DeviceStatusWidget.h"
#include "VrDateUtils.h"
#include <thread>
BeltTearingPresenter::BeltTearingPresenter(QWidget* parent)
: QWidget(parent)
, m_config(nullptr)
{
// 创建配置实例
IVrBeltTearingConfig::CreateInstance(&m_config);
}
BeltTearingPresenter::~BeltTearingPresenter()
{
disconnectFromServer();
2025-09-18 23:49:32 +08:00
// 删除所有TCP客户端
for (auto it = m_tcpClients.begin(); it != m_tcpClients.end(); ++it) {
2025-09-18 23:49:32 +08:00
IVrTCPClient::DestroyInstance(it.value());
}
m_tcpClients.clear();
2025-09-18 23:49:32 +08:00
if (m_config) {
delete m_config;
m_config = nullptr;
}
}
void BeltTearingPresenter::Init()
{
QString configPath = PathManager::GetConfigFilePath();
2025-08-31 21:08:28 +08:00
bool result = initializeConfig(configPath);
if (!result) {
// Even if config loading fails, we should notify the UI about the number of images to show (0)
if(m_statusUpdate){
m_statusUpdate->OnNeedShowImageCount(QStringList());
}
LOG_DEBUG("Init config finished with no configuration\n");
} else {
LOG_DEBUG("Init config finish \n");
}
}
bool BeltTearingPresenter::initializeConfig(const QString &configPath)
{
if (!m_config) {
LOG_WARNING("Config instance is null");
return false;
}
BeltTearingConfigResult configResult = m_config->LoadConfig(configPath.toStdString());
if (configResult.servers.empty()) {
2025-08-31 21:08:28 +08:00
LOG_WARNING("Failed to load config from: %s \n", configPath.toStdString().c_str());
return false;
}
// 获取所有服务器配置
const auto &servers = configResult.servers;
if (servers.empty()) {
LOG_WARNING("No servers configured");
return false;
}
// 清空现有配置
m_serverInfos.clear();
// 存储所有启用的服务器信息
QList<DeviceInfo> devices;
2025-09-18 23:49:32 +08:00
QStringList deviceAliases;
for (const auto &server : servers) {
2025-08-31 21:08:28 +08:00
QString serverAliaseName = QString("%1_%2").arg(QString::fromStdString(server.name)).arg(CVrDateUtils::GetTimestamp());
m_serverInfos[serverAliaseName] = server;
// 添加到设备列表
2025-08-31 21:08:28 +08:00
devices.append(DeviceInfo(QString::fromStdString(server.name), serverAliaseName, QString::fromStdString(server.ip), DeviceStatus::Offline, true));
2025-09-18 23:49:32 +08:00
deviceAliases.append(serverAliaseName);
2025-08-31 21:08:28 +08:00
LOG_DEBUG("Server configured: %s %s:%d \n", serverAliaseName.toStdString().c_str(), server.ip.c_str(), server.port);
}
2025-08-31 21:08:28 +08:00
LOG_DEBUG("Init config finish. Found %d enabled servers \n", m_serverInfos.size());
if(m_statusUpdate){
m_statusUpdate->OnNeedShowImageCount(deviceAliases);
}
2025-09-18 23:49:32 +08:00
// 连接到所有服务器
2025-09-18 23:49:32 +08:00
for(size_t i = 0 ; i < devices.size() ; i++){
connectToServer(servers[i], deviceAliases[i]);
}
2025-08-31 21:08:28 +08:00
if (m_serverInfos.empty()) {
LOG_WARNING("No enabled servers found\n");
return false;
}
LOG_DEBUG("Config loaded successfully. Found %d enabled servers\n", m_serverInfos.size());
return true;
}
bool BeltTearingPresenter::connectToServer(const ServerInfo &serverInfo, const QString &serverName)
{
QString targetServerName = serverName;
// 创建TCP客户端如果不存在
if (!m_tcpClients.contains(targetServerName)) {
2025-09-18 23:49:32 +08:00
IVrTCPClient *client = IVrTCPClient::CreateInstance();
if (!client) {
LOG_ERROR("Failed to create TCP client for %s", targetServerName.toStdString().c_str());
return false;
}
m_tcpClients[targetServerName] = client;
2025-09-18 23:49:32 +08:00
m_connectionStatus[targetServerName] = false;
}
2025-09-18 23:49:32 +08:00
IVrTCPClient *client = m_tcpClients[targetServerName];
// 连接服务器 - 启用TCP客户端自动重连
2025-09-18 23:49:32 +08:00
int linkResult = client->LinkDevice(serverInfo.ip, serverInfo.port, true, // 启用自动重连
[this, targetServerName](IVrTCPClient* pClient, bool connected, void* pParam) {
LOG_DEBUG("connectToServer %s link status : %d \n", targetServerName.toStdString().c_str(), connected);
2025-09-18 23:49:32 +08:00
this->handleTcpLinkStatus(targetServerName, connected);
}, this
);
LOG_DEBUG("connectToServer %s ret : %d \n", targetServerName.toStdString().c_str(), linkResult);
// 启动工作线程
int workResult = client->StartWork(
[this, targetServerName](IVrTCPClient* pClient, const char* pData, const int nLen, void* pParam) {
this->handleTcpDataReceived(targetServerName, pData, nLen);
}, this
);
if (workResult != 0) {
LOG_ERROR("Failed to start TCP client work thread for %s", targetServerName.toStdString().c_str());
return false;
}
if (linkResult != 0) {
LOG_ERROR("Failed to initiate connection to %s", targetServerName.toStdString().c_str());
2025-09-18 23:49:32 +08:00
return false;
}
2025-09-18 23:49:32 +08:00
return true;
}
void BeltTearingPresenter::disconnectFromServer(const QString &serverName)
{
if (serverName.isEmpty()) {
// 断开所有连接
for (auto it = m_tcpClients.begin(); it != m_tcpClients.end(); ++it) {
2025-09-18 23:49:32 +08:00
it.value()->CloseDevice();
m_connectionStatus[it.key()] = false;
}
} else {
// 断开指定服务器连接
2025-09-18 23:49:32 +08:00
if (m_tcpClients.contains(serverName)) {
m_tcpClients[serverName]->CloseDevice();
m_connectionStatus[serverName] = false;
}
}
}
bool BeltTearingPresenter::isConnected(const QString &serverName) const
{
if(serverName.isEmpty()) return false;
2025-09-18 23:49:32 +08:00
QString targetServerName = serverName;
2025-09-18 23:49:32 +08:00
if (m_connectionStatus.contains(targetServerName)) {
return m_connectionStatus[targetServerName];
}
2025-09-18 23:49:32 +08:00
return false;
}
bool BeltTearingPresenter::sendData(const QByteArray &data, const QString &serverName)
{
if(serverName.isEmpty()) return false;
QString targetServerName = serverName;
2025-09-18 23:49:32 +08:00
if (!isConnected(targetServerName)) {
LOG_ERROR("Not connected to server: %s", targetServerName.toStdString().c_str());
return false;
}
2025-09-18 23:49:32 +08:00
if (data.isEmpty()) {
LOG_ERROR("Empty data to send");
return false;
}
2025-09-18 23:49:32 +08:00
if (!m_tcpClients.contains(targetServerName)) {
LOG_ERROR("Server client not found: %s", targetServerName.toStdString().c_str());
2025-09-18 23:49:32 +08:00
return false;
}
2025-09-18 23:49:32 +08:00
bool success = m_tcpClients[targetServerName]->SendData(data.constData(), data.size());
if (!success) {
LOG_ERROR("Failed to send data to %s", targetServerName.toStdString().c_str());
}
2025-09-18 23:49:32 +08:00
return success;
}
QStringList BeltTearingPresenter::getServerNames() const
{
return m_serverInfos.keys();
}
QString BeltTearingPresenter::getServerIp(const QString &serverName) const
{
if (m_serverInfos.contains(serverName)) {
return QString::fromStdString(m_serverInfos[serverName].ip);
}
return QString();
}
quint16 BeltTearingPresenter::getServerPort(const QString &serverName) const
{
if (m_serverInfos.contains(serverName)) {
return m_serverInfos[serverName].port;
}
return 0;
}
QString BeltTearingPresenter::getServerDisplayName(const QString &serverName) const
{
if (m_serverInfos.contains(serverName)) {
return QString::fromStdString(m_serverInfos[serverName].name);
}
return QString();
}
void BeltTearingPresenter::onConnected(const QString &serverName)
{
// 通知主界面设备状态变更
2025-09-18 23:49:32 +08:00
if (m_statusUpdate) {
m_statusUpdate->OnDeviceStatusChanged(serverName, static_cast<int>(DeviceStatus::Online));
2025-09-18 23:49:32 +08:00
m_statusUpdate->OnServerConnected(serverName);
m_statusUpdate->OnWorkStatusChanged(BeltTearingWorkStatus::Ready);
m_statusUpdate->OnStatusUpdate(QString("TCP客户端 %1 连接成功").arg(serverName));
}
}
void BeltTearingPresenter::onDisconnected(const QString &serverName)
{
// 通知主界面设备状态变更
2025-09-18 23:49:32 +08:00
if (m_statusUpdate) {
m_statusUpdate->OnDeviceStatusChanged(serverName, static_cast<int>(DeviceStatus::Offline));
2025-09-18 23:49:32 +08:00
m_statusUpdate->OnServerDisconnected(serverName);
m_statusUpdate->OnWorkStatusChanged(BeltTearingWorkStatus::Disconnected);
m_statusUpdate->OnStatusUpdate(QString("TCP客户端 %1 连接断开").arg(serverName));
}
}
void BeltTearingPresenter::onTcpError(const QString &serverName, const QString &error)
{
// 通知主界面设备状态变更和错误信息
if (m_statusUpdate) {
m_statusUpdate->OnDeviceStatusChanged(serverName, static_cast<int>(DeviceStatus::Error));
m_statusUpdate->OnWorkStatusChanged(BeltTearingWorkStatus::Error);
m_statusUpdate->OnErrorOccurred(QString("TCP客户端 %1 错误: %2").arg(serverName, error));
}
}
void BeltTearingPresenter::handleTcpDataReceived(const QString &serverName, const char* pData, const int nLen)
{
if (!pData || nLen <= 0) return;
// 将新数据添加到缓存
m_dataBuffers[serverName].append(pData, nLen);
// 检查是否有完整的数据包
QByteArray &buffer = m_dataBuffers[serverName];
const QByteArray endMarker = "___END___\r\n";
int endPos = buffer.indexOf(endMarker);
while (endPos != -1) {
// 找到完整数据包
QByteArray completePacket = buffer.left(endPos);
2025-09-24 22:36:13 +08:00
// LOG_DEBUG("Found complete packet for %s: size=%d\n", serverName.toStdString().c_str(), completePacket.size());
// 处理完整数据包
processCompletePacket(serverName, completePacket);
// 从缓存中移除已处理的数据(包括结束标记)
buffer.remove(0, endPos + endMarker.length());
// 检查缓存中是否还有其他完整数据包
endPos = buffer.indexOf(endMarker);
}
// 如果缓存过大,清空以避免内存问题
if (buffer.size() > 1024 * 1024) { // 1MB 限制
LOG_WARNING("Buffer too large for %s, clearing buffer\n", serverName.toStdString().c_str());
buffer.clear();
}
}
void BeltTearingPresenter::processCompletePacket(const QString &serverName, const QByteArray &completeData)
{
2025-09-24 22:36:13 +08:00
// LOG_DEBUG("Processing complete packet from %s: size=%d\n", serverName.toStdString().c_str(), completeData.size());
// 解析数据包协议头
if (completeData.size() < 5) {
LOG_ERROR("Packet too small: %d bytes\n", completeData.size());
return;
}
quint8 dataType;
quint32 dataSize;
QDataStream stream(completeData);
stream.setByteOrder(QDataStream::BigEndian);
stream >> dataType >> dataSize;
// 验证数据包完整性
if (dataSize + 5 > static_cast<quint32>(completeData.size())) {
LOG_ERROR("Incomplete packet: expected %d+5, got %d bytes\n", dataSize, completeData.size());
return;
}
QByteArray payloadData = completeData.mid(5, dataSize);
2025-09-24 22:36:13 +08:00
// LOG_DEBUG("Parsed packet: dataType=%d, dataSize=%d, payload_size=%d\n", dataType, dataSize, payloadData.size());
BeltTearingResult tearResult;
tearResult.bImageValid = false;
if (dataType == static_cast<int>(ByteDataType::Text))
{
// 处理文本数据
QString textData = QString::fromUtf8(payloadData);
2025-08-31 21:08:28 +08:00
// 解析JSON数据
QJsonDocument doc = QJsonDocument::fromJson(textData.toUtf8());
if (!doc.isNull()) {
if (doc.isObject()) {
// 处理单个撕裂数据对象
QJsonObject jsonObj = doc.object();
tearResult.bResultVaild = true;
tearResult.result.push_back(TearingData::fromJsonObject(jsonObj));
} else if (doc.isArray()) {
// 处理撕裂数据数组
QJsonArray jsonArray = doc.array();
if (!jsonArray.isEmpty()) {
for (const QJsonValue &value : jsonArray) {
if (value.isObject()) {
tearResult.result.push_back(TearingData::fromJsonObject(value.toObject()));
}
}
tearResult.bResultVaild = !tearResult.result.empty();
}
}
}
}
else if (dataType == static_cast<int>(ByteDataType::Image))
{
// 处理图像数据
if (tearResult.image.loadFromData(payloadData)) {
tearResult.bImageValid = true;
} else {
LOG_ERROR("Failed to load image from data\n");
}
}
else
{
LOG_ERROR("Unknown data type %d\n", dataType);
return;
}
2025-09-18 23:49:32 +08:00
// 通知上层处理结果
2025-09-18 23:49:32 +08:00
if (m_statusUpdate) {
tearResult.serverName = serverName;
tearResult.timestamp = QDateTime::currentDateTime();
m_statusUpdate->OnTearingResult(tearResult);
2025-09-18 23:49:32 +08:00
}
}
void BeltTearingPresenter::handleTcpLinkStatus(const QString &serverName, bool connected)
{
m_connectionStatus[serverName] = connected;
if (connected) {
onConnected(serverName);
} else {
onDisconnected(serverName);
}
}