#include "./packageinfolookup.h" #include "./repository.h" #include 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(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