#include "BeltTearingPresenter.h" #include "IVrTCPClient.h" #include "PathManager.h" #include "VrLog.h" #include #include #include #include #include #include #include #include #include #include #include #include "widgets/DeviceStatusWidget.h" #include "VrDateUtils.h" #include 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(); 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); } // 连接到所有服务器 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; } IVrTCPClient *client = m_tcpClients[targetServerName]; // 连接服务器 - 启用TCP客户端自动重连 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); 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; } } else { // 断开指定服务器连接 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; 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_statusUpdate) { m_statusUpdate->OnDeviceStatusChanged(serverName, static_cast(DeviceStatus::Online)); 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_statusUpdate) { m_statusUpdate->OnDeviceStatusChanged(serverName, static_cast(DeviceStatus::Offline)); 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(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); // 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) { // 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(completeData.size())) { LOG_ERROR("Incomplete packet: expected %d+5, got %d bytes\n", dataSize, completeData.size()); return; } QByteArray payloadData = completeData.mid(5, dataSize); // 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(ByteDataType::Text)) { // 处理文本数据 QString textData = QString::fromUtf8(payloadData); // 解析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(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; } // 通知上层处理结果 if (m_statusUpdate) { tearResult.serverName = serverName; tearResult.timestamp = QDateTime::currentDateTime(); m_statusUpdate->OnTearingResult(tearResult); } } void BeltTearingPresenter::handleTcpLinkStatus(const QString &serverName, bool connected) { m_connectionStatus[serverName] = connected; if (connected) { onConnected(serverName); } else { onDisconnected(serverName); } }