24ms average on WINDOWS is wild
This commit is contained in:
parent
7e7678f5f0
commit
0027fa6520
22 changed files with 627 additions and 529 deletions
|
@ -52,21 +52,21 @@ location = "London" # Your city name
|
|||
Vec<fs::path> possiblePaths;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (Result<String, DracError> result = GetEnv("LOCALAPPDATA"))
|
||||
if (Result<String> result = GetEnv("LOCALAPPDATA"))
|
||||
possiblePaths.push_back(fs::path(*result) / "draconis++" / "config.toml");
|
||||
|
||||
if (Result<String, DracError> result = GetEnv("USERPROFILE")) {
|
||||
if (Result<String> result = GetEnv("USERPROFILE")) {
|
||||
possiblePaths.push_back(fs::path(*result) / ".config" / "draconis++" / "config.toml");
|
||||
possiblePaths.push_back(fs::path(*result) / "AppData" / "Local" / "draconis++" / "config.toml");
|
||||
}
|
||||
|
||||
if (Result<String, DracError> result = GetEnv("APPDATA"))
|
||||
if (Result<String> result = GetEnv("APPDATA"))
|
||||
possiblePaths.push_back(fs::path(*result) / "draconis++" / "config.toml");
|
||||
#else
|
||||
if (Result<String, DracError> result = GetEnv("XDG_CONFIG_HOME"))
|
||||
if (Result<String> result = GetEnv("XDG_CONFIG_HOME"))
|
||||
possiblePaths.emplace_back(fs::path(*result) / "draconis++" / "config.toml");
|
||||
|
||||
if (Result<String, DracError> result = GetEnv("HOME")) {
|
||||
if (Result<String> result = GetEnv("HOME")) {
|
||||
possiblePaths.emplace_back(fs::path(*result) / ".config" / "draconis++" / "config.toml");
|
||||
possiblePaths.emplace_back(fs::path(*result) / ".draconis++" / "config.toml");
|
||||
}
|
||||
|
@ -121,8 +121,8 @@ location = "London" # Your city name
|
|||
const passwd* pwd = getpwuid(getuid());
|
||||
CStr pwdName = pwd ? pwd->pw_name : nullptr;
|
||||
|
||||
const Result<String, DracError> envUser = util::helpers::GetEnv("USER");
|
||||
const Result<String, DracError> envLogname = util::helpers::GetEnv("LOGNAME");
|
||||
const Result<String> envUser = util::helpers::GetEnv("USER");
|
||||
const Result<String> envLogname = util::helpers::GetEnv("LOGNAME");
|
||||
|
||||
defaultName = pwdName ? pwdName : envUser ? *envUser : envLogname ? *envLogname : "User";
|
||||
#endif
|
||||
|
|
|
@ -57,11 +57,11 @@ struct General {
|
|||
return pwd->pw_name;
|
||||
|
||||
// Try to get the username using environment variables
|
||||
if (Result<String, DracError> envUser = GetEnv("USER"))
|
||||
if (Result<String> envUser = GetEnv("USER"))
|
||||
return *envUser;
|
||||
|
||||
// Finally, try to get the username using LOGNAME
|
||||
if (Result<String, DracError> envLogname = GetEnv("LOGNAME"))
|
||||
if (Result<String> envLogname = GetEnv("LOGNAME"))
|
||||
return *envLogname;
|
||||
|
||||
// If all else fails, return a default name
|
||||
|
@ -151,7 +151,7 @@ struct Weather {
|
|||
* API key, and units. It returns a WeatherOutput object containing the
|
||||
* retrieved weather data.
|
||||
*/
|
||||
[[nodiscard]] fn getWeatherInfo() const -> Result<weather::Output, DracError>;
|
||||
[[nodiscard]] fn getWeatherInfo() const -> Result<weather::Output>;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <glaze/core/opts.hpp> // glz::opts
|
||||
#include <glaze/core/reflect.hpp> // glz::format_error
|
||||
#include <glaze/json/read.hpp> // NOLINT(misc-include-cleaner) - glaze/json/read.hpp is needed for glz::read<glz::opts>
|
||||
#include <ios> // std::ios::{binary, trunc}
|
||||
#include <iterator> // std::istreambuf_iterator
|
||||
#include <variant> // std::{get, holds_alternative}
|
||||
|
||||
|
@ -44,13 +43,13 @@ namespace {
|
|||
return totalSize;
|
||||
}
|
||||
|
||||
fn MakeApiRequest(const String& url) -> Result<Output, String> {
|
||||
fn MakeApiRequest(const String& url) -> Result<Output> {
|
||||
debug_log("Making API request to URL: {}", url);
|
||||
CURL* curl = curl_easy_init();
|
||||
String responseBuffer;
|
||||
|
||||
if (!curl)
|
||||
return Err("Failed to initialize cURL");
|
||||
return Err(DracError(DracErrorCode::ApiUnavailable, "Failed to initialize cURL"));
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
|
@ -62,41 +61,40 @@ namespace {
|
|||
curl_easy_cleanup(curl);
|
||||
|
||||
if (res != CURLE_OK)
|
||||
return Err(std::format("cURL error: {}", curl_easy_strerror(res)));
|
||||
return Err(DracError(DracErrorCode::ApiUnavailable, std::format("cURL error: {}", curl_easy_strerror(res))));
|
||||
|
||||
Output output;
|
||||
|
||||
if (const error_ctx errc = read<glaze_opts>(output, responseBuffer); errc.ec != error_code::none)
|
||||
return Err("API response parse error: " + format_error(errc, responseBuffer));
|
||||
return Err(DracError(
|
||||
DracErrorCode::ParseError, std::format("Failed to parse JSON response: {}", format_error(errc, responseBuffer))
|
||||
));
|
||||
|
||||
return output;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
fn Weather::getWeatherInfo() const -> Result<Output, DracError> {
|
||||
fn Weather::getWeatherInfo() const -> Result<Output> {
|
||||
using namespace std::chrono;
|
||||
using util::types::i32;
|
||||
|
||||
if (Result<Output, DracError> data = ReadCache<Output>("weather")) {
|
||||
if (Result<Output> data = ReadCache<Output>("weather")) {
|
||||
const Output& dataVal = *data;
|
||||
|
||||
if (const duration<double> cacheAge = system_clock::now() - system_clock::time_point(seconds(dataVal.dt));
|
||||
cacheAge < 60min) { // NOLINT(misc-include-cleaner) - inherited from <chrono>
|
||||
debug_log("Using valid cache");
|
||||
cacheAge < 60min) // NOLINT(misc-include-cleaner) - inherited from <chrono>
|
||||
return dataVal;
|
||||
}
|
||||
|
||||
debug_log("Cache expired");
|
||||
} else {
|
||||
} else
|
||||
error_at(data.error());
|
||||
}
|
||||
|
||||
fn handleApiResult = [](const Result<Output, String>& result) -> Result<Output, DracError> {
|
||||
fn handleApiResult = [](const Result<Output>& result) -> Result<Output> {
|
||||
if (!result)
|
||||
return Err(DracError(DracErrorCode::ApiUnavailable, result.error()));
|
||||
return Err(result.error());
|
||||
|
||||
if (Result<void, DracError> writeResult = WriteCache("weather", *result); !writeResult)
|
||||
error_at(writeResult.error());
|
||||
if (Result writeResult = WriteCache("weather", *result); !writeResult)
|
||||
return Err(writeResult.error());
|
||||
|
||||
return *result;
|
||||
};
|
||||
|
@ -106,8 +104,6 @@ fn Weather::getWeatherInfo() const -> Result<Output, DracError> {
|
|||
|
||||
char* escaped = curl_easy_escape(nullptr, city.c_str(), static_cast<i32>(city.length()));
|
||||
|
||||
debug_log("Requesting city: {}", escaped);
|
||||
|
||||
const String apiUrl =
|
||||
std::format("https://api.openweathermap.org/data/2.5/weather?q={}&appid={}&units={}", escaped, apiKey, units);
|
||||
|
||||
|
@ -118,7 +114,6 @@ fn Weather::getWeatherInfo() const -> Result<Output, DracError> {
|
|||
|
||||
if (std::holds_alternative<Coords>(location)) {
|
||||
const auto& [lat, lon] = std::get<Coords>(location);
|
||||
debug_log("Requesting coordinates: lat={:.3f}, lon={:.3f}", lat, lon);
|
||||
|
||||
const String apiUrl = std::format(
|
||||
"https://api.openweathermap.org/data/2.5/weather?lat={:.3f}&lon={:.3f}&appid={}&units={}", lat, lon, apiKey, units
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include "package.hpp"
|
||||
|
||||
#ifndef __serenity__
|
||||
#if !defined(__serenity_) && !defined(_WIN32)
|
||||
#include <SQLiteCpp/Database.h> // SQLite::{Database, OPEN_READONLY}
|
||||
#include <SQLiteCpp/Exception.h> // SQLite::Exception
|
||||
#include <SQLiteCpp/Statement.h> // SQLite::Statement
|
||||
#endif // __serenity__
|
||||
#endif
|
||||
|
||||
#include <chrono> // std::chrono
|
||||
#include <filesystem> // std::filesystem
|
||||
|
@ -23,93 +23,131 @@ using namespace std::chrono;
|
|||
using util::cache::ReadCache, util::cache::WriteCache;
|
||||
using util::error::DracError, util::error::DracErrorCode;
|
||||
using util::types::Err, util::types::Exception, util::types::Future, util::types::Result, util::types::String,
|
||||
util::types::Vec, util::types::i64, util::types::u64;
|
||||
util::types::Vec, util::types::i64, util::types::u64, util::types::Option, util::types::None;
|
||||
|
||||
namespace {
|
||||
fn GetCountFromDirectoryImpl(
|
||||
const String& pmId,
|
||||
const fs::path& dirPath,
|
||||
const String& fileExtensionFilter,
|
||||
const Option<String>& fileExtensionFilter,
|
||||
const bool subtractOne
|
||||
) -> Result<u64, DracError> {
|
||||
debug_log("Counting packages for '{}' in directory: {}", pmId, dirPath.string());
|
||||
) -> Result<u64> {
|
||||
using package::PkgCountCacheData;
|
||||
|
||||
std::error_code errc;
|
||||
std::error_code fsErrCode;
|
||||
|
||||
if (!fs::exists(dirPath, errc)) {
|
||||
if (errc)
|
||||
warn_log("Filesystem error checking {} directory '{}': {}", pmId, dirPath.string(), errc.message());
|
||||
if (Result<PkgCountCacheData> cachedDataResult = ReadCache<PkgCountCacheData>(pmId)) {
|
||||
const auto& [cachedCount, timestamp] = *cachedDataResult;
|
||||
|
||||
return Err(DracError(DracErrorCode::NotFound, std::format("{} directory not found: {}", pmId, dirPath.string())));
|
||||
if (!fs::exists(dirPath, fsErrCode) || fsErrCode)
|
||||
warn_log(
|
||||
"Error checking existence for directory '{}' before cache validation: {}, Invalidating {} cache",
|
||||
dirPath.string(),
|
||||
fsErrCode.message(),
|
||||
pmId
|
||||
);
|
||||
else {
|
||||
fsErrCode.clear();
|
||||
const fs::file_time_type dirModTime = fs::last_write_time(dirPath, fsErrCode);
|
||||
|
||||
if (fsErrCode)
|
||||
warn_log(
|
||||
"Could not get modification time for directory '{}': {}. Invalidating {} cache",
|
||||
dirPath.string(),
|
||||
fsErrCode.message(),
|
||||
pmId
|
||||
);
|
||||
else {
|
||||
if (const system_clock::time_point cacheTimePoint = system_clock::time_point(seconds(timestamp));
|
||||
cacheTimePoint.time_since_epoch() >= dirModTime.time_since_epoch()) {
|
||||
debug_log(
|
||||
"Using valid {} directory count cache (Dir '{}' unchanged since {}). Count: {}",
|
||||
pmId,
|
||||
dirPath.string(),
|
||||
std::format("{:%F %T %Z}", floor<seconds>(cacheTimePoint)),
|
||||
cachedCount
|
||||
);
|
||||
return cachedCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (cachedDataResult.error().code != DracErrorCode::NotFound) {
|
||||
debug_at(cachedDataResult.error());
|
||||
} else
|
||||
debug_log("{} directory count cache not found or unreadable", pmId, pmId);
|
||||
|
||||
errc.clear();
|
||||
fsErrCode.clear();
|
||||
|
||||
if (!fs::is_directory(dirPath, errc)) {
|
||||
if (errc)
|
||||
if (!fs::is_directory(dirPath, fsErrCode)) {
|
||||
if (fsErrCode)
|
||||
return Err(DracError(
|
||||
DracErrorCode::IoError,
|
||||
std::format("Filesystem error checking if '{}' is a directory: {}", dirPath.string(), errc.message())
|
||||
std::format("Filesystem error checking if '{}' is a directory: {}", dirPath.string(), fsErrCode.message())
|
||||
));
|
||||
|
||||
return Err(
|
||||
DracError(DracErrorCode::IoError, std::format("{} path is not a directory: {}", pmId, dirPath.string()))
|
||||
);
|
||||
}
|
||||
|
||||
errc.clear();
|
||||
fsErrCode.clear();
|
||||
|
||||
u64 count = 0;
|
||||
bool filterActive = !fileExtensionFilter.empty();
|
||||
|
||||
try {
|
||||
const fs::directory_iterator dirIter(dirPath, fs::directory_options::skip_permission_denied, errc);
|
||||
const fs::directory_iterator dirIter(dirPath, fs::directory_options::skip_permission_denied, fsErrCode);
|
||||
|
||||
if (errc) {
|
||||
if (fsErrCode)
|
||||
return Err(DracError(
|
||||
DracErrorCode::IoError,
|
||||
std::format("Failed to create iterator for {} directory '{}': {}", pmId, dirPath.string(), errc.message())
|
||||
std::format(
|
||||
"Failed to create iterator for {} directory '{}': {}", pmId, dirPath.string(), fsErrCode.message()
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
errc.clear();
|
||||
|
||||
for (const fs::directory_entry& entry : dirIter) {
|
||||
fsErrCode.clear();
|
||||
|
||||
if (entry.path().empty())
|
||||
continue;
|
||||
|
||||
std::error_code entryStatErr;
|
||||
if (fileExtensionFilter) {
|
||||
bool isFile = false;
|
||||
isFile = entry.is_regular_file(fsErrCode);
|
||||
|
||||
if (filterActive) {
|
||||
isFile = entry.is_regular_file(entryStatErr);
|
||||
if (entryStatErr) {
|
||||
warn_log(
|
||||
"Error stating entry '{}' in {} directory: {}", entry.path().string(), pmId, entryStatErr.message()
|
||||
);
|
||||
entryStatErr.clear();
|
||||
if (fsErrCode) {
|
||||
warn_log("Error stating entry '{}' in {} directory: {}", entry.path().string(), pmId, fsErrCode.message());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isFile && entry.path().extension().string() == *fileExtensionFilter)
|
||||
count++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (filterActive) {
|
||||
if (isFile && entry.path().extension().string() == fileExtensionFilter)
|
||||
count++;
|
||||
} else
|
||||
if (!fileExtensionFilter)
|
||||
count++;
|
||||
}
|
||||
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
return Err(DracError(DracErrorCode::IoError, std::format("Filesystem error during {} directory iteration", pmId))
|
||||
);
|
||||
} catch (const Exception& e) { return Err(DracError(DracErrorCode::InternalError, e.what())); } catch (...) {
|
||||
} catch (const fs::filesystem_error& fsCatchErr) {
|
||||
return Err(DracError(
|
||||
DracErrorCode::IoError,
|
||||
std::format("Filesystem error during {} directory iteration: {}", pmId, fsCatchErr.what())
|
||||
));
|
||||
} catch (const Exception& exc) { return Err(DracError(DracErrorCode::InternalError, exc.what())); } catch (...) {
|
||||
return Err(DracError(DracErrorCode::Other, std::format("Unknown error iterating {} directory", pmId)));
|
||||
}
|
||||
|
||||
if (subtractOne && count > 0)
|
||||
count--;
|
||||
|
||||
debug_log("Successfully counted {} packages for '{}': {}", std::to_string(count), pmId, dirPath.string());
|
||||
if (count == 0)
|
||||
return Err(DracError(DracErrorCode::NotFound, std::format("No packages found in {} directory", pmId)));
|
||||
|
||||
const i64 nowEpochSeconds = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
|
||||
const PkgCountCacheData dataToCache = { .count = count, .timestampEpochSeconds = nowEpochSeconds };
|
||||
|
||||
if (Result writeResult = WriteCache(pmId, dataToCache); !writeResult)
|
||||
error_at(writeResult.error());
|
||||
|
||||
return count;
|
||||
}
|
||||
} // namespace
|
||||
|
@ -120,32 +158,29 @@ namespace package {
|
|||
const fs::path& dirPath,
|
||||
const String& fileExtensionFilter,
|
||||
const bool subtractOne
|
||||
) -> Result<u64, DracError> {
|
||||
) -> Result<u64> {
|
||||
return GetCountFromDirectoryImpl(pmId, dirPath, fileExtensionFilter, subtractOne);
|
||||
}
|
||||
|
||||
fn GetCountFromDirectory(const String& pmId, const fs::path& dirPath, const String& fileExtensionFilter)
|
||||
-> Result<u64, DracError> {
|
||||
-> Result<u64> {
|
||||
return GetCountFromDirectoryImpl(pmId, dirPath, fileExtensionFilter, false);
|
||||
}
|
||||
|
||||
fn GetCountFromDirectory(const String& pmId, const fs::path& dirPath, const bool subtractOne)
|
||||
-> Result<u64, DracError> {
|
||||
const String noFilter;
|
||||
return GetCountFromDirectoryImpl(pmId, dirPath, noFilter, subtractOne);
|
||||
fn GetCountFromDirectory(const String& pmId, const fs::path& dirPath, const bool subtractOne) -> Result<u64> {
|
||||
return GetCountFromDirectoryImpl(pmId, dirPath, None, subtractOne);
|
||||
}
|
||||
|
||||
fn GetCountFromDirectory(const String& pmId, const fs::path& dirPath) -> Result<u64, DracError> {
|
||||
const String noFilter;
|
||||
return GetCountFromDirectoryImpl(pmId, dirPath, noFilter, false);
|
||||
fn GetCountFromDirectory(const String& pmId, const fs::path& dirPath) -> Result<u64> {
|
||||
return GetCountFromDirectoryImpl(pmId, dirPath, None, false);
|
||||
}
|
||||
|
||||
#ifndef __serenity__
|
||||
fn GetCountFromDb(const PackageManagerInfo& pmInfo) -> Result<u64, DracError> {
|
||||
#if !defined(__serenity__) && !defined(_WIN32)
|
||||
fn GetCountFromDb(const PackageManagerInfo& pmInfo) -> Result<u64> {
|
||||
const auto& [pmId, dbPath, countQuery] = pmInfo;
|
||||
const String cacheKey = "pkg_count_" + pmId; // More specific cache key
|
||||
|
||||
if (Result<PkgCountCacheData, DracError> cachedDataResult = ReadCache<PkgCountCacheData>(cacheKey)) {
|
||||
if (Result<PkgCountCacheData> cachedDataResult = ReadCache<PkgCountCacheData>(cacheKey)) {
|
||||
const auto& [count, timestamp] = *cachedDataResult;
|
||||
std::error_code errc;
|
||||
const std::filesystem::file_time_type dbModTime = fs::last_write_time(dbPath, errc);
|
||||
|
@ -177,7 +212,6 @@ namespace package {
|
|||
u64 count = 0;
|
||||
|
||||
try {
|
||||
// Ensure database file exists before trying to open
|
||||
std::error_code existsErr;
|
||||
if (!fs::exists(dbPath, existsErr) || existsErr) {
|
||||
if (existsErr) {
|
||||
|
@ -198,20 +232,13 @@ namespace package {
|
|||
DracError(DracErrorCode::ParseError, std::format("Negative count returned by {} DB COUNT query.", pmId))
|
||||
);
|
||||
count = static_cast<u64>(countInt64);
|
||||
} else {
|
||||
// It's possible a query legitimately returns 0 rows (e.g., no packages)
|
||||
debug_log("No rows returned by {} DB COUNT query for '{}', assuming count is 0.", pmId, dbPath.string());
|
||||
count = 0;
|
||||
// return Err(DracError(DracErrorCode::ParseError, std::format("No rows returned by {} DB COUNT query.",
|
||||
// pmId)));
|
||||
}
|
||||
} else
|
||||
return Err(DracError(DracErrorCode::ParseError, std::format("No rows returned by {} DB COUNT query.", pmId)));
|
||||
} catch (const SQLite::Exception& e) {
|
||||
// Log specific SQLite errors but return a more general error type
|
||||
error_log("SQLite error occurred accessing {} DB '{}': {}", pmId, dbPath.string(), e.what());
|
||||
return Err(DracError(
|
||||
DracErrorCode::ApiUnavailable, // Or IoError?
|
||||
std::format("Failed to query {} database: {}", pmId, dbPath.string())
|
||||
));
|
||||
return Err(
|
||||
DracError(DracErrorCode::ApiUnavailable, std::format("Failed to query {} database: {}", pmId, dbPath.string()))
|
||||
);
|
||||
} catch (const Exception& e) {
|
||||
error_log("Standard exception accessing {} DB '{}': {}", pmId, dbPath.string(), e.what());
|
||||
return Err(DracError(DracErrorCode::InternalError, e.what()));
|
||||
|
@ -225,15 +252,15 @@ namespace package {
|
|||
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(cacheKey, dataToCache); !writeResult)
|
||||
error_at(writeResult.error()); // Log cache write error but return the count anyway
|
||||
if (Result writeResult = WriteCache(cacheKey, dataToCache); !writeResult)
|
||||
error_at(writeResult.error());
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif // __serenity__
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
fn GetNixCount() -> Result<u64, DracError> {
|
||||
fn GetNixCount() -> Result<u64> {
|
||||
const PackageManagerInfo nixInfo = {
|
||||
.id = "nix",
|
||||
.dbPath = "/nix/var/nix/db/db.sqlite",
|
||||
|
@ -253,14 +280,14 @@ namespace package {
|
|||
}
|
||||
#endif // __linux__ || __APPLE__
|
||||
|
||||
fn GetCargoCount() -> Result<u64, DracError> {
|
||||
fn CountCargo() -> Result<u64> {
|
||||
using util::helpers::GetEnv;
|
||||
|
||||
fs::path cargoPath {};
|
||||
|
||||
if (const Result<String, DracError> cargoHome = GetEnv("CARGO_HOME"))
|
||||
if (const Result<String> cargoHome = GetEnv("CARGO_HOME"))
|
||||
cargoPath = fs::path(*cargoHome) / "bin";
|
||||
else if (const Result<String, DracError> homeDir = GetEnv("HOME"))
|
||||
else if (const Result<String> homeDir = GetEnv("HOME"))
|
||||
cargoPath = fs::path(*homeDir) / ".cargo" / "bin";
|
||||
|
||||
if (cargoPath.empty() || !fs::exists(cargoPath))
|
||||
|
@ -277,8 +304,8 @@ namespace package {
|
|||
return count;
|
||||
}
|
||||
|
||||
fn GetTotalCount() -> Result<u64, DracError> {
|
||||
Vec<Future<Result<u64, DracError>>> futures;
|
||||
fn GetTotalCount() -> Result<u64> {
|
||||
Vec<Future<Result<u64>>> futures;
|
||||
|
||||
#ifdef __linux__
|
||||
futures.push_back(std::async(std::launch::async, GetDpkgCount));
|
||||
|
@ -292,9 +319,9 @@ namespace package {
|
|||
futures.push_back(std::async(std::launch::async, GetHomebrewCount));
|
||||
futures.push_back(std::async(std::launch::async, GetMacPortsCount));
|
||||
#elifdef _WIN32
|
||||
futures.push_back(std::async(std::launch::async, GetWinRTCount));
|
||||
futures.push_back(std::async(std::launch::async, GetChocolateyCount));
|
||||
futures.push_back(std::async(std::launch::async, GetScoopCount));
|
||||
futures.push_back(std::async(std::launch::async, CountWinGet));
|
||||
futures.push_back(std::async(std::launch::async, CountChocolatey));
|
||||
futures.push_back(std::async(std::launch::async, CountScoop));
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
futures.push_back(std::async(std::launch::async, GetPkgNgCount));
|
||||
#elifdef __NetBSD__
|
||||
|
@ -307,27 +334,27 @@ namespace package {
|
|||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
futures.push_back(std::async(std::launch::async, GetNixCount));
|
||||
#endif // __linux__ || __APPLE__
|
||||
futures.push_back(std::async(std::launch::async, GetCargoCount));
|
||||
#endif
|
||||
futures.push_back(std::async(std::launch::async, CountCargo));
|
||||
|
||||
u64 totalCount = 0;
|
||||
bool oneSucceeded = false;
|
||||
|
||||
for (Future<Result<u64, DracError>>& fut : futures) {
|
||||
for (Future<Result<u64>>& fut : futures) {
|
||||
try {
|
||||
if (Result<u64, DracError> result = fut.get()) {
|
||||
using enum util::error::DracErrorCode;
|
||||
|
||||
if (Result<u64> result = fut.get()) {
|
||||
totalCount += *result;
|
||||
oneSucceeded = true;
|
||||
debug_log("Added {} packages. Current total: {}", *result, totalCount);
|
||||
} else {
|
||||
if (result.error().code != DracErrorCode::NotFound && result.error().code != DracErrorCode::ApiUnavailable &&
|
||||
result.error().code != DracErrorCode::NotSupported) {
|
||||
} else if (result.error().code != NotFound && result.error().code != ApiUnavailable &&
|
||||
result.error().code != NotSupported) {
|
||||
error_at(result.error());
|
||||
} else
|
||||
debug_at(result.error());
|
||||
}
|
||||
} catch (const Exception& e) {
|
||||
error_log("Caught exception while getting package count future: {}", e.what());
|
||||
} catch (const Exception& exc) {
|
||||
error_log("Caught exception while getting package count future: {}", exc.what());
|
||||
} catch (...) { error_log("Caught unknown exception while getting package count future."); }
|
||||
}
|
||||
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
#include <glaze/core/common.hpp> // glz::object
|
||||
#include <glaze/core/meta.hpp> // glz::detail::Object
|
||||
|
||||
// Include necessary type headers used in declarations
|
||||
#include "src/util/defs.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/types.hpp" // Brings in Result, u64, etc.
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
namespace package {
|
||||
namespace fs = std::filesystem;
|
||||
|
@ -51,14 +50,14 @@ namespace package {
|
|||
* @return Result containing the total package count (u64) on success,
|
||||
* or a DracError if aggregation fails (individual errors logged).
|
||||
*/
|
||||
fn GetTotalCount() -> Result<u64, DracError>;
|
||||
fn GetTotalCount() -> Result<u64>;
|
||||
|
||||
/**
|
||||
* @brief Gets package count from a database using SQLite.
|
||||
* @param pmInfo Information about the package manager database.
|
||||
* @return Result containing the count (u64) or a DracError.
|
||||
*/
|
||||
fn GetCountFromDb(const PackageManagerInfo& pmInfo) -> Result<u64, DracError>;
|
||||
fn GetCountFromDb(const PackageManagerInfo& pmInfo) -> Result<u64>;
|
||||
|
||||
/**
|
||||
* @brief Gets package count by iterating entries in a directory, optionally filtering and subtracting.
|
||||
|
@ -73,7 +72,7 @@ namespace package {
|
|||
const fs::path& dirPath,
|
||||
const String& fileExtensionFilter,
|
||||
bool subtractOne
|
||||
) -> Result<u64, DracError>;
|
||||
) -> Result<u64>;
|
||||
|
||||
/**
|
||||
* @brief Gets package count by iterating entries in a directory, filtering by extension.
|
||||
|
@ -83,7 +82,7 @@ namespace package {
|
|||
* @return Result containing the count (u64) or a DracError. Defaults subtractOne to false.
|
||||
*/
|
||||
fn GetCountFromDirectory(const String& pmId, const fs::path& dirPath, const String& fileExtensionFilter)
|
||||
-> Result<u64, DracError>;
|
||||
-> Result<u64>;
|
||||
|
||||
/**
|
||||
* @brief Gets package count by iterating entries in a directory, optionally subtracting one.
|
||||
|
@ -92,7 +91,7 @@ namespace package {
|
|||
* @param subtractOne Subtract one from the final count.
|
||||
* @return Result containing the count (u64) or a DracError. Defaults fileExtensionFilter to "".
|
||||
*/
|
||||
fn GetCountFromDirectory(const String& pmId, const fs::path& dirPath, bool subtractOne) -> Result<u64, DracError>;
|
||||
fn GetCountFromDirectory(const String& pmId, const fs::path& dirPath, bool subtractOne) -> Result<u64>;
|
||||
|
||||
/**
|
||||
* @brief Gets package count by iterating all entries in a directory.
|
||||
|
@ -100,36 +99,36 @@ namespace package {
|
|||
* @param dirPath Path to the directory to iterate.
|
||||
* @return Result containing the count (u64) or a DracError. Defaults filter to "" and subtractOne to false.
|
||||
*/
|
||||
fn GetCountFromDirectory(const String& pmId, const fs::path& dirPath) -> Result<u64, DracError>;
|
||||
fn GetCountFromDirectory(const String& pmId, const fs::path& dirPath) -> Result<u64>;
|
||||
|
||||
#ifdef __linux__
|
||||
fn GetDpkgCount() -> Result<u64, DracError>;
|
||||
fn GetPacmanCount() -> Result<u64, DracError>;
|
||||
fn GetMossCount() -> Result<u64, DracError>;
|
||||
fn GetRpmCount() -> Result<u64, DracError>;
|
||||
fn GetZypperCount() -> Result<u64, DracError>;
|
||||
fn GetPortageCount() -> Result<u64, DracError>;
|
||||
fn GetApkCount() -> Result<u64, DracError>;
|
||||
fn GetDpkgCount() -> Result<u64>;
|
||||
fn GetPacmanCount() -> Result<u64>;
|
||||
fn GetMossCount() -> Result<u64>;
|
||||
fn GetRpmCount() -> Result<u64>;
|
||||
fn GetZypperCount() -> Result<u64>;
|
||||
fn GetPortageCount() -> Result<u64>;
|
||||
fn GetApkCount() -> Result<u64>;
|
||||
#elifdef __APPLE__
|
||||
fn GetHomebrewCount() -> Result<u64, DracError>;
|
||||
fn GetMacPortsCount() -> Result<u64, DracError>;
|
||||
fn GetHomebrewCount() -> Result<u64>;
|
||||
fn GetMacPortsCount() -> Result<u64>;
|
||||
#elifdef _WIN32
|
||||
fn GetWinRTCount() -> Result<u64, DracError>;
|
||||
fn GetChocolateyCount() -> Result<u64, DracError>;
|
||||
fn GetScoopCount() -> Result<u64, DracError>;
|
||||
fn CountWinGet() -> Result<u64>;
|
||||
fn CountChocolatey() -> Result<u64>;
|
||||
fn CountScoop() -> Result<u64>;
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
fn GetPkgNgCount() -> Result<u64, DracError>;
|
||||
fn GetPkgNgCount() -> Result<u64>;
|
||||
#elifdef __NetBSD__
|
||||
fn GetPkgSrcCount() -> Result<u64, DracError>;
|
||||
fn GetPkgSrcCount() -> Result<u64>;
|
||||
#elifdef __HAIKU__
|
||||
fn GetHaikuCount() -> Result<u64, DracError>;
|
||||
fn GetHaikuCount() -> Result<u64>;
|
||||
#elifdef __serenity__
|
||||
fn GetSerenityCount() -> Result<u64, DracError>;
|
||||
fn GetSerenityCount() -> Result<u64>;
|
||||
#endif
|
||||
|
||||
// Common (potentially cross-platform)
|
||||
#ifndef _WIN32
|
||||
fn GetNixCount() -> Result<u64, DracError>;
|
||||
fn GetNixCount() -> Result<u64>;
|
||||
#endif
|
||||
fn GetCargoCount() -> Result<u64, DracError>;
|
||||
fn CountCargo() -> Result<u64>;
|
||||
} // namespace package
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
fn getDate() -> Result<String, DracError> {
|
||||
fn getDate() -> Result<String> {
|
||||
using std::chrono::system_clock;
|
||||
using util::types::String, util::types::usize, util::types::Err;
|
||||
|
||||
|
@ -68,21 +68,20 @@ namespace {
|
|||
namespace os {
|
||||
SystemData::SystemData(const Config& config) {
|
||||
using enum std::launch;
|
||||
using package::GetTotalCount;
|
||||
using util::types::Future, util::types::Err;
|
||||
using weather::Output;
|
||||
|
||||
Future<Result<String, DracError>> hostFut = std::async(async, GetHost);
|
||||
Future<Result<String, DracError>> kernelFut = std::async(async, GetKernelVersion);
|
||||
Future<Result<String, DracError>> osFut = std::async(async, GetOSVersion);
|
||||
Future<Result<u64, DracError>> memFut = std::async(async, GetMemInfo);
|
||||
Future<Result<String, DracError>> deFut = std::async(async, GetDesktopEnvironment);
|
||||
Future<Result<String, DracError>> wmFut = std::async(async, GetWindowManager);
|
||||
Future<Result<DiskSpace, DracError>> diskFut = std::async(async, GetDiskUsage);
|
||||
Future<Result<String, DracError>> shellFut = std::async(async, GetShell);
|
||||
Future<Result<u64, DracError>> pkgFut = std::async(async, package::GetTotalCount);
|
||||
Future<Result<MediaInfo, DracError>> npFut =
|
||||
std::async(config.nowPlaying.enabled ? async : deferred, GetNowPlaying);
|
||||
Future<Result<Output, DracError>> wthrFut =
|
||||
Future<Result<String>> hostFut = std::async(async, GetHost);
|
||||
Future<Result<String>> kernelFut = std::async(async, GetKernelVersion);
|
||||
Future<Result<String>> osFut = std::async(async, GetOSVersion);
|
||||
Future<Result<u64>> memFut = std::async(async, GetMemInfo);
|
||||
Future<Result<String>> deFut = std::async(async, GetDesktopEnvironment);
|
||||
Future<Result<String>> wmFut = std::async(async, GetWindowManager);
|
||||
Future<Result<DiskSpace>> diskFut = std::async(async, GetDiskUsage);
|
||||
Future<Result<String>> shellFut = std::async(async, GetShell);
|
||||
Future<Result<u64>> pkgFut = std::async(async, GetTotalCount);
|
||||
Future<Result<MediaInfo>> npFut = std::async(config.nowPlaying.enabled ? async : deferred, GetNowPlaying);
|
||||
Future<Result<weather::Output>> wthrFut =
|
||||
std::async(config.weather.enabled ? async : deferred, [&config] { return config.weather.getWeatherInfo(); });
|
||||
|
||||
this->date = getDate();
|
||||
|
|
|
@ -34,7 +34,7 @@ constexpr u64 GIB = 1'073'741'824;
|
|||
*
|
||||
* @code{.cpp}
|
||||
* #include <format>
|
||||
* #include "system_data.h" // Assuming BytesToGiB is defined here
|
||||
* #include "system_data.h"
|
||||
*
|
||||
* i32 main() {
|
||||
* BytesToGiB data_size{2'147'483'648}; // 2 GiB
|
||||
|
@ -66,18 +66,18 @@ namespace os {
|
|||
* in order to display it at all at once during runtime.
|
||||
*/
|
||||
struct SystemData {
|
||||
Result<String, DracError> date; ///< Current date (e.g., "April 26th").
|
||||
Result<String, DracError> host; ///< Host/product family (e.g., "MacBook Air").
|
||||
Result<String, DracError> kernelVersion; ///< OS kernel version (e.g., "6.14.4").
|
||||
Result<String, DracError> osVersion; ///< OS pretty name (e.g., "Ubuntu 24.04.2 LTS").
|
||||
Result<u64, DracError> memInfo; ///< Total physical RAM in bytes.
|
||||
Result<String, DracError> desktopEnv; ///< Desktop environment (e.g., "KDE").
|
||||
Result<String, DracError> windowMgr; ///< Window manager (e.g., "KWin").
|
||||
Result<DiskSpace, DracError> diskUsage; ///< Used/Total disk space for root filesystem.
|
||||
Result<String, DracError> shell; ///< Name of the current user shell (e.g., "zsh").
|
||||
Result<u64, DracError> packageCount; ///< Total number of packages installed.
|
||||
Result<MediaInfo, DracError> nowPlaying; ///< Result of fetching media info.
|
||||
Result<weather::Output, DracError> weather; ///< Result of fetching weather info.
|
||||
Result<String> date; ///< Current date (e.g., "April 26th").
|
||||
Result<String> host; ///< Host/product family (e.g., "MacBook Air").
|
||||
Result<String> kernelVersion; ///< OS kernel version (e.g., "6.14.4").
|
||||
Result<String> osVersion; ///< OS pretty name (e.g., "Ubuntu 24.04.2 LTS").
|
||||
Result<u64> memInfo; ///< Total physical RAM in bytes.
|
||||
Result<String> desktopEnv; ///< Desktop environment (e.g., "KDE").
|
||||
Result<String> windowMgr; ///< Window manager (e.g., "KWin").
|
||||
Result<DiskSpace> diskUsage; ///< Used/Total disk space for root filesystem.
|
||||
Result<String> shell; ///< Name of the current user shell (e.g., "zsh").
|
||||
Result<u64> packageCount; ///< Total number of packages installed.
|
||||
Result<MediaInfo> nowPlaying; ///< Result of fetching media info.
|
||||
Result<weather::Output> weather; ///< Result of fetching weather info.
|
||||
|
||||
/**
|
||||
* @brief Constructs a SystemData object and initializes its members.
|
||||
|
|
81
src/main.cpp
81
src/main.cpp
|
@ -1,13 +1,17 @@
|
|||
#include <cmath> // std::lround
|
||||
#include <format> // std::format
|
||||
#include <ftxui/dom/elements.hpp> // ftxui::{Element, hbox, vbox, text, separator, filler, etc.}
|
||||
#include <ftxui/dom/node.hpp> // ftxui::{Render}
|
||||
#include <ftxui/screen/color.hpp> // ftxui::Color
|
||||
#include <ftxui/screen/screen.hpp> // ftxui::{Screen, Dimension::Full}
|
||||
#include <ftxui/screen/string.hpp> // ftxui::string_width
|
||||
#include <iostream> // std::cout
|
||||
#include <ranges> // std::ranges::{iota, to, transform}
|
||||
|
||||
#ifdef __cpp_lib_print
|
||||
#include <print> // std::print
|
||||
#else
|
||||
#include <iostream> // std::cout
|
||||
#endif
|
||||
|
||||
#include "src/config/config.hpp"
|
||||
#include "src/config/weather.hpp"
|
||||
#include "src/core/system_data.hpp"
|
||||
|
@ -116,7 +120,7 @@ namespace {
|
|||
};
|
||||
|
||||
fn CreateColorCircles() -> Element {
|
||||
fn colorView =
|
||||
auto colorView =
|
||||
std::views::iota(0, 16) | std::views::transform([](i32 colorIndex) {
|
||||
return ftxui::hbox(
|
||||
{ ftxui::text("◯") | ftxui::bold | ftxui::color(static_cast<ftxui::Color::Palette256>(colorIndex)),
|
||||
|
@ -124,9 +128,7 @@ namespace {
|
|||
);
|
||||
});
|
||||
|
||||
Elements elementsContainer(std::ranges::begin(colorView), std::ranges::end(colorView));
|
||||
|
||||
return hbox(elementsContainer);
|
||||
return hbox(Elements(std::ranges::begin(colorView), std::ranges::end(colorView)));
|
||||
}
|
||||
|
||||
fn get_visual_width(const String& str) -> usize { return ftxui::string_width(str); }
|
||||
|
@ -151,56 +153,64 @@ namespace {
|
|||
std::vector<RowInfo> envInfoRows; // DE, WM
|
||||
|
||||
if (data.date)
|
||||
initialRows.push_back({ calendarIcon, "Date", *data.date });
|
||||
initialRows.push_back({ .icon = calendarIcon, .label = "Date", .value = *data.date });
|
||||
|
||||
if (weather.enabled && data.weather) {
|
||||
const weather::Output& weatherInfo = *data.weather;
|
||||
String weatherValue = weather.showTownName
|
||||
? std::format("{}°F in {}", std::lround(weatherInfo.main.temp), weatherInfo.name)
|
||||
: std::format("{}°F, {}", std::lround(weatherInfo.main.temp), weatherInfo.weather[0].description);
|
||||
initialRows.push_back({ weatherIcon, "Weather", std::move(weatherValue) });
|
||||
}
|
||||
initialRows.push_back({ .icon = weatherIcon, .label = "Weather", .value = std::move(weatherValue) });
|
||||
} else if (weather.enabled && !data.weather.has_value())
|
||||
debug_at(data.weather.error());
|
||||
|
||||
if (data.host && !data.host->empty())
|
||||
systemInfoRows.push_back({ hostIcon, "Host", *data.host });
|
||||
systemInfoRows.push_back({ .icon = hostIcon, .label = "Host", .value = *data.host });
|
||||
|
||||
if (data.osVersion)
|
||||
systemInfoRows.push_back({ osIcon, "OS", *data.osVersion });
|
||||
systemInfoRows.push_back({ .icon = osIcon, .label = "OS", .value = *data.osVersion });
|
||||
|
||||
if (data.kernelVersion)
|
||||
systemInfoRows.push_back({ kernelIcon, "Kernel", *data.kernelVersion });
|
||||
systemInfoRows.push_back({ .icon = kernelIcon, .label = "Kernel", .value = *data.kernelVersion });
|
||||
|
||||
if (data.memInfo)
|
||||
systemInfoRows.push_back({ memoryIcon, "RAM", std::format("{}", BytesToGiB { *data.memInfo }) });
|
||||
systemInfoRows.push_back(
|
||||
{ .icon = memoryIcon, .label = "RAM", .value = std::format("{}", BytesToGiB { *data.memInfo }) }
|
||||
);
|
||||
else if (!data.memInfo.has_value())
|
||||
debug_at(data.memInfo.error());
|
||||
|
||||
if (data.diskUsage)
|
||||
systemInfoRows.push_back(
|
||||
{ diskIcon,
|
||||
"Disk",
|
||||
std::format("{}/{}", BytesToGiB { data.diskUsage->used_bytes }, BytesToGiB { data.diskUsage->total_bytes }) }
|
||||
{
|
||||
.icon = diskIcon,
|
||||
.label = "Disk",
|
||||
.value =
|
||||
std::format("{}/{}", BytesToGiB { data.diskUsage->usedBytes }, BytesToGiB { data.diskUsage->totalBytes }),
|
||||
}
|
||||
);
|
||||
|
||||
if (data.shell)
|
||||
systemInfoRows.push_back({ shellIcon, "Shell", *data.shell });
|
||||
systemInfoRows.push_back({ .icon = shellIcon, .label = "Shell", .value = *data.shell });
|
||||
|
||||
if (data.packageCount) {
|
||||
if (*data.packageCount > 0)
|
||||
systemInfoRows.push_back({ packageIcon, "Packages", std::format("{}", *data.packageCount) });
|
||||
systemInfoRows.push_back(
|
||||
{ .icon = packageIcon, .label = "Packages", .value = std::format("{}", *data.packageCount) }
|
||||
);
|
||||
else
|
||||
debug_log("Package count is 0, skipping");
|
||||
}
|
||||
|
||||
bool addedDe = false;
|
||||
if (data.desktopEnv && (!data.windowMgr || *data.desktopEnv != *data.windowMgr)) {
|
||||
envInfoRows.push_back({ deIcon, "DE", *data.desktopEnv });
|
||||
envInfoRows.push_back({ .icon = deIcon, .label = "DE", .value = *data.desktopEnv });
|
||||
addedDe = true;
|
||||
}
|
||||
|
||||
if (data.windowMgr) {
|
||||
if (!addedDe || (data.desktopEnv && *data.desktopEnv != *data.windowMgr))
|
||||
envInfoRows.push_back({ wmIcon, "WM", *data.windowMgr });
|
||||
envInfoRows.push_back({ .icon = wmIcon, .label = "WM", .value = *data.windowMgr });
|
||||
}
|
||||
|
||||
bool nowPlayingActive = false;
|
||||
|
@ -215,22 +225,23 @@ namespace {
|
|||
|
||||
usize maxContentWidth = 0;
|
||||
|
||||
usize greetingWidth = get_visual_width_sv(userIcon) + get_visual_width_sv("Hello ") + get_visual_width(name) +
|
||||
const usize greetingWidth = get_visual_width_sv(userIcon) + get_visual_width_sv("Hello ") + get_visual_width(name) +
|
||||
get_visual_width_sv("! ");
|
||||
maxContentWidth = std::max(maxContentWidth, greetingWidth);
|
||||
|
||||
usize paletteWidth = get_visual_width_sv(userIcon) + (16 * (get_visual_width_sv("◯") + get_visual_width_sv(" ")));
|
||||
const usize paletteWidth =
|
||||
get_visual_width_sv(userIcon) + (16 * (get_visual_width_sv("◯") + get_visual_width_sv(" ")));
|
||||
maxContentWidth = std::max(maxContentWidth, paletteWidth);
|
||||
|
||||
usize iconActualWidth = get_visual_width_sv(userIcon);
|
||||
const usize iconActualWidth = get_visual_width_sv(userIcon);
|
||||
|
||||
usize maxLabelWidthInitial = find_max_label_len(initialRows);
|
||||
usize maxLabelWidthSystem = find_max_label_len(systemInfoRows);
|
||||
usize maxLabelWidthEnv = find_max_label_len(envInfoRows);
|
||||
const usize maxLabelWidthInitial = find_max_label_len(initialRows);
|
||||
const usize maxLabelWidthSystem = find_max_label_len(systemInfoRows);
|
||||
const usize maxLabelWidthEnv = find_max_label_len(envInfoRows);
|
||||
|
||||
usize requiredWidthInitialW = iconActualWidth + maxLabelWidthInitial;
|
||||
usize requiredWidthSystemW = iconActualWidth + maxLabelWidthSystem;
|
||||
usize requiredWidthEnvW = iconActualWidth + maxLabelWidthEnv;
|
||||
const usize requiredWidthInitialW = iconActualWidth + maxLabelWidthInitial;
|
||||
const usize requiredWidthSystemW = iconActualWidth + maxLabelWidthSystem;
|
||||
const usize requiredWidthEnvW = iconActualWidth + maxLabelWidthEnv;
|
||||
|
||||
fn calculateRowVisualWidth = [&](const RowInfo& row, const usize requiredLabelVisualWidth) -> usize {
|
||||
return requiredLabelVisualWidth + get_visual_width(row.value) + get_visual_width_sv(" ");
|
||||
|
@ -245,7 +256,7 @@ namespace {
|
|||
for (const RowInfo& row : envInfoRows)
|
||||
maxContentWidth = std::max(maxContentWidth, calculateRowVisualWidth(row, requiredWidthEnvW));
|
||||
|
||||
usize targetBoxWidth = maxContentWidth + 2;
|
||||
const usize targetBoxWidth = maxContentWidth + 2;
|
||||
|
||||
usize npFixedWidthLeft = 0;
|
||||
usize npFixedWidthRight = 0;
|
||||
|
@ -289,9 +300,9 @@ namespace {
|
|||
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
||||
content.push_back(hbox({ text(String(paletteIcon)) | color(ui::DEFAULT_THEME.icon), CreateColorCircles() }));
|
||||
|
||||
bool section1Present = !initialRows.empty();
|
||||
bool section2Present = !systemInfoRows.empty();
|
||||
bool section3Present = !envInfoRows.empty();
|
||||
const bool section1Present = !initialRows.empty();
|
||||
const bool section2Present = !systemInfoRows.empty();
|
||||
const bool section3Present = !envInfoRows.empty();
|
||||
|
||||
if (section1Present)
|
||||
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
||||
|
@ -342,7 +353,11 @@ fn main() -> i32 {
|
|||
Render(screen, document);
|
||||
screen.Print();
|
||||
|
||||
#ifdef __cpp_lib_print
|
||||
std::println();
|
||||
#else
|
||||
std::cout << '\n';
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ using util::error::DracError, util::error::DracErrorCode;
|
|||
|
||||
namespace {
|
||||
#ifdef __FreeBSD__
|
||||
fn GetPathByPid(pid_t pid) -> Result<String, DracError> {
|
||||
fn GetPathByPid(pid_t pid) -> Result<String> {
|
||||
Array<char, PATH_MAX> exePathBuf;
|
||||
usize size = exePathBuf.size();
|
||||
Array<i32, 4> mib;
|
||||
|
@ -57,7 +57,7 @@ namespace {
|
|||
}
|
||||
#endif
|
||||
|
||||
fn GetX11WindowManager() -> Result<String, DracError> {
|
||||
fn GetX11WindowManager() -> Result<String> {
|
||||
using namespace xcb;
|
||||
|
||||
const DisplayGuard conn;
|
||||
|
@ -81,7 +81,7 @@ namespace {
|
|||
return std::format("Unknown Error Code ({})", err);
|
||||
}()));
|
||||
|
||||
fn internAtom = [&conn](const StringView name) -> Result<atom_t, DracError> {
|
||||
fn internAtom = [&conn](const StringView name) -> Result<atom_t> {
|
||||
const ReplyGuard<intern_atom_reply_t> reply(
|
||||
intern_atom_reply(conn.get(), intern_atom(conn.get(), 0, static_cast<u16>(name.size()), name.data()), nullptr)
|
||||
);
|
||||
|
@ -94,9 +94,9 @@ namespace {
|
|||
return reply->atom;
|
||||
};
|
||||
|
||||
const Result<atom_t, DracError> supportingWmCheckAtom = internAtom("_NET_SUPPORTING_WM_CHECK");
|
||||
const Result<atom_t, DracError> wmNameAtom = internAtom("_NET_WM_NAME");
|
||||
const Result<atom_t, DracError> utf8StringAtom = internAtom("UTF8_STRING");
|
||||
const Result<atom_t> supportingWmCheckAtom = internAtom("_NET_SUPPORTING_WM_CHECK");
|
||||
const Result<atom_t> wmNameAtom = internAtom("_NET_WM_NAME");
|
||||
const Result<atom_t> utf8StringAtom = internAtom("UTF8_STRING");
|
||||
|
||||
if (!supportingWmCheckAtom || !wmNameAtom || !utf8StringAtom) {
|
||||
if (!supportingWmCheckAtom)
|
||||
|
@ -136,7 +136,7 @@ namespace {
|
|||
return String(nameData, length);
|
||||
}
|
||||
|
||||
fn GetWaylandCompositor() -> Result<String, DracError> {
|
||||
fn GetWaylandCompositor() -> Result<String> {
|
||||
#ifndef __FreeBSD__
|
||||
return "Wayland Compositor";
|
||||
#else
|
||||
|
@ -163,7 +163,7 @@ namespace {
|
|||
if (peerPid <= 0)
|
||||
return Err(DracError(DracErrorCode::PlatformSpecific, "Failed to obtain a valid peer PID"));
|
||||
|
||||
Result<String, DracError> exePathResult = GetPathByPid(peerPid);
|
||||
Result<String> exePathResult = GetPathByPid(peerPid);
|
||||
|
||||
if (!exePathResult)
|
||||
return Err(std::move(exePathResult).error());
|
||||
|
@ -199,7 +199,7 @@ namespace {
|
|||
namespace os {
|
||||
using util::helpers::GetEnv;
|
||||
|
||||
fn GetOSVersion() -> Result<String, DracError> {
|
||||
fn GetOSVersion() -> Result<String> {
|
||||
constexpr CStr path = "/etc/os-release";
|
||||
|
||||
std::ifstream file(path);
|
||||
|
@ -234,7 +234,7 @@ namespace os {
|
|||
return osName;
|
||||
}
|
||||
|
||||
fn GetMemInfo() -> Result<u64, DracError> {
|
||||
fn GetMemInfo() -> Result<u64> {
|
||||
u64 mem = 0;
|
||||
usize size = sizeof(mem);
|
||||
|
||||
|
@ -247,10 +247,10 @@ namespace os {
|
|||
return mem;
|
||||
}
|
||||
|
||||
fn GetNowPlaying() -> Result<MediaInfo, DracError> {
|
||||
fn GetNowPlaying() -> Result<MediaInfo> {
|
||||
using namespace dbus;
|
||||
|
||||
Result<Connection, DracError> connectionResult = Connection::busGet(DBUS_BUS_SESSION);
|
||||
Result<Connection> connectionResult = Connection::busGet(DBUS_BUS_SESSION);
|
||||
if (!connectionResult)
|
||||
return Err(connectionResult.error());
|
||||
|
||||
|
@ -259,12 +259,12 @@ namespace os {
|
|||
Option<String> activePlayer = None;
|
||||
|
||||
{
|
||||
Result<Message, DracError> listNamesResult =
|
||||
Result<Message> listNamesResult =
|
||||
Message::newMethodCall("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames");
|
||||
if (!listNamesResult)
|
||||
return Err(listNamesResult.error());
|
||||
|
||||
Result<Message, DracError> listNamesReplyResult = connection.sendWithReplyAndBlock(*listNamesResult, 100);
|
||||
Result<Message> listNamesReplyResult = connection.sendWithReplyAndBlock(*listNamesResult, 100);
|
||||
if (!listNamesReplyResult)
|
||||
return Err(listNamesReplyResult.error());
|
||||
|
||||
|
@ -292,7 +292,7 @@ namespace os {
|
|||
if (!activePlayer)
|
||||
return Err(DracError(DracErrorCode::NotFound, "No active MPRIS players found"));
|
||||
|
||||
Result<Message, DracError> msgResult = Message::newMethodCall(
|
||||
Result<Message> msgResult = Message::newMethodCall(
|
||||
activePlayer->c_str(), "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get"
|
||||
);
|
||||
|
||||
|
@ -304,7 +304,7 @@ namespace os {
|
|||
if (!msg.appendArgs("org.mpris.MediaPlayer2.Player", "Metadata"))
|
||||
return Err(DracError(DracErrorCode::InternalError, "Failed to append arguments to Properties.Get message"));
|
||||
|
||||
Result<Message, DracError> replyResult = connection.sendWithReplyAndBlock(msg, 100);
|
||||
Result<Message> replyResult = connection.sendWithReplyAndBlock(msg, 100);
|
||||
|
||||
if (!replyResult)
|
||||
return Err(replyResult.error());
|
||||
|
@ -378,20 +378,20 @@ namespace os {
|
|||
return MediaInfo(std::move(title), std::move(artist));
|
||||
}
|
||||
|
||||
fn GetWindowManager() -> Result<String, DracError> {
|
||||
fn GetWindowManager() -> Result<String> {
|
||||
if (!GetEnv("DISPLAY") && !GetEnv("WAYLAND_DISPLAY") && !GetEnv("XDG_SESSION_TYPE"))
|
||||
return Err(DracError(DracErrorCode::NotFound, "Could not find a graphical session"));
|
||||
|
||||
if (Result<String, DracError> waylandResult = GetWaylandCompositor())
|
||||
if (Result<String> waylandResult = GetWaylandCompositor())
|
||||
return *waylandResult;
|
||||
|
||||
if (Result<String, DracError> x11Result = GetX11WindowManager())
|
||||
if (Result<String> x11Result = GetX11WindowManager())
|
||||
return *x11Result;
|
||||
|
||||
return Err(DracError(DracErrorCode::NotFound, "Could not detect window manager (Wayland/X11) or both failed"));
|
||||
}
|
||||
|
||||
fn GetDesktopEnvironment() -> Result<String, DracError> {
|
||||
fn GetDesktopEnvironment() -> Result<String> {
|
||||
if (!GetEnv("DISPLAY") && !GetEnv("WAYLAND_DISPLAY") && !GetEnv("XDG_SESSION_TYPE"))
|
||||
return Err(DracError(DracErrorCode::NotFound, "Could not find a graphical session"));
|
||||
|
||||
|
@ -402,11 +402,11 @@ namespace os {
|
|||
|
||||
return xdgDesktop;
|
||||
})
|
||||
.or_else([](const DracError&) -> Result<String, DracError> { return GetEnv("DESKTOP_SESSION"); });
|
||||
.or_else([](const DracError&) -> Result<String> { return GetEnv("DESKTOP_SESSION"); });
|
||||
}
|
||||
|
||||
fn GetShell() -> Result<String, DracError> {
|
||||
if (const Result<String, DracError> shellPath = GetEnv("SHELL")) {
|
||||
fn GetShell() -> Result<String> {
|
||||
if (const Result<String> shellPath = GetEnv("SHELL")) {
|
||||
// clang-format off
|
||||
constexpr Array<Pair<StringView, StringView>, 5> shellMap {{
|
||||
{ "bash", "Bash" },
|
||||
|
@ -427,7 +427,7 @@ namespace os {
|
|||
return Err(DracError(DracErrorCode::NotFound, "Could not find SHELL environment variable"));
|
||||
}
|
||||
|
||||
fn GetHost() -> Result<String, DracError> {
|
||||
fn GetHost() -> Result<String> {
|
||||
Array<char, 256> buffer {};
|
||||
usize size = buffer.size();
|
||||
|
||||
|
@ -459,7 +459,7 @@ namespace os {
|
|||
return String(buffer.data());
|
||||
}
|
||||
|
||||
fn GetKernelVersion() -> Result<String, DracError> {
|
||||
fn GetKernelVersion() -> Result<String> {
|
||||
utsname uts;
|
||||
|
||||
if (uname(&uts) == -1)
|
||||
|
@ -471,7 +471,7 @@ namespace os {
|
|||
return uts.release;
|
||||
}
|
||||
|
||||
fn GetDiskUsage() -> Result<DiskSpace, DracError> {
|
||||
fn GetDiskUsage() -> Result<DiskSpace> {
|
||||
struct statvfs stat;
|
||||
|
||||
if (statvfs("/", &stat) == -1)
|
||||
|
@ -486,11 +486,11 @@ namespace os {
|
|||
|
||||
namespace package {
|
||||
#ifdef __NetBSD__
|
||||
fn GetPkgSrcCount() -> Result<u64, DracError> {
|
||||
fn GetPkgSrcCount() -> Result<u64> {
|
||||
return GetCountFromDirectory("pkgsrc", fs::current_path().root_path() / "usr" / "pkg" / "pkgdb", true);
|
||||
}
|
||||
#else
|
||||
fn GetPkgNgCount() -> Result<u64, DracError> {
|
||||
fn GetPkgNgCount() -> Result<u64> {
|
||||
const PackageManagerInfo pkgInfo = {
|
||||
.id = "pkgng",
|
||||
.dbPath = "/var/db/pkg/local.sqlite",
|
||||
|
|
|
@ -31,7 +31,7 @@ using util::error::DracError, util::error::DracErrorCode;
|
|||
using util::helpers::GetEnv;
|
||||
|
||||
namespace os {
|
||||
fn GetOSVersion() -> Result<String, DracError> {
|
||||
fn GetOSVersion() -> Result<String> {
|
||||
BFile file;
|
||||
status_t status = file.SetTo("/boot/system/lib/libbe.so", B_READ_ONLY);
|
||||
|
||||
|
@ -58,7 +58,7 @@ namespace os {
|
|||
return std::format("Haiku {}", versionShortString);
|
||||
}
|
||||
|
||||
fn GetMemInfo() -> Result<u64, DracError> {
|
||||
fn GetMemInfo() -> Result<u64> {
|
||||
system_info sysinfo;
|
||||
const status_t status = get_system_info(&sysinfo);
|
||||
|
||||
|
@ -68,16 +68,16 @@ namespace os {
|
|||
return static_cast<u64>(sysinfo.max_pages) * B_PAGE_SIZE;
|
||||
}
|
||||
|
||||
fn GetNowPlaying() -> Result<MediaInfo, DracError> {
|
||||
fn GetNowPlaying() -> Result<MediaInfo> {
|
||||
return Err(DracError(DracErrorCode::NotSupported, "Now playing is not supported on Haiku"));
|
||||
}
|
||||
|
||||
fn GetWindowManager() -> Result<String, DracError> { return "app_server"; }
|
||||
fn GetWindowManager() -> Result<String> { return "app_server"; }
|
||||
|
||||
fn GetDesktopEnvironment() -> Result<String, DracError> { return "Haiku Desktop Environment"; }
|
||||
fn GetDesktopEnvironment() -> Result<String> { return "Haiku Desktop Environment"; }
|
||||
|
||||
fn GetShell() -> Result<String, DracError> {
|
||||
if (const Result<String, DracError> shellPath = GetEnv("SHELL")) {
|
||||
fn GetShell() -> Result<String> {
|
||||
if (const Result<String> shellPath = GetEnv("SHELL")) {
|
||||
// clang-format off
|
||||
constexpr Array<Pair<StringView, StringView>, 5> shellMap {{
|
||||
{ "bash", "Bash" },
|
||||
|
@ -98,7 +98,7 @@ namespace os {
|
|||
return Err(DracError(DracErrorCode::NotFound, "Could not find SHELL environment variable"));
|
||||
}
|
||||
|
||||
fn GetHost() -> Result<String, DracError> {
|
||||
fn GetHost() -> Result<String> {
|
||||
Array<char, HOST_NAME_MAX + 1> hostnameBuffer {};
|
||||
|
||||
if (gethostname(hostnameBuffer.data(), hostnameBuffer.size()) != 0)
|
||||
|
@ -111,7 +111,7 @@ namespace os {
|
|||
return String(hostnameBuffer.data(), hostnameBuffer.size());
|
||||
}
|
||||
|
||||
fn GetKernelVersion() -> Result<String, DracError> {
|
||||
fn GetKernelVersion() -> Result<String> {
|
||||
system_info sysinfo;
|
||||
const status_t status = get_system_info(&sysinfo);
|
||||
|
||||
|
@ -121,7 +121,7 @@ namespace os {
|
|||
return std::to_string(sysinfo.kernel_version);
|
||||
}
|
||||
|
||||
fn GetDiskUsage() -> Result<DiskSpace, DracError> {
|
||||
fn GetDiskUsage() -> Result<DiskSpace> {
|
||||
struct statvfs stat;
|
||||
|
||||
if (statvfs("/boot", &stat) == -1)
|
||||
|
@ -135,7 +135,7 @@ namespace os {
|
|||
} // namespace os
|
||||
|
||||
namespace package {
|
||||
fn GetHaikuCount() -> Result<u64, DracError> {
|
||||
fn GetHaikuCount() -> Result<u64> {
|
||||
BPackageKit::BPackageRoster roster;
|
||||
BPackageKit::BPackageInfoSet packageList;
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ using util::error::DracError, util::error::DracErrorCode;
|
|||
using util::helpers::GetEnv;
|
||||
|
||||
namespace {
|
||||
fn GetX11WindowManager() -> Result<String, DracError> {
|
||||
fn GetX11WindowManager() -> Result<String> {
|
||||
using namespace xcb;
|
||||
|
||||
const DisplayGuard conn;
|
||||
|
@ -66,7 +66,7 @@ namespace {
|
|||
return std::format("Unknown Error Code ({})", err);
|
||||
}()));
|
||||
|
||||
fn internAtom = [&conn](const StringView name) -> Result<atom_t, DracError> {
|
||||
fn internAtom = [&conn](const StringView name) -> Result<atom_t> {
|
||||
const ReplyGuard<intern_atom_reply_t> reply(
|
||||
intern_atom_reply(conn.get(), intern_atom(conn.get(), 0, static_cast<u16>(name.size()), name.data()), nullptr)
|
||||
);
|
||||
|
@ -79,9 +79,9 @@ namespace {
|
|||
return reply->atom;
|
||||
};
|
||||
|
||||
const Result<atom_t, DracError> supportingWmCheckAtom = internAtom("_NET_SUPPORTING_WM_CHECK");
|
||||
const Result<atom_t, DracError> wmNameAtom = internAtom("_NET_WM_NAME");
|
||||
const Result<atom_t, DracError> utf8StringAtom = internAtom("UTF8_STRING");
|
||||
const Result<atom_t> supportingWmCheckAtom = internAtom("_NET_SUPPORTING_WM_CHECK");
|
||||
const Result<atom_t> wmNameAtom = internAtom("_NET_WM_NAME");
|
||||
const Result<atom_t> utf8StringAtom = internAtom("UTF8_STRING");
|
||||
|
||||
if (!supportingWmCheckAtom || !wmNameAtom || !utf8StringAtom) {
|
||||
if (!supportingWmCheckAtom)
|
||||
|
@ -121,7 +121,7 @@ namespace {
|
|||
return String(nameData, length);
|
||||
}
|
||||
|
||||
fn GetWaylandCompositor() -> Result<String, DracError> {
|
||||
fn GetWaylandCompositor() -> Result<String> {
|
||||
const wl::DisplayGuard display;
|
||||
|
||||
if (!display)
|
||||
|
@ -194,7 +194,7 @@ namespace {
|
|||
} // namespace
|
||||
|
||||
namespace os {
|
||||
fn GetOSVersion() -> Result<String, DracError> {
|
||||
fn GetOSVersion() -> Result<String> {
|
||||
constexpr CStr path = "/etc/os-release";
|
||||
|
||||
std::ifstream file(path);
|
||||
|
@ -225,7 +225,7 @@ namespace os {
|
|||
return Err(DracError(DracErrorCode::NotFound, std::format("PRETTY_NAME line not found in {}", path)));
|
||||
}
|
||||
|
||||
fn GetMemInfo() -> Result<u64, DracError> {
|
||||
fn GetMemInfo() -> Result<u64> {
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) != 0)
|
||||
|
@ -243,10 +243,10 @@ namespace os {
|
|||
return info.totalram * info.mem_unit;
|
||||
}
|
||||
|
||||
fn GetNowPlaying() -> Result<MediaInfo, DracError> {
|
||||
fn GetNowPlaying() -> Result<MediaInfo> {
|
||||
using namespace dbus;
|
||||
|
||||
Result<Connection, DracError> connectionResult = Connection::busGet(DBUS_BUS_SESSION);
|
||||
Result<Connection> connectionResult = Connection::busGet(DBUS_BUS_SESSION);
|
||||
if (!connectionResult)
|
||||
return Err(connectionResult.error());
|
||||
|
||||
|
@ -255,12 +255,12 @@ namespace os {
|
|||
Option<String> activePlayer = None;
|
||||
|
||||
{
|
||||
Result<Message, DracError> listNamesResult =
|
||||
Result<Message> listNamesResult =
|
||||
Message::newMethodCall("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames");
|
||||
if (!listNamesResult)
|
||||
return Err(listNamesResult.error());
|
||||
|
||||
Result<Message, DracError> listNamesReplyResult = connection.sendWithReplyAndBlock(*listNamesResult, 100);
|
||||
Result<Message> listNamesReplyResult = connection.sendWithReplyAndBlock(*listNamesResult, 100);
|
||||
if (!listNamesReplyResult)
|
||||
return Err(listNamesReplyResult.error());
|
||||
|
||||
|
@ -288,7 +288,7 @@ namespace os {
|
|||
if (!activePlayer)
|
||||
return Err(DracError(DracErrorCode::NotFound, "No active MPRIS players found"));
|
||||
|
||||
Result<Message, DracError> msgResult = Message::newMethodCall(
|
||||
Result<Message> msgResult = Message::newMethodCall(
|
||||
activePlayer->c_str(), "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get"
|
||||
);
|
||||
|
||||
|
@ -300,7 +300,7 @@ namespace os {
|
|||
if (!msg.appendArgs("org.mpris.MediaPlayer2.Player", "Metadata"))
|
||||
return Err(DracError(DracErrorCode::InternalError, "Failed to append arguments to Properties.Get message"));
|
||||
|
||||
Result<Message, DracError> replyResult = connection.sendWithReplyAndBlock(msg, 100);
|
||||
Result<Message> replyResult = connection.sendWithReplyAndBlock(msg, 100);
|
||||
|
||||
if (!replyResult)
|
||||
return Err(replyResult.error());
|
||||
|
@ -374,17 +374,17 @@ namespace os {
|
|||
return MediaInfo(std::move(title), std::move(artist));
|
||||
}
|
||||
|
||||
fn GetWindowManager() -> Result<String, DracError> {
|
||||
if (Result<String, DracError> waylandResult = GetWaylandCompositor())
|
||||
fn GetWindowManager() -> Result<String> {
|
||||
if (Result<String> waylandResult = GetWaylandCompositor())
|
||||
return *waylandResult;
|
||||
|
||||
if (Result<String, DracError> x11Result = GetX11WindowManager())
|
||||
if (Result<String> x11Result = GetX11WindowManager())
|
||||
return *x11Result;
|
||||
|
||||
return Err(DracError(DracErrorCode::NotFound, "Could not detect window manager (Wayland/X11) or both failed"));
|
||||
}
|
||||
|
||||
fn GetDesktopEnvironment() -> Result<String, DracError> {
|
||||
fn GetDesktopEnvironment() -> Result<String> {
|
||||
return GetEnv("XDG_CURRENT_DESKTOP")
|
||||
.transform([](String xdgDesktop) -> String {
|
||||
if (const usize colon = xdgDesktop.find(':'); colon != String::npos)
|
||||
|
@ -392,11 +392,11 @@ namespace os {
|
|||
|
||||
return xdgDesktop;
|
||||
})
|
||||
.or_else([](const DracError&) -> Result<String, DracError> { return GetEnv("DESKTOP_SESSION"); });
|
||||
.or_else([](const DracError&) -> Result<String> { return GetEnv("DESKTOP_SESSION"); });
|
||||
}
|
||||
|
||||
fn GetShell() -> Result<String, DracError> {
|
||||
if (const Result<String, DracError> shellPath = GetEnv("SHELL")) {
|
||||
fn GetShell() -> Result<String> {
|
||||
if (const Result<String> shellPath = GetEnv("SHELL")) {
|
||||
// clang-format off
|
||||
constexpr Array<Pair<StringView, StringView>, 5> shellMap {{
|
||||
{ "bash", "Bash" },
|
||||
|
@ -417,11 +417,11 @@ namespace os {
|
|||
return Err(DracError(DracErrorCode::NotFound, "Could not find SHELL environment variable"));
|
||||
}
|
||||
|
||||
fn GetHost() -> Result<String, DracError> {
|
||||
fn GetHost() -> Result<String> {
|
||||
constexpr CStr primaryPath = "/sys/class/dmi/id/product_family";
|
||||
constexpr CStr fallbackPath = "/sys/class/dmi/id/product_name";
|
||||
|
||||
fn readFirstLine = [&](const String& path) -> Result<String, DracError> {
|
||||
fn readFirstLine = [&](const String& path) -> Result<String> {
|
||||
std::ifstream file(path);
|
||||
String line;
|
||||
|
||||
|
@ -438,8 +438,8 @@ namespace os {
|
|||
return line;
|
||||
};
|
||||
|
||||
return readFirstLine(primaryPath).or_else([&](const DracError& primaryError) -> Result<String, DracError> {
|
||||
return readFirstLine(fallbackPath).or_else([&](const DracError& fallbackError) -> Result<String, DracError> {
|
||||
return readFirstLine(primaryPath).or_else([&](const DracError& primaryError) -> Result<String> {
|
||||
return readFirstLine(fallbackPath).or_else([&](const DracError& fallbackError) -> Result<String> {
|
||||
return Err(DracError(
|
||||
DracErrorCode::InternalError,
|
||||
std::format(
|
||||
|
@ -454,7 +454,7 @@ namespace os {
|
|||
});
|
||||
}
|
||||
|
||||
fn GetKernelVersion() -> Result<String, DracError> {
|
||||
fn GetKernelVersion() -> Result<String> {
|
||||
utsname uts;
|
||||
|
||||
if (uname(&uts) == -1)
|
||||
|
@ -466,7 +466,7 @@ namespace os {
|
|||
return uts.release;
|
||||
}
|
||||
|
||||
fn GetDiskUsage() -> Result<DiskSpace, DracError> {
|
||||
fn GetDiskUsage() -> Result<DiskSpace> {
|
||||
struct statvfs stat;
|
||||
|
||||
if (statvfs("/", &stat) == -1)
|
||||
|
@ -482,18 +482,18 @@ namespace os {
|
|||
namespace package {
|
||||
using namespace std::string_literals;
|
||||
|
||||
fn GetDpkgCount() -> Result<u64, DracError> {
|
||||
fn GetDpkgCount() -> Result<u64> {
|
||||
return GetCountFromDirectory("Dpkg", fs::current_path().root_path() / "var" / "lib" / "dpkg" / "info", ".list"s);
|
||||
}
|
||||
|
||||
fn GetMossCount() -> Result<u64, DracError> {
|
||||
fn GetMossCount() -> Result<u64> {
|
||||
const PackageManagerInfo mossInfo = {
|
||||
.id = "moss",
|
||||
.dbPath = "/.moss/db/install",
|
||||
.countQuery = "SELECT COUNT(*) FROM meta",
|
||||
};
|
||||
|
||||
Result<u64, DracError> countResult = GetCountFromDb(mossInfo);
|
||||
Result<u64> countResult = GetCountFromDb(mossInfo);
|
||||
|
||||
if (countResult)
|
||||
if (*countResult > 0)
|
||||
|
@ -502,7 +502,7 @@ namespace package {
|
|||
return countResult;
|
||||
}
|
||||
|
||||
fn GetPacmanCount() -> Result<u64, DracError> {
|
||||
fn GetPacmanCount() -> Result<u64> {
|
||||
return GetCountFromDirectory("Pacman", fs::current_path().root_path() / "var" / "lib" / "pacman" / "local", true);
|
||||
}
|
||||
} // namespace package
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
using namespace util::types;
|
||||
using util::error::DracError;
|
||||
|
||||
fn os::GetMemInfo() -> Result<u64, DracError> {
|
||||
fn os::GetMemInfo() -> Result<u64> {
|
||||
u64 mem = 0;
|
||||
usize size = sizeof(mem);
|
||||
|
||||
|
@ -25,19 +25,19 @@ fn os::GetMemInfo() -> Result<u64, DracError> {
|
|||
return mem;
|
||||
}
|
||||
|
||||
fn os::GetNowPlaying() -> Result<MediaInfo, DracError> { return GetCurrentPlayingInfo(); }
|
||||
fn os::GetNowPlaying() -> Result<MediaInfo> { return GetCurrentPlayingInfo(); }
|
||||
|
||||
fn os::GetOSVersion() -> Result<String, DracError> { return GetMacOSVersion(); }
|
||||
fn os::GetOSVersion() -> Result<String> { return GetMacOSVersion(); }
|
||||
|
||||
fn os::GetDesktopEnvironment() -> Result<String, DracError> {
|
||||
fn os::GetDesktopEnvironment() -> Result<String> {
|
||||
return "Aqua"; // TODO: Implement
|
||||
}
|
||||
|
||||
fn os::GetWindowManager() -> Result<String, DracError> {
|
||||
fn os::GetWindowManager() -> Result<String> {
|
||||
return "Yabai"; // TODO: Implement
|
||||
}
|
||||
|
||||
fn os::GetKernelVersion() -> Result<String, DracError> {
|
||||
fn os::GetKernelVersion() -> Result<String> {
|
||||
Array<char, 256> kernelVersion {};
|
||||
usize kernelVersionLen = sizeof(kernelVersion);
|
||||
|
||||
|
@ -47,7 +47,7 @@ fn os::GetKernelVersion() -> Result<String, DracError> {
|
|||
return kernelVersion.data();
|
||||
}
|
||||
|
||||
fn os::GetHost() -> Result<String, DracError> {
|
||||
fn os::GetHost() -> Result<String> {
|
||||
Array<char, 256> hwModel {};
|
||||
usize hwModelLen = sizeof(hwModel);
|
||||
|
||||
|
@ -212,7 +212,7 @@ fn os::GetHost() -> Result<String, DracError> {
|
|||
return String(iter->second);
|
||||
}
|
||||
|
||||
fn os::GetDiskUsage() -> Result<DiskSpace, DracError> {
|
||||
fn os::GetDiskUsage() -> Result<DiskSpace> {
|
||||
struct statvfs vfs;
|
||||
|
||||
if (statvfs("/", &vfs) != 0)
|
||||
|
@ -222,11 +222,11 @@ fn os::GetDiskUsage() -> Result<DiskSpace, DracError> {
|
|||
.total_bytes = vfs.f_blocks * vfs.f_frsize };
|
||||
}
|
||||
|
||||
fn os::GetPackageCount() -> Result<u64, DracError> {
|
||||
fn os::GetPackageCount() -> Result<u64> {
|
||||
return Err(DracError(DracErrorCode::NotSupported, "Package count is not supported on macOS")); // TODO: Implement
|
||||
}
|
||||
|
||||
fn os::GetShell() -> Result<String, DracError> {
|
||||
fn os::GetShell() -> Result<String> {
|
||||
return "Fish"; // TODO: Implement
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ using MRMediaRemoteGetNowPlayingInfoFunction =
|
|||
);
|
||||
}
|
||||
|
||||
+ (Result<String, DracError>)macOSVersion {
|
||||
+ (Result<String>)macOSVersion {
|
||||
NSProcessInfo* processInfo = [NSProcessInfo processInfo];
|
||||
NSOperatingSystemVersion osVersion = [processInfo operatingSystemVersion];
|
||||
|
||||
|
@ -91,8 +91,8 @@ using MRMediaRemoteGetNowPlayingInfoFunction =
|
|||
|
||||
extern "C++" {
|
||||
// NOLINTBEGIN(misc-use-internal-linkage)
|
||||
fn GetCurrentPlayingInfo() -> Result<MediaInfo, DracError> {
|
||||
__block Result<MediaInfo, DracError> result;
|
||||
fn GetCurrentPlayingInfo() -> Result<MediaInfo> {
|
||||
__block Result<MediaInfo> result;
|
||||
|
||||
const dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
|
@ -124,7 +124,7 @@ extern "C++" {
|
|||
return result;
|
||||
}
|
||||
|
||||
fn GetMacOSVersion() -> Result<String, DracError> { return [Bridge macOSVersion]; }
|
||||
fn GetMacOSVersion() -> Result<String> { return [Bridge macOSVersion]; }
|
||||
// NOLINTEND(misc-use-internal-linkage)
|
||||
}
|
||||
|
||||
|
|
|
@ -23,21 +23,21 @@ namespace os {
|
|||
* @return A Result containing the total RAM in bytes (u64) on success,
|
||||
* or a DracError on failure.
|
||||
*/
|
||||
fn GetMemInfo() -> Result<u64, DracError>;
|
||||
fn GetMemInfo() -> Result<u64>;
|
||||
|
||||
/**
|
||||
* @brief Gets structured metadata about the currently playing media.
|
||||
* @return A Result containing the media information (MediaInfo struct) on success,
|
||||
* or a NowPlayingError (indicating player state or system error) on failure.
|
||||
*/
|
||||
fn GetNowPlaying() -> Result<MediaInfo, DracError>;
|
||||
fn GetNowPlaying() -> Result<MediaInfo>;
|
||||
|
||||
/**
|
||||
* @brief Gets the "pretty" name of the operating system.
|
||||
* @details Examples: "Ubuntu 24.04.2 LTS", "Windows 11 Pro 24H2", "macOS 15 Sequoia".
|
||||
* @return A Result containing the OS version String on success, or a DracError on failure.
|
||||
*/
|
||||
fn GetOSVersion() -> Result<String, DracError>;
|
||||
fn GetOSVersion() -> Result<String>;
|
||||
|
||||
/**
|
||||
* @brief Attempts to retrieve the desktop environment name.
|
||||
|
@ -46,7 +46,7 @@ namespace os {
|
|||
* @return A Result containing the DE name String on success,
|
||||
* or a DracError on failure (e.g., permission error, API error).
|
||||
*/
|
||||
fn GetDesktopEnvironment() -> Result<String, DracError>;
|
||||
fn GetDesktopEnvironment() -> Result<String>;
|
||||
|
||||
/**
|
||||
* @brief Attempts to retrieve the window manager name.
|
||||
|
@ -55,7 +55,7 @@ namespace os {
|
|||
* @return A Result containing the detected WM name String on success,
|
||||
* or a DracError on failure (e.g., permission error, API error).
|
||||
*/
|
||||
fn GetWindowManager() -> Result<String, DracError>;
|
||||
fn GetWindowManager() -> Result<String>;
|
||||
|
||||
/**
|
||||
* @brief Attempts to detect the current user shell name.
|
||||
|
@ -64,7 +64,7 @@ namespace os {
|
|||
* @return A Result containing the shell name String on success,
|
||||
* or a DracError on failure (e.g., permission error, API error).
|
||||
*/
|
||||
fn GetShell() -> Result<String, DracError>;
|
||||
fn GetShell() -> Result<String>;
|
||||
|
||||
/**
|
||||
* @brief Gets a system identifier, often the hardware model or product family.
|
||||
|
@ -73,7 +73,7 @@ namespace os {
|
|||
* @return A Result containing the host/product identifier String on success,
|
||||
* or a DracError on failure (e.g., permission reading DMI/registry, API error).
|
||||
*/
|
||||
fn GetHost() -> Result<String, DracError>;
|
||||
fn GetHost() -> Result<String>;
|
||||
|
||||
/**
|
||||
* @brief Gets the operating system's kernel version string.
|
||||
|
@ -82,7 +82,7 @@ namespace os {
|
|||
* @return A Result containing the kernel version String on success,
|
||||
* or a DracError on failure.
|
||||
*/
|
||||
fn GetKernelVersion() -> Result<String, DracError>;
|
||||
fn GetKernelVersion() -> Result<String>;
|
||||
|
||||
/**
|
||||
* @brief Gets the disk usage for the primary/root filesystem.
|
||||
|
@ -90,5 +90,5 @@ namespace os {
|
|||
* @return A Result containing the DiskSpace struct (used/total bytes) on success,
|
||||
* or a DracError on failure (e.g., filesystem not found, permission error).
|
||||
*/
|
||||
fn GetDiskUsage() -> Result<DiskSpace, DracError>;
|
||||
fn GetDiskUsage() -> Result<DiskSpace>;
|
||||
} // namespace os
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace {
|
|||
// NOLINTEND(readability-identifier-naming)
|
||||
};
|
||||
|
||||
fn CountUniquePackages(const String& dbPath) -> Result<u64, DracError> {
|
||||
fn CountUniquePackages(const String& dbPath) -> Result<u64> {
|
||||
std::ifstream dbFile(dbPath);
|
||||
|
||||
if (!dbFile.is_open())
|
||||
|
@ -68,7 +68,7 @@ namespace {
|
|||
} // namespace
|
||||
|
||||
namespace os {
|
||||
fn GetOSVersion() -> Result<String, DracError> {
|
||||
fn GetOSVersion() -> Result<String> {
|
||||
utsname uts;
|
||||
|
||||
if (uname(&uts) == -1)
|
||||
|
@ -77,7 +77,7 @@ namespace os {
|
|||
return uts.sysname;
|
||||
}
|
||||
|
||||
fn GetMemInfo() -> Result<u64, DracError> {
|
||||
fn GetMemInfo() -> Result<u64> {
|
||||
CStr path = "/sys/kernel/memstat";
|
||||
std::ifstream file(path);
|
||||
|
||||
|
@ -106,15 +106,15 @@ namespace os {
|
|||
return (data.physical_allocated + data.physical_available) * PAGE_SIZE;
|
||||
}
|
||||
|
||||
fn GetNowPlaying() -> Result<MediaInfo, DracError> {
|
||||
fn GetNowPlaying() -> Result<MediaInfo> {
|
||||
return Err(DracError(DracErrorCode::NotSupported, "Now playing is not supported on SerenityOS"));
|
||||
}
|
||||
|
||||
fn GetWindowManager() -> Result<String, DracError> { return "WindowManager"; }
|
||||
fn GetWindowManager() -> Result<String> { return "WindowManager"; }
|
||||
|
||||
fn GetDesktopEnvironment() -> Result<String, DracError> { return "SerenityOS Desktop"; }
|
||||
fn GetDesktopEnvironment() -> Result<String> { return "SerenityOS Desktop"; }
|
||||
|
||||
fn GetShell() -> Result<String, DracError> {
|
||||
fn GetShell() -> Result<String> {
|
||||
uid_t userId = getuid();
|
||||
passwd* pw = getpwuid(userId);
|
||||
|
||||
|
@ -134,7 +134,7 @@ namespace os {
|
|||
return shell;
|
||||
}
|
||||
|
||||
fn GetHost() -> Result<String, DracError> {
|
||||
fn GetHost() -> Result<String> {
|
||||
Array<char, HOST_NAME_MAX> hostname_buffer;
|
||||
|
||||
if (gethostname(hostname_buffer.data(), hostname_buffer.size()) != 0)
|
||||
|
@ -143,7 +143,7 @@ namespace os {
|
|||
return String(hostname_buffer.data());
|
||||
}
|
||||
|
||||
fn GetKernelVersion() -> Result<String, DracError> {
|
||||
fn GetKernelVersion() -> Result<String> {
|
||||
utsname uts;
|
||||
|
||||
if (uname(&uts) == -1)
|
||||
|
@ -152,7 +152,7 @@ namespace os {
|
|||
return uts.release;
|
||||
}
|
||||
|
||||
fn GetDiskUsage() -> Result<DiskSpace, DracError> {
|
||||
fn GetDiskUsage() -> Result<DiskSpace> {
|
||||
struct statvfs stat;
|
||||
if (statvfs("/", &stat) == -1)
|
||||
return Err(DracError::withErrno("statvfs call failed for '/'"));
|
||||
|
@ -166,7 +166,7 @@ namespace os {
|
|||
} // namespace os
|
||||
|
||||
namespace package {
|
||||
fn GetSerenityCount() -> Result<u64, DracError> { return CountUniquePackages("/usr/Ports/installed.db"); }
|
||||
fn GetSerenityCount() -> Result<u64> { return CountUniquePackages("/usr/Ports/installed.db"); }
|
||||
} // namespace package
|
||||
|
||||
#endif // __serenity__
|
||||
|
|
|
@ -2,20 +2,21 @@
|
|||
|
||||
// clang-format off
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#include <dwmapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
#include <ranges>
|
||||
#include <tlhelp32.h>
|
||||
#include <wincrypt.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.Management.Deployment.h>
|
||||
#include <winrt/Windows.Media.Control.h>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
#include <winrt/Windows.System.Profile.h>
|
||||
#include <winrt/Windows.Management.Deployment.h>
|
||||
#include <winrt/base.h>
|
||||
#include <winrt/impl/Windows.Media.Control.2.h>
|
||||
|
||||
#include "src/core/package.hpp"
|
||||
#include "src/util/error.hpp"
|
||||
#include "src/util/helpers.hpp"
|
||||
#include "src/util/logging.hpp"
|
||||
|
@ -63,6 +64,7 @@ namespace {
|
|||
|
||||
String value((type == REG_SZ || type == REG_EXPAND_SZ) ? dataSize - 1 : dataSize, '\0');
|
||||
|
||||
// NOLINTNEXTLINE(*-pro-type-reinterpret-cast) - required here
|
||||
if (RegQueryValueExA(key, valueName.c_str(), nullptr, nullptr, reinterpret_cast<LPBYTE>(value.data()), &dataSize) !=
|
||||
ERROR_SUCCESS) {
|
||||
RegCloseKey(key);
|
||||
|
@ -81,7 +83,8 @@ namespace {
|
|||
|
||||
std::unordered_map<DWORD, ProcessData> processMap;
|
||||
|
||||
const HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
// ReSharper disable once CppLocalVariableMayBeConst
|
||||
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
|
||||
if (hSnap == INVALID_HANDLE_VALUE) {
|
||||
error_log("FindShellInProcessTree: Failed snapshot, error {}", GetLastError());
|
||||
|
@ -92,8 +95,9 @@ namespace {
|
|||
pe32.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
if (Process32First(hSnap, &pe32)) {
|
||||
// NOLINTNEXTLINE(*-avoid-do-while)
|
||||
do {
|
||||
String fullName = pe32.szExeFile;
|
||||
const String fullName = pe32.szExeFile;
|
||||
String baseName;
|
||||
|
||||
const size_t lastSlash = fullName.find_last_of("\\/");
|
||||
|
@ -107,11 +111,11 @@ namespace {
|
|||
if (baseName.length() > 4 && baseName.ends_with(".exe"))
|
||||
baseName.resize(baseName.length() - 4);
|
||||
|
||||
processMap[pe32.th32ProcessID] = ProcessData { pe32.th32ParentProcessID, std::move(baseName) };
|
||||
processMap[pe32.th32ProcessID] =
|
||||
ProcessData { .parentPid = pe32.th32ParentProcessID, .baseExeNameLower = std::move(baseName) };
|
||||
} while (Process32Next(hSnap, &pe32));
|
||||
} else {
|
||||
} else
|
||||
error_log("FindShellInProcessTree: Process32First failed, error {}", GetLastError());
|
||||
}
|
||||
|
||||
CloseHandle(hSnap);
|
||||
|
||||
|
@ -165,7 +169,7 @@ namespace {
|
|||
} // namespace
|
||||
|
||||
namespace os {
|
||||
fn GetMemInfo() -> Result<u64, DracError> {
|
||||
fn GetMemInfo() -> Result<u64> {
|
||||
MEMORYSTATUSEX memInfo;
|
||||
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
|
||||
|
||||
|
@ -178,7 +182,7 @@ namespace os {
|
|||
));
|
||||
}
|
||||
|
||||
fn GetNowPlaying() -> Result<MediaInfo, DracError> {
|
||||
fn GetNowPlaying() -> Result<MediaInfo> {
|
||||
using namespace winrt::Windows::Media::Control;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
|
||||
|
@ -200,7 +204,7 @@ namespace os {
|
|||
} catch (const winrt::hresult_error& e) { return Err(DracError(e)); }
|
||||
}
|
||||
|
||||
fn GetOSVersion() -> Result<String, DracError> {
|
||||
fn GetOSVersion() -> Result<String> {
|
||||
try {
|
||||
const String regSubKey = R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)";
|
||||
|
||||
|
@ -230,13 +234,14 @@ namespace os {
|
|||
} catch (const std::exception& e) { return Err(DracError(e)); }
|
||||
}
|
||||
|
||||
fn GetHost() -> Result<String, DracError> {
|
||||
fn GetHost() -> Result<String> {
|
||||
return GetRegistryValue(HKEY_LOCAL_MACHINE, R"(SYSTEM\HardwareConfig\Current)", "SystemFamily");
|
||||
}
|
||||
|
||||
fn GetKernelVersion() -> Result<String, DracError> {
|
||||
fn GetKernelVersion() -> Result<String> {
|
||||
if (const HMODULE ntdllHandle = GetModuleHandleW(L"ntdll.dll")) {
|
||||
if (const auto rtlGetVersion = std::bit_cast<RtlGetVersionPtr>(GetProcAddress(ntdllHandle, "RtlGetVersion"))) {
|
||||
// NOLINTNEXTLINE(*-pro-type-reinterpret-cast) - required here
|
||||
if (const auto rtlGetVersion = reinterpret_cast<RtlGetVersionPtr>(GetProcAddress(ntdllHandle, "RtlGetVersion"))) {
|
||||
RTL_OSVERSIONINFOW osInfo = {};
|
||||
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
|
||||
|
||||
|
@ -250,7 +255,7 @@ namespace os {
|
|||
return Err(DracError(DracErrorCode::NotFound, "Could not determine kernel version using RtlGetVersion"));
|
||||
}
|
||||
|
||||
fn GetWindowManager() -> Result<String, DracError> {
|
||||
fn GetWindowManager() -> Result<String> {
|
||||
BOOL compositionEnabled = FALSE;
|
||||
|
||||
if (SUCCEEDED(DwmIsCompositionEnabled(&compositionEnabled)))
|
||||
|
@ -259,7 +264,7 @@ namespace os {
|
|||
return Err(DracError(DracErrorCode::NotFound, "Failed to get window manager (DwmIsCompositionEnabled failed"));
|
||||
}
|
||||
|
||||
fn GetDesktopEnvironment() -> Result<String, DracError> {
|
||||
fn GetDesktopEnvironment() -> Result<String> {
|
||||
const String buildStr =
|
||||
GetRegistryValue(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", "CurrentBuildNumber");
|
||||
|
||||
|
@ -301,18 +306,17 @@ namespace os {
|
|||
} catch (...) { return Err(DracError(DracErrorCode::ParseError, "Failed to parse CurrentBuildNumber")); }
|
||||
}
|
||||
|
||||
fn GetShell() -> Result<String, DracError> {
|
||||
fn GetShell() -> Result<String> {
|
||||
using util::helpers::GetEnv;
|
||||
|
||||
if (const Result<String, DracError> msystemResult = GetEnv("MSYSTEM"); msystemResult && !msystemResult->empty()) {
|
||||
if (const Result<String> msystemResult = GetEnv("MSYSTEM"); msystemResult && !msystemResult->empty()) {
|
||||
String shellPath;
|
||||
|
||||
if (const Result<String, DracError> shellResult = GetEnv("SHELL"); shellResult && !shellResult->empty()) {
|
||||
if (const Result<String> shellResult = GetEnv("SHELL"); shellResult && !shellResult->empty())
|
||||
shellPath = *shellResult;
|
||||
} else if (const Result<String, DracError> loginShellResult = GetEnv("LOGINSHELL");
|
||||
loginShellResult && !loginShellResult->empty()) {
|
||||
else if (const Result<String> loginShellResult = GetEnv("LOGINSHELL");
|
||||
loginShellResult && !loginShellResult->empty())
|
||||
shellPath = *loginShellResult;
|
||||
}
|
||||
|
||||
if (!shellPath.empty()) {
|
||||
const usize lastSlash = shellPath.find_last_of("\\/");
|
||||
|
@ -341,20 +345,51 @@ namespace os {
|
|||
return Err(DracError(DracErrorCode::NotFound, "Shell not found"));
|
||||
}
|
||||
|
||||
fn GetDiskUsage() -> Result<DiskSpace, DracError> {
|
||||
fn GetDiskUsage() -> Result<DiskSpace> {
|
||||
ULARGE_INTEGER freeBytes, totalBytes;
|
||||
|
||||
if (GetDiskFreeSpaceExW(L"C:\\", nullptr, &totalBytes, &freeBytes))
|
||||
return DiskSpace { .used_bytes = totalBytes.QuadPart - freeBytes.QuadPart, .total_bytes = totalBytes.QuadPart };
|
||||
return DiskSpace { .usedBytes = totalBytes.QuadPart - freeBytes.QuadPart, .totalBytes = totalBytes.QuadPart };
|
||||
|
||||
return Err(DracError(util::error::DracErrorCode::NotFound, "Failed to get disk usage"));
|
||||
}
|
||||
} // namespace os
|
||||
|
||||
fn GetPackageCount() -> Result<u64, DracError> {
|
||||
namespace package {
|
||||
using util::helpers::GetEnv;
|
||||
|
||||
fn CountChocolatey() -> Result<u64> {
|
||||
const fs::path chocoPath = fs::path(GetEnv("ChocolateyInstall").value_or("C:\\ProgramData\\chocolatey")) / "lib";
|
||||
|
||||
if (!fs::exists(chocoPath) || !fs::is_directory(chocoPath))
|
||||
return Err(
|
||||
DracError(DracErrorCode::NotFound, std::format("Chocolatey directory not found: {}", chocoPath.string()))
|
||||
);
|
||||
|
||||
return GetCountFromDirectory("Chocolatey", chocoPath);
|
||||
}
|
||||
|
||||
fn CountScoop() -> Result<u64> {
|
||||
fs::path scoopAppsPath;
|
||||
|
||||
if (const Result<String> scoopEnvPath = GetEnv("SCOOP"))
|
||||
scoopAppsPath = fs::path(*scoopEnvPath) / "apps";
|
||||
else if (const Result<String> userProfilePath = GetEnv("USERPROFILE"))
|
||||
scoopAppsPath = fs::path(*userProfilePath) / "scoop" / "apps";
|
||||
else
|
||||
return Err(DracError(
|
||||
DracErrorCode::NotFound,
|
||||
"Could not determine Scoop installation directory (SCOOP and USERPROFILE environment variables not found)"
|
||||
));
|
||||
|
||||
return GetCountFromDirectory("Scoop", scoopAppsPath, true);
|
||||
}
|
||||
|
||||
fn CountWinGet() -> Result<u64> {
|
||||
try {
|
||||
return std::ranges::distance(winrt::Windows::Management::Deployment::PackageManager().FindPackagesForUser(L""));
|
||||
} catch (const winrt::hresult_error& e) { return Err(DracError(e)); }
|
||||
}
|
||||
} // namespace os
|
||||
} // namespace package
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,24 +25,33 @@ namespace util::cache {
|
|||
* Should ideally only contain filesystem-safe characters.
|
||||
* @return Result containing the filesystem path on success, or a DracError on failure.
|
||||
*/
|
||||
inline fn GetCachePath(const String& cache_key) -> Result<fs::path, DracError> {
|
||||
inline fn GetCachePath(const String& cache_key) -> Result<fs::path> {
|
||||
if (cache_key.empty())
|
||||
return Err(DracError(DracErrorCode::InvalidArgument, "Cache key cannot be empty."));
|
||||
|
||||
// Basic check for potentially problematic characters in the key for filename safety.
|
||||
// You might want to expand this or implement more robust sanitization if needed.
|
||||
if (cache_key.find_first_of("/\\:*?\"<>|") != String::npos)
|
||||
return Err(
|
||||
DracError(DracErrorCode::InvalidArgument, std::format("Cache key '{}' contains invalid characters.", cache_key))
|
||||
);
|
||||
|
||||
std::error_code errc;
|
||||
const fs::path cacheDir = fs::temp_directory_path(errc);
|
||||
|
||||
const fs::path cacheDir = fs::temp_directory_path(errc) / "draconis++";
|
||||
|
||||
if (!fs::exists(cacheDir, errc)) {
|
||||
if (errc)
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to check existence of cache directory: " + errc.message())
|
||||
);
|
||||
|
||||
fs::create_directories(cacheDir, errc);
|
||||
|
||||
if (errc)
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to create cache directory: " + errc.message()));
|
||||
}
|
||||
|
||||
if (errc)
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to get system temporary directory: " + errc.message()));
|
||||
|
||||
// Use a consistent naming scheme
|
||||
return cacheDir / (cache_key + "_cache.beve");
|
||||
}
|
||||
|
||||
|
@ -53,18 +62,17 @@ namespace util::cache {
|
|||
* @return Result containing the deserialized object of type T on success, or a DracError on failure.
|
||||
*/
|
||||
template <typename T>
|
||||
fn ReadCache(const String& cache_key) -> Result<T, DracError> {
|
||||
Result<fs::path, DracError> cachePathResult = GetCachePath(cache_key);
|
||||
fn ReadCache(const String& cache_key) -> Result<T> {
|
||||
Result<fs::path> cachePathResult = GetCachePath(cache_key);
|
||||
if (!cachePathResult)
|
||||
return Err(cachePathResult.error());
|
||||
|
||||
const fs::path& cachePath = *cachePathResult;
|
||||
|
||||
if (std::error_code existsEc; !fs::exists(cachePath, existsEc) || existsEc) {
|
||||
if (existsEc) {
|
||||
// Log if there was an error checking existence, but still return NotFound
|
||||
if (existsEc)
|
||||
warn_log("Error checking existence of cache file '{}': {}", cachePath.string(), existsEc.message());
|
||||
}
|
||||
|
||||
return Err(DracError(DracErrorCode::NotFound, "Cache file not found: " + cachePath.string()));
|
||||
}
|
||||
|
||||
|
@ -72,17 +80,13 @@ namespace util::cache {
|
|||
if (!ifs.is_open())
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to open cache file for reading: " + cachePath.string()));
|
||||
|
||||
debug_log("Reading cache for key '{}' from: {}", cache_key, cachePath.string());
|
||||
|
||||
try {
|
||||
// Read the entire file content
|
||||
const String content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||
ifs.close(); // Close the file as soon as content is read
|
||||
ifs.close();
|
||||
|
||||
if (content.empty())
|
||||
return Err(DracError(DracErrorCode::ParseError, "BEVE cache file is empty: " + cachePath.string()));
|
||||
|
||||
// Ensure T is default constructible for Glaze
|
||||
static_assert(std::is_default_constructible_v<T>, "Cache type T must be default constructible for Glaze.");
|
||||
T result {};
|
||||
|
||||
|
@ -98,14 +102,12 @@ namespace util::cache {
|
|||
));
|
||||
}
|
||||
|
||||
debug_log("Successfully read cache for key '{}'.", cache_key);
|
||||
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) {
|
||||
// Catching std::exception or a project-specific base exception
|
||||
return Err(DracError(
|
||||
DracErrorCode::InternalError,
|
||||
std::format("Standard exception reading cache file {}: {}", cachePath.string(), e.what())
|
||||
|
@ -123,24 +125,20 @@ namespace util::cache {
|
|||
* @return Result containing void on success, or a DracError on failure.
|
||||
*/
|
||||
template <typename T>
|
||||
fn WriteCache(const String& cache_key, const T& data) -> Result<void, DracError> {
|
||||
Result<fs::path, DracError> cachePathResult = GetCachePath(cache_key);
|
||||
fn WriteCache(const String& cache_key, const T& data) -> Result<> {
|
||||
Result<fs::path> cachePathResult = GetCachePath(cache_key);
|
||||
if (!cachePathResult)
|
||||
return Err(cachePathResult.error());
|
||||
|
||||
const fs::path& cachePath = *cachePathResult;
|
||||
fs::path tempPath = cachePath;
|
||||
tempPath += ".tmp"; // Use a temporary file for atomic write
|
||||
|
||||
debug_log("Writing cache for key '{}' to: {}", cache_key, cachePath.string());
|
||||
tempPath += ".tmp";
|
||||
|
||||
try {
|
||||
String binaryBuffer;
|
||||
|
||||
// Use Glaze to serialize
|
||||
// Need to decay T in case it's a reference type from the caller
|
||||
using DecayedT = std::decay_t<T>;
|
||||
DecayedT dataToSerialize = data; // Make a copy if needed for non-const Glaze operations
|
||||
DecayedT dataToSerialize = data;
|
||||
|
||||
if (glz::error_ctx glazeErr = glz::write_beve(dataToSerialize, binaryBuffer); glazeErr) {
|
||||
return Err(DracError(
|
||||
|
@ -154,7 +152,6 @@ namespace util::cache {
|
|||
));
|
||||
}
|
||||
|
||||
// Scope for ofstream to ensure it's closed before rename
|
||||
{
|
||||
std::ofstream ofs(tempPath, std::ios::binary | std::ios::trunc);
|
||||
if (!ofs.is_open())
|
||||
|
@ -163,22 +160,18 @@ namespace util::cache {
|
|||
ofs.write(binaryBuffer.data(), static_cast<isize>(binaryBuffer.size()));
|
||||
|
||||
if (!ofs) {
|
||||
// Attempt cleanup before returning error
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc); // Ignore error on cleanup attempt
|
||||
fs::remove(tempPath, removeEc);
|
||||
return Err(DracError(DracErrorCode::IoError, "Failed to write to temporary cache file: " + tempPath.string())
|
||||
);
|
||||
}
|
||||
// ofstream automatically closed here
|
||||
}
|
||||
|
||||
// Attempt to atomically replace the old cache file
|
||||
std::error_code renameEc;
|
||||
fs::rename(tempPath, cachePath, renameEc);
|
||||
if (renameEc) {
|
||||
// If rename failed, attempt to clean up the temp file
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc); // Ignore error on cleanup attempt
|
||||
fs::remove(tempPath, removeEc);
|
||||
return Err(DracError(
|
||||
DracErrorCode::IoError,
|
||||
std::format(
|
||||
|
@ -190,26 +183,24 @@ namespace util::cache {
|
|||
));
|
||||
}
|
||||
|
||||
debug_log("Successfully wrote cache for key '{}'.", cache_key);
|
||||
return {}; // Success
|
||||
return {};
|
||||
} catch (const std::ios_base::failure& e) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc); // Cleanup attempt
|
||||
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); // Cleanup attempt
|
||||
fs::remove(tempPath, removeEc);
|
||||
return Err(DracError(
|
||||
DracErrorCode::InternalError,
|
||||
std::format("Standard exception writing cache file {}: {}", tempPath.string(), e.what())
|
||||
));
|
||||
} catch (...) {
|
||||
std::error_code removeEc;
|
||||
fs::remove(tempPath, removeEc); // Cleanup attempt
|
||||
fs::remove(tempPath, removeEc);
|
||||
return Err(DracError(DracErrorCode::Other, "Unknown error writing cache file: " + tempPath.string()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace util::cache
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <format>
|
||||
#include <expected> // std::{unexpected, expected}
|
||||
#include <source_location> // std::source_location
|
||||
#include <system_error> // std::error_code
|
||||
|
||||
|
@ -11,7 +11,10 @@
|
|||
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
namespace util::error {
|
||||
#include "include/matchit.h"
|
||||
|
||||
namespace util {
|
||||
namespace error {
|
||||
using types::u8, types::i32, types::String, types::StringView, types::Exception;
|
||||
|
||||
/**
|
||||
|
@ -55,33 +58,40 @@ namespace util::error {
|
|||
|
||||
explicit DracError(const std::error_code& errc, const std::source_location& loc = std::source_location::current())
|
||||
: message(errc.message()), location(loc) {
|
||||
using namespace matchit;
|
||||
using enum DracErrorCode;
|
||||
using enum std::errc;
|
||||
|
||||
switch (static_cast<std::errc>(errc.value())) {
|
||||
case permission_denied: code = PermissionDenied; break;
|
||||
case no_such_file_or_directory: code = NotFound; break;
|
||||
case timed_out: code = Timeout; break;
|
||||
case io_error: code = IoError; break;
|
||||
case network_unreachable:
|
||||
case network_down:
|
||||
case connection_refused: code = NetworkError; break;
|
||||
case not_supported: code = NotSupported; break;
|
||||
default: code = errc.category() == std::generic_category() ? InternalError : PlatformSpecific; break;
|
||||
}
|
||||
code = match(errc)(
|
||||
is | or_(file_too_large, io_error) = IoError,
|
||||
is | invalid_argument = InvalidArgument,
|
||||
is | not_enough_memory = OutOfMemory,
|
||||
is | or_(address_family_not_supported, operation_not_supported, not_supported) = NotSupported,
|
||||
is | or_(network_unreachable, network_down, connection_refused) = NetworkError,
|
||||
is | or_(no_such_file_or_directory, not_a_directory, is_a_directory, file_exists) = NotFound,
|
||||
is | permission_denied = PermissionDenied,
|
||||
is | timed_out = Timeout,
|
||||
is | _ = errc.category() == std::generic_category() ? InternalError : PlatformSpecific
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
explicit DracError(const winrt::hresult_error& e) : message(winrt::to_string(e.message())) {
|
||||
switch (e.code()) {
|
||||
case E_ACCESSDENIED: code = DracErrorCode::PermissionDenied; break;
|
||||
case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
|
||||
case HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND):
|
||||
case HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_FOUND): code = DracErrorCode::NotFound; break;
|
||||
case HRESULT_FROM_WIN32(ERROR_TIMEOUT):
|
||||
case HRESULT_FROM_WIN32(ERROR_SEM_TIMEOUT): code = DracErrorCode::Timeout; break;
|
||||
case HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED): code = DracErrorCode::NotSupported; break;
|
||||
default: code = DracErrorCode::PlatformSpecific; break;
|
||||
}
|
||||
using namespace matchit;
|
||||
using enum DracErrorCode;
|
||||
|
||||
fn fromWin32 = [](const types::u32 x) -> HRESULT { return HRESULT_FROM_WIN32(x); };
|
||||
|
||||
code = match(e.code())(
|
||||
is | or_(E_ACCESSDENIED, fromWin32(ERROR_ACCESS_DENIED)) = PermissionDenied,
|
||||
is | fromWin32(ERROR_FILE_NOT_FOUND) = NotFound,
|
||||
is | fromWin32(ERROR_PATH_NOT_FOUND) = NotFound,
|
||||
is | fromWin32(ERROR_SERVICE_NOT_FOUND) = NotFound,
|
||||
is | fromWin32(ERROR_TIMEOUT) = Timeout,
|
||||
is | fromWin32(ERROR_SEM_TIMEOUT) = Timeout,
|
||||
is | fromWin32(ERROR_NOT_SUPPORTED) = NotSupported,
|
||||
is | _ = PlatformSpecific
|
||||
);
|
||||
}
|
||||
#else
|
||||
DracError(const DracErrorCode code_hint, const int errno_val)
|
||||
|
@ -122,4 +132,25 @@ namespace util::error {
|
|||
}
|
||||
#endif
|
||||
};
|
||||
} // namespace util::error
|
||||
} // namespace error
|
||||
|
||||
namespace types {
|
||||
/**
|
||||
* @typedef Result
|
||||
* @brief Alias for std::expected<Tp, Er>. Represents a value that can either be
|
||||
* a success value of type Tp or an error value of type Er.
|
||||
* @tparam Tp The type of the success value.
|
||||
* @tparam Er The type of the error value.
|
||||
*/
|
||||
template <typename Tp = void, typename Er = error::DracError>
|
||||
using Result = std::expected<Tp, Er>;
|
||||
|
||||
/**
|
||||
* @typedef Err
|
||||
* @brief Alias for std::unexpected<Er>. Used to construct a Result in an error state.
|
||||
* @tparam Er The type of the error value.
|
||||
*/
|
||||
template <typename Er = error::DracError>
|
||||
using Err = std::unexpected<Er>;
|
||||
} // namespace types
|
||||
} // namespace util
|
|
@ -14,7 +14,7 @@ namespace util::helpers {
|
|||
* @return A Result containing the value of the environment variable as a String,
|
||||
* or an EnvError if an error occurred.
|
||||
*/
|
||||
[[nodiscard]] inline fn GetEnv(CStr name) -> Result<String, DracError> {
|
||||
[[nodiscard]] inline fn GetEnv(CStr name) -> Result<String> {
|
||||
#ifdef _WIN32
|
||||
using types::i32, types::usize, types::UniquePointer;
|
||||
|
||||
|
|
|
@ -5,10 +5,15 @@
|
|||
#include <filesystem> // std::filesystem::path
|
||||
#include <format> // std::format
|
||||
#include <ftxui/screen/color.hpp> // ftxui::Color
|
||||
#include <iostream> // std::cout
|
||||
#include <mutex> // std::{mutex, lock_guard}
|
||||
#include <utility> // std::forward
|
||||
|
||||
#ifdef __cpp_lib_print
|
||||
#include <print> // std::print
|
||||
#else
|
||||
#include <iostream> // std::cout
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <source_location> // std::source_location
|
||||
#endif
|
||||
|
@ -17,6 +22,8 @@
|
|||
#include "src/util/error.hpp"
|
||||
#include "src/util/types.hpp"
|
||||
|
||||
#include "ftxui/dom/elements.hpp"
|
||||
|
||||
namespace util::logging {
|
||||
using types::usize, types::u8, types::i32, types::i64, types::CStr, types::String, types::StringView, types::Array,
|
||||
types::Option, types::None, types::Mutex, types::LockGuard;
|
||||
|
@ -118,13 +125,15 @@ namespace util::logging {
|
|||
* @return FTXUI color code
|
||||
*/
|
||||
constexpr fn GetLevelColor(const LogLevel level) -> ftxui::Color::Palette16 {
|
||||
switch (level) {
|
||||
case LogLevel::Debug: return LogLevelConst::DEBUG_COLOR;
|
||||
case LogLevel::Info: return LogLevelConst::INFO_COLOR;
|
||||
case LogLevel::Warn: return LogLevelConst::WARN_COLOR;
|
||||
case LogLevel::Error: return LogLevelConst::ERROR_COLOR;
|
||||
default: std::unreachable();
|
||||
}
|
||||
using namespace matchit;
|
||||
using enum LogLevel;
|
||||
|
||||
return match(level)(
|
||||
is | Debug = LogLevelConst::DEBUG_COLOR,
|
||||
is | Info = LogLevelConst::INFO_COLOR,
|
||||
is | Warn = LogLevelConst::WARN_COLOR,
|
||||
is | Error = LogLevelConst::ERROR_COLOR
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,13 +142,15 @@ namespace util::logging {
|
|||
* @return String representation
|
||||
*/
|
||||
constexpr fn GetLevelString(const LogLevel level) -> StringView {
|
||||
switch (level) {
|
||||
case LogLevel::Debug: return LogLevelConst::DEBUG_STR;
|
||||
case LogLevel::Info: return LogLevelConst::INFO_STR;
|
||||
case LogLevel::Warn: return LogLevelConst::WARN_STR;
|
||||
case LogLevel::Error: return LogLevelConst::ERROR_STR;
|
||||
default: std::unreachable();
|
||||
}
|
||||
using namespace matchit;
|
||||
using enum LogLevel;
|
||||
|
||||
return match(level)(
|
||||
is | Debug = LogLevelConst::DEBUG_STR,
|
||||
is | Info = LogLevelConst::INFO_STR,
|
||||
is | Warn = LogLevelConst::WARN_STR,
|
||||
is | Error = LogLevelConst::ERROR_STR
|
||||
);
|
||||
}
|
||||
|
||||
// ReSharper disable once CppDoxygenUnresolvedReference
|
||||
|
@ -180,7 +191,8 @@ namespace util::logging {
|
|||
if (localtime_r(&nowTt, &localTm) != nullptr) {
|
||||
#endif
|
||||
Array<char, 64> timeBuffer {};
|
||||
auto formattedTime =
|
||||
|
||||
const usize formattedTime =
|
||||
std::strftime(timeBuffer.data(), sizeof(timeBuffer), LogLevelConst::TIMESTAMP_FORMAT, &localTm);
|
||||
|
||||
if (formattedTime > 0) {
|
||||
|
@ -188,11 +200,10 @@ namespace util::logging {
|
|||
} else {
|
||||
try {
|
||||
timestamp = std::format("{:%X}", nowTp);
|
||||
} catch (const std::format_error& fmt_err) { timestamp = "??:??:?? (fmt_err)"; }
|
||||
}
|
||||
} else {
|
||||
timestamp = "??:??:?? (conv_err)";
|
||||
} catch ([[maybe_unused]] const std::format_error& fmtErr) { timestamp = "??:??:??"; }
|
||||
}
|
||||
} else
|
||||
timestamp = "??:??:??";
|
||||
|
||||
const String message = std::format(fmt, std::forward<Args>(args)...);
|
||||
|
||||
|
@ -203,16 +214,28 @@ namespace util::logging {
|
|||
message
|
||||
);
|
||||
|
||||
#ifdef __cpp_lib_print
|
||||
std::print("{}", mainLogLine);
|
||||
#else
|
||||
std::cout << mainLogLine;
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
const String fileLine =
|
||||
std::format(LogLevelConst::FILE_LINE_FORMAT, path(loc.file_name()).lexically_normal().string(), loc.line());
|
||||
const String fullDebugLine = std::format("{}{}", LogLevelConst::DEBUG_LINE_PREFIX, fileLine);
|
||||
#ifdef __cpp_lib_print
|
||||
std::print("\n{}", Italic(Colorize(fullDebugLine, LogLevelConst::DEBUG_INFO_COLOR)));
|
||||
#else
|
||||
std::cout << '\n' << Italic(Colorize(fullDebugLine, LogLevelConst::DEBUG_INFO_COLOR));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_lib_print
|
||||
std::println("{}", LogLevelConst::RESET_CODE);
|
||||
#else
|
||||
std::cout << LogLevelConst::RESET_CODE << '\n';
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename ErrorType>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <array> // std::array (Array)
|
||||
#include <expected> // std::expected (Result)
|
||||
#include <future> // std::future (Future)
|
||||
#include <map> // std::map (Map)
|
||||
#include <memory> // std::shared_ptr and std::unique_ptr (SharedPointer, UniquePointer)
|
||||
|
@ -12,6 +11,8 @@
|
|||
#include <utility> // std::pair (Pair)
|
||||
#include <vector> // std::vector (Vec)
|
||||
|
||||
#include "include/matchit.h"
|
||||
|
||||
namespace util::types {
|
||||
using u8 = std::uint8_t; ///< 8-bit unsigned integer.
|
||||
using u16 = std::uint16_t; ///< 16-bit unsigned integer.
|
||||
|
@ -40,24 +41,6 @@ namespace util::types {
|
|||
|
||||
inline constexpr std::nullopt_t None = std::nullopt; ///< Represents an empty optional value.
|
||||
|
||||
/**
|
||||
* @typedef Result
|
||||
* @brief Alias for std::expected<Tp, Er>. Represents a value that can either be
|
||||
* a success value of type Tp or an error value of type Er.
|
||||
* @tparam Tp The type of the success value.
|
||||
* @tparam Er The type of the error value.
|
||||
*/
|
||||
template <typename Tp, typename Er>
|
||||
using Result = std::expected<Tp, Er>;
|
||||
|
||||
/**
|
||||
* @typedef Err
|
||||
* @brief Alias for std::unexpected<Er>. Used to construct a Result in an error state.
|
||||
* @tparam Er The type of the error value.
|
||||
*/
|
||||
template <typename Er>
|
||||
using Err = std::unexpected<Er>;
|
||||
|
||||
/**
|
||||
* @typedef Option
|
||||
* @brief Alias for std::optional<Tp>. Represents a value that may or may not be present.
|
||||
|
@ -133,8 +116,8 @@ namespace util::types {
|
|||
* Used as the success type for os::GetDiskUsage.
|
||||
*/
|
||||
struct DiskSpace {
|
||||
u64 used_bytes; ///< Currently used disk space in bytes.
|
||||
u64 total_bytes; ///< Total disk space in bytes.
|
||||
u64 usedBytes; ///< Currently used disk space in bytes.
|
||||
u64 totalBytes; ///< Total disk space in bytes.
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -265,7 +265,7 @@ namespace dbus {
|
|||
* @return Result containing a MessageGuard on success, or DraconisError on failure.
|
||||
*/
|
||||
static fn newMethodCall(const char* destination, const char* path, const char* interface, const char* method)
|
||||
-> Result<Message, DracError> {
|
||||
-> Result<Message> {
|
||||
DBusMessage* rawMsg = dbus_message_new_method_call(destination, path, interface, method);
|
||||
|
||||
if (!rawMsg)
|
||||
|
@ -331,7 +331,7 @@ namespace dbus {
|
|||
* @return Result containing the reply MessageGuard on success, or DraconisError on failure.
|
||||
*/
|
||||
[[nodiscard]] fn sendWithReplyAndBlock(const Message& message, const i32 timeout_milliseconds = 1000) const
|
||||
-> Result<Message, DracError> {
|
||||
-> Result<Message> {
|
||||
if (!m_conn || !message.get())
|
||||
return Err(
|
||||
DracError(DracErrorCode::InvalidArgument, "Invalid connection or message provided to sendWithReplyAndBlock")
|
||||
|
@ -371,7 +371,7 @@ namespace dbus {
|
|||
* @param bus_type The type of bus (DBUS_BUS_SESSION or DBUS_BUS_SYSTEM).
|
||||
* @return Result containing a ConnectionGuard on success, or DraconisError on failure.
|
||||
*/
|
||||
static fn busGet(const DBusBusType bus_type) -> Result<Connection, DracError> {
|
||||
static fn busGet(const DBusBusType bus_type) -> Result<Connection> {
|
||||
Error err;
|
||||
DBusConnection* rawConn = dbus_bus_get(bus_type, err.get());
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue