From 42f058ca69acc1dda7b7d1e4d03bda5cdff36770 Mon Sep 17 00:00:00 2001 From: zhuzichu Date: Wed, 26 Jul 2023 17:48:35 +0800 Subject: [PATCH] update --- example/qml/page/T_Http.qml | 256 ++++++++++++++++++------------------ src/FluHttp.cpp | 117 ++++++++++------ src/FluHttp.h | 21 ++- src/MainThread.cpp | 39 ++++++ src/MainThread.h | 24 ++++ 5 files changed, 277 insertions(+), 180 deletions(-) create mode 100644 src/MainThread.cpp create mode 100644 src/MainThread.h diff --git a/example/qml/page/T_Http.qml b/example/qml/page/T_Http.qml index 539ceed5..4e7ff175 100644 --- a/example/qml/page/T_Http.qml +++ b/example/qml/page/T_Http.qml @@ -7,152 +7,152 @@ import QtQuick.Dialogs import FluentUI import "qrc:///example/qml/component" -FluScrollablePage{ +FluContentPage{ title:"Http" FluHttp{ - id:http_get - url:"https://api.github.com/search/repositories" - onStart: { - showLoading() - } - onFinish: { - hideLoading() - } - onError: - (status,errorString)=>{ - console.debug(status+"->"+errorString) - showError(errorString) - } - onSuccess: - (result)=>{ - window_result.result = result - window_result.show() - } + id:http } - FluHttp{ - id:http_post - url:"https://www.wanandroid.com/article/query/0/json" - onStart: { - showLoading() - } - onFinish: { - hideLoading() - } - onError: - (status,errorString)=>{ - console.debug(status+"->"+errorString) - showError(errorString) + ListModel{ + id:data_model + ListElement{ + name:"Get请求" + onClickListener : function(){ + var callable = {} + callable.onStart = function(){ + showLoading() + } + callable.onFinish = function(){ + hideLoading() + } + callable.onSuccess = function(result){ + text_info.text = result + console.debug(result) + } + callable.onError = function(status,errorString){ + console.debug(status+";"+errorString) + } + http.get("https://httpbingo.org/get",callable) } - onSuccess: - (result)=>{ - window_result.result = result - window_result.show() + } + ListElement{ + name:"Post表单请求" + onClickListener : function(){ + var callable = {} + callable.onStart = function(){ + showLoading() + } + callable.onFinish = function(){ + hideLoading() + } + callable.onSuccess = function(result){ + text_info.text = result + console.debug(result) + } + callable.onError = function(status,errorString){ + console.debug(status+";"+errorString) + } + var param = {} + param.custname = "朱子楚" + param.custtel = "1234567890" + param.custemail = "zhuzichu520@gmail.com" + http.post("https://httpbingo.org/post",callable,param) } + } + ListElement{ + name:"Post Json请求" + onClickListener : function(){ + var callable = {} + callable.onStart = function(){ + showLoading() + } + callable.onFinish = function(){ + hideLoading() + } + callable.onSuccess = function(result){ + text_info.text = result + console.debug(result) + } + callable.onError = function(status,errorString){ + console.debug(status+";"+errorString) + } + var param = {} + param.custname = "朱子楚" + param.custtel = "1234567890" + param.custemail = "zhuzichu520@gmail.com" + http.postJson("https://httpbingo.org/post",callable,param) + } + } + ListElement{ + name:"Post String请求" + onClickListener : function(){ + var callable = {} + callable.onStart = function(){ + showLoading() + } + callable.onFinish = function(){ + hideLoading() + } + callable.onSuccess = function(result){ + text_info.text = result + console.debug(result) + } + callable.onError = function(status,errorString){ + console.debug(status+";"+errorString) + } + var param = "我命由我不由天" + http.postString("https://httpbingo.org/post",callable,param) + } + } } - FluHttp{ - id:http_download - url:"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" - // url:"https://www.w3school.com.cn/example/html5/mov_bbb.mp4" - onStart: { - btn_download.disabled = true + + ListView{ + id:list_view + width: 160 + clip: true + anchors{ + top: parent.top + topMargin: 20 + bottom: parent.bottom + left: parent.left } - onFinish: { - btn_download.disabled = false - btn_download.text = "下载文件" - text_file_size.text = "" + model:data_model + delegate: FluButton{ + implicitWidth: ListView.view.width + implicitHeight: 30 + text: model.name + onClicked: { + model.onClickListener() + } } - onDownloadProgress: - (recv,total)=>{ - var locale = Qt.locale() - var precent = (recv/total * 100).toFixed(0) + "%" - console.debug(precent) - btn_download.text = "下载中..."+precent - text_file_size.text = "%1/%2".arg(locale.formattedDataSize(recv)).arg(locale.formattedDataSize(total)) - } - onError: - (status,errorString)=>{ - showError(errorString) - } - onSuccess: - (result)=>{ - showSuccess(result) - } } FluArea{ - Layout.fillWidth: true - Layout.topMargin: 20 - height: 160 - paddings: 10 - - ColumnLayout{ - spacing: 14 - anchors.verticalCenter: parent.verticalCenter - FluButton{ - text:"Get请求" - onClicked: { - http_get.get({q:"FluentUI"}) - } + anchors{ + top: list_view.top + bottom: list_view.bottom + left: list_view.right + right: parent.right + } + Flickable{ + clip: true + id:scrollview + width: parent.width + height: parent.height + contentWidth: width + contentHeight: text_info.height + ScrollBar.vertical: FluScrollBar {} + FluText{ + id:text_info + width: scrollview.width + wrapMode: Text.WrapAnywhere + padding: 14 } - FluButton{ - text:"Post请求" - onClicked: { - http_post.post({k:"jitpack"}) - } - } - RowLayout{ - FluButton{ - id:btn_download - text:disabled ? "下载中..." : "下载文件" - onClicked: { - file_dialog.open() - } - } - FluText{ - id:text_file_size - Layout.alignment: Qt.AlignVCenter - } - } - } } - FolderDialog { - id: file_dialog - currentFolder: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0] - onAccepted: { - var path = FluTools.toLocalPath(currentFolder)+ "/big_buck_bunny.mp4" - http_download.download(path) - } - } - Window{ - property string result : "" - id:window_result - width: 600 - height: 400 - color: FluTheme.dark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1) - Item{ - anchors.fill: parent - Flickable{ - id:scrollview - width: parent.width - height: parent.height - contentWidth: width - contentHeight: text_info.height - ScrollBar.vertical: FluScrollBar {} - FluText{ - id:text_info - width: scrollview.width - wrapMode: Text.WrapAnywhere - text:window_result.result - padding: 14 - } - } - } - } } diff --git a/src/FluHttp.cpp b/src/FluHttp.cpp index a18a76c4..dfb1ff5a 100644 --- a/src/FluHttp.cpp +++ b/src/FluHttp.cpp @@ -6,6 +6,7 @@ #include #include #include +#include "MainThread.h" #include "FluApp.h" FluHttp::FluHttp(QObject *parent) @@ -31,15 +32,15 @@ void FluHttp::handleReply(QNetworkReply* reply){ _cache.append(reply); } -void FluHttp::post(QVariantMap params,QVariantMap headers){ +void FluHttp::post(QString url,QJSValue callable,QVariantMap params,QVariantMap headers){ QVariantMap data = invokeIntercept(params,headers,"post").toMap(); QThreadPool::globalInstance()->start([=](){ - Q_EMIT start(); + onStart(callable); for (int i = 0; i < retry(); ++i) { QNetworkAccessManager manager; manager.setTransferTimeout(timeout()); - QUrl url(_url); - QNetworkRequest request(url); + QUrl _url(url); + QNetworkRequest request(_url); addHeaders(&request,data["headers"].toMap()); QHttpMultiPart multiPart(QHttpMultiPart::FormDataType); QString contentType = QString("multipart/form-data;boundary=%1").arg(multiPart.boundary()); @@ -69,28 +70,30 @@ void FluHttp::post(QVariantMap params,QVariantMap headers){ reply->deleteLater(); reply = nullptr; if (isSuccess) { - Q_EMIT success(result); + onSuccess(callable,result); break; }else{ if(i == retry()-1){ - Q_EMIT error(status,errorString); + onError(callable,status,errorString); } } } - Q_EMIT finish(); + onFinish(callable); }); } -void FluHttp::postString(QString params,QVariantMap headers){ +void FluHttp::postString(QString url,QJSValue callable,QString params,QVariantMap headers){ QVariantMap data = invokeIntercept(params,headers,"postString").toMap(); QThreadPool::globalInstance()->start([=](){ - Q_EMIT start(); + onStart(callable); for (int i = 0; i < retry(); ++i) { QNetworkAccessManager manager; manager.setTransferTimeout(timeout()); - QUrl url(_url); - QNetworkRequest request(url); + QUrl _url(url); + QNetworkRequest request(_url); addHeaders(&request,data["headers"].toMap()); + QString contentType = QString("text/plain;charset=utf-8"); + request.setHeader(QNetworkRequest::ContentTypeHeader, contentType); QEventLoop loop; QNetworkReply* reply = manager.post(request,params.toUtf8()); _cache.append(reply); @@ -106,27 +109,27 @@ void FluHttp::postString(QString params,QVariantMap headers){ reply->deleteLater(); reply = nullptr; if (isSuccess) { - Q_EMIT success(result); + onSuccess(callable,result); break; }else{ if(i == retry()-1){ - Q_EMIT error(status,errorString); + onError(callable,status,errorString); } } } - Q_EMIT finish(); + onFinish(callable); }); } -void FluHttp::postJson(QVariantMap params,QVariantMap headers){ +void FluHttp::postJson(QString url,QJSValue callable,QVariantMap params,QVariantMap headers){ QVariantMap data = invokeIntercept(params,headers,"postJson").toMap(); QThreadPool::globalInstance()->start([=](){ - Q_EMIT start(); + onStart(callable); for (int i = 0; i < retry(); ++i) { QNetworkAccessManager manager; manager.setTransferTimeout(timeout()); - QUrl url(_url); - QNetworkRequest request(url); + QUrl _url(url); + QNetworkRequest request(_url); addHeaders(&request,data["headers"].toMap()); QString contentType = QString("application/json;charset=utf-8"); request.setHeader(QNetworkRequest::ContentTypeHeader, contentType); @@ -145,28 +148,28 @@ void FluHttp::postJson(QVariantMap params,QVariantMap headers){ reply->deleteLater(); reply = nullptr; if (isSuccess) { - Q_EMIT success(result); + onSuccess(callable,result); break; }else{ if(i == retry()-1){ - Q_EMIT error(status,errorString); + onError(callable,status,errorString); } } } - Q_EMIT finish(); + onFinish(callable); }); } -void FluHttp::get(QVariantMap params,QVariantMap headers){ +void FluHttp::get(QString url,QJSValue callable,QVariantMap params,QVariantMap headers){ QVariantMap data = invokeIntercept(params,headers,"get").toMap(); QThreadPool::globalInstance()->start([=](){ - Q_EMIT start(); for (int i = 0; i < retry(); ++i) { + onStart(callable); QNetworkAccessManager manager; manager.setTransferTimeout(timeout()); - QUrl url(_url); - addQueryParam(&url,data["params"].toMap()); - QNetworkRequest request(url); + QUrl _url(url); + addQueryParam(&_url,data["params"].toMap()); + QNetworkRequest request(_url); addHeaders(&request,data["headers"].toMap()); QEventLoop loop; QNetworkReply* reply = manager.get(request); @@ -183,33 +186,33 @@ void FluHttp::get(QVariantMap params,QVariantMap headers){ reply->deleteLater(); reply = nullptr; if (isSuccess) { - Q_EMIT success(result); + onSuccess(callable,result); break; }else{ if(i == retry()-1){ - Q_EMIT error(status,errorString); + onError(callable,status,errorString); } } } - Q_EMIT finish(); + onFinish(callable); }); } -void FluHttp::download(QString path,QVariantMap params,QVariantMap headers){ +void FluHttp::download(QString url,QJSValue callable,QString filePath,QVariantMap params,QVariantMap headers){ QVariantMap data = invokeIntercept(params,headers,"download").toMap(); QThreadPool::globalInstance()->start([=](){ - Q_EMIT start(); + onStart(callable); QNetworkAccessManager manager; - QUrl url(_url); - addQueryParam(&url,data["params"].toMap()); - QNetworkRequest request(url); + QUrl _url(url); + addQueryParam(&_url,data["params"].toMap()); + QNetworkRequest request(_url); addHeaders(&request,data["headers"].toMap()); - QSharedPointer file(new QFile(path)); + QSharedPointer file(new QFile(filePath)); QIODevice::OpenMode mode = QIODevice::WriteOnly|QIODevice::Truncate; if (!file->open(mode)) { - Q_EMIT error(-1,QString("Url: %1 %2 Non-Writable").arg(request.url().toString(),file->fileName())); - Q_EMIT finish(); + onError(callable,-1,QString("Url: %1 %2 Non-Writable").arg(request.url().toString(),file->fileName())); + onFinish(callable); return; } QEventLoop loop; @@ -219,22 +222,22 @@ void FluHttp::download(QString path,QVariantMap params,QVariantMap headers){ QPointer reply = manager.get(request); _cache.append(reply); connect(reply,&QNetworkReply::downloadProgress,this,[=](qint64 bytesReceived, qint64 bytesTotal){ - Q_EMIT downloadProgress(bytesReceived,bytesTotal); + onDownloadProgress(callable,bytesReceived,bytesTotal); }); connect(reply,&QNetworkReply::readyRead,this,[=](){ file->write(reply->readAll()); }); loop.exec(); if (reply->error() == QNetworkReply::NoError) { - Q_EMIT success(path); + onSuccess(callable,filePath); }else{ - Q_EMIT error(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); + onError(callable,reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); } _cache.removeOne(reply); file->close(); reply->deleteLater(); reply = nullptr; - Q_EMIT finish(); + onFinish(callable); }); } @@ -271,3 +274,35 @@ void FluHttp::addHeaders(QNetworkRequest* request,const QMap& request->setRawHeader(iter.key().toUtf8(), iter.value().toString().toUtf8()); } } + +void FluHttp::onStart(const QJSValue& callable){ + QJSValue onStart = callable.property("onStart"); + MainThread::post([=](){onStart.call();}); +} + +void FluHttp::onFinish(const QJSValue& callable){ + QJSValue onFinish = callable.property("onFinish"); + MainThread::post([=](){onFinish.call();}); +} + +void FluHttp::onError(const QJSValue& callable,int status,QString errorString){ + QJSValue onError = callable.property("onError"); + QJSValueList args; + args<(recv); + args<(total); + QJSValue onDownloadProgress = callable.property("onDownloadProgress"); + MainThread::post([=](){onDownloadProgress.call(args);}); +} diff --git a/src/FluHttp.h b/src/FluHttp.h index 12881406..3c60089b 100644 --- a/src/FluHttp.h +++ b/src/FluHttp.h @@ -10,7 +10,6 @@ class FluHttp : public QObject { Q_OBJECT - Q_PROPERTY_AUTO(QString,url); Q_PROPERTY_AUTO(int,retry); Q_PROPERTY_AUTO(int,timeout) QML_NAMED_ELEMENT(FluHttp) @@ -19,19 +18,19 @@ private: void handleReply(QNetworkReply* reply); void addQueryParam(QUrl* url,const QMap& params); void addHeaders(QNetworkRequest* request,const QMap& params); + void onStart(const QJSValue& callable); + void onFinish(const QJSValue& callable); + void onError(const QJSValue& callable,int status,QString errorString); + void onSuccess(const QJSValue& callable,QString result); + void onDownloadProgress(const QJSValue& callable,qint64 recv, qint64 total); public: explicit FluHttp(QObject *parent = nullptr); ~FluHttp(); - Q_SIGNAL void start(); - Q_SIGNAL void finish(); - Q_SIGNAL void error(int status,QString errorString); - Q_SIGNAL void success(QString result); - Q_SIGNAL void downloadProgress(qint64 recv, qint64 total); - Q_INVOKABLE void get(QVariantMap params = {},QVariantMap headers = {}); - Q_INVOKABLE void post(QVariantMap params = {},QVariantMap headers = {}); - Q_INVOKABLE void postString(QString params = "",QVariantMap headers = {}); - Q_INVOKABLE void postJson(QVariantMap params = {},QVariantMap headers = {}); - Q_INVOKABLE void download(QString path,QVariantMap params = {},QVariantMap headers = {}); + Q_INVOKABLE void get(QString url,QJSValue callable,QVariantMap params = {},QVariantMap headers = {}); + Q_INVOKABLE void post(QString url,QJSValue callable,QVariantMap params = {},QVariantMap headers = {}); + Q_INVOKABLE void postString(QString url,QJSValue callable,QString params = "",QVariantMap headers = {}); + Q_INVOKABLE void postJson(QString url,QJSValue callable,QVariantMap params = {},QVariantMap headers = {}); + Q_INVOKABLE void download(QString url,QJSValue callable,QString filePath,QVariantMap params = {},QVariantMap headers = {}); Q_INVOKABLE void cancel(); private: QList> _cache; diff --git a/src/MainThread.cpp b/src/MainThread.cpp new file mode 100644 index 00000000..cb5ae18e --- /dev/null +++ b/src/MainThread.cpp @@ -0,0 +1,39 @@ +#include "MainThread.h" +#include +#include + +std::shared_ptr MainThread::createShared(QObject* bindObject) +{ + return std::shared_ptr(new MainThread(bindObject), [=](QObject* mainThread) { + mainThread->deleteLater(); + }); +} + +MainThread::MainThread(QObject* bindObject) + : mBindObject(bindObject) + , mIgnoreNullObject(bindObject == nullptr) +{ + qRegisterMetaType>("std::function"); + auto mainUIThread = qApp->thread(); + if (this->thread() != mainUIThread) + { + this->moveToThread(mainUIThread); + } +} + +MainThread::~MainThread() +{ +} + +void MainThread::post(std::function func) +{ + QMetaObject::invokeMethod(createShared().get(), "mainThreadSlot", Q_ARG(std::function, func)); +} + +void MainThread::mainThreadSlot(std::function func) +{ + if ((mIgnoreNullObject || mBindObject) && func) + { + func(); + } +} diff --git a/src/MainThread.h b/src/MainThread.h new file mode 100644 index 00000000..e108c026 --- /dev/null +++ b/src/MainThread.h @@ -0,0 +1,24 @@ +#ifndef MAINTHREAD_H +#define MAINTHREAD_H + +#include +#include +#include + +class MainThread : public QObject +{ + Q_OBJECT +public: + + static void post(std::function func); + ~MainThread(); +private: + static std::shared_ptr createShared(QObject* bindObject = nullptr); +private slots: + void mainThreadSlot(std::function func); +private: + MainThread(QObject* bindObject = nullptr); + QPointer mBindObject; + bool mIgnoreNullObject{ false }; +}; +#endif // MAINTHREAD_H