This commit is contained in:
Mars 2024-06-21 03:03:42 -04:00
parent 1926ef4a92
commit bedf45b831
Signed by: pupbrained
GPG key ID: 0FF5B8826803F895
5 changed files with 101 additions and 236 deletions

View file

@ -1,55 +1,8 @@
#include <util/macros.h>
#include "config.h" #include "config.h"
// -------------
// -- General --
// -------------
DEFINE_GETTER(General, const std::string, Name)
General::General(std::string name) : m_Name(std::move(name)) {}
fn GeneralImpl::from_class(const General& instance) noexcept -> GeneralImpl {
return { instance.getName() };
}
fn GeneralImpl::to_class() const -> General { return General { name }; }
// -------------
// ----------------
// -- NowPlaying --
// ----------------
DEFINE_GETTER(NowPlaying, bool, Enabled)
NowPlaying::NowPlaying(bool enabled) : m_Enabled(enabled) {}
fn NowPlayingImpl::from_class(const NowPlaying& instance) noexcept -> NowPlayingImpl {
return { .enabled = instance.getEnabled() };
}
fn NowPlayingImpl::to_class() const -> NowPlaying { return NowPlaying { enabled.value_or(false) }; }
// ----------------
// ------------
// -- Config --
// ------------
DEFINE_GETTER(Config, const General, General)
DEFINE_GETTER(Config, const NowPlaying, NowPlaying)
DEFINE_GETTER(Config, const Weather, Weather)
Config::Config(General general, NowPlaying now_playing, Weather weather)
: m_General(std::move(general)), m_NowPlaying(now_playing), m_Weather(std::move(weather)) {}
fn Config::getInstance() -> const Config& { fn Config::getInstance() -> const Config& {
static const auto* INSTANCE = new Config(rfl::toml::load<Config>("./config.toml").value()); static const Config* INSTANCE = new Config(rfl::toml::load<Config>("./config.toml").value());
return *INSTANCE; return *INSTANCE;
} }
fn ConfigImpl::from_class(const Config& instance) noexcept -> ConfigImpl {
return {
instance.getGeneral(),
instance.getNowPlaying(),
instance.getWeather(),
};
}
fn ConfigImpl::to_class() const -> Config { return { general, now_playing, weather }; }
// ------------

View file

@ -1,76 +1,36 @@
#pragma once #pragma once
#include <cstdlib>
#include <rfl.hpp> #include <rfl.hpp>
#include <rfl/Field.hpp>
#include <rfl/default.hpp>
#include <string> #include <string>
#include <util/macros.h>
#include "util/macros.h"
#include "weather.h" #include "weather.h"
// TODO: Make config values optional and supply defaults using Location = std::variant<std::string, Coords>;
class General { struct General {
private: rfl::Field<"name", std::string> name = "user";
std::string m_Name;
public:
explicit General(std::string name);
[[nodiscard]] fn getName() const -> const std::string;
}; };
class NowPlaying { struct NowPlaying {
private: bool enabled = false;
bool m_Enabled;
public:
explicit NowPlaying(bool enabled);
[[nodiscard]] fn getEnabled() const -> bool;
}; };
class Config { struct Weather {
private: Location location;
General m_General; std::string api_key;
NowPlaying m_NowPlaying; std::string units;
Weather m_Weather;
public: fn getWeatherInfo() const -> WeatherOutput;
/** };
* @brief Creates a new Config instance.
* struct Config {
* @param general The general section of the configuration. rfl::Field<"general", General> general = General { .name = "user" };
* @param now_playing The now playing section of the configuration. rfl::Field<"now_playing", NowPlaying> now_playing = NowPlaying();
* @param weather The weather section of the configuration. rfl::Field<"weather", Weather> weather = Weather();
*/
Config(General general, NowPlaying now_playing, Weather weather);
/**
* @brief Gets the current (read-only) configuration.
*
* @return The current Config instance.
*/
static fn getInstance() -> const Config&; static fn getInstance() -> const Config&;
[[nodiscard]] fn getWeather() const -> const Weather;
[[nodiscard]] fn getGeneral() const -> const General;
[[nodiscard]] fn getNowPlaying() const -> const NowPlaying;
}; };
// reflect-cpp Stuff
DEF_IMPL(General, std::string name)
DEF_IMPL(NowPlaying, std::optional<bool> enabled)
DEF_IMPL(Config, General general; NowPlaying now_playing; Weather weather)
namespace rfl::parsing {
template <class ReaderType, class WriterType, class ProcessorsType>
struct Parser<ReaderType, WriterType, General, ProcessorsType>
: CustomParser<ReaderType, WriterType, ProcessorsType, General, GeneralImpl> {};
template <class ReaderType, class WriterType, class ProcessorsType>
struct Parser<ReaderType, WriterType, NowPlaying, ProcessorsType>
: CustomParser<ReaderType, WriterType, ProcessorsType, NowPlaying, NowPlayingImpl> {};
template <class ReaderType, class WriterType, class ProcessorsType>
struct Parser<ReaderType, WriterType, Config, ProcessorsType>
: CustomParser<ReaderType, WriterType, ProcessorsType, Config, ConfigImpl> {};
}

