diff --git a/AicsKnowledgeBase/src/FileTransferListModel.cpp b/AicsKnowledgeBase/src/FileTransferListModel.cpp index b079988..663eb4b 100644 --- a/AicsKnowledgeBase/src/FileTransferListModel.cpp +++ b/AicsKnowledgeBase/src/FileTransferListModel.cpp @@ -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; +} + diff --git a/AicsKnowledgeBase/src/FileTransferListModel.h b/AicsKnowledgeBase/src/FileTransferListModel.h index 092e357..dfb14fd 100644 --- a/AicsKnowledgeBase/src/FileTransferListModel.h +++ b/AicsKnowledgeBase/src/FileTransferListModel.h @@ -2,13 +2,15 @@ #define AICSKNOWLEDGEBASE_FILETRANSFERLISTMODEL_H #include +#include +#include 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 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 m_data; QHash m_roleName; }; diff --git a/AicsKnowledgeBase/src/FileTransferManager.cpp b/AicsKnowledgeBase/src/FileTransferManager.cpp index ff98641..a2ba674 100644 --- a/AicsKnowledgeBase/src/FileTransferManager.cpp +++ b/AicsKnowledgeBase/src/FileTransferManager.cpp @@ -7,6 +7,7 @@ #include #include #include +#include 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(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(*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; }); diff --git a/AicsKnowledgeBase/src/FileTransferManager.h b/AicsKnowledgeBase/src/FileTransferManager.h index 8c438c2..e7096f9 100644 --- a/AicsKnowledgeBase/src/FileTransferManager.h +++ b/AicsKnowledgeBase/src/FileTransferManager.h @@ -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; }; diff --git a/AicsKnowledgeBase/src/main.cpp b/AicsKnowledgeBase/src/main.cpp index 731c748..ef750eb 100644 --- a/AicsKnowledgeBase/src/main.cpp +++ b/AicsKnowledgeBase/src/main.cpp @@ -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("AicsKB.HttpClient", 1, 0, "HttpClient", httpClient); qmlRegisterSingletonInstance("AicsKB.FileTransferManager", 1, 0, "FileTransferManager",