repoindex/alpm/packageinfolookup.cpp

142 lines
5.4 KiB
C++

#include "./packageinfolookup.h"
#include "./repository.h"
#include <cassert>
using namespace std;
namespace RepoIndex {
PackageInfoLookup::PackageInfoLookup(Manager &manager, const QJsonObject &request, QObject *parent) :
PackageLookup(parent),
m_manager(manager),
m_what(request.value(QStringLiteral("what")).toString()),
m_part(Manager::None)
{
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();
m_repos.reserve(m_packageSelection.size());
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()) {
m_repos << qMakePair(repo, packagesToBeRequested);
}
} else {
// specified repository can not be found
QJsonObject errorObj;
errorObj.insert(QStringLiteral("repo"), i.key());
errorObj.insert(QStringLiteral("error"), QStringLiteral("na"));
m_results << errorObj;
}
}
performLookup();
}
void PackageInfoLookup::performLookup()
{
for(auto &entry : m_repos) {
if(Repository *repo = entry.first) {
const QStringList &packagesToBeRequested = entry.second;
if(repo->isBusy()) {
// repo is busy -> try again when available
connect(repo, &Repository::available, this, &PackageInfoLookup::performLookup);
} else {
// disconnect to ensure the lookup isn't done twice
disconnect(repo, nullptr, this, nullptr);
// this repo can be skipped when this method is called again because other repos where busy
entry.first = nullptr;
// request package info
QReadLocker locker(repo->lock());
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: repo already processed
}
}
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()
{
#ifdef DEBUG_BUILD
assert(m_remainingReplies);
#endif
auto *reply = static_cast<PackageReply *>(sender());
reply->deleteLater();
if(reply->error().isEmpty()) {
QReadLocker lock(reply->repository()->lock());
addResultsDirectly(reply->requestedPackages(), reply->repository());
} else {
// TODO: bunch error messages together
for(const auto &packageName : reply->requestedPackages()) {
QJsonObject res;
res.insert(QStringLiteral("name"), packageName);
res.insert(QStringLiteral("repo"), reply->repository()->name());
res.insert(QStringLiteral("error"), reply->error());
m_results << res;
}
}
if(!--m_remainingReplies) {
emit resultsAvailable(m_what, m_id, m_results);
deleteLater();
}
}
} // namespace RepoIndex