PackageInfoLookup

This commit is contained in:
Martchus 2015-09-29 21:52:30 +02:00
parent 6d8cf66f99
commit a0d494ca93
12 changed files with 167 additions and 93 deletions

View File

@ -607,6 +607,12 @@ const QJsonArray Manager::packageInfo(const QJsonObject &pkgSelection, PackageIn
const auto pkgName = entryObj.value(QStringLiteral("name")).toString();
if(!pkgName.isEmpty()) {
QJsonObject res;
res.insert(QStringLiteral("name"), pkgName);
res.insert(QStringLiteral("repo"), repo->name());
const auto index = entryObj.value(QStringLiteral("index"));
if(!index.isNull() && !index.isUndefined()) {
res.insert(QStringLiteral("index"), index);
}
if(auto *pkg = repo->packageByName(pkgName)) {
if(part & Basics) {
res.insert(QStringLiteral("basics"), pkg->basicInfo());
@ -617,12 +623,6 @@ const QJsonArray Manager::packageInfo(const QJsonObject &pkgSelection, PackageIn
} else {
res.insert(QStringLiteral("error"), QStringLiteral("na"));
}
res.insert(QStringLiteral("name"), pkgName);
res.insert(QStringLiteral("repo"), repo->name());
const auto index = entryObj.value(QStringLiteral("index"));
if(!index.isNull() && !index.isUndefined()) {
res.insert(QStringLiteral("index"), index);
}
results << res;
}
}

View File

@ -1,4 +1,4 @@
#include "./package.h"
#include "./package.h"
#include "./alpmdatabase.h"
#include "./utilities.h"
#include "./repository.h"

View File

@ -1,49 +1,101 @@
#include "./packageinfolookup.h"
#include "./repository.h"
#include <cassert>
using namespace std;
namespace RepoIndex {
PackageInfoLookup::PackageInfoLookup(Manager &manager, const QJsonObject &packageSelection, Manager::PackageInfoPart part, QObject *parent) :
PackageLookup(parent)
PackageInfoLookup::PackageInfoLookup(Manager &manager, const QJsonObject &request, QObject *parent) :
PackageLookup(parent),
m_what(request.value(QStringLiteral("what")).toString()),
m_part(Manager::None)
{
if(part != Manager::None) {
for(auto i = packageSelection.constBegin(), end = packageSelection.constEnd(); i != end; ++i) {
if(auto *repo = manager.repositoryByName(i.key())) {
QStringList packagesToBeRequested;
for(const auto &entry : i.value().toArray()) {
const auto entryObj = entry.toObject();
const auto pkgName = entryObj.value(QStringLiteral("name")).toString();
if(!pkgName.isEmpty()) {
packagesToBeRequested << pkgName;
}
m_id = request.value(QStringLiteral("id"));
if(m_what == QLatin1String("basicpkginfo")) {
m_part = Manager::Basics;
} else if(m_what == QLatin1String("pkgdetails")) {
m_part = Manager::Details;
} else if(m_what == QLatin1String("fullpkginfo")) {
m_part = Manager::Basics | Manager::Details;
} else {
QJsonObject errorObj;
errorObj.insert(QStringLiteral("error"), QStringLiteral("invalid_request"));
m_results << errorObj;
return;
}
m_packageSelection = request.value(QStringLiteral("sel")).toObject();
for(auto i = m_packageSelection.constBegin(), end = m_packageSelection.constEnd(); i != end; ++i) {
if(auto *repo = manager.repositoryByName(i.key())) {
QStringList packagesToBeRequested;
for(const auto &entry : i.value().toArray()) {
const auto entryObj = entry.toObject();
const auto pkgName = entryObj.value(QStringLiteral("name")).toString();
if(!pkgName.isEmpty()) {
packagesToBeRequested << pkgName;
}
if(!packagesToBeRequested.isEmpty()) {
if(const auto *reply = (part & Manager::Details ? repo->requestFullPackageInfo(packagesToBeRequested) : repo->requestPackageInfo(packagesToBeRequested))) {
connect(reply, &PackageReply::resultsAvailable, this, &PackageInfoLookup::addResults);
++m_remainingReplies;
} else {
// no need to request any of the packages
}
}
} else {
// specified repository can not be found
QJsonObject errorObj;
errorObj.insert(QStringLiteral("repo"), i.key());
errorObj.insert(QStringLiteral("error"), QStringLiteral("na"));
m_results << errorObj;
}
if(!packagesToBeRequested.isEmpty()) {
if(const auto *reply = (m_part & Manager::Details ? repo->requestFullPackageInfo(packagesToBeRequested) : repo->requestPackageInfo(packagesToBeRequested))) {
connect(reply, &PackageReply::resultsAvailable, this, &PackageInfoLookup::addResultsFromReply);
++m_remainingReplies;
} else {
// no need to request any of the packages
addResultsDirectly(packagesToBeRequested, repo);
}
}
} else {
// specified repository can not be found
QJsonObject errorObj;
errorObj.insert(QStringLiteral("repo"), i.key());
errorObj.insert(QStringLiteral("error"), QStringLiteral("na"));
m_results << errorObj;
}
}
}
void PackageInfoLookup::addResults()
void PackageInfoLookup::addResultsDirectly(const QStringList &packageNames, const Repository *repo)
{
const auto &packages = repo->packages();
for(const auto &packageName : packageNames) {
QJsonObject res;
res.insert(QStringLiteral("name"), packageName);
res.insert(QStringLiteral("repo"), repo->name());
// TODO: remember index
const auto index = m_packageSelection.value(repo->name()).toObject().value(packageName).toObject().value(QStringLiteral("index"));
if(!index.isNull() && !index.isUndefined()) {
res.insert(QStringLiteral("index"), index);
}
bool avail = false;
try {
if(const auto &pkg = packages.at(packageName)) {
avail = true;
if(m_part & Manager::Basics) {
res.insert(QStringLiteral("basics"), pkg->basicInfo());
}
if(m_part & Manager::Details) {
res.insert(QStringLiteral("details"), pkg->detailedInfo());
}
}
} catch(const out_of_range &) {
}
if(!avail) {
res.insert(QStringLiteral("error"), QStringLiteral("na"));
}
m_results << res;
}
}
void PackageInfoLookup::addResultsFromReply()
{
assert(m_remainingReplies);
auto *reply = static_cast<PackageReply *>(sender());
m_results << reply->;
reply->deleteLater();
const auto *repo = reply->repository();
addResultsDirectly(reply->requestedPackages(), repo);
if(!--m_remainingReplies) {
emit resultsAvailable(QStringLiteral("pkginfo"), m_id, m_results);
emit resultsAvailable(m_what, m_id, m_results);
deleteLater();
}
}

View File

@ -10,11 +10,16 @@ class PackageInfoLookup : public PackageLookup
{
Q_OBJECT
public:
explicit PackageInfoLookup(Manager &manager, const QJsonObject &packageSelection, Manager::PackageInfoPart part, QObject *parent = nullptr);
explicit PackageInfoLookup(Manager &manager, const QJsonObject &request, QObject *parent = nullptr);
private slots:
void addResultsDirectly(const QStringList &packageNames, const Repository *repo);
void addResultsFromReply();
private:
void addResults();
const QString m_what;
Manager::PackageInfoParts m_part;
QJsonObject m_packageSelection;
QList<Package *> m_packages;
};

View File

@ -1,4 +1 @@
#include "./packagelookup.h"

View File

@ -267,7 +267,7 @@ QJsonObject Repository::suggestions(const QString &term) const
// }
// }
for(const auto &pkgEntry : packages()) {
if(pkgEntry.first.compare(term, Qt::CaseInsensitive) == 0) {
if(pkgEntry.first.contains(term, Qt::CaseInsensitive)) {
suggestions << pkgEntry.first;
}
}

View File

@ -45,27 +45,36 @@ class PackageReply : public Reply
{
Q_OBJECT
public:
PackageReply(QNetworkReply *networkReply, std::map<QString, std::unique_ptr<Package> > &packages);
PackageReply(const QList<QNetworkReply *> &networkReplies, std::map<QString, std::unique_ptr<Package> > &packages);
const std::map<QString, std::unique_ptr<Package> > &packages() const;
PackageReply(QNetworkReply *networkReply, const QStringList &requestedPackages, Repository *repo);
PackageReply(const QList<QNetworkReply *> &networkReplies, const QStringList &requestedPackages, Repository *repo);
const QStringList &requestedPackages() const;
const Repository *repository() const;
protected:
std::map<QString, std::unique_ptr<Package> > &m_packages;
QStringList m_requestedPackages;
Repository *m_repo;
};
inline PackageReply::PackageReply(QNetworkReply *networkReply, std::map<QString, std::unique_ptr<Package> > &packages) :
inline PackageReply::PackageReply(QNetworkReply *networkReply, const QStringList &requestedPackages, Repository *repo) :
Reply(networkReply),
m_packages(packages)
m_requestedPackages(requestedPackages),
m_repo(repo)
{}
inline PackageReply::PackageReply(const QList<QNetworkReply *> &networkReplies, std::map<QString, std::unique_ptr<Package> > &packages) :
inline PackageReply::PackageReply(const QList<QNetworkReply *> &networkReplies, const QStringList &requestedPackages, Repository *repo) :
Reply(networkReplies),
m_packages(packages)
m_requestedPackages(requestedPackages),
m_repo(repo)
{}
inline const std::map<QString, std::unique_ptr<Package> > &PackageReply::packages() const
inline const QStringList &PackageReply::requestedPackages() const
{
return m_packages;
return m_requestedPackages;
}
inline const Repository *PackageReply::repository() const
{
return m_repo;
}
class SuggestionsReply : public Reply

View File

@ -116,6 +116,7 @@ private slots:
protected:
explicit UpgradeLookup(QObject *parent = nullptr);
Repository *m_toCheck;
unsigned int m_remainingProcesses;
bool m_firstFinished;
@ -136,6 +137,8 @@ class UpgradeLookupJson : public UpgradeLookup
public:
explicit UpgradeLookupJson(Manager &manager, const QJsonObject &request, QObject *parent = nullptr);
const QJsonArray &errors() const;
QJsonArray results() const;
bool finished() const;
signals:
void resultsAvailable(const QJsonValue &what, const QJsonValue &id, const QJsonValue &value);
@ -158,6 +161,16 @@ inline const QJsonArray &UpgradeLookupJson::errors() const
return m_errorsArray;
}
inline QJsonArray UpgradeLookupJson::results() const
{
return QJsonArray(); // results are currently only returned by emitting resultsAvailable()
}
inline bool UpgradeLookupJson::finished() const
{
return !m_remainingProcesses && m_errorsArray.isEmpty();
}
class UpgradeLookupCli : public UpgradeLookup
{
Q_OBJECT

View File

@ -71,6 +71,28 @@ void Connection::sendResults(const QJsonValue &what, const QJsonValue &id, const
sendJson(response);
}
template<class Lookup, typename... Args>
void Connection::performLookup(const QJsonObject &request, Args &&...args)
{
auto *lookup = new Lookup(forward<Args>(args)...);
if(lookup->finished()) {
// the lookup has already finished when constructing the lookup object
// -> send the results immidiately
sendResult(request.value(QStringLiteral("what")), request.value(QStringLiteral("id")), lookup->results());
} else if(!lookup->errors().isEmpty()) {
// error occured during the construction of the lookup object
// -> send the errors immidiately
QJsonObject results;
results.insert(QStringLiteral("errors"), lookup->errors());
sendResult(request.value(QStringLiteral("what")), request.value(QStringLiteral("id")), results);
} else {
// the lookup object has been created without errors but the lookup is not done yet
// -> send results when available
connect(lookup, &Lookup::resultsAvailable, this, &Connection::sendResult);
}
// in any case: the lookup object destroys itself
}
void Connection::handleQuery(const QJsonObject &obj)
{
const auto what = obj.value(QStringLiteral("what")).toString();
@ -79,39 +101,14 @@ void Connection::handleQuery(const QJsonObject &obj)
m_repoInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_repoInfoUpdatesRequested);
sendResult(what, id, m_manager.basicRepoInfo());
} else if(what == QLatin1String("basicpkginfo") || what == QLatin1String("pkgdetails") || what == QLatin1String("fullpkginfo")) {
auto *packageInfoLookup = new PackageInfoLookup(m_manager, obj);
if(packageInfoLookup->finished()) {
sendResult(what, id, packageInfoLookup->results());
} else if(!packageInfoLookup->errors().isEmpty()) {
QJsonObject results;
results.insert(QStringLiteral("errors"), packageInfoLookup->errors());
sendResult(what, id, results);
} else {
connect(packageInfoLookup, &SuggestionsLookup::resultsAvailable, this, &Connection::sendResult);
}
performLookup<PackageInfoLookup>(obj, m_manager, obj);
} else if(what == QLatin1String("groupinfo")) {
m_groupInfoUpdatesRequested = obj.value(QStringLiteral("updates")).toBool(m_groupInfoUpdatesRequested);
sendResults(what, id, m_manager.groupInfo());
} else if(what == QLatin1String("suggestions")) {
auto *suggestionsLookup = new SuggestionsLookup(m_manager, obj);
if(suggestionsLookup->finished()) {
sendResult(what, id, suggestionsLookup->results());
} else if(!suggestionsLookup->errors().isEmpty()) {
QJsonObject results;
results.insert(QStringLiteral("errors"), suggestionsLookup->errors());
sendResult(what, id, results);
} else {
connect(suggestionsLookup, &SuggestionsLookup::resultsAvailable, this, &Connection::sendResult);
}
performLookup<SuggestionsLookup>(obj, m_manager, obj);
} else if(what == QLatin1String("upgradelookup")) {
auto *upgradeLookup = new UpgradeLookupJson(m_manager, obj);
if(upgradeLookup->errors().isEmpty()) {
connect(upgradeLookup, &UpgradeLookupJson::resultsAvailable, this, &Connection::sendResult);
} else {
QJsonObject results;
results.insert(QStringLiteral("errors"), upgradeLookup->errors());
sendResult(what, id, results);
}
performLookup<UpgradeLookupJson>(obj, m_manager, obj);
} else if(what == QLatin1String("ping")) {
sendResult(what, id, QStringLiteral("pong"));
} else {

View File

@ -31,12 +31,12 @@ private:
void sendError(const QString &msg, const QJsonValue &id = QJsonValue());
void handleQuery(const QJsonObject &obj);
void handleCmd(const QJsonObject &obj);
template<class Lookup, typename... Args> void performLookup(const QJsonObject &request, Args &&...args);
QWebSocket *m_socket;
RepoIndex::Manager &m_manager;
bool m_repoInfoUpdatesRequested;
bool m_groupInfoUpdatesRequested;
};
}

View File

@ -33,8 +33,8 @@ QUrl UserRepository::m_aurPkgbuildUrl = QUrl(QStringLiteral("https://aur.archlin
QUrl UserRepository::m_aurSrcInfoUrl = QUrl(QStringLiteral("https://aur.archlinux.org/cgit/aur.git/plain/.SRCINFO"));
QString UserRepository::m_aurSnapshotPath = QStringLiteral("https://aur.archlinux.org/cgit/aur.git/snapshot/%1.tar.gz");
AurPackageReply::AurPackageReply(QNetworkReply *networkReply, UserRepository *userRepo) :
PackageReply(networkReply, userRepo->packages()),
AurPackageReply::AurPackageReply(QNetworkReply *networkReply, const QStringList &requestedPackages, UserRepository *userRepo) :
PackageReply(networkReply, requestedPackages, userRepo),
m_userRepo(userRepo)
{}
@ -46,13 +46,14 @@ void AurPackageReply::processData()
//QByteArray data = m_networkReply->readAll();
//cerr << shchar << "AUR reply: " << data.data() << endl;
//const QJsonDocument doc = QJsonDocument::fromJson(data, &error);
const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &error);
const auto doc = QJsonDocument::fromJson(reply->readAll(), &error);
auto &packages = m_repo->packages();
if(error.error == QJsonParseError::NoError) {
for(const auto &result : doc.object().value(QStringLiteral("results")).toArray()) {
QJsonObject obj = result.toObject();
QString packageName = obj.value(QStringLiteral("Name")).toString();
if(!packageName.isEmpty()) {
auto &package = m_packages[packageName];
auto &package = packages[packageName];
if(package) {
static_cast<AurPackage *>(package.get())->putJson(obj);
} else {
@ -69,8 +70,8 @@ void AurPackageReply::processData()
emit resultsAvailable();
}
AurFullPackageReply::AurFullPackageReply(const QList<QNetworkReply *> &networkReplies, UserRepository *userRepo) :
PackageReply(networkReplies, userRepo->packages()),
AurFullPackageReply::AurFullPackageReply(const QList<QNetworkReply *> &networkReplies, const QStringList &requestedPackages, UserRepository *userRepo) :
PackageReply(networkReplies, requestedPackages, userRepo),
m_userRepo(userRepo)
{}
@ -122,7 +123,7 @@ void AurSuggestionsReply::processData()
//QByteArray data = m_networkReply->readAll();
//cerr << shchar << "AUR reply: " << data.data() << endl;
//const QJsonDocument doc = QJsonDocument::fromJson(data, &error);
const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &error);
const auto doc = QJsonDocument::fromJson(reply->readAll(), &error);
if(error.error == QJsonParseError::NoError) {
auto &packages = m_repo->packages();
if(doc.isObject()) {
@ -226,7 +227,7 @@ AurPackageReply *UserRepository::requestPackageInfo(const QStringList &packageNa
auto url = m_aurRpcUrl;
query.addQueryItem(rpcRequestTypeKey, rpcRequestTypeMultiInfo);
url.setQuery(query);
return new AurPackageReply(m_networkAccessManager.get(QNetworkRequest(url)), this);
return new AurPackageReply(m_networkAccessManager.get(QNetworkRequest(url)), packageNames, this);
}
}
@ -252,7 +253,7 @@ AurFullPackageReply *UserRepository::requestFullPackageInfo(const QStringList &p
if(replies.isEmpty()) {
return nullptr;
} else {
return new AurFullPackageReply(replies, this);
return new AurFullPackageReply(replies, packageNames, this);
}
}

View File

@ -21,7 +21,7 @@ class AurPackageReply : public PackageReply
{
Q_OBJECT
public:
AurPackageReply(QNetworkReply *networkReply, UserRepository *userRepo);
AurPackageReply(QNetworkReply *networkReply, const QStringList &requestedPackages, UserRepository *userRepo);
private slots:
void processData();
@ -34,7 +34,7 @@ class AurFullPackageReply : public PackageReply
{
Q_OBJECT
public:
AurFullPackageReply(const QList<QNetworkReply *> &networkReplies, UserRepository *userRepo);
AurFullPackageReply(const QList<QNetworkReply *> &networkReplies, const QStringList &requestedPackages, UserRepository *userRepo);
private slots:
void processData();