Limit results returned by the API for better scalability
This commit is contained in:
parent
ff7f039519
commit
90ff9678fe
|
@ -1 +1 @@
|
||||||
Subproject commit bf6dbf0e42c081c7b75bea9bb59ffbd0c0d6b529
|
Subproject commit f6fd78155b0a4fd229b1b352fe87efed2460d982
|
|
@ -97,7 +97,8 @@ Database *Config::findOrCreateDatabaseFromDenotation(std::string_view databaseDe
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns all packages with the specified database name, database architecture and package name.
|
* \brief Returns all packages with the specified database name, database architecture and package name.
|
||||||
*/
|
*/
|
||||||
std::vector<PackageSearchResult> Config::findPackages(std::tuple<std::string_view, std::string_view, std::string_view> dbAndPackageName)
|
std::vector<PackageSearchResult> Config::findPackages(
|
||||||
|
std::tuple<std::string_view, std::string_view, std::string_view> dbAndPackageName, std::size_t limit)
|
||||||
{
|
{
|
||||||
auto pkgs = std::vector<PackageSearchResult>();
|
auto pkgs = std::vector<PackageSearchResult>();
|
||||||
const auto &[dbName, dbArch, packageName] = dbAndPackageName;
|
const auto &[dbName, dbArch, packageName] = dbAndPackageName;
|
||||||
|
@ -115,6 +116,9 @@ std::vector<PackageSearchResult> Config::findPackages(std::tuple<std::string_vie
|
||||||
if (const auto [id, package] = db.findPackageWithID(name); package) {
|
if (const auto [id, package] = db.findPackageWithID(name); package) {
|
||||||
pkgs.emplace_back(db, package, id);
|
pkgs.emplace_back(db, package, id);
|
||||||
}
|
}
|
||||||
|
if (pkgs.size() >= limit) {
|
||||||
|
return pkgs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return pkgs;
|
return pkgs;
|
||||||
}
|
}
|
||||||
|
@ -146,7 +150,7 @@ PackageSearchResult Config::findPackage(const Dependency &dependency)
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns all packages satisfying \a dependency or - if \a reverse is true - all packages requiring \a dependency.
|
* \brief Returns all packages satisfying \a dependency or - if \a reverse is true - all packages requiring \a dependency.
|
||||||
*/
|
*/
|
||||||
std::vector<PackageSearchResult> Config::findPackages(const Dependency &dependency, bool reverse)
|
std::vector<PackageSearchResult> Config::findPackages(const Dependency &dependency, bool reverse, std::size_t limit)
|
||||||
{
|
{
|
||||||
auto results = std::vector<PackageSearchResult>();
|
auto results = std::vector<PackageSearchResult>();
|
||||||
for (auto &db : databases) {
|
for (auto &db : databases) {
|
||||||
|
@ -155,7 +159,7 @@ std::vector<PackageSearchResult> Config::findPackages(const Dependency &dependen
|
||||||
if (visited.emplace(packageID).second) {
|
if (visited.emplace(packageID).second) {
|
||||||
results.emplace_back(db, package, packageID);
|
results.emplace_back(db, package, packageID);
|
||||||
}
|
}
|
||||||
return false;
|
return results.size() >= limit;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
|
@ -164,7 +168,7 @@ std::vector<PackageSearchResult> Config::findPackages(const Dependency &dependen
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns all packages providing \a library or - if \a reverse is true - all packages requiring \a library.
|
* \brief Returns all packages providing \a library or - if \a reverse is true - all packages requiring \a library.
|
||||||
*/
|
*/
|
||||||
std::vector<PackageSearchResult> Config::findPackagesProvidingLibrary(const std::string &library, bool reverse)
|
std::vector<PackageSearchResult> Config::findPackagesProvidingLibrary(const std::string &library, bool reverse, std::size_t limit)
|
||||||
{
|
{
|
||||||
auto results = std::vector<PackageSearchResult>();
|
auto results = std::vector<PackageSearchResult>();
|
||||||
auto visited = std::unordered_set<StorageID>();
|
auto visited = std::unordered_set<StorageID>();
|
||||||
|
@ -173,7 +177,7 @@ std::vector<PackageSearchResult> Config::findPackagesProvidingLibrary(const std:
|
||||||
if (visited.emplace(packageID).second) {
|
if (visited.emplace(packageID).second) {
|
||||||
results.emplace_back(db, package, packageID);
|
results.emplace_back(db, package, packageID);
|
||||||
}
|
}
|
||||||
return false;
|
return results.size() >= limit;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
|
@ -182,7 +186,7 @@ std::vector<PackageSearchResult> Config::findPackagesProvidingLibrary(const std:
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns all packages which names matches \a regex.
|
* \brief Returns all packages which names matches \a regex.
|
||||||
*/
|
*/
|
||||||
std::vector<PackageSearchResult> Config::findPackages(const std::regex ®ex)
|
std::vector<PackageSearchResult> Config::findPackages(const std::regex ®ex, std::size_t limit)
|
||||||
{
|
{
|
||||||
auto pkgs = std::vector<PackageSearchResult>();
|
auto pkgs = std::vector<PackageSearchResult>();
|
||||||
for (auto &db : databases) {
|
for (auto &db : databases) {
|
||||||
|
@ -191,13 +195,14 @@ std::vector<PackageSearchResult> Config::findPackages(const std::regex ®ex)
|
||||||
auto [packageID, package] = getPackage();
|
auto [packageID, package] = getPackage();
|
||||||
pkgs.emplace_back(db, package, packageID);
|
pkgs.emplace_back(db, package, packageID);
|
||||||
}
|
}
|
||||||
return false;
|
return pkgs.size() >= limit;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return pkgs;
|
return pkgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(const Database &)> &databasePred, std::string_view term)
|
std::vector<PackageSearchResult> Config::findPackages(
|
||||||
|
const std::function<bool(const Database &)> &databasePred, std::string_view term, std::size_t limit)
|
||||||
{
|
{
|
||||||
auto pkgs = std::vector<PackageSearchResult>();
|
auto pkgs = std::vector<PackageSearchResult>();
|
||||||
for (auto &db : databases) {
|
for (auto &db : databases) {
|
||||||
|
@ -209,7 +214,7 @@ std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(c
|
||||||
const auto [packageID, package] = getPackage();
|
const auto [packageID, package] = getPackage();
|
||||||
pkgs.emplace_back(db, package, packageID);
|
pkgs.emplace_back(db, package, packageID);
|
||||||
}
|
}
|
||||||
return false;
|
return pkgs.size() >= limit;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return pkgs;
|
return pkgs;
|
||||||
|
@ -219,13 +224,16 @@ std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(c
|
||||||
* \brief Returns all packages considered "the same" as \a package.
|
* \brief Returns all packages considered "the same" as \a package.
|
||||||
* \remarks See Package::isSame().
|
* \remarks See Package::isSame().
|
||||||
*/
|
*/
|
||||||
std::vector<PackageSearchResult> Config::findPackages(const Package &package)
|
std::vector<PackageSearchResult> Config::findPackages(const Package &package, std::size_t limit)
|
||||||
{
|
{
|
||||||
auto pkgs = std::vector<PackageSearchResult>();
|
auto pkgs = std::vector<PackageSearchResult>();
|
||||||
for (auto &db : databases) {
|
for (auto &db : databases) {
|
||||||
if (const auto [id, pkg] = db.findPackageWithID(package.name); pkg && pkg->isSame(package)) {
|
if (const auto [id, pkg] = db.findPackageWithID(package.name); pkg && pkg->isSame(package)) {
|
||||||
pkgs.emplace_back(db, pkg, id);
|
pkgs.emplace_back(db, pkg, id);
|
||||||
}
|
}
|
||||||
|
if (pkgs.size() >= limit) {
|
||||||
|
return pkgs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return pkgs;
|
return pkgs;
|
||||||
}
|
}
|
||||||
|
@ -233,8 +241,8 @@ std::vector<PackageSearchResult> Config::findPackages(const Package &package)
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns all packages \a packagePred returns true for from all databases \a databasePred returns true for.
|
* \brief Returns all packages \a packagePred returns true for from all databases \a databasePred returns true for.
|
||||||
*/
|
*/
|
||||||
std::vector<PackageSearchResult> Config::findPackages(
|
std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(const Database &)> &databasePred,
|
||||||
const std::function<bool(const Database &)> &databasePred, const std::function<bool(const Database &, const Package &)> &packagePred)
|
const std::function<bool(const Database &, const Package &)> &packagePred, std::size_t limit)
|
||||||
{
|
{
|
||||||
auto pkgs = std::vector<PackageSearchResult>();
|
auto pkgs = std::vector<PackageSearchResult>();
|
||||||
for (auto &db : databases) {
|
for (auto &db : databases) {
|
||||||
|
@ -245,7 +253,7 @@ std::vector<PackageSearchResult> Config::findPackages(
|
||||||
if (packagePred(db, *package)) {
|
if (packagePred(db, *package)) {
|
||||||
pkgs.emplace_back(db, std::move(package), packageID);
|
pkgs.emplace_back(db, std::move(package), packageID);
|
||||||
}
|
}
|
||||||
return false;
|
return pkgs.size() >= limit;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return pkgs;
|
return pkgs;
|
||||||
|
@ -254,7 +262,7 @@ std::vector<PackageSearchResult> Config::findPackages(
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns all packages \a pred returns true for.
|
* \brief Returns all packages \a pred returns true for.
|
||||||
*/
|
*/
|
||||||
std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(const Database &, const Package &)> &pred)
|
std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(const Database &, const Package &)> &pred, std::size_t limit)
|
||||||
{
|
{
|
||||||
auto pkgs = std::vector<PackageSearchResult>();
|
auto pkgs = std::vector<PackageSearchResult>();
|
||||||
for (auto &db : databases) {
|
for (auto &db : databases) {
|
||||||
|
@ -262,7 +270,7 @@ std::vector<PackageSearchResult> Config::findPackages(const std::function<bool(c
|
||||||
if (pred(db, *package)) {
|
if (pred(db, *package)) {
|
||||||
pkgs.emplace_back(db, std::move(package), packageID);
|
pkgs.emplace_back(db, std::move(package), packageID);
|
||||||
}
|
}
|
||||||
return false;
|
return pkgs.size() >= limit;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return pkgs;
|
return pkgs;
|
||||||
|
|
|
@ -140,18 +140,24 @@ struct LIBPKG_EXPORT Config : public Lockable, public ReflectiveRapidJSON::Binar
|
||||||
Database *findOrCreateDatabase(std::string_view name, std::string_view architecture);
|
Database *findOrCreateDatabase(std::string_view name, std::string_view architecture);
|
||||||
Database *findOrCreateDatabaseFromDenotation(std::string_view databaseDenotation);
|
Database *findOrCreateDatabaseFromDenotation(std::string_view databaseDenotation);
|
||||||
static std::tuple<std::string_view, std::string_view, std::string_view> parsePackageDenotation(std::string_view packageDenotation);
|
static std::tuple<std::string_view, std::string_view, std::string_view> parsePackageDenotation(std::string_view packageDenotation);
|
||||||
std::vector<PackageSearchResult> findPackages(std::string_view packageDenotation);
|
std::vector<PackageSearchResult> findPackages(std::string_view packageDenotation, std::size_t limit = std::numeric_limits<std::size_t>::max());
|
||||||
std::vector<PackageSearchResult> findPackages(std::string_view dbName, std::string_view dbArch, std::string_view packageName);
|
|
||||||
std::vector<PackageSearchResult> findPackages(std::tuple<std::string_view, std::string_view, std::string_view> dbAndPackageName);
|
|
||||||
PackageSearchResult findPackage(const Dependency &dependency);
|
|
||||||
std::vector<PackageSearchResult> findPackages(const Dependency &dependency, bool reverse = false);
|
|
||||||
std::vector<PackageSearchResult> findPackagesProvidingLibrary(const std::string &library, bool reverse = false);
|
|
||||||
std::vector<PackageSearchResult> findPackages(const std::regex ®ex);
|
|
||||||
std::vector<PackageSearchResult> findPackages(const std::function<bool(const Database &)> &databasePred, std::string_view term);
|
|
||||||
std::vector<PackageSearchResult> findPackages(const Package &package);
|
|
||||||
std::vector<PackageSearchResult> findPackages(
|
std::vector<PackageSearchResult> findPackages(
|
||||||
const std::function<bool(const Database &)> &databasePred, const std::function<bool(const Database &, const Package &)> &packagePred);
|
std::string_view dbName, std::string_view dbArch, std::string_view packageName, std::size_t limit = std::numeric_limits<std::size_t>::max());
|
||||||
std::vector<PackageSearchResult> findPackages(const std::function<bool(const Database &, const Package &)> &pred);
|
std::vector<PackageSearchResult> findPackages(std::tuple<std::string_view, std::string_view, std::string_view> dbAndPackageName,
|
||||||
|
std::size_t limit = std::numeric_limits<std::size_t>::max());
|
||||||
|
PackageSearchResult findPackage(const Dependency &dependency);
|
||||||
|
std::vector<PackageSearchResult> findPackages(
|
||||||
|
const Dependency &dependency, bool reverse = false, std::size_t limit = std::numeric_limits<std::size_t>::max());
|
||||||
|
std::vector<PackageSearchResult> findPackagesProvidingLibrary(
|
||||||
|
const std::string &library, bool reverse = false, std::size_t limit = std::numeric_limits<std::size_t>::max());
|
||||||
|
std::vector<PackageSearchResult> findPackages(const std::regex ®ex, std::size_t limit = std::numeric_limits<std::size_t>::max());
|
||||||
|
std::vector<PackageSearchResult> findPackages(const std::function<bool(const Database &)> &databasePred, std::string_view term,
|
||||||
|
std::size_t limit = std::numeric_limits<std::size_t>::max());
|
||||||
|
std::vector<PackageSearchResult> findPackages(const Package &package, std::size_t limit = std::numeric_limits<std::size_t>::max());
|
||||||
|
std::vector<PackageSearchResult> findPackages(const std::function<bool(const Database &)> &databasePred,
|
||||||
|
const std::function<bool(const Database &, const Package &)> &packagePred, std::size_t limit = std::numeric_limits<std::size_t>::max());
|
||||||
|
std::vector<PackageSearchResult> findPackages(
|
||||||
|
const std::function<bool(const Database &, const Package &)> &pred, std::size_t limit = std::numeric_limits<std::size_t>::max());
|
||||||
|
|
||||||
std::vector<Database> databases;
|
std::vector<Database> databases;
|
||||||
Database aur = Database("aur");
|
Database aur = Database("aur");
|
||||||
|
@ -181,14 +187,15 @@ inline Status Config::computeStatus() const
|
||||||
return Status(*this);
|
return Status(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::vector<PackageSearchResult> Config::findPackages(std::string_view dbName, std::string_view dbArch, std::string_view packageName)
|
inline std::vector<PackageSearchResult> Config::findPackages(
|
||||||
|
std::string_view dbName, std::string_view dbArch, std::string_view packageName, std::size_t limit)
|
||||||
{
|
{
|
||||||
return findPackages(std::make_tuple(dbName, dbArch, packageName));
|
return findPackages(std::make_tuple(dbName, dbArch, packageName), limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::vector<PackageSearchResult> Config::findPackages(std::string_view packageDenotation)
|
inline std::vector<PackageSearchResult> Config::findPackages(std::string_view packageDenotation, std::size_t limit)
|
||||||
{
|
{
|
||||||
return findPackages(parsePackageDenotation(packageDenotation));
|
return findPackages(parsePackageDenotation(packageDenotation), limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace LibPkg
|
} // namespace LibPkg
|
||||||
|
|
|
@ -39,7 +39,7 @@ inline std::optional<std::string_view> getLastValueSv(const std::multimap<std::s
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TargetType, Traits::DisableIf<std::is_integral<TargetType>> * = nullptr>
|
template <typename TargetType, Traits::DisableIfAny<std::is_integral<TargetType>, Traits::IsSpecializationOf<TargetType, std::atomic>> * = nullptr>
|
||||||
void convertValue(const std::multimap<std::string, std::string> &multimap, const std::string &key, TargetType &result);
|
void convertValue(const std::multimap<std::string, std::string> &multimap, const std::string &key, TargetType &result);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -60,7 +60,7 @@ inline void convertValue(const std::multimap<std::string, std::string> &multimap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TargetType, Traits::EnableIf<std::is_integral<TargetType>> * = nullptr>
|
template <typename TargetType, Traits::EnableIfAny<std::is_integral<TargetType>, Traits::IsSpecializationOf<TargetType, std::atomic>> * = nullptr>
|
||||||
inline void convertValue(const std::multimap<std::string, std::string> &multimap, const std::string &key, TargetType &result)
|
inline void convertValue(const std::multimap<std::string, std::string> &multimap, const std::string &key, TargetType &result)
|
||||||
{
|
{
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -69,7 +69,11 @@ inline void convertValue(const std::multimap<std::string, std::string> &multimap
|
||||||
|
|
||||||
if (const char *const value = getLastValue(multimap, key)) {
|
if (const char *const value = getLastValue(multimap, key)) {
|
||||||
try {
|
try {
|
||||||
result = stringToNumber<TargetType>(value);
|
if constexpr (Traits::IsSpecializationOf<TargetType, std::atomic>::value) {
|
||||||
|
result = stringToNumber<typename TargetType::value_type>(value);
|
||||||
|
} else {
|
||||||
|
result = stringToNumber<TargetType>(value);
|
||||||
|
}
|
||||||
} catch (const ConversionException &) {
|
} catch (const ConversionException &) {
|
||||||
cerr << Phrases::ErrorMessage << "Specified number \"" << value << "\" for key \"" << key << "\" is invalid." << Phrases::End;
|
cerr << Phrases::ErrorMessage << "Specified number \"" << value << "\" for key \"" << key << "\" is invalid." << Phrases::End;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -90,6 +90,8 @@ void ServiceSetup::WebServerSetup::applyConfig(const std::multimap<std::string,
|
||||||
convertValue(multimap, "port", port);
|
convertValue(multimap, "port", port);
|
||||||
convertValue(multimap, "threads", threadCount);
|
convertValue(multimap, "threads", threadCount);
|
||||||
convertValue(multimap, "static_files", staticFilesPath);
|
convertValue(multimap, "static_files", staticFilesPath);
|
||||||
|
convertValue(multimap, "package_search_response_limit", packageSearchResponseLimit);
|
||||||
|
convertValue(multimap, "build_actions_response_limit", buildActionsResponseLimit);
|
||||||
convertValue(multimap, "verify_ssl_certificates", verifySslCertificates);
|
convertValue(multimap, "verify_ssl_certificates", verifySslCertificates);
|
||||||
convertValue(multimap, "log_ssl_certificate_validation", logSslCertificateValidation);
|
convertValue(multimap, "log_ssl_certificate_validation", logSslCertificateValidation);
|
||||||
|
|
||||||
|
@ -338,11 +340,16 @@ std::size_t ServiceSetup::BuildSetup::buildActionCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceSetup::BuildSetup::forEachBuildAction(
|
void ServiceSetup::BuildSetup::forEachBuildAction(
|
||||||
std::function<void(std::size_t)> count, std::function<bool(LibPkg::StorageID, BuildAction &&)> &&func)
|
std::function<void(std::size_t)> count, std::function<bool(LibPkg::StorageID, BuildAction &&)> &&func, std::size_t limit, std::size_t start)
|
||||||
{
|
{
|
||||||
auto txn = m_storage->buildActions.getROTransaction();
|
auto txn = m_storage->buildActions.getROTransaction();
|
||||||
count(txn.size());
|
const auto total = txn.size();
|
||||||
for (auto i = txn.begin(); i != txn.end(); ++i) {
|
count(std::min(limit, total));
|
||||||
|
const auto reverse = start == std::numeric_limits<std::size_t>::max();
|
||||||
|
for (auto i = reverse ? txn.rbegin()
|
||||||
|
: txn.lower_bound(static_cast<LibPkg::StorageID>(
|
||||||
|
start > std::numeric_limits<LibPkg::StorageID>::max() ? std::numeric_limits<LibPkg::StorageID>::max() : start));
|
||||||
|
i != txn.end() && limit; reverse ? --i : ++i, --limit) {
|
||||||
if (func(i.getID(), std::move(i.value()))) {
|
if (func(i.getID(), std::move(i.value()))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,8 @@ struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable {
|
||||||
unsigned short threadCount = 1;
|
unsigned short threadCount = 1;
|
||||||
boost::asio::io_context ioContext;
|
boost::asio::io_context ioContext;
|
||||||
boost::asio::ssl::context sslContext{ boost::asio::ssl::context::sslv23_client };
|
boost::asio::ssl::context sslContext{ boost::asio::ssl::context::sslv23_client };
|
||||||
|
std::atomic_size_t packageSearchResponseLimit = 20000; // sufficient to return a "full architecture"
|
||||||
|
std::atomic_size_t buildActionsResponseLimit = 200;
|
||||||
bool verifySslCertificates = true;
|
bool verifySslCertificates = true;
|
||||||
bool logSslCertificateValidation = false;
|
bool logSslCertificateValidation = false;
|
||||||
|
|
||||||
|
@ -138,7 +140,8 @@ struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable {
|
||||||
void deleteBuildAction(const std::vector<std::shared_ptr<BuildAction>> &actions);
|
void deleteBuildAction(const std::vector<std::shared_ptr<BuildAction>> &actions);
|
||||||
std::size_t buildActionCount();
|
std::size_t buildActionCount();
|
||||||
std::size_t runningBuildActionCount();
|
std::size_t runningBuildActionCount();
|
||||||
void forEachBuildAction(std::function<void(std::size_t)> count, std::function<bool(LibPkg::StorageID, BuildAction &&)> &&func);
|
void forEachBuildAction(std::function<void(std::size_t)> count, std::function<bool(LibPkg::StorageID, BuildAction &&)> &&func,
|
||||||
|
std::size_t limit, std::size_t start);
|
||||||
void forEachBuildAction(std::function<bool(LibPkg::StorageID, BuildAction &, bool &)> &&func);
|
void forEachBuildAction(std::function<bool(LibPkg::StorageID, BuildAction &, bool &)> &&func);
|
||||||
std::vector<std::shared_ptr<BuildAction>> followUpBuildActions(BuildActionIdType forId);
|
std::vector<std::shared_ptr<BuildAction>> followUpBuildActions(BuildActionIdType forId);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
#include "./session.h"
|
#include "./session.h"
|
||||||
#include "./typedefs.h"
|
#include "./typedefs.h"
|
||||||
|
|
||||||
|
#include <c++utilities/conversion/stringbuilder.h>
|
||||||
|
#include <c++utilities/conversion/stringconversion.h>
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
@ -51,10 +54,28 @@ struct LIBREPOMGR_EXPORT Url {
|
||||||
bool hasPrettyFlag() const;
|
bool hasPrettyFlag() const;
|
||||||
std::string_view value(std::string_view paramName) const;
|
std::string_view value(std::string_view paramName) const;
|
||||||
std::vector<std::string> decodeValues(std::string_view paramName) const;
|
std::vector<std::string> decodeValues(std::string_view paramName) const;
|
||||||
|
template <typename Number> Number asNumber(std::string_view paramName, Number def = Number()) const;
|
||||||
static std::string decodeValue(std::string_view value);
|
static std::string decodeValue(std::string_view value);
|
||||||
static std::string encodeValue(std::string_view value);
|
static std::string encodeValue(std::string_view value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Number> Number Url::asNumber(std::string_view paramName, Number def) const
|
||||||
|
{
|
||||||
|
using namespace CppUtilities;
|
||||||
|
const auto values = decodeValues(paramName);
|
||||||
|
if (values.size() > 1) {
|
||||||
|
throw BadRequest("more than one " % paramName + " specified");
|
||||||
|
}
|
||||||
|
if (!values.empty()) {
|
||||||
|
try {
|
||||||
|
return stringToNumber<Number>(values.front());
|
||||||
|
} catch (const ConversionException &) {
|
||||||
|
throw BadRequest(argsToString(paramName, " must be an integer"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool Url::hasPrettyFlag() const
|
inline bool Url::hasPrettyFlag() const
|
||||||
{
|
{
|
||||||
return hasFlag("pretty");
|
return hasFlag("pretty");
|
||||||
|
|
|
@ -150,7 +150,7 @@ void getUnresolved(const Params ¶ms, ResponseHandler &&handler)
|
||||||
void getPackages(const Params ¶ms, ResponseHandler &&handler)
|
void getPackages(const Params ¶ms, ResponseHandler &&handler)
|
||||||
{
|
{
|
||||||
// read mode
|
// read mode
|
||||||
const auto modes(params.target.decodeValues("mode"));
|
const auto modes = params.target.decodeValues("mode");
|
||||||
if (modes.size() > 1) {
|
if (modes.size() > 1) {
|
||||||
throw BadRequest("more than one mode specified");
|
throw BadRequest("more than one mode specified");
|
||||||
}
|
}
|
||||||
|
@ -181,6 +181,13 @@ void getPackages(const Params ¶ms, ResponseHandler &&handler)
|
||||||
mode = modeIterator->second;
|
mode = modeIterator->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// limit
|
||||||
|
auto limit = params.target.asNumber<std::size_t>("limit");
|
||||||
|
const auto serverLimit = params.setup.webServer.packageSearchResponseLimit.load();
|
||||||
|
if (!limit || limit > serverLimit) {
|
||||||
|
limit = serverLimit;
|
||||||
|
}
|
||||||
|
|
||||||
// check for details flag
|
// check for details flag
|
||||||
const auto details = params.target.hasFlag("details");
|
const auto details = params.target.hasFlag("details");
|
||||||
if (details && mode != Mode::Name) {
|
if (details && mode != Mode::Name) {
|
||||||
|
@ -214,7 +221,8 @@ void getPackages(const Params ¶ms, ResponseHandler &&handler)
|
||||||
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kArrayType);
|
RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kArrayType);
|
||||||
RAPIDJSON_NAMESPACE::Document::Array array(document.GetArray());
|
RAPIDJSON_NAMESPACE::Document::Array array(document.GetArray());
|
||||||
|
|
||||||
const auto pushPackages = [&dbs, &document, &array](auto &&packages) {
|
const auto pushPackages = [&dbs, &document, &array, &limit](auto &&packages) {
|
||||||
|
limit -= packages.size();
|
||||||
for (const auto &package : packages) {
|
for (const auto &package : packages) {
|
||||||
if (!dbs.empty()) {
|
if (!dbs.empty()) {
|
||||||
const auto *const db = std::get<Database *>(package.db);
|
const auto *const db = std::get<Database *>(package.db);
|
||||||
|
@ -248,15 +256,17 @@ void getPackages(const Params ¶ms, ResponseHandler &&handler)
|
||||||
} else {
|
} else {
|
||||||
neededAurPackages.emplace_back(std::move(packageNameStr));
|
neededAurPackages.emplace_back(std::move(packageNameStr));
|
||||||
}
|
}
|
||||||
|
--limit;
|
||||||
}
|
}
|
||||||
if (!isDbAur && (!dbs.empty() || !onlyFromAur)) {
|
if (!isDbAur && (!dbs.empty() || !onlyFromAur)) {
|
||||||
auto packages = params.setup.config.findPackages(packageDenotation);
|
auto packages = params.setup.config.findPackages(packageDenotation, limit);
|
||||||
if (details) {
|
if (details) {
|
||||||
for (const auto &package : packages) {
|
for (const auto &package : packages) {
|
||||||
if (dbs.empty() || dbs.find(std::get<LibPkg::Database *>(package.db)->name) != dbs.end()) {
|
if (dbs.empty() || dbs.find(std::get<LibPkg::Database *>(package.db)->name) != dbs.end()) {
|
||||||
ReflectiveRapidJSON::JsonReflector::push(package.pkg, array, document.GetAllocator());
|
ReflectiveRapidJSON::JsonReflector::push(package.pkg, array, document.GetAllocator());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
limit -= packages.size();
|
||||||
} else {
|
} else {
|
||||||
pushPackages(std::move(packages));
|
pushPackages(std::move(packages));
|
||||||
}
|
}
|
||||||
|
@ -265,7 +275,8 @@ void getPackages(const Params ¶ms, ResponseHandler &&handler)
|
||||||
}
|
}
|
||||||
case Mode::NameContains:
|
case Mode::NameContains:
|
||||||
pushPackages(params.setup.config.findPackages(
|
pushPackages(params.setup.config.findPackages(
|
||||||
[&dbs, onlyFromAur](const LibPkg::Database &db) { return (dbs.empty() && !onlyFromAur) || dbs.find(db.name) != dbs.end(); }, name));
|
[&dbs, onlyFromAur](const LibPkg::Database &db) { return (dbs.empty() && !onlyFromAur) || dbs.find(db.name) != dbs.end(); }, name,
|
||||||
|
limit));
|
||||||
if (fromAur && !name.empty()) {
|
if (fromAur && !name.empty()) {
|
||||||
neededAurPackages.emplace_back(std::move(name));
|
neededAurPackages.emplace_back(std::move(name));
|
||||||
}
|
}
|
||||||
|
@ -273,7 +284,7 @@ void getPackages(const Params ¶ms, ResponseHandler &&handler)
|
||||||
case Mode::Regex:
|
case Mode::Regex:
|
||||||
// assume names are regexes
|
// assume names are regexes
|
||||||
try {
|
try {
|
||||||
pushPackages(params.setup.config.findPackages(std::regex(name.data(), name.size())));
|
pushPackages(params.setup.config.findPackages(std::regex(name.data(), name.size()), limit));
|
||||||
} catch (const std::regex_error &e) {
|
} catch (const std::regex_error &e) {
|
||||||
throw BadRequest(argsToString("regex is invalid: ", e.what()));
|
throw BadRequest(argsToString("regex is invalid: ", e.what()));
|
||||||
}
|
}
|
||||||
|
@ -281,12 +292,12 @@ void getPackages(const Params ¶ms, ResponseHandler &&handler)
|
||||||
case Mode::Provides:
|
case Mode::Provides:
|
||||||
case Mode::Depends:
|
case Mode::Depends:
|
||||||
// assume names are dependency notation
|
// assume names are dependency notation
|
||||||
pushPackages(params.setup.config.findPackages(Dependency::fromString(name), mode == Mode::Depends));
|
pushPackages(params.setup.config.findPackages(Dependency::fromString(name), mode == Mode::Depends, limit));
|
||||||
break;
|
break;
|
||||||
case Mode::LibProvides:
|
case Mode::LibProvides:
|
||||||
case Mode::LibDepends:
|
case Mode::LibDepends:
|
||||||
// assume names are "normalized" library names with platform prefix
|
// assume names are "normalized" library names with platform prefix
|
||||||
pushPackages(params.setup.config.findPackagesProvidingLibrary(name, mode == Mode::LibDepends));
|
pushPackages(params.setup.config.findPackagesProvidingLibrary(name, mode == Mode::LibDepends, limit));
|
||||||
break;
|
break;
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,13 +23,21 @@ void getBuildActions(const Params ¶ms, ResponseHandler &&handler)
|
||||||
RAPIDJSON_NAMESPACE::Document jsonDoc(RAPIDJSON_NAMESPACE::kArrayType);
|
RAPIDJSON_NAMESPACE::Document jsonDoc(RAPIDJSON_NAMESPACE::kArrayType);
|
||||||
RAPIDJSON_NAMESPACE::Value::Array array(jsonDoc.GetArray());
|
RAPIDJSON_NAMESPACE::Value::Array array(jsonDoc.GetArray());
|
||||||
|
|
||||||
|
const auto start = params.target.asNumber<std::size_t>("start", std::numeric_limits<std::size_t>::max());
|
||||||
|
const auto serverLimit = params.setup.webServer.buildActionsResponseLimit.load();
|
||||||
|
auto limit = params.target.asNumber<std::size_t>("limit");
|
||||||
|
if (!limit || limit > serverLimit) {
|
||||||
|
limit = serverLimit;
|
||||||
|
}
|
||||||
|
|
||||||
auto buildActionLock = params.setup.building.lockToRead();
|
auto buildActionLock = params.setup.building.lockToRead();
|
||||||
params.setup.building.forEachBuildAction(
|
params.setup.building.forEachBuildAction(
|
||||||
[&array, &jsonDoc](std::size_t count) { array.Reserve(ReflectiveRapidJSON::JsonReflector::rapidJsonSize(count), jsonDoc.GetAllocator()); },
|
[&array, &jsonDoc](std::size_t count) { array.Reserve(ReflectiveRapidJSON::JsonReflector::rapidJsonSize(count), jsonDoc.GetAllocator()); },
|
||||||
[&array, &jsonDoc](LibPkg::StorageID, BuildAction &&buildAction) {
|
[&array, &jsonDoc, limit](LibPkg::StorageID, BuildAction &&buildAction) {
|
||||||
ReflectiveRapidJSON::JsonReflector::push(BuildActionBasicInfo(buildAction), array, jsonDoc.GetAllocator());
|
ReflectiveRapidJSON::JsonReflector::push(BuildActionBasicInfo(buildAction), array, jsonDoc.GetAllocator());
|
||||||
return false;
|
return array.Size() >= limit;
|
||||||
});
|
},
|
||||||
|
limit, start);
|
||||||
buildActionLock.unlock();
|
buildActionLock.unlock();
|
||||||
|
|
||||||
handler(makeJson(params.request(), jsonDoc, params.target.hasPrettyFlag()));
|
handler(makeJson(params.request(), jsonDoc, params.target.hasPrettyFlag()));
|
||||||
|
|
Loading…
Reference in New Issue