初步实现文件下载

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

View File

@ -7,6 +7,7 @@
#include <curl/curl.h> #include <curl/curl.h>
#include <QJsonDocument> #include <QJsonDocument>
#include <QtConcurrent/QtConcurrent> #include <QtConcurrent/QtConcurrent>
#include <fstream>
static const std::string baseUrl = "http://127.0.0.1:4523/m1/2914957-0-default/"; 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; return res;
} }
FileTransferManager::FileTransferManager(FileTransferListModel &model, QObject *parent) FileTransferManager::FileTransferManager(QObject *parent)
: model(model), QObject(parent) : QObject(parent)
{ {
} }
@ -96,6 +97,84 @@ void FileTransferManager::upload(QUrl fileUrl)
curl_easy_cleanup(curl); 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) void FileTransferManager::download(QString fileId)
{ {
static int _fileId = 0; static int _fileId = 0;
@ -103,6 +182,7 @@ void FileTransferManager::download(QString fileId)
QtConcurrent::run([fileId, this] { QtConcurrent::run([fileId, this] {
qDebug() << "Start Get"; qDebug() << "Start Get";
std::string resData; std::string resData;
if (CURLE_OK != httpGet(fileId.toStdString() + "/status", resData)) if (CURLE_OK != httpGet(fileId.toStdString() + "/status", resData))
return; return;
@ -112,16 +192,29 @@ void FileTransferManager::download(QString fileId)
//if(!resJson["isCompleted"].toBool()) //if(!resJson["isCompleted"].toBool())
// return; // return;
int size = resJson["size"].toInt();
/* int size = resJson["size"].toInt();
FileItem item{fileId, resJson["md5"].toString(), 0, size}; FileItem item{fileId, resJson["md5"].toString(), 0, size};
QTimer::singleShot(0, qApp, [this, item]() { 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; item.completedSize += 1;
QTimer::singleShot(0, qApp, [this, item]() { QTimer::singleShot(0, qApp, [this, item]() {
model.setItem(item); FileTransferListModel::instance().setItem(item);
}); });
using namespace std::chrono_literals; 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 Q_OBJECT
public: public:
explicit FileTransferManager(FileTransferListModel &model, QObject *parent = nullptr); explicit FileTransferManager(QObject *parent = nullptr);
Q_INVOKABLE void upload(QUrl fileUrl); Q_INVOKABLE void upload(QUrl fileUrl);
Q_INVOKABLE void download(QString fileId); Q_INVOKABLE void download(QString fileId);
private:
FileTransferListModel &model;
}; };

View File

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