初步实现文件下载

main
wuyize 2023-07-04 15:13:50 +08:00
parent 78865cd93c
commit 7c2db1bcc0
5 changed files with 118 additions and 19 deletions

View File

@ -61,7 +61,6 @@ QAbstractItemModel *FileTransferListModel::model()
}
void FileTransferListModel::insertItem(const FileItem &item)
{
beginInsertRows(QModelIndex(), 0, 0);
@ -82,4 +81,10 @@ void FileTransferListModel::setItem(const FileItem &item)
}
}
FileTransferListModel &FileTransferListModel::instance()
{
static FileTransferListModel model;
return model;
}

View File

@ -2,13 +2,15 @@
#define AICSKNOWLEDGEBASE_FILETRANSFERLISTMODEL_H
#include <QAbstractListModel>
#include <curl/curl.h>
#include <fstream>
struct FileItem
{
QString id;
QString name;
int completedSize;
int totalSize;
int64_t completedSize;
int64_t totalSize;
};
@ -17,14 +19,14 @@ class FileTransferListModel : public QAbstractListModel
Q_OBJECT
public:
explicit FileTransferListModel(QObject *parent = nullptr);
static FileTransferListModel& instance();
// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int rowCount(const QModelIndex &parent) const override;
QHash<int, QByteArray> roleNames() const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVariant data(const QModelIndex &index, int role) const override;
void insertItem(const FileItem &item);
@ -40,6 +42,8 @@ public:
kTotalSizeRole
};
private:
explicit FileTransferListModel(QObject *parent = nullptr);
QList<FileItem> m_data;
QHash<int, QByteArray> m_roleName;
};

View File

