#include "BeltTearingPresenter.h" #include "IVrTCPClient.h" #include "PathManager.h" #include "VrLog.h" #include #include #include #include #include #include #include #include #include #include #include "widgets/DeviceStatusWidget.h" #include "VrDateUtils.h" BeltTearingPresenter::BeltTearingPresenter(QWidget* parent) : QWidget(parent) , m_config(nullptr) { // 创建配置实例 IVrBeltTearingConfig::CreateInstance(&m_config); } BeltTearingPresenter::~BeltTearingPresenter() { disconnectFromServer(); // 删除所有TCP客户端 for (auto it = m_tcpClients.begin(); it != m_tcpClients.end(); ++it) { IVrTCPClient::DestroyInstance(it.value()); } m_tcpClients.clear(); // 删除所有重连定时器 for (auto it = m_reconnectTimers.begin(); it != m_reconnectTimers.end(); ++it) { delete it.value(); } m_reconnectTimers.clear(); if (m_config) { delete m_config; m_config = nullptr; } } void BeltTearingPresenter::Init() { QString configPath = PathManager::GetConfigFilePath(); 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()) { 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 devices; QStringList deviceAliases; for (const auto &server : servers) { QString serverAliaseName = QString("%1_%2").arg(QString::fromStdString(server.name)).arg(CVrDateUtils::GetTimestamp()); m_serverInfos[serverAliaseName] = server; // 添加到设备列表 devices.append(DeviceInfo(QString::fromStdString(server.name), serverAliaseName, QString::fromStdString(server.ip), DeviceStatus::Offline, true)); deviceAliases.append(serverAliaseName); LOG_DEBUG("Server configured: %s %s:%d \n", serverAliaseName.toStdString().c_str(), server.ip.c_str(), server.port); } LOG_DEBUG("Init config finish. Found %d enabled servers \n", m_serverInfos.size()); if(m_statusUpdate){ m_statusUpdate->OnNeedShowImageCount(deviceAliases); } if (m_deviceStatusWidget) { m_deviceStatusWidget->setDevices(devices); } // 连接 for(size_t i = 0 ; i < devices.size() ; i++){ connectToServer(servers[i], deviceAliases[i]); } 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)) { 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; m_connectionStatus[targetServerName] = false; // 创建重连定时器 QTimer *reconnectTimer = new QTimer(this); reconnectTimer->setSingleShot(true); reconnectTimer->setInterval(5000); // 5秒重连间隔 connect(reconnectTimer, &QTimer::timeout, this, &BeltTearingPresenter::onReconnectTimer); m_reconnectTimers[targetServerName] = reconnectTimer; } IVrTCPClient *client = m_tcpClients[targetServerName]; // 连接服务器 int linkResult = client->LinkDevice(serverInfo.ip, serverInfo.port, true, // 启用自动重连 [this, targetServerName](IVrTCPClient* pClient, bool connected, void* pParam) { 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()); return false; } return true; } void BeltTearingPresenter::disconnectFromServer(const QString &serverName) { if (serverName.isEmpty()) { // 断开所有连接 for (auto it = m_tcpClients.begin(); it != m_tcpClients.end(); ++it) { it.value()->CloseDevice(); m_connectionStatus[it.key()] = false; } // 停止所有重连定时器 for (auto it = m_reconnectTimers.begin(); it != m_reconnectTimers.end(); ++it) { it.value()->stop(); } } else { // 断开指定服务器连接 if (m_tcpClients.contains(serverName)) { m_tcpClients[serverName]->CloseDevice(); m_connectionStatus[serverName] = false; } // 停止重连定时器 if (m_reconnectTimers.contains(serverName)) { m_reconnectTimers[serverName]->stop(); } } } bool BeltTearingPresenter::isConnected(const QString &serverName) const { if(serverName.isEmpty()) return false; QString targetServerName = serverName; if (m_connectionStatus.contains(targetServerName)) { return m_connectionStatus[targetServerName]; } return false; } bool BeltTearingPresenter::sendData(const QByteArray &data, const QString &serverName) { if(serverName.isEmpty()) return false; QString targetServerName = serverName; if (!isConnected(targetServerName)) { LOG_ERROR("Not connected to server: %s", targetServerName.toStdString().c_str()); return false; } if (data.isEmpty()) { LOG_ERROR("Empty data to send"); return false; } if (!m_tcpClients.contains(targetServerName)) { LOG_ERROR("Server client not found: %s", targetServerName.toStdString().c_str()); return false; } bool success = m_tcpClients[targetServerName]->SendData(data.constData(), data.size()); if (!success) { LOG_ERROR("Failed to send data to %s", targetServerName.toStdString().c_str()); } 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) { // 更新设备状态为在线 if (m_deviceStatusWidget) { m_deviceStatusWidget->updateDeviceStatus(serverName, DeviceStatus::Online); } // 通知主界面TCP客户端连接成功 if (m_statusUpdate) { m_statusUpdate->OnServerConnected(serverName); m_statusUpdate->OnWorkStatusChanged(BeltTearingWorkStatus::Ready); m_statusUpdate->OnStatusUpdate(QString("TCP客户端 %1 连接成功").arg(serverName)); } } void BeltTearingPresenter::onDisconnected(const QString &serverName) { // 更新设备状态为离线 if (m_deviceStatusWidget) { m_deviceStatusWidget->updateDeviceStatus(serverName, DeviceStatus::Offline); } // 通知主界面TCP客户端连接断开 if (m_statusUpdate) { m_statusUpdate->OnServerDisconnected(serverName); m_statusUpdate->OnWorkStatusChanged(BeltTearingWorkStatus::Disconnected); m_statusUpdate->OnStatusUpdate(QString("TCP客户端 %1 连接断开").arg(serverName)); } } void BeltTearingPresenter::onDataReceived(const QString &serverName, const QByteArray &data) { // 解析数据包 quint8 dataType; quint32 dataSize; QDataStream stream(data); stream.setByteOrder(QDataStream::BigEndian); stream >> dataType >> dataSize; QByteArray byteArray = data.mid(5, dataSize); BeltTearingResult tearResult; tearResult.bImageValid = false; if (dataType == static_cast(ByteDataType::Text)) { // 处理文本数据 QString textData = QString::fromUtf8(byteArray); // 解析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()) { // 遍历数组中的所有对象并添加到tearResult.result中 for (const QJsonValue &value : jsonArray) { if (value.isObject()) { tearResult.result.push_back(TearingData::fromJsonObject(value.toObject())); } } tearResult.bResultVaild = !tearResult.result.empty(); } } } LOG_DEBUG("Received text data from server %s \n", serverName.toStdString().c_str()); } else if (dataType == static_cast(ByteDataType::Image)) { // 处理图像数据 if (tearResult.image.loadFromData(byteArray)) { // 这里可以添加处理图像数据的逻辑 tearResult.bImageValid = true; LOG_DEBUG("Received image data from server %s, size: %dx%d \n", serverName.toStdString().c_str(), tearResult.image.width(), tearResult.image.height()); } } if(m_statusUpdate){ tearResult.serverName = serverName; tearResult.timestamp = QDateTime::currentDateTime(); m_statusUpdate->OnTearingResult(tearResult); } } void BeltTearingPresenter::onTcpError(const QString &serverName, const QString &error) { if (m_deviceStatusWidget) { m_deviceStatusWidget->updateDeviceStatus(serverName, DeviceStatus::Error); } // 通知主界面TCP客户端发生错误 if (m_statusUpdate) { m_statusUpdate->OnWorkStatusChanged(BeltTearingWorkStatus::Error); m_statusUpdate->OnErrorOccurred(QString("TCP客户端 %1 错误: %2").arg(serverName, error)); } } void BeltTearingPresenter::onReconnectTimer() { QTimer *timer = qobject_cast(sender()); if (!timer) return; // 找到对应的服务器名称 QString serverName; for (auto it = m_reconnectTimers.begin(); it != m_reconnectTimers.end(); ++it) { if (it.value() == timer) { serverName = it.key(); break; } } if (serverName.isEmpty()) return; // 如果当前没有连接,尝试重连 if (!isConnected(serverName) && m_serverInfos.contains(serverName)) { const ServerInfo &serverInfo = m_serverInfos[serverName]; LOG_DEBUG("Attempting to reconnect to %s", serverName.toStdString().c_str()); connectToServer(serverInfo, serverName); } } void BeltTearingPresenter::handleTcpDataReceived(const QString &serverName, const char* pData, const int nLen) { if (!pData || nLen <= 0) return; QByteArray data(pData, nLen); onDataReceived(serverName, data); } void BeltTearingPresenter::handleTcpLinkStatus(const QString &serverName, bool connected) { m_connectionStatus[serverName] = connected; if (connected) { // 停止重连定时器 if (m_reconnectTimers.contains(serverName)) { m_reconnectTimers[serverName]->stop(); } onConnected(serverName); } else { // 启动重连定时器 if (m_reconnectTimers.contains(serverName)) { m_reconnectTimers[serverName]->start(); } onDisconnected(serverName); } }