DPS_Manage/FileTransfer.h

211 lines
7.9 KiB
C++
Raw Permalink 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.

#ifndef FILETRANSFER_H
#define FILETRANSFER_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QJsonDocument>
#include <QJsonObject>
#include <QHttpMultiPart>
class FileTransfer : public QObject {
Q_OBJECT
Q_PROPERTY(double downloadProgress READ downloadProgress NOTIFY downloadProgressChanged)
Q_PROPERTY(double uploadProgress READ uploadProgress NOTIFY uploadProgressChanged)
public:
static FileTransfer* instance() {
static FileTransfer _instance;
return &_instance;
}
Q_INVOKABLE void postDownload(const QString& url,
const QString& savePath,
const QVariantMap& postData,
const QString& additionalobj) {
if (m_currentDownload) {
emit downloadCompleted(false, u8"已有进行中的下载");
return;
}
// 获取文件所在的目录路径
QFileInfo fileInfo(savePath);
QString dirPath = fileInfo.absolutePath();
// 检查目录是否存在,如果不存在则创建
QDir dir;
if (!dir.exists(dirPath)) {
if (!dir.mkpath(dirPath)) {
emit downloadCompleted(false, u8"无法创建目录");
cleanup();
return;
}
}
// 创建目标文件
m_downloadFile = new QFile(savePath, this);
if (!m_downloadFile->open(QIODevice::WriteOnly)) {
emit downloadCompleted(false, u8"无法创建文件");
cleanup();
return;
}
QUrl u(url);
// 配置 HTTPS
QNetworkRequest request(u);
QSslConfiguration sslConfig = request.sslConfiguration();
sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone); // 跳过证书验证
request.setSslConfiguration(sslConfig);
// 构建 POST 数据JSON 格式示例)
QJsonDocument jsonDoc(QJsonObject::fromVariantMap (postData));
QByteArray postBody = jsonDoc.toJson();
// 发送请求
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
m_currentDownload = manager.post(request, postBody);
// 连接信号
connect(m_currentDownload, &QNetworkReply::readyRead, [this](){
m_downloadFile->write(m_currentDownload->readAll());
});
connect(m_currentDownload, &QNetworkReply::downloadProgress,
[this,additionalobj](qint64 bytesReceived, qint64 bytesTotal){
m_downloadProgress = bytesTotal > 0
? bytesReceived / (double)bytesTotal
: 0;
emit downloadProgressChanged(m_downloadProgress,additionalobj);
});
connect(m_currentDownload, &QNetworkReply::finished, [this,additionalobj](){
if (m_downloadFile) {
m_downloadFile->flush();
m_downloadFile->close();
}
QVariant statusCodeVariant = m_currentDownload->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (statusCodeVariant.isValid()) {
int statusCode = statusCodeVariant.toInt();
qDebug() << "HTTP Status Code:" << statusCode;
}
bool success = !m_currentDownload->error();
QString message = success ? additionalobj : m_currentDownload->errorString();
if (success) {
// 验证文件完整性
QFileInfo fi(m_downloadFile->fileName());
qint64 expectedSize = m_currentDownload->header(
QNetworkRequest::ContentLengthHeader).toLongLong();
if (fi.size() != expectedSize && expectedSize > 0) {
success = false;
message = "文件不完整";
}
}
cleanup();
emit downloadCompleted(success, message.toUtf8());
});
}
Q_INVOKABLE void postUpload(const QString& url,
const QString& filePath,
const QString& remotePath,
const QString& additionalobj) {
if (m_currentDownload) { // 复用同一个网络管理器,保持单请求
emit uploadCompleted(false, u8"已有进行中的传输");
return;
}
// 准备要上传的文件
QFile *uploadFile = new QFile(filePath, this);
if (!uploadFile->open(QIODevice::ReadOnly)) {
emit uploadCompleted(false, u8"无法打开文件");
uploadFile->deleteLater();
return;
}
// 创建多部分数据
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType, this);
// 添加文件部分
QHttpPart filePart;
filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
filePart.setHeader(QNetworkRequest::ContentDispositionHeader,
QVariant(QString("form-data; name=\"file\"; filename=\"%1\"")
.arg(remotePath + QFileInfo(filePath).fileName())));
filePart.setBodyDevice(uploadFile);
uploadFile->setParent(multiPart); // 文件对象由multiPart管理生命周期
multiPart->append(filePart);
QUrl u(url);
QNetworkRequest request(u);
// 配置HTTPS
QSslConfiguration sslConfig = request.sslConfiguration();
sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
request.setSslConfiguration(sslConfig);
// 发送请求
m_currentDownload = manager.post(request, multiPart);
multiPart->setParent(m_currentDownload); // 由reply管理multiPart生命周期
// 连接进度信号
connect(m_currentDownload, &QNetworkReply::uploadProgress,
[this, additionalobj](qint64 bytesSent, qint64 bytesTotal){
m_uploadProgress = bytesTotal > 0
? bytesSent / (double)bytesTotal
: 1;
emit uploadProgressChanged(m_uploadProgress, additionalobj); // 带附加参数
});
// 处理完成信号
connect(m_currentDownload, &QNetworkReply::finished, [this, additionalobj](){
bool success = (m_currentDownload->error() == QNetworkReply::NoError);
QString message = success ? u8"上传成功" : m_currentDownload->errorString();
cleanup();
emit uploadCompleted(success, additionalobj);
});
}
double downloadProgress() const { return m_downloadProgress; }
double uploadProgress() const { return m_uploadProgress; }
signals:
// 下载相关信号
void downloadProgressChanged(double progress,const QString& additional);
void downloadCompleted(bool success, const QString& message);
// 上传相关信号(原有)
void uploadProgressChanged(double progress ,const QString& additional);
void uploadCompleted(bool success, const QString& message);
private:
explicit FileTransfer(QObject* parent = nullptr)
: QObject(parent), m_downloadProgress(0), m_uploadProgress(0),
m_currentDownload(nullptr), m_downloadFile(nullptr) {}
QNetworkAccessManager manager;
double m_downloadProgress;
double m_uploadProgress;
QNetworkReply* m_currentDownload;
QFile* m_downloadFile;
void cleanup() {
if (m_downloadFile) {
m_downloadFile->deleteLater();
m_downloadFile = nullptr;
}
if (m_currentDownload) {
m_currentDownload->deleteLater();
m_currentDownload = nullptr;
}
m_downloadProgress = 0;
}
};
#endif // FILETRANSFER_H