GrabBag/App/BeltTearing/BeltTearingApp/Presenter/Src/BeltTearingPresenter.cpp
2025-09-18 23:49:32 +08:00

429 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "BeltTearingPresenter.h"
#include "IVrTCPClient.h"
#include "PathManager.h"
#include "VrLog.h"
#include <QDebug>
#include <QTimer>
#include <QImage>
#include <QBuffer>
#include <QVariant>
#include <QSettings>
#include <QDir>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#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<DeviceInfo> 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<int>(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<int>(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<QTimer*>(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);
}
}