View file

@ -5,27 +5,9 @@
#include "weather.h" #include "weather.h"
#include "config.h"
#include "util/result.h" #include "util/result.h"
using WeatherOutput = Weather::WeatherOutput;
DEFINE_GETTER(Weather, const Weather::Location, Location)
DEFINE_GETTER(Weather, const std::string, ApiKey)
DEFINE_GETTER(Weather, const std::string, Units)
Weather::Weather(Location location, std::string api_key, std::string units)
: m_Location(std::move(location)), m_ApiKey(std::move(api_key)), m_Units(std::move(units)) {}
fn WeatherImpl::from_class(const Weather& weather) noexcept -> WeatherImpl {
return {
weather.getLocation(),
weather.getApiKey(),
weather.getUnits(),
};
}
fn WeatherImpl::to_class() const -> Weather { return { location, api_key, units }; }
// Function to read cache from file // Function to read cache from file
fn ReadCacheFromFile() -> Result<WeatherOutput> { fn ReadCacheFromFile() -> Result<WeatherOutput> {
std::ifstream ifs("/tmp/weather_cache.json"); std::ifstream ifs("/tmp/weather_cache.json");
@ -91,6 +73,7 @@ fn MakeApiRequest(const std::string& url) -> Result<WeatherOutput> {
} }
fmt::println("Received response from API. Response size: {}", responseBuffer.size()); fmt::println("Received response from API. Response size: {}", responseBuffer.size());
fmt::println("Response: {}", responseBuffer);
WeatherOutput output = rfl::json::read<WeatherOutput>(responseBuffer).value(); WeatherOutput output = rfl::json::read<WeatherOutput>(responseBuffer).value();
@ -104,10 +87,6 @@ fn MakeApiRequest(const std::string& url) -> Result<WeatherOutput> {
fn Weather::getWeatherInfo() const -> WeatherOutput { fn Weather::getWeatherInfo() const -> WeatherOutput {
using namespace std::chrono; using namespace std::chrono;
const Location loc = m_Location;
const std::string apiKey = m_ApiKey;
const std::string units = m_Units;
// Check if cache is valid // Check if cache is valid
if (Result<WeatherOutput> data = ReadCacheFromFile(); data.isOk()) { if (Result<WeatherOutput> data = ReadCacheFromFile(); data.isOk()) {
WeatherOutput dataVal = data.value(); WeatherOutput dataVal = data.value();
@ -126,24 +105,24 @@ fn Weather::getWeatherInfo() const -> WeatherOutput {
WeatherOutput result; WeatherOutput result;
if (holds_alternative<std::string>(loc)) { if (holds_alternative<std::string>(location)) {
const std::string city = get<std::string>(loc); const std::string city = get<std::string>(location);
const char* location = 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: {}", location); fmt::println("City: {}", loc);
const std::string apiUrl = fmt::format( const std::string apiUrl = fmt::format(
"https://api.openweathermap.org/data/2.5/" "https://api.openweathermap.org/data/2.5/"
"weather?q={}&appid={}&units={}", "weather?q={}&appid={}&units={}",
location, loc,
apiKey, api_key,
units units
); );
result = MakeApiRequest(apiUrl).value(); result = MakeApiRequest(apiUrl).value();
} else { } else {
const auto [lat, lon] = get<Coords>(loc); const auto [lat, lon] = get<Coords>(location);
fmt::println("Coordinates: lat = {:.3f}, lon = {:.3f}", lat, lon); fmt::println("Coordinates: lat = {:.3f}, lon = {:.3f}", lat, lon);
@ -152,7 +131,7 @@ fn Weather::getWeatherInfo() const -> WeatherOutput {
"weather?lat={:.3f}&lon={:.3f}&appid={}&units={}", "weather?lat={:.3f}&lon={:.3f}&appid={}&units={}",
lat, lat,
lon, lon,
apiKey, api_key,
units units
); );

View file

@ -4,99 +4,73 @@
#include <rfl.hpp> #include <rfl.hpp>
#include <rfl/toml.hpp> #include <rfl/toml.hpp>
#include <string> #include <string>
#include <variant> #include <util/macros.h>
#include "util/macros.h"
#include "util/numtypes.h" #include "util/numtypes.h"
class Weather { using degrees = rfl::Validator<u16, rfl::Minimum<0>, rfl::Maximum<360>>;
public: using percentage = rfl::Validator<i8, rfl::Minimum<0>, rfl::Maximum<100>>;
using degrees = rfl::Validator<u16, rfl::Minimum<0>, rfl::Maximum<360>>;
using percentage = rfl::Validator<i8, rfl::Minimum<0>, rfl::Maximum<100>>;
struct Condition { struct Condition {
std::string description; std::string description;
std::string icon; std::string icon;
std::string main; std::string main;
usize id; usize id;
};
struct Main {
f64 feels_like;
f64 temp;
f64 temp_max;
f64 temp_min;
isize pressure;
percentage humidity;
std::optional<isize> grnd_level;
std::optional<isize> sea_level;
};
struct Wind {
degrees deg;
f64 speed;
std::optional<f64> gust;
};
struct Precipitation {
rfl::Rename<"1h", f64> one_hour;
rfl::Rename<"3h", f64> three_hours;
};
struct Sys {
std::string country;
usize id;
usize sunrise;
usize sunset;
usize type;
};
struct Clouds {
percentage all;
};
struct Coords {
double lat;
double lon;
};
struct WeatherOutput {
Clouds clouds;
isize timezone;
isize visibility;
Main main;
rfl::Rename<"coord", Coords> coords;
std::optional<Precipitation> rain;
std::optional<Precipitation> snow;
std::string base;
std::string name;
std::vector<Condition> weather;
Sys sys;
usize cod;
usize dt;
usize id;
Wind wind;
};
using Location = std::variant<std::string, Coords>;
Weather(Location location, std::string api_key, std::string units);
[[nodiscard]] fn getWeatherInfo() const -> WeatherOutput;
[[nodiscard]] fn getLocation() const -> const Location;
[[nodiscard]] fn getApiKey() const -> const std::string;
[[nodiscard]] fn getUnits() const -> const std::string;
private:
Location m_Location;
std::string m_ApiKey;
std::string m_Units;
}; };
DEF_IMPL(Weather, Weather::Location location; std::string api_key; std::string units) struct Main {
f64 feels_like;
f64 temp;
f64 temp_max;
f64 temp_min;
isize pressure;
percentage humidity;
std::optional<isize> grnd_level;
std::optional<isize> sea_level;
};
namespace rfl::parsing { struct Wind {
template <class ReaderType, class WriterType, class ProcessorsType> degrees deg;
struct Parser<ReaderType, WriterType, Weather, ProcessorsType> f64 speed;
: CustomParser<ReaderType, WriterType, ProcessorsType, Weather, WeatherImpl> {}; std::optional<f64> gust;
} };
struct Precipitation {
rfl::Rename<"1h", f64> one_hour;
rfl::Rename<"3h", f64> three_hours;
};
struct Sys {
std::string country;
usize id;
usize sunrise;
usize sunset;
usize type;
};
struct Clouds {
percentage all;
};
struct Coords {
double lat;
double lon;
};
struct WeatherOutput {
Clouds clouds;
isize timezone;
isize visibility;
Main main;
rfl::Rename<"coord", Coords> coords;
std::optional<Precipitation> rain;
std::optional<Precipitation> snow;
std::string base;
std::string name;
std::vector<Condition> weather;
Sys sys;
usize cod;
usize dt;
usize id;
Wind wind;
};

View file

@ -48,16 +48,14 @@ fn GetDate() -> string {
} }
fn main() -> int { fn main() -> int {
using WeatherOutput = Weather::WeatherOutput;
const Config& config = Config::getInstance(); const Config& config = Config::getInstance();
auto weatherFuture = auto weatherFuture =
std::async(std::launch::async, [&config]() { return config.getWeather().getWeatherInfo(); }); std::async(std::launch::async, [&config]() { return config.weather.get().getWeatherInfo(); });
auto osVersionFuture = std::async(std::launch::async, GetOSVersion); auto osVersionFuture = std::async(std::launch::async, GetOSVersion);
auto nowPlayingEnabledFuture = auto nowPlayingEnabledFuture =
std::async(std::launch::async, [&config]() { return config.getNowPlaying().getEnabled(); }); std::async(std::launch::async, [&config]() { return config.now_playing.get().enabled; });
auto dateFuture = std::async(std::launch::async, GetDate); auto dateFuture = std::async(std::launch::async, GetDate);
auto memInfoFuture = std::async(std::launch::async, GetMemInfo); auto memInfoFuture = std::async(std::launch::async, GetMemInfo);
@ -66,8 +64,9 @@ fn main() -> int {
const long temp = std::lround(json.main.temp); const long temp = std::lround(json.main.temp);
const std::string townName = json.name; const std::string townName = json.name;
const char* version = osVersionFuture.get(); const char* version = osVersionFuture.get();
const std::string name = config.getGeneral().getName();
const std::string name = config.general.value().name.get();
const bool nowPlayingEnabled = nowPlayingEnabledFuture.get(); const bool nowPlayingEnabled = nowPlayingEnabledFuture.get();
fmt::println("Hello {}!", name); fmt::println("Hello {}!", name);