diff --git a/alpm/manager.cpp b/alpm/manager.cpp index 88e99a6..16b5128 100644 --- a/alpm/manager.cpp +++ b/alpm/manager.cpp @@ -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; } } diff --git a/alpm/package.cpp b/alpm/package.cpp index 5ceacaf..26f674c 100644 --- a/alpm/package.cpp +++ b/alpm/package.cpp @@ -1,4 +1,4 @@ - #include "./package.h" +#include "./package.h" #include "./alpmdatabase.h" #include "./utilities.h" #include "./repository.h" diff --git a/alpm/packageinfolookup.cpp b/alpm/packageinfolookup.cpp index 854ded2..cd6fa4a 100644 --- a/alpm/packageinfolookup.cpp +++ b/alpm/packageinfolookup.cpp @@ -1,49 +1,101 @@ #include "./packageinfolookup.h" #include "./repository.h" +#include + +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(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(); } } diff --git a/alpm/packageinfolookup.h b/alpm/packageinfolookup.h index cdacd93..ae3683e 100644 --- a/alpm/packageinfolookup.h +++ b/alpm/packageinfolookup.h @@ -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 m_packages; }; diff --git a/alpm/packagelookup.cpp b/alpm/packagelookup.cpp index c7b4094..1936236 100644 --- a/alpm/packagelookup.cpp +++ b/alpm/packagelookup.cpp @@ -1,4 +1 @@ #include "./packagelookup.h" - - - diff --git a/alpm/repository.cpp b/alpm/repository.cpp index c98ee61..c8cb458 100644 --- a/alpm/repository.cpp +++ b/alpm/repository.cpp @@ -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; } } diff --git a/alpm/repository.h b/alpm/repository.h index 2c4234e..c48c840 100644 --- a/alpm/repository.h +++ b/alpm/repository.h @@ -45,27 +45,36 @@ class PackageReply : public Reply { Q_OBJECT public: - PackageReply(QNetworkReply *networkReply, std::map > &packages); - PackageReply(const QList &networkReplies, std::map > &packages); - const std::map > &packages() const; + PackageReply(QNetworkReply *networkReply, const QStringList &requestedPackages, Repository *repo); + PackageReply(const QList &networkReplies, const QStringList &requestedPackages, Repository *repo); + const QStringList &requestedPackages() const; + const Repository *repository() const; protected: - std::map > &m_packages; + QStringList m_requestedPackages; + Repository *m_repo; }; -inline PackageReply::PackageReply(QNetworkReply *networkReply, std::map > &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 &networkReplies, std::map > &packages) : +inline PackageReply::PackageReply(const QList &networkReplies, const QStringList &requestedPackages, Repository *repo) : Reply(networkReplies), - m_packages(packages) + m_requestedPackages(requestedPackages), + m_repo(repo) {} -inline const std::map > &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 diff --git a/alpm/upgradelookup.h b/alpm/upgradelookup.h index 2617ad1..53475fc 100644 --- a/alpm/upgradelookup.h +++ b/alpm/upgradelookup.h @@ -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 diff --git a/network/connection.cpp b/network/connection.cpp index 915f8b1..7b55453 100644 --- a/network/connection.cpp +++ b/network/connection.cpp @@ -71,6 +71,28 @@ void Connection::sendResults(const QJsonValue &what, const QJsonValue &id, const sendJson(response); } +template +void Connection::performLookup(const QJsonObject &request, Args &&...args) +{ + auto *lookup = new Lookup(forward(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(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(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(obj, m_manager, obj); } else if(what == QLatin1String("ping")) { sendResult(what, id, QStringLiteral("pong")); } else { diff --git a/network/connection.h b/network/connection.h index f5bb3af..bc02424 100644 --- a/network/connection.h +++ b/network/connection.h @@ -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 void performLookup(const QJsonObject &request, Args &&...args); QWebSocket *m_socket; RepoIndex::Manager &m_manager; bool m_repoInfoUpdatesRequested; bool m_groupInfoUpdatesRequested; - }; } diff --git a/network/userrepository.cpp b/network/userrepository.cpp index a918605..1cad5e5 100644 --- a/network/userrepository.cpp +++ b/network/userrepository.cpp @@ -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(package.get())->putJson(obj); } else { @@ -69,8 +70,8 @@ void AurPackageReply::processData() emit resultsAvailable(); } -AurFullPackageReply::AurFullPackageReply(const QList &networkReplies, UserRepository *userRepo) : - PackageReply(networkReplies, userRepo->packages()), +AurFullPackageReply::AurFullPackageReply(const QList &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); } } diff --git a/network/userrepository.h b/network/userrepository.h index 19a8794..8619254 100644 --- a/network/userrepository.h +++ b/network/userrepository.h @@ -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 &networkReplies, UserRepository *userRepo); + AurFullPackageReply(const QList &networkReplies, const QStringList &requestedPackages, UserRepository *userRepo); private slots: void processData();