初步实现文件下载
parent
78865cd93c
commit
7c2db1bcc0
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in New Issue