429 lines
14 KiB
C++
429 lines
14 KiB
C++
#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);
|
||
}
|
||
}
|
||
|