@ -7,6 +7,7 @@
#include <curl/curl.h>
#include <QJsonDocument>
#include <QtConcurrent/QtConcurrent>
#include <fstream>
static const std::string baseUrl = "http://127.0.0.1:4523/m1/2914957-0-default/";
@ -51,8 +52,8 @@ CURLcode httpGet(const std::string &url, std::string &response, int timeout = 30
return res;
}
FileTransferManager::FileTransferManager(FileTransferListModel &model, QObject *parent)
: model(model), QObject(parent)
FileTransferManager::FileTransferManager(QObject *parent)
: QObject(parent)
{
}
@ -96,6 +97,84 @@ void FileTransferManager::upload(QUrl fileUrl)
curl_easy_cleanup(curl);
}
struct FileTransfering : FileItem
{
CURL *curlHandle = nullptr;
std::ofstream file;
};
curl_off_t getHttpFileSize(const std::string &url)
{
curl_off_t fileLength = 0;
CURL *handle = curl_easy_init();
curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
curl_easy_setopt(handle, CURLOPT_HEADER, 0); //只需要header头
curl_easy_setopt(handle, CURLOPT_NOBODY, 1); //不需要body
if (curl_easy_perform(handle) == CURLE_OK)
curl_easy_getinfo(handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &fileLength);
else {
qDebug() << "get file size error " << url.c_str();
fileLength = -1;
}
curl_easy_cleanup(handle);
return fileLength;
}
size_t receiveDataFunc(const void *ptr, size_t size, size_t nmemb, void *obj)
{
auto buf = (FileTransfering *) obj;
auto writeSize = size * nmemb;
buf->file.write(reinterpret_cast<const char *>(ptr), writeSize);
buf->completedSize += writeSize;
qDebug() << std::format("Downloading: {} / {}", buf->completedSize, buf->totalSize).c_str();
QTimer::singleShot(0, qApp, [buf]() {
FileTransferListModel::instance().setItem(static_cast<FileItem>(*buf));
});
return writeSize;
}
bool httpDownload(const std::string &url, const FileItem &item)
{
auto fileSize = getHttpFileSize(url);//获得文件大小。
if (fileSize != -1) {
qDebug() << "FileSize: " << fileSize;
FileTransfering obj = (FileTransfering) item;
obj.curlHandle = curl_easy_init();
if (!obj.curlHandle)
return false;
obj.totalSize = fileSize;//原始文件大小
obj.file = std::ofstream("D:\\Downloads\\" + obj.name.toStdString() + ".zip", std::ios::binary);
if (!obj.file.is_open()) {
qDebug() << "Open File Failed";
curl_easy_cleanup(obj.curlHandle);
return false;
} else {
curl_easy_setopt(obj.curlHandle, CURLOPT_VERBOSE, 0L);
curl_easy_setopt(obj.curlHandle, CURLOPT_HEADER, 0);
curl_easy_setopt(obj.curlHandle, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(obj.curlHandle, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(obj.curlHandle, CURLOPT_URL, url.c_str());
curl_easy_setopt(obj.curlHandle, CURLOPT_WRITEDATA, (void *) &obj);
curl_easy_setopt(obj.curlHandle, CURLOPT_WRITEFUNCTION, receiveDataFunc);
//下载
auto res = curl_easy_perform(obj.curlHandle);
curl_easy_cleanup(obj.curlHandle);
obj.file.close();
return res == CURLE_OK && obj.completedSize == obj.totalSize;
}
} else
return false;
}
void FileTransferManager::download(QString fileId)
{
static int _fileId = 0;
@ -103,6 +182,7 @@ void FileTransferManager::download(QString fileId)
QtConcurrent::run([fileId, this] {
qDebug() << "Start Get";
std::string resData;
if (CURLE_OK != httpGet(fileId.toStdString() + "/status", resData))
return;
@ -112,16 +192,29 @@ void FileTransferManager::download(QString fileId)
//if(!resJson["isCompleted"].toBool())
// return;
int size = resJson["size"].toInt();
/* int size = resJson["size"].toInt();
FileItem item{fileId, resJson["md5"].toString(), 0, size};
QTimer::singleShot(0, qApp, [this, item]() {
model.insertItem(item);
FileTransferListModel::instance().insertItem(item);
});*/
auto fileUrl = "https://curl.se/download/curl-8.1.2.zip";
int64_t size = getHttpFileSize(fileUrl);
FileItem item{fileId, resJson["md5"].toString(), 0, size};
QTimer::singleShot(0, qApp, [this, item]() {
FileTransferListModel::instance().insertItem(item);
});
while (item.completedSize < item.totalSize) {
auto res = httpDownload(fileUrl, item);
while (item.completedSize < item.totalSize && false) {
item.completedSize += 1;
QTimer::singleShot(0, qApp, [this, item]() {
model.setItem(item);
FileTransferListModel::instance().setItem(item);
});
using namespace std::chrono_literals;
@ -129,7 +222,7 @@ void FileTransferManager::download(QString fileId)
}
qDebug() << "End Get";
qDebug() << "End Get" << res;
});

View File

@ -14,14 +14,12 @@ class FileTransferManager : public QObject
{
Q_OBJECT
public:
explicit FileTransferManager(FileTransferListModel &model, QObject *parent = nullptr);
explicit FileTransferManager(QObject *parent = nullptr);
Q_INVOKABLE void upload(QUrl fileUrl);
Q_INVOKABLE void download(QString fileId);
private:
FileTransferListModel &model;
};

View File

@ -45,11 +45,10 @@ int main(int argc, char *argv[])
QQmlApplicationEngine engine;
FramelessHelper::Quick::registerTypes(&engine);
FileTransferListModel fileTransferListModel;
engine.rootContext()->setContextProperty("FileTransferListModel", &fileTransferListModel);
engine.rootContext()->setContextProperty("FileTransferListModel", &FileTransferListModel::instance());
auto httpClient = new HttpClient(engine);
auto fileTransferManager = new FileTransferManager(fileTransferListModel);
auto fileTransferManager = new FileTransferManager();
qmlRegisterSingletonInstance<HttpClient>("AicsKB.HttpClient", 1, 0, "HttpClient", httpClient);
qmlRegisterSingletonInstance<FileTransferManager>("AicsKB.FileTransferManager", 1, 0, "FileTransferManager",