temp stuff
This commit is contained in:
parent
5b63fe4cce
commit
95374d942d
12
flake.lock
12
flake.lock
|
@ -2,11 +2,11 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1738012240,
|
"lastModified": 1738611518,
|
||||||
"narHash": "sha256-4wmhkSSdgkVR02zG7nP4MTUpA2oih7E+9AWu4zEqP+k=",
|
"narHash": "sha256-gOP/qsGtUCTkazx3qQ/tn6xaDERRgOtF2eRe1gmIU5s=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "0542e87760a8f611f089dcf38862f783c8c8f890",
|
"rev": "eb3431789cef743af9dace58eb2ba7b33a332b56",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -58,11 +58,11 @@
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1737483750,
|
"lastModified": 1738070913,
|
||||||
"narHash": "sha256-5An1wq5U8sNycOBBg3nsDDgpwBmR9liOpDGlhliA6Xo=",
|
"narHash": "sha256-j6jC12vCFsTGDmY2u1H12lMr62fnclNjuCtAdF1a4Nk=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "treefmt-nix",
|
"repo": "treefmt-nix",
|
||||||
"rev": "f2cc121df15418d028a59c9737d38e3a90fbaf8f",
|
"rev": "bebf27d00f7d10ba75332a0541ac43676985dea3",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
tomlplusplus
|
tomlplusplus
|
||||||
yyjson
|
yyjson
|
||||||
reflect-cpp
|
reflect-cpp
|
||||||
|
sqlitecpp
|
||||||
ftxui
|
ftxui
|
||||||
]
|
]
|
||||||
++ linuxPkgs
|
++ linuxPkgs
|
||||||
|
@ -75,7 +76,6 @@
|
||||||
systemdLibs
|
systemdLibs
|
||||||
sdbus-cpp
|
sdbus-cpp
|
||||||
valgrind
|
valgrind
|
||||||
linuxKernel.packages.linux_zen.perf.out
|
|
||||||
xorg.libX11
|
xorg.libX11
|
||||||
wayland
|
wayland
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -92,6 +92,7 @@ if host_machine.system() == 'darwin'
|
||||||
deps += dependency('SystemConfiguration')
|
deps += dependency('SystemConfiguration')
|
||||||
deps += dependency('iconv')
|
deps += dependency('iconv')
|
||||||
elif host_machine.system() == 'linux' or host_machine.system() == 'freebsd'
|
elif host_machine.system() == 'linux' or host_machine.system() == 'freebsd'
|
||||||
|
deps += dependency('SQLiteCpp')
|
||||||
deps += dependency('sdbus-c++')
|
deps += dependency('sdbus-c++')
|
||||||
deps += dependency('x11')
|
deps += dependency('x11')
|
||||||
deps += dependency('wayland-client')
|
deps += dependency('wayland-client')
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
#include <expected>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <rfl/json.hpp>
|
#include <rfl/json.hpp>
|
||||||
|
@ -7,9 +8,12 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
using rfl::Error;
|
|
||||||
using rfl::Result;
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
// Alias for cleaner error handling
|
||||||
|
template <typename T>
|
||||||
|
using Result = std::expected<T, std::string>;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Common function to get cache path
|
// Common function to get cache path
|
||||||
|
@ -18,7 +22,7 @@ namespace {
|
||||||
fs::path cachePath = fs::temp_directory_path(errc);
|
fs::path cachePath = fs::temp_directory_path(errc);
|
||||||
|
|
||||||
if (errc)
|
if (errc)
|
||||||
return Error("Failed to get temp directory: " + errc.message());
|
return std::unexpected("Failed to get temp directory: "s + errc.message());
|
||||||
|
|
||||||
cachePath /= "weather_cache.json";
|
cachePath /= "weather_cache.json";
|
||||||
return cachePath;
|
return cachePath;
|
||||||
|
@ -28,91 +32,94 @@ namespace {
|
||||||
fn ReadCacheFromFile() -> Result<WeatherOutput> {
|
fn ReadCacheFromFile() -> Result<WeatherOutput> {
|
||||||
Result<fs::path> cachePath = GetCachePath();
|
Result<fs::path> cachePath = GetCachePath();
|
||||||
if (!cachePath)
|
if (!cachePath)
|
||||||
return Error(cachePath.error()->what());
|
return std::unexpected(cachePath.error());
|
||||||
|
|
||||||
std::ifstream ifs(*cachePath, std::ios::binary);
|
std::ifstream ifs(*cachePath, std::ios::binary);
|
||||||
if (!ifs.is_open())
|
if (!ifs.is_open())
|
||||||
return Error("Cache file not found: " + cachePath.value().string());
|
return std::unexpected("Cache file not found: "s + cachePath->string());
|
||||||
|
|
||||||
DEBUG_LOG("Reading from cache file...");
|
DEBUG_LOG("Reading from cache file...");
|
||||||
|
|
||||||
std::string content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
std::string content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
Result<WeatherOutput> result = rfl::json::read<WeatherOutput>(content);
|
rfl::Result<WeatherOutput> result = rfl::json::read<WeatherOutput>(content);
|
||||||
|
if (!result)
|
||||||
|
return std::unexpected(result.error()->what());
|
||||||
|
|
||||||
DEBUG_LOG("Successfully read from cache file.");
|
DEBUG_LOG("Successfully read from cache file.");
|
||||||
return result;
|
return *result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to write cache to file
|
// Function to write cache to file
|
||||||
fn WriteCacheToFile(const WeatherOutput& data) -> Result<u8> {
|
fn WriteCacheToFile(const WeatherOutput& data) -> Result<void> {
|
||||||
Result<fs::path> cachePath = GetCachePath();
|
Result<fs::path> cachePath = GetCachePath();
|
||||||
if (!cachePath)
|
if (!cachePath)
|
||||||
return Error(cachePath.error()->what());
|
return std::unexpected(cachePath.error());
|
||||||
|
|
||||||
DEBUG_LOG("Writing to cache file...");
|
DEBUG_LOG("Writing to cache file...");
|
||||||
|
|
||||||
// Write to temporary file first
|
|
||||||
fs::path tempPath = *cachePath;
|
fs::path tempPath = *cachePath;
|
||||||
tempPath += ".tmp";
|
tempPath += ".tmp";
|
||||||
|
|
||||||
{
|
{
|
||||||
std::ofstream ofs(tempPath, std::ios::binary | std::ios::trunc);
|
std::ofstream ofs(tempPath, std::ios::binary | std::ios::trunc);
|
||||||
if (!ofs.is_open())
|
if (!ofs.is_open())
|
||||||
return Error("Failed to open temp file: " + tempPath.string());
|
return std::unexpected("Failed to open temp file: "s + tempPath.string());
|
||||||
|
|
||||||
auto json = rfl::json::write(data);
|
std::string json = rfl::json::write(data);
|
||||||
ofs << json;
|
ofs << json;
|
||||||
|
|
||||||
if (!ofs)
|
if (!ofs)
|
||||||
return Error("Failed to write to temp file");
|
return std::unexpected("Failed to write to temp file");
|
||||||
} // File stream closes here
|
}
|
||||||
|
|
||||||
// Atomic replace
|
|
||||||
std::error_code errc;
|
std::error_code errc;
|
||||||
fs::rename(tempPath, *cachePath, errc);
|
fs::rename(tempPath, *cachePath, errc);
|
||||||
|
|
||||||
if (errc) {
|
if (errc) {
|
||||||
fs::remove(tempPath, errc);
|
fs::remove(tempPath, errc);
|
||||||
return Error("Failed to replace cache file: " + errc.message());
|
return std::unexpected("Failed to replace cache file: "s + errc.message());
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG("Successfully wrote to cache file.");
|
DEBUG_LOG("Successfully wrote to cache file.");
|
||||||
return 0;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn WriteCallback(void* contents, const usize size, const usize nmemb, string* str) -> usize {
|
fn WriteCallback(void* contents, size_t size, size_t nmemb, std::string* str) -> size_t {
|
||||||
const usize totalSize = size * nmemb;
|
const size_t totalSize = size * nmemb;
|
||||||
str->append(static_cast<char*>(contents), totalSize);
|
str->append(static_cast<char*>(contents), totalSize);
|
||||||
return totalSize;
|
return totalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to make API request
|
// Function to make API request
|
||||||
fn MakeApiRequest(const string& url) -> Result<WeatherOutput> {
|
fn MakeApiRequest(const std::string& url) -> Result<WeatherOutput> {
|
||||||
DEBUG_LOG("Making API request to URL: {}", url);
|
DEBUG_LOG("Making API request to URL: {}", url);
|
||||||
|
|
||||||
CURL* curl = curl_easy_init();
|
CURL* curl = curl_easy_init();
|
||||||
string responseBuffer;
|
std::string responseBuffer;
|
||||||
|
|
||||||
|
if (!curl)
|
||||||
|
return std::unexpected("Failed to initialize cURL");
|
||||||
|
|
||||||
if (curl) {
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBuffer);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBuffer);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 5);
|
||||||
|
|
||||||
const CURLcode res = curl_easy_perform(curl);
|
const CURLcode res = curl_easy_perform(curl);
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
if (res != CURLE_OK)
|
if (res != CURLE_OK)
|
||||||
return Error(fmt::format("Failed to perform cURL request: {}", curl_easy_strerror(res)));
|
return std::unexpected(fmt::format("cURL error: {}", curl_easy_strerror(res)));
|
||||||
|
|
||||||
DEBUG_LOG("Received response from API. Response size: {}", responseBuffer.size());
|
DEBUG_LOG("API response size: {}", responseBuffer.size());
|
||||||
DEBUG_LOG("Response: {}", responseBuffer);
|
|
||||||
|
|
||||||
WeatherOutput output = rfl::json::read<WeatherOutput>(responseBuffer).value();
|
rfl::Result<WeatherOutput> output = rfl::json::read<WeatherOutput>(responseBuffer);
|
||||||
|
if (!output)
|
||||||
|
return std::unexpected(output.error()->what());
|
||||||
|
|
||||||
return output; // Return an empty result for now
|
return *output;
|
||||||
}
|
|
||||||
|
|
||||||
return Error("Failed to initialize cURL.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,60 +127,48 @@ namespace {
|
||||||
fn Weather::getWeatherInfo() const -> WeatherOutput {
|
fn Weather::getWeatherInfo() const -> WeatherOutput {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
// Check if cache is valid
|
|
||||||
if (Result<WeatherOutput> data = ReadCacheFromFile()) {
|
if (Result<WeatherOutput> data = ReadCacheFromFile()) {
|
||||||
WeatherOutput dataVal = *data;
|
const WeatherOutput& dataVal = *data;
|
||||||
|
const duration<double> cacheAge = system_clock::now() - system_clock::time_point(seconds(dataVal.dt));
|
||||||
if (system_clock::now() - system_clock::time_point(seconds(dataVal.dt)) < minutes(10)) {
|
|
||||||
DEBUG_LOG("Cache is valid. Returning cached data.");
|
|
||||||
|
|
||||||
|
if (cacheAge < 10min) {
|
||||||
|
DEBUG_LOG("Using valid cache");
|
||||||
return dataVal;
|
return dataVal;
|
||||||
}
|
}
|
||||||
|
DEBUG_LOG("Cache expired");
|
||||||
DEBUG_LOG("Cache is expired.");
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG_LOG("No valid cache found.");
|
DEBUG_LOG("Cache error: {}", data.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
WeatherOutput result;
|
fn handleApiResult = [](const Result<WeatherOutput>& result) -> WeatherOutput {
|
||||||
|
if (!result)
|
||||||
|
ERROR_LOG("API request failed: {}", result.error());
|
||||||
|
|
||||||
if (holds_alternative<string>(location)) {
|
// Fix for second warning: Check the write result
|
||||||
const string city = get<string>(location);
|
if (Result<void> writeResult = WriteCacheToFile(*result); !writeResult)
|
||||||
|
ERROR_LOG("Failed to write cache: {}", writeResult.error());
|
||||||
|
|
||||||
const char* loc = curl_easy_escape(nullptr, city.c_str(), static_cast<int>(city.length()));
|
return *result;
|
||||||
|
};
|
||||||
|
|
||||||
DEBUG_LOG("City: {}", loc);
|
if (std::holds_alternative<std::string>(location)) {
|
||||||
|
const auto& city = std::get<std::string>(location);
|
||||||
|
char* escaped = curl_easy_escape(nullptr, city.c_str(), static_cast<int>(city.length()));
|
||||||
|
|
||||||
const string apiUrl = fmt::format(
|
DEBUG_LOG("Requesting city: {}", escaped);
|
||||||
"https://api.openweathermap.org/data/2.5/"
|
const std::string apiUrl =
|
||||||
"weather?q={}&appid={}&units={}",
|
fmt::format("https://api.openweathermap.org/data/2.5/weather?q={}&appid={}&units={}", escaped, api_key, units);
|
||||||
loc,
|
|
||||||
api_key,
|
curl_free(escaped);
|
||||||
units
|
return handleApiResult(MakeApiRequest(apiUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& [lat, lon] = std::get<Coords>(location);
|
||||||
|
DEBUG_LOG("Requesting coordinates: lat={:.3f}, lon={:.3f}", lat, lon);
|
||||||
|
|
||||||
|
const std::string apiUrl = fmt::format(
|
||||||
|
"https://api.openweathermap.org/data/2.5/weather?lat={:.3f}&lon={:.3f}&appid={}&units={}", lat, lon, api_key, units
|
||||||
);
|
);
|
||||||
|
|
||||||
result = MakeApiRequest(apiUrl).value();
|
return handleApiResult(MakeApiRequest(apiUrl));
|
||||||
} else {
|
|
||||||
const auto [lat, lon] = get<Coords>(location);
|
|
||||||
|
|
||||||
DEBUG_LOG("Coordinates: lat = {:.3f}, lon = {:.3f}", lat, lon);
|
|
||||||
|
|
||||||
const string apiUrl = fmt::format(
|
|
||||||
"https://api.openweathermap.org/data/2.5/"
|
|
||||||
"weather?lat={:.3f}&lon={:.3f}&appid={}&units={}",
|
|
||||||
lat,
|
|
||||||
lon,
|
|
||||||
api_key,
|
|
||||||
units
|
|
||||||
);
|
|
||||||
|
|
||||||
result = MakeApiRequest(apiUrl).value();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the cache with the new data
|
|
||||||
WriteCacheToFile(result);
|
|
||||||
|
|
||||||
DEBUG_LOG("Returning new data.");
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
24
src/main.cpp
24
src/main.cpp
|
@ -10,6 +10,8 @@
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "os/os.h"
|
#include "os/os.h"
|
||||||
|
|
||||||
|
constexpr const bool SHOW_ICONS = true;
|
||||||
|
|
||||||
struct BytesToGiB {
|
struct BytesToGiB {
|
||||||
u64 value;
|
u64 value;
|
||||||
};
|
};
|
||||||
|
@ -83,14 +85,19 @@ namespace {
|
||||||
const bool nowPlayingEnabled = config.now_playing.get().enabled;
|
const bool nowPlayingEnabled = config.now_playing.get().enabled;
|
||||||
const std::string& nowPlaying = nowPlayingEnabled ? GetNowPlaying() : "";
|
const std::string& nowPlaying = nowPlayingEnabled ? GetNowPlaying() : "";
|
||||||
|
|
||||||
// Icon constants (using Nerd Font v3)
|
const char *calendarIcon = "", *hostIcon = "", *kernelIcon = "", *osIcon = "", *memoryIcon = "", *weatherIcon = "",
|
||||||
constexpr const char* calendarIcon = " ";
|
*musicIcon = "";
|
||||||
constexpr const char* hostIcon = " ";
|
|
||||||
constexpr const char* kernelIcon = " ";
|
if (SHOW_ICONS) {
|
||||||
constexpr const char* osIcon = " ";
|
calendarIcon = " ";
|
||||||
constexpr const char* memoryIcon = " ";
|
hostIcon = " ";
|
||||||
constexpr const char* weatherIcon = " ";
|
kernelIcon = " ";
|
||||||
constexpr const char* musicIcon = " ";
|
osIcon = " ";
|
||||||
|
memoryIcon = " ";
|
||||||
|
weatherIcon = " ";
|
||||||
|
musicIcon = " ";
|
||||||
|
}
|
||||||
|
|
||||||
const Color::Palette16 labelColor = Color::Yellow;
|
const Color::Palette16 labelColor = Color::Yellow;
|
||||||
const Color::Palette16 valueColor = Color::White;
|
const Color::Palette16 valueColor = Color::White;
|
||||||
const Color::Palette16 borderColor = Color::GrayLight;
|
const Color::Palette16 borderColor = Color::GrayLight;
|
||||||
|
@ -111,7 +118,6 @@ namespace {
|
||||||
return hbox({
|
return hbox({
|
||||||
text(icon) | color(iconColor),
|
text(icon) | color(iconColor),
|
||||||
text(label) | color(labelColor),
|
text(label) | color(labelColor),
|
||||||
text(" "),
|
|
||||||
filler(),
|
filler(),
|
||||||
text(value) | color(valueColor),
|
text(value) | color(valueColor),
|
||||||
text(" "),
|
text(" "),
|
||||||
|
|
108
src/os/linux.cpp
108
src/os/linux.cpp
|
@ -1,5 +1,6 @@
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
|
||||||
|
#include <SQLiteCpp/SQLiteCpp.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -9,6 +10,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <sdbus-c++/sdbus-c++.h>
|
#include <sdbus-c++/sdbus-c++.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -51,9 +53,8 @@ namespace {
|
||||||
|
|
||||||
// Find the end of the numeric part
|
// Find the end of the numeric part
|
||||||
const size_t end = view.find_first_not_of("0123456789");
|
const size_t end = view.find_first_not_of("0123456789");
|
||||||
if (end != std::string_view::npos) {
|
if (end != std::string_view::npos)
|
||||||
view = view.substr(0, end);
|
view = view.substr(0, end);
|
||||||
}
|
|
||||||
|
|
||||||
// Get pointers via iterators
|
// Get pointers via iterators
|
||||||
const char* startPtr = &*view.begin(); // Safe iterator-to-pointer conversion
|
const char* startPtr = &*view.begin(); // Safe iterator-to-pointer conversion
|
||||||
|
@ -346,14 +347,81 @@ namespace {
|
||||||
std::ifstream cmdline("/proc/self/environ");
|
std::ifstream cmdline("/proc/self/environ");
|
||||||
std::string envVars((std::istreambuf_iterator<char>(cmdline)), std::istreambuf_iterator<char>());
|
std::string envVars((std::istreambuf_iterator<char>(cmdline)), std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
for (const auto& [process, deName] : processChecks) {
|
for (const auto& [process, deName] : processChecks)
|
||||||
if (envVars.find(process) != std::string::npos)
|
if (envVars.find(process) != std::string::npos)
|
||||||
return deName;
|
return deName;
|
||||||
}
|
|
||||||
|
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn CountNix() noexcept -> std::optional<size_t> {
|
||||||
|
constexpr std::string_view dbPath = "/nix/var/nix/db/db.sqlite";
|
||||||
|
constexpr std::string_view querySql = "SELECT COUNT(*) FROM ValidPaths WHERE sigs IS NOT NULL;";
|
||||||
|
|
||||||
|
sqlite3* sqlDB = nullptr;
|
||||||
|
sqlite3_stmt* stmt = nullptr;
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
// 1. Direct URI construction without string concatenation
|
||||||
|
const std::string uri =
|
||||||
|
fmt::format("file:{}{}immutable=1", dbPath, (dbPath.find('?') != std::string_view::npos) ? "&" : "?");
|
||||||
|
|
||||||
|
// 2. Open database with optimized flags
|
||||||
|
if (sqlite3_open_v2(uri.c_str(), &sqlDB, SQLITE_OPEN_READONLY | SQLITE_OPEN_URI | SQLITE_OPEN_NOMUTEX, nullptr) !=
|
||||||
|
SQLITE_OK) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Configure database for maximum read performance
|
||||||
|
sqlite3_exec(sqlDB, "PRAGMA journal_mode=OFF; PRAGMA mmap_size=268435456;", nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
|
// 4. Single-step prepared statement execution
|
||||||
|
if (sqlite3_prepare_v3(sqlDB, querySql.data(), querySql.size(), SQLITE_PREPARE_PERSISTENT, &stmt, nullptr) ==
|
||||||
|
SQLITE_OK) {
|
||||||
|
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||||
|
count = static_cast<size_t>(sqlite3_column_int64(stmt, 0));
|
||||||
|
}
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_close(sqlDB);
|
||||||
|
return count ? std::optional { count } : std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn CountNixWithCache() noexcept -> std::optional<size_t> {
|
||||||
|
constexpr std::string_view dbPath = "/nix/var/nix/db/db.sqlite";
|
||||||
|
constexpr std::string_view cachePath = "/tmp/nix_pkg_count.cache";
|
||||||
|
|
||||||
|
// 1. Check cache validity atomically
|
||||||
|
try {
|
||||||
|
const auto dbMtime = std::filesystem::last_write_time(dbPath);
|
||||||
|
const auto cacheMtime = std::filesystem::last_write_time(cachePath);
|
||||||
|
|
||||||
|
if (std::filesystem::exists(cachePath) && dbMtime <= cacheMtime) {
|
||||||
|
// Read cached value (atomic read)
|
||||||
|
std::ifstream cache(cachePath.data(), std::ios::binary);
|
||||||
|
size_t count = 0;
|
||||||
|
cache.read(std::bit_cast<char*>(&count), sizeof(count));
|
||||||
|
return cache ? std::optional(count) : std::nullopt;
|
||||||
|
}
|
||||||
|
} catch (...) {} // Ignore errors, fall through to rebuild cache
|
||||||
|
|
||||||
|
// 2. Compute fresh value
|
||||||
|
const auto count = CountNix(); // Original optimized function
|
||||||
|
|
||||||
|
// 3. Update cache atomically (write+rename pattern)
|
||||||
|
if (count) {
|
||||||
|
constexpr std::string_view tmpPath = "/tmp/nix_pkg_count.tmp";
|
||||||
|
{
|
||||||
|
std::ofstream tmp(tmpPath.data(), std::ios::binary | std::ios::trunc);
|
||||||
|
tmp.write(std::bit_cast<const char*>(&*count), sizeof(*count));
|
||||||
|
} // RAII close
|
||||||
|
|
||||||
|
std::filesystem::rename(tmpPath, cachePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn GetOSVersion() -> std::string {
|
fn GetOSVersion() -> std::string {
|
||||||
|
@ -414,10 +482,33 @@ fn GetNowPlaying() -> string {
|
||||||
const std::map<std::basic_string<char>, sdbus::Variant>& metadata =
|
const std::map<std::basic_string<char>, sdbus::Variant>& metadata =
|
||||||
metadataVariant.get<std::map<std::string, sdbus::Variant>>();
|
metadataVariant.get<std::map<std::string, sdbus::Variant>>();
|
||||||
|
|
||||||
auto iter = metadata.find("xesam:title");
|
std::string title;
|
||||||
|
auto titleIter = metadata.find("xesam:title");
|
||||||
|
if (titleIter != metadata.end() && titleIter->second.containsValueOfType<std::string>()) {
|
||||||
|
title = titleIter->second.get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
if (iter != metadata.end() && iter->second.containsValueOfType<std::string>())
|
std::string artist;
|
||||||
return iter->second.get<std::string>();
|
auto artistIter = metadata.find("xesam:artist");
|
||||||
|
if (artistIter != metadata.end() && artistIter->second.containsValueOfType<std::vector<std::string>>()) {
|
||||||
|
auto artists = artistIter->second.get<std::vector<std::string>>();
|
||||||
|
if (!artists.empty()) {
|
||||||
|
artist = artists[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
if (!artist.empty() && !title.empty()) {
|
||||||
|
result = artist + " - " + title;
|
||||||
|
} else if (!title.empty()) {
|
||||||
|
result = title;
|
||||||
|
} else if (!artist.empty()) {
|
||||||
|
result = artist;
|
||||||
|
} else {
|
||||||
|
result = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
} catch (const sdbus::Error& e) {
|
} catch (const sdbus::Error& e) {
|
||||||
if (e.getName() != "com.github.altdesktop.playerctld.NoActivePlayer") {
|
if (e.getName() != "com.github.altdesktop.playerctld.NoActivePlayer") {
|
||||||
|
@ -430,7 +521,6 @@ fn GetNowPlaying() -> string {
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn GetWindowManager() -> string {
|
fn GetWindowManager() -> string {
|
||||||
// Check environment variables first
|
// Check environment variables first
|
||||||
const char* xdgSessionType = std::getenv("XDG_SESSION_TYPE");
|
const char* xdgSessionType = std::getenv("XDG_SESSION_TYPE");
|
||||||
|
@ -505,6 +595,8 @@ fn GetKernelVersion() -> string {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUG_LOG("{}", CountNixWithCache().value_or(0));
|
||||||
|
|
||||||
return static_cast<const char*>(uts.release);
|
return static_cast<const char*>(uts.release);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,218 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <utility>
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
#include "macros.h"
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class Error
|
|
||||||
* @brief Represents an error with a message.
|
|
||||||
*
|
|
||||||
* This class is used to encapsulate error messages that can be returned from functions.
|
|
||||||
*/
|
|
||||||
class Error {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Constructs an Error with a message.
|
|
||||||
* @param message The error message.
|
|
||||||
*/
|
|
||||||
explicit Error(string message) : m_Message(std::move(message)) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Retrieves the error message.
|
|
||||||
* @return A constant reference to the error message string.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] fn message() const -> const string& { return m_Message; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
string m_Message; ///< The error message.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Primary template for Result with a default type of void
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class Result
|
|
||||||
* @brief Represents a result that can either be a value or an error.
|
|
||||||
*
|
|
||||||
* This is the primary template for Result, which defaults to handling void results.
|
|
||||||
*/
|
|
||||||
template <typename T = void>
|
|
||||||
class Result;
|
|
||||||
|
|
||||||
// Specialization for Result<void>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class Result<void>
|
|
||||||
* @brief Specialization of Result for handling void results.
|
|
||||||
*
|
|
||||||
* This class is used when a function either succeeds with no value or fails with an error.
|
|
||||||
*/
|
|
||||||
template <>
|
|
||||||
class Result<void> {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Constructs a successful Result.
|
|
||||||
*/
|
|
||||||
Result() : m_Result(std::monostate {}) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Constructs an error Result.
|
|
||||||
* @param error The error object.
|
|
||||||
*/
|
|
||||||
Result(const Error& error) : m_Result(error) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Constructs an error Result.
|
|
||||||
* @param error An rvalue reference to the error object.
|
|
||||||
*/
|
|
||||||
Result(Error&& error) : m_Result(std::move(error)) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if the Result is successful.
|
|
||||||
* @return True if the Result is successful, otherwise false.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] fn isOk() const -> bool { return std::holds_alternative<std::monostate>(m_Result); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if the Result contains an error.
|
|
||||||
* @return True if the Result contains an error, otherwise false.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] fn isErr() const -> bool { return std::holds_alternative<Error>(m_Result); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Throws an exception if the Result contains an error.
|
|
||||||
*
|
|
||||||
* This function should be called only if the Result is successful.
|
|
||||||
*/
|
|
||||||
void value() const {
|
|
||||||
if (isErr()) {
|
|
||||||
throw std::logic_error("Attempted to access value of an error Result");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Retrieves the error object.
|
|
||||||
* @return A constant reference to the Error object.
|
|
||||||
* @throws std::logic_error if the Result is successful.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] fn error() const -> const Error& {
|
|
||||||
if (isOk()) {
|
|
||||||
throw std::logic_error("Attempted to access error of an ok Result");
|
|
||||||
}
|
|
||||||
return std::get<Error>(m_Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::variant<std::monostate, Error>
|
|
||||||
m_Result; ///< The underlying result, which can be either void or an Error.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Primary template for Result
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class Result
|
|
||||||
* @brief Represents a result that can either be a value of type T or an error.
|
|
||||||
*
|
|
||||||
* This template class is used to handle results that can either be a successful value or an error.
|
|
||||||
* @tparam T The type of the successful value.
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
class Result {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Constructs a successful Result with a value.
|
|
||||||
* @param value The value of the Result.
|
|
||||||
*/
|
|
||||||
Result(const T& value) : m_Result(value) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Constructs a successful Result with a value.
|
|
||||||
* @param value An rvalue reference to the value.
|
|
||||||
*/
|
|
||||||
Result(T&& value) : m_Result(std::move(value)) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Constructs an error Result.
|
|
||||||
* @param error The error object.
|
|
||||||
*/
|
|
||||||
Result(const Error& error) : m_Result(error) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Constructs an error Result.
|
|
||||||
* @param error An rvalue reference to the error object.
|
|
||||||
*/
|
|
||||||
Result(Error&& error) : m_Result(std::move(error)) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if the Result is successful.
|
|
||||||
* @return True if the Result is successful, otherwise false.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] fn isOk() const -> bool { return std::holds_alternative<T>(m_Result); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if the Result contains an error.
|
|
||||||
* @return True if the Result contains an error, otherwise false.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] fn isErr() const -> bool { return std::holds_alternative<Error>(m_Result); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Retrieves the value.
|
|
||||||
* @return A constant reference to the value.
|
|
||||||
* @throws std::logic_error if the Result contains an error.
|
|
||||||
*/
|
|
||||||
fn value() const -> const T& {
|
|
||||||
if (isErr()) {
|
|
||||||
throw std::logic_error("Attempted to access value of an error Result");
|
|
||||||
}
|
|
||||||
return std::get<T>(m_Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Retrieves the error object.
|
|
||||||
* @return A constant reference to the Error object.
|
|
||||||
* @throws std::logic_error if the Result is successful.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] fn error() const -> const Error& {
|
|
||||||
if (isOk()) {
|
|
||||||
throw std::logic_error("Attempted to access error of an ok Result");
|
|
||||||
}
|
|
||||||
return std::get<Error>(m_Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Retrieves the value or returns a default value.
|
|
||||||
* @param defaultValue The default value to return if the Result contains an error.
|
|
||||||
* @return The value if the Result is successful, otherwise the default value.
|
|
||||||
*/
|
|
||||||
fn valueOr(const T& defaultValue) const -> T {
|
|
||||||
return isOk() ? std::get<T>(m_Result) : defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::variant<T, Error>
|
|
||||||
m_Result; ///< The underlying result, which can be either a value of type T or an Error.
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Helper function to create a successful Result.
|
|
||||||
*
|
|
||||||
* This function deduces the type of the value and creates a successful Result.
|
|
||||||
* @tparam T The type of the value.
|
|
||||||
* @param value The value to be stored in the Result.
|
|
||||||
* @return A Result object containing the value.
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
fn Ok(T&& value) {
|
|
||||||
return Result<std::decay_t<T>>(std::forward<T>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Helper function to create a successful Result<void>.
|
|
||||||
*
|
|
||||||
* This function creates a successful Result that does not contain a value.
|
|
||||||
* @return A Result<void> object indicating success.
|
|
||||||
*/
|
|
||||||
inline fn Ok() -> Result<void> { return {}; }
|
|
Loading…
Reference in a new issue