枯叶蚊 14e3e7f9a2 星火商店搜索功能
* 更换搜索服务器域名为星火的域名
* 更新搜索服务器为线上服务器
* 完成搜索功能
* 解决搜索结果图标锯齿问题
* 更新appitem的样式
* 完成应用搜索列表的滚动问题
* 合并master分支
* 添加一些文件到忽略列表
* 更新项目结构
* 更新搜索列表UI
* 添加 QtNetworkService库
2020-12-05 16:06:52 +08:00

332 lines
12 KiB
C++

/**********************************************************
Author: Qt君
微信公众号: Qt君(文章首发)
Website: qtbig.com(后续更新)
Email: 2088201923@qq.com
QQ交流群: 732271126
LISCENSE: MIT
**********************************************************/
#include "HttpResponse.h"
#include <QRegExp>
#include <QStringList>
#include <QByteArray>
#include <QNetworkConfigurationManager>
#include <QMetaEnum>
#include <QEventLoop>
#include <QJsonDocument>
#include <QJsonObject>
#define T2S(t) (QString(#t).remove(QRegExp("\\s"))) //type to string
#define _exec(target, type, arg) \
if (target.canConvert<std::function<void (type)> >()) { \
std::function<void (type)> func = target.value<std::function<void (type)> >(); func(arg); \
} \
else
#define _exec2(target, type1, type2, arg1, arg2) \
if (target.canConvert<std::function<void (type1, type2)> >()) { \
std::function<void (type1, type2)> func = target.value<std::function<void (type1, type2)> >(); func(arg1, arg2); \
} else
using namespace AeaQt;
static const QMap<HttpResponse::SupportMethod, QMap<QString, QVariant>> methodParams =
{
{
HttpResponse::onResponse_QNetworkReply_A_Pointer,
{
{"types", QStringList({T2S(QNetworkReply*)})},
{"lambda", T2S(std::function<void (QNetworkReply*)>)},
{"signal", SIGNAL(finished(QNetworkReply*))},
{"isAutoInfer", true}
}
},
{
HttpResponse::onResponse_QByteArray,
{
{"types", QStringList({T2S(QByteArray)})},
{"lambda", T2S(std::function<void (QByteArray)>)},
{"signal", SIGNAL(finished(QByteArray))},
{"isAutoInfer", true}
}
},
{
HttpResponse::onResponse_QVariantMap,
{
{"types", QStringList({T2S(QVariantMap)})},
{"lambda", T2S(std::function<void (QVariantMap)>)},
{"signal", SIGNAL(finished(QVariantMap))},
{"isAutoInfer", true}
}
},
{
HttpResponse::onDownloadProgress_qint64_qint64,
{
{"types", QStringList({T2S(qint64), T2S(qint64)})},
{"lambda", T2S(std::function<void (qint64, qint64)>)},
{"signal", SIGNAL(downloadProgress(qint64, qint64))},
{"isAutoInfer", true}
}
},
{
HttpResponse::onError_QNetworkReply_To_NetworkError,
{
{"types", QStringList({T2S(QNetworkReply::NetworkError)})},
{"lambda", T2S(std::function<void (QNetworkReply::NetworkError)>)},
{"signal", SIGNAL(error(QNetworkReply::NetworkError))},
{"isAutoInfer", true}
}
},
{
HttpResponse::onError_QString,
{
{"types", QStringList({T2S(QString)})},
{"lambda", T2S(std::function<void (QString)>)},
{"signal", SIGNAL(error(QString))},
{"isAutoInfer", true}
}
},
{
HttpResponse::onError_QNetworkReply_To_NetworkError_QNetworkReply_A_Pointer,
{
{"types", QStringList({T2S(QNetworkReply::NetworkError), T2S(QNetworkReply*)})},
{"lambda", T2S(std::function<void (QNetworkReply::NetworkError, QNetworkReply*)>)},
{"signal", SIGNAL(error(QNetworkReply::NetworkError, QNetworkReply*))},
{"isAutoInfer", true}
}
},
{
HttpResponse::onError_QString_QNetworkReply_A_Poniter,
{
{"types", QStringList({T2S(QString), T2S(QNetworkReply*)})},
{"lambda", T2S(std::function<void (QString, QNetworkReply*)>)},
{"signal", SIGNAL(error(QString, QNetworkReply*))},
{"isAutoInfer", true}
}
},
};
static int extractCode(const char *member)
{
/* extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE */
return (((int)(*member) - '0') & 0x3);
}
HttpResponse::HttpResponse(QNetworkReply *networkReply,
const QMultiMap<SupportMethod, QPair<QString, QVariant> > &slotsMap,
const int &timeout,
bool isBlock)
: m_networkReply(networkReply),
m_slotsMap(slotsMap),
QObject(networkReply)
{
slotsMapOperation(m_slotsMap);
new HttpResponseTimeout(networkReply, timeout);
connect(m_networkReply, SIGNAL(finished()), this, SLOT(onFinished()));
connect(m_networkReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
connect(m_networkReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(onDownloadProgress(qint64, qint64)));
if (isBlock) {
QEventLoop loop;
QObject::connect(m_networkReply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
}
}
HttpResponse::~HttpResponse()
{
}
QNetworkReply *HttpResponse::networkReply()
{
return m_networkReply;
}
void HttpResponse::onFinished()
{
QNetworkReply *reply = m_networkReply;
if (reply->error() != QNetworkReply::NoError)
return;
if (m_slotsMap.contains(onResponse_QNetworkReply_A_Pointer)) {
_exec(m_slotsMap.value(onResponse_QNetworkReply_A_Pointer).second, QNetworkReply*, reply) {
emit finished(reply);
}
}
else if (m_slotsMap.contains((onResponse_QByteArray))) {
QByteArray result = reply->readAll();
_exec(m_slotsMap.value((onResponse_QByteArray)).second, QByteArray, result) {
emit finished(result);
}
reply->deleteLater();
}
else if (m_slotsMap.contains((onResponse_QVariantMap))) {
QByteArray result = reply->readAll();
QVariantMap resultMap = QJsonDocument::fromJson(result).object().toVariantMap();
_exec(m_slotsMap.value((onResponse_QVariantMap)).second, QVariantMap, resultMap){
emit finished(resultMap);
}
reply->deleteLater();
}
}
void HttpResponse::onError(QNetworkReply::NetworkError error)
{
QNetworkReply *reply = m_networkReply;
const QMetaObject & metaObject = QNetworkReply::staticMetaObject;
QMetaEnum metaEnum = metaObject.enumerator(metaObject.indexOfEnumerator("NetworkError"));
QString errorString = reply->errorString().isEmpty() ? metaEnum.valueToKey(error) : reply->errorString();
if (m_slotsMap.contains((onError_QString_QNetworkReply_A_Poniter))) {
_exec2(m_slotsMap.value((onError_QString_QNetworkReply_A_Poniter)).second, QString, QNetworkReply*, errorString, reply) {
emit this->error(errorString, reply);
}
}
else if (m_slotsMap.contains((onError_QNetworkReply_To_NetworkError_QNetworkReply_A_Pointer))) {
_exec2(m_slotsMap.value((onError_QNetworkReply_To_NetworkError_QNetworkReply_A_Pointer)).second,
QNetworkReply::NetworkError, QNetworkReply*,
error, reply) {
emit this->error(error, reply);
}
}
else if (m_slotsMap.contains((onError_QString))) {
_exec(m_slotsMap.value((onError_QString)).second, QString, errorString) {
emit this->error(errorString);
}
reply->deleteLater();
}
else if (m_slotsMap.contains((onError_QNetworkReply_To_NetworkError))) {
_exec(m_slotsMap.value((onError_QNetworkReply_To_NetworkError)).second, QNetworkReply::NetworkError, error) {
emit this->error(error);
}
reply->deleteLater();
}
}
void HttpResponse::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
if (m_slotsMap.contains((onDownloadProgress_qint64_qint64))) {
_exec2(m_slotsMap.value((onDownloadProgress_qint64_qint64)).second, qint64, qint64, bytesReceived, bytesTotal) {
emit downloadProgress(bytesReceived, bytesTotal);
}
}
}
static void extractSlot(const QString &respReceiverSlot, QString &extractSlot, QStringList &extractSlotTypes)
{
QString slot(respReceiverSlot);
if (extractCode(respReceiverSlot.toStdString().data()) == QSLOT_CODE && !slot.isEmpty()) {
slot.remove(0, 1);
QString unconvertedSlotType = slot;
int startIndex = slot.indexOf('(');
int endIndex = slot.indexOf(')');
Q_ASSERT(startIndex != -1 && endIndex != -1);
extractSlot = slot.remove(startIndex, endIndex-startIndex+1);
extractSlotTypes = unconvertedSlotType.mid(startIndex+1, endIndex-startIndex-1)
.remove(QRegExp("\\s"))
.split(',');
}
}
/* from slotMap get [SupportMethod] */
static HttpResponse::SupportMethod getSupportMethod(const QPair<QString, QVariant> &slotMap) {
QMapIterator<HttpResponse::SupportMethod, QMap<QString, QVariant>> iter(methodParams);
QString receiverSlot = slotMap.first;
QString slot;
QStringList slotTypes;
extractSlot(receiverSlot, slot, slotTypes);
while (iter.hasNext()) {
iter.next();
HttpResponse::SupportMethod supportMethod = iter.key();
QMap<QString, QVariant> value = iter.value();
if (slotTypes == value.value("types").toStringList()) {
return supportMethod;
}
else if (receiverSlot == value.value("lambda").toString()) {
return supportMethod;
}
}
return HttpResponse::Invalid;
}
static void autoInfterConvertedSupportMethod(QMultiMap<HttpResponse::SupportMethod, QPair<QString, QVariant> > &unconvertedSlotsMap)
{
QMultiMap<HttpResponse::SupportMethod, QPair<QString, QVariant> > convertedSlotsMap;
QMapIterator<HttpResponse::SupportMethod, QPair<QString, QVariant> > iter(unconvertedSlotsMap);
while (iter.hasNext()) {
iter.next();
const HttpResponse::SupportMethod supportMethod = iter.key();
const QPair<QString, QVariant> slotMap = iter.value();
if (supportMethod == HttpResponse::AutoInfer) {
HttpResponse::SupportMethod supportMethod = getSupportMethod(slotMap);
if (supportMethod == HttpResponse::Invalid) {
qDebug()<<"Not find support Method!"<<slotMap.first;
}
else {
if (methodParams[supportMethod].value("isAutoInfer").toBool())
convertedSlotsMap.insert(supportMethod, slotMap);
else
qDebug()<<"This type["<<methodParams[supportMethod].value("types").toString()<<"] does not support automatic derivation";
}
}
else {
if (methodParams[supportMethod].value("isAutoInfer").toBool())
convertedSlotsMap.insert(supportMethod, slotMap);
else
qDebug()<<"This type["<<methodParams[supportMethod].value("types").toString()<<"] does not support automatic derivation";
}
}
unconvertedSlotsMap = convertedSlotsMap;
}
void HttpResponse::slotsMapOperation(QMultiMap<SupportMethod, QPair<QString, QVariant> > &slotsMap)
{
autoInfterConvertedSupportMethod(slotsMap);
QMapIterator<SupportMethod, QPair<QString, QVariant> > iter(slotsMap);
while (iter.hasNext()) {
iter.next();
SupportMethod supportMethod = iter.key();
const QPair<QString, QVariant> &slotMap = iter.value();
const QString &receiverSlot = slotMap.first;
QVariant target = slotMap.second;
const QObject *receiver = target.value<QObject*>();
if (receiver) {
if (methodParams.contains(supportMethod)) {
connect(this,
methodParams[supportMethod].value("signal").toString().toStdString().data(),
receiver,
receiverSlot.toStdString().data(),
Qt::QueuedConnection);
}
}
}
}
HttpResponse::HttpResponse()
{
}