211 lines
7.9 KiB
C++
211 lines
7.9 KiB
C++
#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
|