blegh
This commit is contained in:
parent
b366a7ee63
commit
6e5045f1f4
9 changed files with 988 additions and 70 deletions
|
@ -2,6 +2,8 @@
|
|||
#include <fmt/core.h>
|
||||
#include <toml++/toml.h>
|
||||
#include <unistd.h>
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/toml.hpp>
|
||||
|
||||
#define DEFINE_GETTER(class_name, type, name) \
|
||||
type class_name::get##name() const { \
|
||||
|
@ -13,32 +15,16 @@ DEFINE_GETTER(Config, const NowPlaying, NowPlaying)
|
|||
DEFINE_GETTER(Config, const Weather, Weather)
|
||||
DEFINE_GETTER(General, const string, Name)
|
||||
DEFINE_GETTER(NowPlaying, bool, Enabled)
|
||||
DEFINE_GETTER(Weather, const Location, Location)
|
||||
DEFINE_GETTER(Weather, const Weather::Location, Location)
|
||||
DEFINE_GETTER(Weather, const string, ApiKey)
|
||||
DEFINE_GETTER(Weather, const string, Units)
|
||||
|
||||
const Config& Config::getInstance() {
|
||||
static const Config& INSTANCE =
|
||||
*new Config(toml::parse_file("./config.toml"));
|
||||
*new Config(rfl::toml::load<Config>("./config.toml").value());
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
Config::Config(toml::table toml)
|
||||
: m_General(toml["general"]["name"].value_or(getlogin())),
|
||||
m_NowPlaying(toml["now_playing"]["enable"].value_or(false)),
|
||||
m_Weather([location = toml["weather"]["location"],
|
||||
apiKey = toml["weather"]["api_key"].value_or(""),
|
||||
units = toml["weather"]["units"].value_or("metric")] {
|
||||
return location.is_string()
|
||||
? Weather(location.value_or(""), apiKey, units)
|
||||
: Weather(
|
||||
Coords {
|
||||
.lat = location["lat"].value_or(0.0),
|
||||
.lon = location["lon"].value_or(0.0),
|
||||
},
|
||||
apiKey, units);
|
||||
}()) {}
|
||||
|
||||
Config::Config(General general, NowPlaying now_playing, Weather weather)
|
||||
: m_General(std::move(general)),
|
||||
m_NowPlaying(now_playing),
|
||||
|
@ -93,3 +79,126 @@ ConfigImpl ConfigImpl::from_class(const Config& config) noexcept {
|
|||
Config ConfigImpl::to_class() const {
|
||||
return {general, now_playing, weather};
|
||||
}
|
||||
|
||||
boost::json::object Weather::getWeatherInfo() const {
|
||||
using namespace std;
|
||||
using namespace cpr;
|
||||
using namespace boost;
|
||||
using namespace std::chrono;
|
||||
|
||||
const Location loc = this->m_Location;
|
||||
const string apiKey = this->m_ApiKey;
|
||||
const string units = this->m_Units;
|
||||
|
||||
// Define cache file and cache duration
|
||||
const string cacheFile = "/tmp/weather_cache.json";
|
||||
constexpr minutes cacheDuration = minutes(10);
|
||||
|
||||
logi("Cache file: {}", cacheFile);
|
||||
logi("Cache duration: {} minutes",
|
||||
duration_cast<minutes>(cacheDuration).count());
|
||||
|
||||
// Function to read cache from file
|
||||
auto readCacheFromFile =
|
||||
[&]() -> optional<pair<json::object, system_clock::time_point>> {
|
||||
ifstream ifs(cacheFile);
|
||||
|
||||
if (!ifs.is_open()) {
|
||||
logi("Cache file not found.");
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
logi("Reading from cache file...");
|
||||
|
||||
json::object cachedData;
|
||||
system_clock::time_point timestamp;
|
||||
|
||||
try {
|
||||
json::value val;
|
||||
ifs >> val;
|
||||
cachedData = val.as_object();
|
||||
|
||||
string tsStr = cachedData["timestamp"].as_string().c_str();
|
||||
timestamp = system_clock::time_point(milliseconds(stoll(tsStr)));
|
||||
|
||||
cachedData.erase("timestamp");
|
||||
} catch (...) {
|
||||
loge("Failed to read from cache file.");
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
logi("Successfully read from cache file.");
|
||||
return make_pair(cachedData, timestamp);
|
||||
};
|
||||
|
||||
// Function to write cache to file
|
||||
auto writeCacheToFile = [&](const json::object& data) {
|
||||
fmt::println("Writing to cache file...");
|
||||
ofstream ofs(cacheFile);
|
||||
|
||||
if (!ofs.is_open()) {
|
||||
loge("Failed to open cache file for writing.");
|
||||
return;
|
||||
}
|
||||
|
||||
json::object dataToWrite = data;
|
||||
dataToWrite["timestamp"] = to_string(
|
||||
duration_cast<milliseconds>(system_clock::now().time_since_epoch())
|
||||
.count());
|
||||
ofs << json::serialize(dataToWrite);
|
||||
logi("Successfully wrote to cache file.");
|
||||
};
|
||||
|
||||
// Check if cache is valid
|
||||
if (auto cachedData = readCacheFromFile()) {
|
||||
auto [data, timestamp] = *cachedData;
|
||||
if (system_clock::now() - timestamp < cacheDuration) {
|
||||
logi("Cache is valid. Returning cached data.");
|
||||
return data;
|
||||
}
|
||||
|
||||
logi("Cache is expired.");
|
||||
} else {
|
||||
logi("No valid cache found.");
|
||||
}
|
||||
|
||||
json::object result;
|
||||
if (holds_alternative<string>(loc)) {
|
||||
const string city = get<string>(loc);
|
||||
|
||||
const char* location = curl_easy_escape(nullptr, city.c_str(),
|
||||
static_cast<int>(city.length()));
|
||||
logi("City: {}", location);
|
||||
|
||||
logi("Making API request for city: {}", city);
|
||||
|
||||
const Response res =
|
||||
Get(Url {fmt::format("https://api.openweathermap.org/data/2.5/"
|
||||
"weather?q={}&appid={}&units={}",
|
||||
location, apiKey, units)});
|
||||
|
||||
logi("Received response from API.");
|
||||
json::value json = json::parse(res.text);
|
||||
result = json.as_object();
|
||||
} else {
|
||||
const auto [lat, lon] = get<Coords>(loc);
|
||||
logi("Coordinates: lat = {:.3f}, lon = {:.3f}", lat, lon);
|
||||
|
||||
logi("Making API request for coordinates.");
|
||||
const Response res =
|
||||
Get(Url {fmt::format("https://api.openweathermap.org/data/2.5/"
|
||||
"weather?lat={:.3f}&lon={:.3f}&appid={}&units={}",
|
||||
lat, lon, apiKey, units)});
|
||||
|
||||
logi("Received response from API.");
|
||||
json::value json = json::parse(res.text);
|
||||
result = json.as_object();
|
||||
}
|
||||
|
||||
// Update the cache with the new data
|
||||
writeCacheToFile(result);
|
||||
|
||||
logi("Returning new data.");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <cpr/cpr.h>
|
||||
#include <fmt/core.h>
|
||||
#include <fmtlog.h>
|
||||
#include <toml++/toml.h>
|
||||
#include <unistd.h>
|
||||
#include <boost/json.hpp>
|
||||
#include <rfl.hpp>
|
||||
#include <string>
|
||||
#include <toml++/impl/parser.hpp>
|
||||
|
@ -26,6 +29,7 @@ class Weather {
|
|||
public:
|
||||
Weather(Location location, string api_key, string units);
|
||||
|
||||
[[nodiscard]] boost::json::object getWeatherInfo() const;
|
||||
[[nodiscard]] const Location getLocation() const;
|
||||
[[nodiscard]] const string getApiKey() const;
|
||||
[[nodiscard]] const string getUnits() const;
|
||||
|
@ -83,8 +87,6 @@ class Config {
|
|||
NowPlaying m_NowPlaying;
|
||||
Weather m_Weather;
|
||||
|
||||
Config(toml::table toml);
|
||||
|
||||
public:
|
||||
Config(General general, NowPlaying now_playing, Weather weather);
|
||||
|
||||
|
|
52
src/main.cpp
52
src/main.cpp
|
@ -12,6 +12,7 @@
|
|||
#include <toml++/toml.hpp>
|
||||
#include <variant>
|
||||
#include "config/config.h"
|
||||
#include "fmtlog.h"
|
||||
#include "os/os.h"
|
||||
|
||||
using std::string;
|
||||
|
@ -23,8 +24,9 @@ struct BytesToGiB {
|
|||
template <>
|
||||
struct fmt::formatter<BytesToGiB> : formatter<double> {
|
||||
template <typename FormatContext>
|
||||
auto format(const BytesToGiB BTG, FormatContext& ctx) {
|
||||
auto out = formatter<double>::format(
|
||||
typename FormatContext::iterator format(const BytesToGiB BTG,
|
||||
FormatContext& ctx) {
|
||||
typename FormatContext::iterator out = formatter<double>::format(
|
||||
static_cast<double>(BTG.value) / pow(1024, 3), ctx);
|
||||
*out++ = 'G';
|
||||
*out++ = 'i';
|
||||
|
@ -48,53 +50,11 @@ DateNum ParseDate(string const& input) {
|
|||
return Default;
|
||||
}
|
||||
|
||||
boost::json::object GetWeather() {
|
||||
using namespace std;
|
||||
using namespace cpr;
|
||||
using namespace boost;
|
||||
|
||||
const Config& config = Config::getInstance();
|
||||
|
||||
Weather weather = config.getWeather();
|
||||
Location loc = weather.getLocation();
|
||||
string apiKey = weather.getApiKey();
|
||||
string units = weather.getUnits();
|
||||
|
||||
fmt::println("Hello!");
|
||||
|
||||
if (holds_alternative<string>(loc)) {
|
||||
const string city = get<string>(loc);
|
||||
|
||||
const char* location = curl_easy_escape(nullptr, city.c_str(),
|
||||
static_cast<int>(city.length()));
|
||||
|
||||
const Response res =
|
||||
Get(Url {fmt::format("https://api.openweathermap.org/data/2.5/"
|
||||
"weather?q={}&appid={}&units={}",
|
||||
location, apiKey, units)});
|
||||
|
||||
json::value json = json::parse(res.text);
|
||||
|
||||
return json.as_object();
|
||||
}
|
||||
|
||||
const auto [lat, lon] = get<Coords>(loc);
|
||||
|
||||
const Response res =
|
||||
Get(Url {format("https://api.openweathermap.org/data/2.5/"
|
||||
"weather?lat={:.3f}&lon={:.3f}&appid={}&units={}",
|
||||
lat, lon, apiKey, units)});
|
||||
|
||||
json::value json = json::parse(res.text);
|
||||
|
||||
return json.as_object();
|
||||
}
|
||||
|
||||
int main() {
|
||||
using boost::json::object;
|
||||
using std::time_t;
|
||||
|
||||
const Config& config = rfl::toml::load<Config>("./config.toml").value();
|
||||
const Config& config = Config::getInstance();
|
||||
|
||||
if (config.getNowPlaying().getEnabled())
|
||||
fmt::println("{}", GetNowPlaying());
|
||||
|
@ -139,7 +99,7 @@ int main() {
|
|||
|
||||
fmt::println("{:%B} {}, {:%-I:%0M %p}", localTime, date, localTime);
|
||||
|
||||
object json = GetWeather();
|
||||
object json = config.getWeather().getWeatherInfo();
|
||||
|
||||
const char* townName =
|
||||
json["name"].is_string() ? json["name"].as_string().c_str() : "Unknown";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue