This commit is contained in:
Mars 2025-05-01 19:47:01 -04:00
parent 9a95178095
commit 631964469f
Signed by: pupbrained
GPG key ID: 0FF5B8826803F895
26 changed files with 482 additions and 335 deletions

View file

@ -18,11 +18,11 @@
#include <unistd.h> // readlink
#include <utility> // std::move
#include "src/core/util/defs.hpp"
#include "src/core/util/error.hpp"
#include "src/core/util/helpers.hpp"
#include "src/core/util/logging.hpp"
#include "src/core/util/types.hpp"
#include "src/util/defs.hpp"
#include "src/util/error.hpp"
#include "src/util/helpers.hpp"
#include "src/util/logging.hpp"
#include "src/util/types.hpp"
#include "src/wrappers/dbus.hpp"
#include "src/wrappers/wayland.hpp"
#include "src/wrappers/xcb.hpp"

View file

@ -15,13 +15,13 @@
#include <iterator> // std::istreambuf_iterator
#include <glaze/beve/read.hpp> // glz::read_beve
#include <glaze/beve/write.hpp> // glz::write_beve
#include <glaze/core/context.hpp> // glz::{context, error_code, error_ctx}
#include <system_error> // std::error_code
#include "src/core/util/defs.hpp"
#include "src/core/util/error.hpp"
#include "src/core/util/logging.hpp"
#include "src/core/util/types.hpp"
#include "src/util/cache.hpp"
#include "src/util/defs.hpp"
#include "src/util/error.hpp"
#include "src/util/logging.hpp"
#include "src/util/types.hpp"
// clang-format on
using util::error::DracError, util::error::DracErrorCode;
@ -31,6 +31,7 @@ using util::types::u64, util::types::i64, util::types::Result, util::types::Err,
namespace {
namespace fs = std::filesystem;
using namespace std::chrono;
using namespace util::cache;
using os::linux::PkgCountCacheData, os::linux::PackageManagerInfo;
fn GetPackageCountInternalDir(
@ -111,6 +112,68 @@ namespace {
return count;
}
fn GetPackageCountInternalDb(const PackageManagerInfo& pmInfo) -> Result<u64, DracError> {
const auto& [pmId, dbPath, countQuery] = pmInfo;
if (Result<PkgCountCacheData, DracError> cachedDataResult = ReadCache<PkgCountCacheData>(pmId)) {
const auto& [count, timestamp] = *cachedDataResult;
std::error_code errc;
const std::filesystem::file_time_type dbModTime = fs::last_write_time(dbPath, errc);
if (errc) {
warn_log(
"Could not get modification time for '{}': {}. Invalidating {} cache.", dbPath.string(), errc.message(), pmId
);
} else {
if (const system_clock::time_point cacheTimePoint = system_clock::time_point(seconds(timestamp));
cacheTimePoint.time_since_epoch() >= dbModTime.time_since_epoch()) {
debug_log(
"Using valid {} package count cache (DB file unchanged since {}).",
pmId,
std::format("{:%F %T %Z}", floor<seconds>(cacheTimePoint))
);
return count;
}
debug_log("{} package count cache stale (DB file modified).", pmId);
}
} else {
if (cachedDataResult.error().code != DracErrorCode::NotFound)
debug_at(cachedDataResult.error());
debug_log("{} package count cache not found or unreadable.", pmId);
}
debug_log("Fetching fresh {} package count from database: {}", pmId, dbPath.string());
u64 count = 0;
try {
const SQLite::Database database(dbPath.string(), SQLite::OPEN_READONLY);
if (SQLite::Statement query(database, countQuery); query.executeStep()) {
const i64 countInt64 = query.getColumn(0).getInt64();
if (countInt64 < 0)
return Err(
DracError(DracErrorCode::ParseError, std::format("Negative count returned by {} DB COUNT query.", pmId))
);
count = static_cast<u64>(countInt64);
} else {
return Err(DracError(DracErrorCode::ParseError, std::format("No rows returned by {} DB COUNT query.", pmId)));
}
} catch (const SQLite::Exception& e) {
return Err(DracError(
DracErrorCode::ApiUnavailable, std::format("SQLite error occurred accessing {} DB: {}", pmId, e.what())
));
} catch (const Exception& e) { return Err(DracError(DracErrorCode::InternalError, e.what())); } catch (...) {
return Err(DracError(DracErrorCode::Other, std::format("Unknown error occurred accessing {} DB", pmId)));
}
const i64 nowEpochSeconds = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
const PkgCountCacheData dataToCache = { .count = count, .timestampEpochSeconds = nowEpochSeconds };
if (Result<void, DracError> writeResult = WriteCache(pmId, dataToCache); !writeResult)
error_at(writeResult.error());
return count;
}
} // namespace
namespace os::linux {
@ -159,10 +222,9 @@ namespace os::linux {
fn GetTotalPackageCount() -> Result<u64, DracError> {
using util::types::Array, util::types::Future;
Array<Future<Result<u64, DracError>>, 4> futures = {
Array<Future<Result<u64, DracError>>, 3> futures = {
std::async(std::launch::async, GetDpkgPackageCount),
std::async(std::launch::async, GetMossPackageCount),
std::async(std::launch::async, GetNixPackageCount),
std::async(std::launch::async, GetPacmanPackageCount),
};

View file

@ -7,9 +7,9 @@
#include <glaze/core/common.hpp> // glz::object
#include <glaze/core/meta.hpp> // glz::detail::Object
#include "src/core/util/defs.hpp"
#include "src/core/util/error.hpp"
#include "src/core/util/types.hpp"
#include "src/util/defs.hpp"
#include "src/util/error.hpp"
#include "src/util/types.hpp"
// clang-format on
namespace os::linux {

View file

@ -7,9 +7,9 @@
#include "macos/bridge.hpp"
#include "os.hpp"
#include "src/core/util/defs.hpp"
#include "src/core/util/error.hpp"
#include "src/core/util/types.hpp"
#include "src/util/defs.hpp"
#include "src/util/error.hpp"
#include "src/util/types.hpp"
// clang-format on
using namespace util::types;

View file

@ -3,9 +3,9 @@
#ifdef __APPLE__
// clang-format off
#include "src/core/util/defs.hpp"
#include "src/core/util/error.hpp"
#include "src/core/util/types.hpp"
#include "src/util/defs.hpp"
#include "src/util/error.hpp"
#include "src/util/types.hpp"
// clang-format on
using util::error::DracError;
using util::types::MediaInfo, util::types::String, util::types::Result;

View file

@ -11,7 +11,7 @@
#include <string>
#include <utility>
#include "src/core/util/error.hpp"
#include "src/util/error.hpp"
// clang-format on
using util::error::DracErrorCode;

View file

@ -1,8 +1,8 @@
#pragma once
#include "src/core/util/defs.hpp"
#include "src/core/util/error.hpp"
#include "src/core/util/types.hpp"
#include "src/util/defs.hpp"
#include "src/util/error.hpp"
#include "src/util/types.hpp"
/**
* @namespace os

View file

@ -1,24 +1,24 @@
#include <SQLiteCpp/Database.h> // SQLite::{Database, OPEN_READONLY}
#include <SQLiteCpp/Exception.h> // SQLite::Exception
#include <SQLiteCpp/Statement.h> // SQLite::Statement
#include <chrono> // std::chrono
#include <filesystem> // std::filesystem
#include <format> // std::format
#include <fstream> // std::{ifstream, ofstream}
#include <glaze/beve/read.hpp> // glz::read_beve
#include <glaze/beve/write.hpp> // glz::write_beve
#include <glaze/core/common.hpp> // glz::object
#include <glaze/core/context.hpp> // glz::{context, error_code, error_ctx}
#include <glaze/core/meta.hpp> // glz::detail::Object
#include <ios> // std::ios::{binary, trunc}, std::ios_base
#include <iterator> // std::istreambuf_iterator
#include <system_error> // std::error_code
#include <SQLiteCpp/Database.h> // SQLite::{Database, OPEN_READONLY}
#include <SQLiteCpp/Exception.h> // SQLite::Exception
#include <SQLiteCpp/Statement.h> // SQLite::Statement
#include <chrono> // std::chrono
#include <filesystem> // std::filesystem
#include <format> // std::format
#include <fstream> // std::{ifstream, ofstream}
#include <glaze/beve/read.hpp> // glz::read_beve
#include <glaze/beve/write.hpp> // glz::write_beve
#include <glaze/core/common.hpp> // glz::object
#include <glaze/core/meta.hpp> // glz::detail::Object
#include <ios> // std::ios::{binary, trunc}, std::ios_base
#include <iterator> // std::istreambuf_iterator
#include <system_error> // std::error_code
#include "src/core/util/defs.hpp"
#include "src/core/util/error.hpp"
#include "src/core/util/helpers.hpp"
#include "src/core/util/logging.hpp"
#include "src/core/util/types.hpp"
#include "src/util/cache.hpp"
#include "src/util/defs.hpp"
#include "src/util/error.hpp"
#include "src/util/helpers.hpp"
#include "src/util/logging.hpp"
#include "src/util/types.hpp"
#include "os.hpp"
@ -30,6 +30,7 @@ namespace fs = std::filesystem;
namespace {
using namespace std::chrono;
using namespace util::cache;
struct PackageManagerInfo {
String id;
@ -51,136 +52,10 @@ namespace {
// NOLINTEND(readability-identifier-naming)
};
constexpr StringView ALLOWED_PMID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
fn GetPkgCountCachePath(const String& pmId) -> Result<fs::path, DracError> {
std::error_code errc;
const fs::path cacheDir = fs::temp_directory_path(errc);
if (errc)
return Err(DracError(DracErrorCode::IoError, "Failed to get temp directory: " + errc.message()));
if (pmId.empty() || pmId.find_first_not_of(ALLOWED_PMID_CHARS) != String::npos)
return Err(DracError(DracErrorCode::ParseError, "Invalid package manager ID for cache path: " + pmId));
return cacheDir / (pmId + "_pkg_count_cache.beve");
}
fn ReadPkgCountCache(const String& pmId) -> Result<PkgCountCacheData, DracError> {
Result<fs::path, DracError> cachePathResult = GetPkgCountCachePath(pmId);
if (!cachePathResult)
return Err(cachePathResult.error());
const fs::path& cachePath = *cachePathResult;
if (!fs::exists(cachePath))
return Err(DracError(DracErrorCode::NotFound, "Cache file not found: " + cachePath.string()));
std::ifstream ifs(cachePath, std::ios::binary);
if (!ifs.is_open())
return Err(DracError(DracErrorCode::IoError, "Failed to open cache file for reading: " + cachePath.string()));
try {
const String content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
ifs.close();
if (content.empty())
return Err(DracError(DracErrorCode::ParseError, "BEVE cache file is empty: " + cachePath.string()));
PkgCountCacheData result;
const glz::context ctx {};
if (glz::error_ctx glazeResult = glz::read_beve(result, content); glazeResult.ec != glz::error_code::none)
return Err(DracError(
DracErrorCode::ParseError,
std::format(
"BEVE parse error reading cache (code {}): {}", static_cast<int>(glazeResult.ec), cachePath.string()
)
));
return result;
} catch (const std::ios_base::failure& e) {
return Err(DracError(
DracErrorCode::IoError, std::format("Filesystem error reading cache file {}: {}", cachePath.string(), e.what())
));
} catch (const Exception& e) {
return Err(DracError(DracErrorCode::InternalError, std::format("Error reading package count cache: {}", e.what()))
);
}
}
fn WritePkgCountCache(const String& pmId, const PkgCountCacheData& data) -> Result<void, DracError> {
using util::types::isize;
Result<fs::path, DracError> cachePathResult = GetPkgCountCachePath(pmId);
if (!cachePathResult)
return Err(cachePathResult.error());
const fs::path& cachePath = *cachePathResult;
fs::path tempPath = cachePath;
tempPath += ".tmp";
try {
String binaryBuffer;
PkgCountCacheData mutableData = data;
if (glz::error_ctx glazeErr = glz::write_beve(mutableData, binaryBuffer); glazeErr)
return Err(DracError(
DracErrorCode::ParseError,
std::format("BEVE serialization error writing cache (code {})", static_cast<int>(glazeErr.ec))
));
{
std::ofstream ofs(tempPath, std::ios::binary | std::ios::trunc);
if (!ofs.is_open())
return Err(DracError(DracErrorCode::IoError, "Failed to open temp cache file: " + tempPath.string()));
ofs.write(binaryBuffer.data(), static_cast<isize>(binaryBuffer.size()));
if (!ofs) {
std::error_code removeEc;
fs::remove(tempPath, removeEc);
return Err(DracError(DracErrorCode::IoError, "Failed to write to temp cache file: " + tempPath.string()));
}
}
std::error_code errc;
fs::rename(tempPath, cachePath, errc);
if (errc) {
fs::remove(tempPath, errc);
return Err(DracError(
DracErrorCode::IoError,
std::format("Failed to replace cache file '{}': {}", cachePath.string(), errc.message())
));
}
return {};
} catch (const std::ios_base::failure& e) {
std::error_code removeEc;
fs::remove(tempPath, removeEc);
return Err(DracError(
DracErrorCode::IoError, std::format("Filesystem error writing cache file {}: {}", tempPath.string(), e.what())
));
} catch (const Exception& e) {
std::error_code removeEc;
fs::remove(tempPath, removeEc);
return Err(DracError(DracErrorCode::InternalError, std::format("Error writing package count cache: {}", e.what()))
);
} catch (...) {
std::error_code removeEc;
fs::remove(tempPath, removeEc);
return Err(DracError(DracErrorCode::Other, std::format("Unknown error writing cache file: {}", tempPath.string()))
);
}
}
fn GetPackageCountInternalDb(const PackageManagerInfo& pmInfo) -> Result<u64, DracError> {
const auto& [pmId, dbPath, countQuery] = pmInfo;
if (Result<PkgCountCacheData, DracError> cachedDataResult = ReadPkgCountCache(pmId)) {
if (Result<PkgCountCacheData, DracError> cachedDataResult = ReadCache<PkgCountCacheData>(pmId)) {
const auto& [count, timestamp] = *cachedDataResult;
std::error_code errc;
const std::filesystem::file_time_type dbModTime = fs::last_write_time(dbPath, errc);
@ -233,12 +108,13 @@ namespace {
const i64 nowEpochSeconds = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
const PkgCountCacheData dataToCache = { .count = count, .timestampEpochSeconds = nowEpochSeconds };
if (Result<void, DracError> writeResult = WritePkgCountCache(pmId, dataToCache); !writeResult)
if (Result<void, DracError> writeResult = WriteCache(pmId, dataToCache); !writeResult)
error_at(writeResult.error());
return count;
}
#ifndef _WIN32
fn GetNixPackageCount() -> Result<u64, DracError> {
debug_log("Attempting to get Nix package count.");
@ -259,6 +135,7 @@ namespace {
return GetPackageCountInternalDb(nixInfo);
}
#endif
fn GetCargoPackageCount() -> Result<u64, DracError> {
using util::helpers::GetEnv;
@ -288,12 +165,15 @@ namespace {
namespace os::shared {
fn GetPackageCount() -> Result<u64, DracError> {
u64 count = 0;
if (Result<u64, DracError> pkgCount = GetNixPackageCount())
#ifndef _WIN32
if (const Result<u64, DracError> pkgCount = GetNixPackageCount())
count += *pkgCount;
else
debug_at(pkgCount.error());
#endif
if (Result<u64, DracError> pkgCount = GetCargoPackageCount())
if (const Result<u64, DracError> pkgCount = GetCargoPackageCount())
count += *pkgCount;
else
debug_at(pkgCount.error());

View file

@ -16,10 +16,10 @@
#include <winrt/base.h>
#include <winrt/impl/Windows.Media.Control.2.h>
#include "src/core/util/error.hpp"
#include "src/core/util/helpers.hpp"
#include "src/core/util/logging.hpp"
#include "src/core/util/types.hpp"
#include "src/util/error.hpp"
#include "src/util/helpers.hpp"
#include "src/util/logging.hpp"
#include "src/util/types.hpp"
#include "os.hpp"
// clang-format on