#include "system_data.hpp" #include // std::chrono::system_clock #include // localtime_r/s, strftime, time_t, tm #include // std::format #include // std::{async, launch} #include "src/config/config.hpp" #include "src/config/weather.hpp" #include "src/core/package.hpp" #include "src/os/os.hpp" #include "src/util/defs.hpp" #include "src/util/error.hpp" #include "src/util/types.hpp" using util::error::DracError, util::error::DracErrorCode; namespace { using util::types::i32, util::types::CStr; fn getOrdinalSuffix(const i32 day) -> CStr { if (day >= 11 && day <= 13) return "th"; switch (day % 10) { case 1: return "st"; case 2: return "nd"; case 3: return "rd"; default: return "th"; } } fn getDate() -> Result { using std::chrono::system_clock; using util::types::String, util::types::usize, util::types::Err; const system_clock::time_point nowTp = system_clock::now(); const std::time_t nowTt = system_clock::to_time_t(nowTp); std::tm nowTm; #ifdef _WIN32 if (localtime_s(&nowTm, &nowTt) == 0) { #else if (localtime_r(&nowTt, &nowTm) != nullptr) { #endif i32 day = nowTm.tm_mday; String monthBuffer(32, '\0'); if (const usize monthLen = std::strftime(monthBuffer.data(), monthBuffer.size(), "%B", &nowTm); monthLen > 0) { monthBuffer.resize(monthLen); CStr suffix = getOrdinalSuffix(day); try { return std::format("{} {}{}", monthBuffer, day, suffix); } catch (const std::format_error& e) { return Err(DracError(DracErrorCode::ParseError, e.what())); } } return Err(DracError(DracErrorCode::ParseError, "Failed to format date")); } return Err(DracError(DracErrorCode::ParseError, "Failed to get local time")); } } // namespace namespace os { SystemData::SystemData(const Config& config) { using enum std::launch; using util::types::Future, util::types::Err; using weather::Output; Future> hostFut = std::async(async, GetHost); Future> kernelFut = std::async(async, GetKernelVersion); Future> osFut = std::async(async, GetOSVersion); Future> memFut = std::async(async, GetMemInfo); Future> deFut = std::async(async, GetDesktopEnvironment); Future> wmFut = std::async(async, GetWindowManager); Future> diskFut = std::async(async, GetDiskUsage); Future> shellFut = std::async(async, GetShell); Future> pkgFut = std::async(async, package::GetTotalCount); Future> npFut = std::async(config.nowPlaying.enabled ? async : deferred, GetNowPlaying); Future> wthrFut = std::async(config.weather.enabled ? async : deferred, [&config] { return config.weather.getWeatherInfo(); }); this->date = getDate(); this->host = hostFut.get(); this->kernelVersion = kernelFut.get(); this->osVersion = osFut.get(); this->memInfo = memFut.get(); this->desktopEnv = deFut.get(); this->windowMgr = wmFut.get(); this->diskUsage = diskFut.get(); this->shell = shellFut.get(); this->packageCount = pkgFut.get(); this->weather = config.weather.enabled ? wthrFut.get() : Err(DracError(DracErrorCode::ApiUnavailable, "Weather API disabled")); this->nowPlaying = config.nowPlaying.enabled ? npFut.get() : Err(DracError(DracErrorCode::ApiUnavailable, "Now Playing API disabled")); } } // namespace os