repoindex/network/aurquery.cpp

138 lines
5.0 KiB
C++

#include "aurquery.h"
#include "alpm/package.h"
#include <QUrlQuery>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <iostream>
using namespace std;
namespace PackageManagement {
QUrl AurQuery::m_aurRpcUrl = QUrl(QStringLiteral("https://aur.archlinux.org/rpc.php"));
QUrl AurQuery::m_aurPkgbuildUrl = QUrl(QStringLiteral("https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD"));
const char *requestTypeProp = "type";
const QString rpcRequestTypeKey(QStringLiteral("type"));
const QString rpcRequestTypeSuggest(QStringLiteral("suggest"));
const QString rpcRequestTypeMultiInfo(QStringLiteral("multiinfo"));
const QString rpcArgKey(QStringLiteral("arg"));
const QString rpcArgArray(QStringLiteral("arg[]"));
const QString pkgbuildRequestType(QString("pkgbuild"));
AurQuery::AurQuery(QNetworkAccessManager &networkAccessManager, QObject *parent) :
QObject(parent),
m_networkAccessManager(networkAccessManager)
{}
QNetworkReply *AurQuery::requestSuggestions(const QString &phrase) const
{
auto url = m_aurRpcUrl;
QUrlQuery query;
query.addQueryItem(rpcRequestTypeKey, rpcRequestTypeSuggest);
query.addQueryItem(rpcArgKey, phrase);
url.setQuery(query);
auto *reply = m_networkAccessManager.get(QNetworkRequest(url));
reply->setProperty(requestTypeProp, rpcRequestTypeSuggest);
connect(reply, &QNetworkReply::finished, this, &AurQuery::dataReceived);
return reply;
}
/*!
* \brief Requests package information for the specified packages from the AUR.
* \returns Returns the QNetworkReply used for the request.
* \remarks
* If \a forceUpdate is true, package information which has already been retrieved
* and is still cached is requested again. Otherwise these packages will not be
* requested again. If it turns out, that all packages are already cached, nullptr
* is returned in this case.
*/
QNetworkReply *AurQuery::requestPackageInfo(const QStringList &packageNames, bool forceUpdate) const
{
QUrlQuery query;
for(const auto &packageName : packageNames) {
if(forceUpdate || !m_packages.count(packageName)) {
query.addQueryItem(rpcArgArray, packageName);
}
}
if(query.isEmpty()) {
return nullptr;
} else {
auto url = m_aurRpcUrl;
query.addQueryItem(rpcRequestTypeKey, rpcRequestTypeMultiInfo);
url.setQuery(query);
auto *reply = m_networkAccessManager.get(QNetworkRequest(url));
reply->setProperty(requestTypeProp, rpcRequestTypeMultiInfo);
connect(reply, &QNetworkReply::finished, this, &AurQuery::dataReceived);
return reply;
}
}
QNetworkReply *AurQuery::requestFullPackageInfo(const QString &package, bool forceUpdate) const
{
try {
const auto &pkg = m_packages.at(package);
if(pkg.hasFullInfo() && !forceUpdate) {
return nullptr;
}
} catch(const out_of_range &) {
}
auto url = m_aurPkgbuildUrl;
QUrlQuery query;
query.addQueryItem(QStringLiteral("h"), package);
url.setQuery(query);
auto *reply = m_networkAccessManager.get(QNetworkRequest(url));
reply->setProperty(requestTypeProp, pkgbuildRequestType);
connect(reply, &QNetworkReply::finished, this, &AurQuery::dataReceived);
return reply;
}
void AurQuery::dataReceived()
{
if(auto *reply = qobject_cast<QNetworkReply *>(sender())) {
if(reply->error() == QNetworkReply::NoError) {
QJsonParseError error;
QByteArray data = reply->readAll();
cerr << "AUR reply: " << data.data() << endl;
const QJsonDocument doc = QJsonDocument::fromJson(data, &error);
//const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &error);
if(error.error == QJsonParseError::NoError) {
const QString requestType = reply->property(requestTypeProp).toString();
if(requestType == rpcRequestTypeSuggest) {
emit suggestionsAvailable(reply, doc.array());
} else if(requestType == rpcRequestTypeMultiInfo) {
processPackageInfo(reply, doc.object().value(QStringLiteral("results")).toArray());
} else {
cerr << "Error: Reply has invalid type. (should never happen)" << endl;
}
} else {
cerr << "Error: Unable to parse JSON received from AUR: " << error.errorString().toLocal8Bit().data() << " at character " << error.offset << endl;
}
} else {
cerr << "Error: Unable to request data from AUR: " << reply->errorString().toLocal8Bit().data() << endl;
}
}
}
void AurQuery::processPackageInfo(const QNetworkReply *reply, const QJsonArray &results)
{
for(const auto &result : results) {
AurPackage package(result);
if(!package.name().isEmpty()) {
m_packages[package.name()] = move(package);
}
}
emit packageInfoAvailable(reply);
}
} // namespace Alpm