stuffs
This commit is contained in:
parent
94a69518b1
commit
bd8c149945
|
@ -139,6 +139,7 @@
|
||||||
clang-tools_19
|
clang-tools_19
|
||||||
cmake
|
cmake
|
||||||
lldb
|
lldb
|
||||||
|
hyperfine
|
||||||
meson
|
meson
|
||||||
ninja
|
ninja
|
||||||
nvfetcher
|
nvfetcher
|
||||||
|
|
|
@ -2,7 +2,7 @@ project(
|
||||||
'draconis++', 'cpp',
|
'draconis++', 'cpp',
|
||||||
version: '0.1.0',
|
version: '0.1.0',
|
||||||
default_options: [
|
default_options: [
|
||||||
'cpp_std=c++20',
|
'cpp_std=c++26',
|
||||||
'default_library=static',
|
'default_library=static',
|
||||||
'warning_level=everything',
|
'warning_level=everything',
|
||||||
'buildtype=debugoptimized'
|
'buildtype=debugoptimized'
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
#include <filesystem>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <rfl/json.hpp>
|
#include <rfl/json.hpp>
|
||||||
#include <rfl/json/load.hpp>
|
#include <rfl/json/load.hpp>
|
||||||
|
@ -8,64 +9,87 @@
|
||||||
|
|
||||||
using rfl::Error;
|
using rfl::Error;
|
||||||
using rfl::Result;
|
using rfl::Result;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
// Function to read cache from file
|
namespace {
|
||||||
fn ReadCacheFromFile() -> Result<WeatherOutput> {
|
// Common function to get cache path
|
||||||
#ifdef __WIN32__
|
fn GetCachePath() -> Result<fs::path> {
|
||||||
const char* tempPath = getenv("TEMP");
|
std::error_code errc;
|
||||||
const string path = string(tempPath) + "\\weather_cache.json";
|
fs::path cachePath = fs::temp_directory_path(errc);
|
||||||
std::ifstream ifs(path);
|
|
||||||
#else
|
|
||||||
std::ifstream ifs("/tmp/weather_cache.json");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
if (errc)
|
||||||
|
return Error("Failed to get temp directory: " + errc.message());
|
||||||
|
|
||||||
|
cachePath /= "weather_cache.json";
|
||||||
|
return cachePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to read cache from file
|
||||||
|
fn ReadCacheFromFile() -> Result<WeatherOutput> {
|
||||||
|
Result<fs::path> cachePath = GetCachePath();
|
||||||
|
if (!cachePath)
|
||||||
|
return Error(cachePath.error()->what());
|
||||||
|
|
||||||
|
std::ifstream ifs(*cachePath, std::ios::binary);
|
||||||
if (!ifs.is_open())
|
if (!ifs.is_open())
|
||||||
return Error("Cache file not found.");
|
return Error("Cache file not found: " + cachePath.value().string());
|
||||||
|
|
||||||
fmt::println("Reading from cache file...");
|
DEBUG_LOG("Reading from cache file...");
|
||||||
|
|
||||||
std::stringstream buf;
|
std::string content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
buf << ifs.rdbuf();
|
Result<WeatherOutput> result = rfl::json::read<WeatherOutput>(content);
|
||||||
|
|
||||||
Result<WeatherOutput> val = rfl::json::read<WeatherOutput>(buf.str());
|
DEBUG_LOG("Successfully read from cache file.");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
fmt::println("Successfully read from cache file.");
|
// Function to write cache to file
|
||||||
|
fn WriteCacheToFile(const WeatherOutput& data) -> Result<u8> {
|
||||||
|
Result<fs::path> cachePath = GetCachePath();
|
||||||
|
if (!cachePath)
|
||||||
|
return Error(cachePath.error()->what());
|
||||||
|
|
||||||
return val;
|
DEBUG_LOG("Writing to cache file...");
|
||||||
}
|
|
||||||
|
|
||||||
// Function to write cache to file
|
// Write to temporary file first
|
||||||
fn WriteCacheToFile(const WeatherOutput& data) -> Result<u8> {
|
fs::path tempPath = *cachePath;
|
||||||
fmt::println("Writing to cache file...");
|
tempPath += ".tmp";
|
||||||
|
|
||||||
#ifdef __WIN32__
|
|
||||||
const char* tempPath = getenv("TEMP");
|
|
||||||
const string path = string(tempPath) + "\\weather_cache.json";
|
|
||||||
std::ofstream ofs(path);
|
|
||||||
#else
|
|
||||||
std::ofstream ofs("/tmp/weather_cache.json");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
{
|
||||||
|
std::ofstream ofs(tempPath, std::ios::binary | std::ios::trunc);
|
||||||
if (!ofs.is_open())
|
if (!ofs.is_open())
|
||||||
return Error("Failed to open cache file for writing.");
|
return Error("Failed to open temp file: " + tempPath.string());
|
||||||
|
|
||||||
ofs << rfl::json::write(data);
|
auto json = rfl::json::write(data);
|
||||||
|
ofs << json;
|
||||||
|
|
||||||
fmt::println("Successfully wrote to cache file.");
|
if (!ofs)
|
||||||
|
return Error("Failed to write to temp file");
|
||||||
|
} // File stream closes here
|
||||||
|
|
||||||
|
// Atomic replace
|
||||||
|
std::error_code errc;
|
||||||
|
fs::rename(tempPath, *cachePath, errc);
|
||||||
|
|
||||||
|
if (errc) {
|
||||||
|
fs::remove(tempPath, errc);
|
||||||
|
return Error("Failed to replace cache file: " + errc.message());
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_LOG("Successfully wrote to cache file.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn WriteCallback(void* contents, const usize size, const usize nmemb, string* str) -> usize {
|
fn WriteCallback(void* contents, const usize size, const usize nmemb, string* str) -> usize {
|
||||||
const usize totalSize = size * nmemb;
|
const usize 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 string& url) -> Result<WeatherOutput> {
|
||||||
fmt::println("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;
|
string responseBuffer;
|
||||||
|
@ -80,8 +104,8 @@ fn MakeApiRequest(const string& url) -> Result<WeatherOutput> {
|
||||||
if (res != CURLE_OK)
|
if (res != CURLE_OK)
|
||||||
return Error(fmt::format("Failed to perform cURL request: {}", curl_easy_strerror(res)));
|
return Error(fmt::format("Failed to perform cURL request: {}", curl_easy_strerror(res)));
|
||||||
|
|
||||||
fmt::println("Received response from API. Response size: {}", responseBuffer.size());
|
DEBUG_LOG("Received response from API. Response size: {}", responseBuffer.size());
|
||||||
fmt::println("Response: {}", responseBuffer);
|
DEBUG_LOG("Response: {}", responseBuffer);
|
||||||
|
|
||||||
WeatherOutput output = rfl::json::read<WeatherOutput>(responseBuffer).value();
|
WeatherOutput output = rfl::json::read<WeatherOutput>(responseBuffer).value();
|
||||||
|
|
||||||
|
@ -89,6 +113,7 @@ fn MakeApiRequest(const string& url) -> Result<WeatherOutput> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Error("Failed to initialize cURL.");
|
return Error("Failed to initialize cURL.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Core function to get weather information
|
// Core function to get weather information
|
||||||
|
@ -100,14 +125,14 @@ fn Weather::getWeatherInfo() const -> WeatherOutput {
|
||||||
WeatherOutput dataVal = *data;
|
WeatherOutput dataVal = *data;
|
||||||
|
|
||||||
if (system_clock::now() - system_clock::time_point(seconds(dataVal.dt)) < minutes(10)) {
|
if (system_clock::now() - system_clock::time_point(seconds(dataVal.dt)) < minutes(10)) {
|
||||||
fmt::println("Cache is valid. Returning cached data.");
|
DEBUG_LOG("Cache is valid. Returning cached data.");
|
||||||
|
|
||||||
return dataVal;
|
return dataVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt::println("Cache is expired.");
|
DEBUG_LOG("Cache is expired.");
|
||||||
} else {
|
} else {
|
||||||
fmt::println("No valid cache found.");
|
DEBUG_LOG("No valid cache found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
WeatherOutput result;
|
WeatherOutput result;
|
||||||
|
@ -117,7 +142,7 @@ fn Weather::getWeatherInfo() const -> WeatherOutput {
|
||||||
|
|
||||||
const char* loc = curl_easy_escape(nullptr, city.c_str(), static_cast<int>(city.length()));
|
const char* loc = curl_easy_escape(nullptr, city.c_str(), static_cast<int>(city.length()));
|
||||||
|
|
||||||
fmt::println("City: {}", loc);
|
DEBUG_LOG("City: {}", loc);
|
||||||
|
|
||||||
const string apiUrl = fmt::format(
|
const string apiUrl = fmt::format(
|
||||||
"https://api.openweathermap.org/data/2.5/"
|
"https://api.openweathermap.org/data/2.5/"
|
||||||
|
@ -131,7 +156,7 @@ fn Weather::getWeatherInfo() const -> WeatherOutput {
|
||||||
} else {
|
} else {
|
||||||
const auto [lat, lon] = get<Coords>(location);
|
const auto [lat, lon] = get<Coords>(location);
|
||||||
|
|
||||||
fmt::println("Coordinates: lat = {:.3f}, lon = {:.3f}", lat, lon);
|
DEBUG_LOG("Coordinates: lat = {:.3f}, lon = {:.3f}", lat, lon);
|
||||||
|
|
||||||
const string apiUrl = fmt::format(
|
const string apiUrl = fmt::format(
|
||||||
"https://api.openweathermap.org/data/2.5/"
|
"https://api.openweathermap.org/data/2.5/"
|
||||||
|
@ -148,7 +173,7 @@ fn Weather::getWeatherInfo() const -> WeatherOutput {
|
||||||
// Update the cache with the new data
|
// Update the cache with the new data
|
||||||
WriteCacheToFile(result);
|
WriteCacheToFile(result);
|
||||||
|
|
||||||
fmt::println("Returning new data.");
|
DEBUG_LOG("Returning new data.");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "../util/types.h"
|
#include "../util/types.h"
|
||||||
|
|
||||||
using degrees = rfl::Validator<u16, rfl::Minimum<0>, rfl::Maximum<360>>;
|
using degrees = rfl::Validator<u16, rfl::Minimum<0>, rfl::Maximum<360>>;
|
||||||
using percentage = rfl::Validator<i8, rfl::Minimum<0>, rfl::Maximum<100>>;
|
using percentage = rfl::Validator<u8, rfl::Minimum<0>, rfl::Maximum<100>>;
|
||||||
|
|
||||||
struct Condition {
|
struct Condition {
|
||||||
string description;
|
string description;
|
||||||
|
|
|
@ -29,7 +29,6 @@ struct fmt::formatter<BytesToGiB> : fmt::formatter<double> {
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
fn GetDate() -> std::string {
|
fn GetDate() -> std::string {
|
||||||
// Get current local time
|
// Get current local time
|
||||||
std::time_t now = std::time(nullptr);
|
std::time_t now = std::time(nullptr);
|
||||||
|
@ -97,8 +96,8 @@ namespace {
|
||||||
return hbox({ text(emoji),
|
return hbox({ text(emoji),
|
||||||
text(label) | color(labelColor),
|
text(label) | color(labelColor),
|
||||||
filler(),
|
filler(),
|
||||||
text(value),
|
text(value) | color(valueColor),
|
||||||
text(" ") | color(valueColor) });
|
text(" ") });
|
||||||
};
|
};
|
||||||
|
|
||||||
// System info rows
|
// System info rows
|
||||||
|
@ -142,6 +141,10 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
|
INFO_LOG("productFamily: {}", GetProductFamily());
|
||||||
|
WARN_LOG("productFamily: {}", GetProductFamily());
|
||||||
|
ERROR_LOG("productFamily: {}", GetProductFamily());
|
||||||
|
|
||||||
const Config& config = Config::getInstance();
|
const Config& config = Config::getInstance();
|
||||||
|
|
||||||
auto document = hbox({ SystemInfoBox(config), filler() });
|
auto document = hbox({ SystemInfoBox(config), filler() });
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sys/sysctl.h>
|
|
||||||
#include <sdbus-c++/sdbus-c++.h>
|
#include <sdbus-c++/sdbus-c++.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
fn GetMemInfo() -> u64 {
|
fn GetMemInfo() -> u64 {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
enum SessionType { Wayland, X11, TTY, Unknown };
|
enum SessionType : u8 { Wayland, X11, TTY, Unknown };
|
||||||
|
|
||||||
fn ParseLineAsNumber(const std::string& input) -> u64 {
|
fn ParseLineAsNumber(const std::string& input) -> u64 {
|
||||||
usize start = input.find_first_of("0123456789");
|
usize start = input.find_first_of("0123456789");
|
||||||
|
@ -132,4 +132,23 @@ fn GetNowPlaying() -> string {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn GetShell() -> string {
|
||||||
|
const char* shell = std::getenv("SHELL");
|
||||||
|
|
||||||
|
return shell ? shell : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
fn GetProductFamily() -> string {
|
||||||
|
std::ifstream file("/sys/class/dmi/id/product_family");
|
||||||
|
|
||||||
|
if (!file.is_open())
|
||||||
|
throw std::runtime_error("Failed to open /sys/class/dmi/id/product_family");
|
||||||
|
|
||||||
|
std::string productFamily;
|
||||||
|
|
||||||
|
std::getline(file, productFamily);
|
||||||
|
|
||||||
|
return productFamily;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
10
src/os/os.h
10
src/os/os.h
|
@ -27,3 +27,13 @@ fn GetDesktopEnvironment() -> string;
|
||||||
* @brief Get the current window manager.
|
* @brief Get the current window manager.
|
||||||
*/
|
*/
|
||||||
fn GetWindowManager() -> string;
|
fn GetWindowManager() -> string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the current shell.
|
||||||
|
*/
|
||||||
|
fn GetShell() -> string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the product family
|
||||||
|
*/
|
||||||
|
fn GetProductFamily() -> string;
|
||||||
|
|
|
@ -1,32 +1,96 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/**
|
#include <filesystem>
|
||||||
* @brief Allows for rust-style function definitions
|
#include <fmt/chrono.h>
|
||||||
*/
|
#include <fmt/color.h>
|
||||||
#define fn auto
|
#include <fmt/format.h>
|
||||||
|
#include <source_location>
|
||||||
|
|
||||||
/**
|
#include "types.h"
|
||||||
* @brief Allows for easy getter creation
|
|
||||||
*
|
|
||||||
* @param class_name The class to use
|
|
||||||
* @param type Type of the getter
|
|
||||||
* @param name Name of the getter
|
|
||||||
*/
|
|
||||||
#define DEFINE_GETTER(class_name, type, name) \
|
|
||||||
fn class_name::get##name() const->type { return m_##name; }
|
|
||||||
|
|
||||||
/**
|
#define fn auto // Rust-style function shorthand
|
||||||
* @brief Helper for making reflect-cpp impls
|
|
||||||
*
|
namespace log_colors {
|
||||||
* @param struct_name The struct name
|
using fmt::terminal_color;
|
||||||
* @param lower_name The arg name
|
constexpr fmt::terminal_color debug = terminal_color::cyan, info = terminal_color::green,
|
||||||
* @param ... Values of the class to convert
|
warn = terminal_color::yellow, error = terminal_color::red,
|
||||||
*/
|
timestamp = terminal_color::bright_white,
|
||||||
#define DEF_IMPL(struct_name, ...) \
|
file_info = terminal_color::bright_white;
|
||||||
struct struct_name##Impl { \
|
}
|
||||||
__VA_ARGS__; \
|
|
||||||
\
|
enum class LogLevel : u8 { DEBUG, INFO, WARN, ERROR };
|
||||||
static fn from_class(const struct_name& instance) noexcept -> struct_name##Impl; \
|
|
||||||
\
|
template <typename... Args>
|
||||||
[[nodiscard]] fn to_class() const -> struct_name; \
|
fn LogImpl(
|
||||||
};
|
LogLevel level,
|
||||||
|
const std::source_location& loc,
|
||||||
|
fmt::format_string<Args...> fmt,
|
||||||
|
Args&&... args
|
||||||
|
) -> void {
|
||||||
|
const time_t now = std::time(nullptr);
|
||||||
|
const auto [color, levelStr] = [&] {
|
||||||
|
switch (level) {
|
||||||
|
case LogLevel::DEBUG:
|
||||||
|
return std::make_pair(log_colors::debug, "DEBUG");
|
||||||
|
case LogLevel::INFO:
|
||||||
|
return std::make_pair(log_colors::info, "INFO ");
|
||||||
|
case LogLevel::WARN:
|
||||||
|
return std::make_pair(log_colors::warn, "WARN ");
|
||||||
|
case LogLevel::ERROR:
|
||||||
|
return std::make_pair(log_colors::error, "ERROR");
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
const std::string filename = std::filesystem::path(loc.file_name()).lexically_normal().string();
|
||||||
|
const u32 line = loc.line();
|
||||||
|
const struct tm time = *std::localtime(&now);
|
||||||
|
|
||||||
|
// Timestamp section
|
||||||
|
fmt::print(fg(log_colors::timestamp), "[{:%H:%M:%S}] ", time);
|
||||||
|
|
||||||
|
// Level section
|
||||||
|
fmt::print(fmt::emphasis::bold | fg(color), "{}", levelStr);
|
||||||
|
|
||||||
|
// Message section
|
||||||
|
fmt::print(" ");
|
||||||
|
fmt::print(fmt, std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
// File info section
|
||||||
|
#ifndef NDEBUG
|
||||||
|
fmt::print(fg(log_colors::file_info), "\n{:>14} ", "╰──");
|
||||||
|
const std::string fileInfo = fmt::format("{}:{}", filename.c_str(), line);
|
||||||
|
fmt::print(fmt::emphasis::italic | fg(log_colors::file_info), "{}", fileInfo);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fmt::print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logging utility wrapper to replace macros
|
||||||
|
// Logging utility wrapper to replace macros
|
||||||
|
template <LogLevel level>
|
||||||
|
struct LogWrapper {
|
||||||
|
std::source_location m_loc; // Changed to m_loc
|
||||||
|
|
||||||
|
constexpr LogWrapper(const std::source_location& loc = std::source_location::current())
|
||||||
|
: m_loc(loc) {} // Initialize member with parameter
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void operator()(fmt::format_string<Args...> fmt, Args&&... args) const {
|
||||||
|
LogImpl(level, m_loc, fmt, std::forward<Args>(args)...); // Use m_loc
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Debug logging is conditionally compiled
|
||||||
|
#ifdef NDEBUG
|
||||||
|
struct {
|
||||||
|
template <typename... Args>
|
||||||
|
void operator()(fmt::format_string<Args...>, Args&&...) const {}
|
||||||
|
} DEBUG_LOG;
|
||||||
|
#else
|
||||||
|
constexpr LogWrapper<LogLevel::DEBUG> DEBUG_LOG;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Define loggers for other levels
|
||||||
|
constexpr LogWrapper<LogLevel::INFO> INFO_LOG;
|
||||||
|
constexpr LogWrapper<LogLevel::WARN> WARN_LOG;
|
||||||
|
constexpr LogWrapper<LogLevel::ERROR> ERROR_LOG;
|
||||||
|
|
Loading…
Reference in a new issue