diff --git a/include/synchronize_item.hpp b/include/synchronize_item.hpp index c286d93..d83e32e 100644 --- a/include/synchronize_item.hpp +++ b/include/synchronize_item.hpp @@ -18,8 +18,8 @@ struct synchronize_item : wups::config::button_item { - std::future sync_result; - std::stop_source sync_stopper; + std::future task_result; + std::stop_source task_stopper; synchronize_item(); diff --git a/include/utils.hpp b/include/utils.hpp index 1118326..689234c 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -56,6 +56,26 @@ namespace utils { std::chrono::minutes> fetch_timezone(int idx); + + // RAII class to ensure network is working. + // It blocks until the network is available, of throws std::runtime_error. + class network_guard { + + struct init_guard { + init_guard(); + ~init_guard(); + }; + + struct connect_guard { + connect_guard(); + ~connect_guard(); + }; + + init_guard init; + connect_guard conn; + + }; + } // namespace utils #endif diff --git a/source/cfg.cpp b/source/cfg.cpp index 5976b47..d3215a4 100644 --- a/source/cfg.cpp +++ b/source/cfg.cpp @@ -192,10 +192,8 @@ namespace cfg { { logger::initialize(PLUGIN_NAME); - // logger::printf("reloading configs\n"); cfg::reload(); - // logger::printf("building config items\n"); root.add(make_config_screen()); root.add(make_preview_screen()); root.add(synchronize_item::create()); diff --git a/source/clock_item.cpp b/source/clock_item.cpp index 1035d2b..cac9808 100644 --- a/source/clock_item.cpp +++ b/source/clock_item.cpp @@ -110,6 +110,8 @@ clock_item::run() using std::to_string; using time_utils::seconds_to_human; + utils::network_guard net_guard; + for (auto& [key, value] : server_infos) { value.name->text.clear(); value.correction->text.clear(); diff --git a/source/core.cpp b/source/core.cpp index 2d83260..7aac978 100644 --- a/source/core.cpp +++ b/source/core.cpp @@ -91,7 +91,7 @@ namespace { return ticks_to_string(ticks); } -} +} // namespace namespace core { @@ -291,6 +291,8 @@ namespace core { { using time_utils::seconds_to_human; + utils::network_guard net_guard; + // ensure notification is initialized if needed notify::guard notify_guard{cfg::notify > 0}; @@ -489,7 +491,4 @@ namespace core { } // namespace background - - - } // namespace core diff --git a/source/synchronize_item.cpp b/source/synchronize_item.cpp index 92a8293..fffa8a6 100644 --- a/source/synchronize_item.cpp +++ b/source/synchronize_item.cpp @@ -40,7 +40,7 @@ synchronize_item::on_started() { status_msg = "Synchronizing..."; - sync_stopper = {}; + task_stopper = {}; auto task = [this](std::stop_token token) { @@ -55,7 +55,9 @@ synchronize_item::on_started() } }; - sync_result = std::async(task, sync_stopper.get_token()); + task_result = std::async(std::launch::async, + std::move(task), + task_stopper.get_token()); } @@ -63,7 +65,7 @@ void synchronize_item::on_finished() { try { - sync_result.get(); + task_result.get(); status_msg = "Success!"; cfg::save_important_vars(); } @@ -77,5 +79,5 @@ synchronize_item::on_finished() void synchronize_item::on_cancel() { - sync_stopper.request_stop(); + task_stopper.request_stop(); } diff --git a/source/utils.cpp b/source/utils.cpp index 3c8256d..f2515c9 100644 --- a/source/utils.cpp +++ b/source/utils.cpp @@ -9,6 +9,8 @@ #include // distance() #include // logic_error, runtime_error +#include + #include "utils.hpp" #include "http_client.hpp" @@ -16,6 +18,9 @@ using namespace std::literals; +using std::logic_error; +using std::runtime_error; + namespace utils { @@ -123,7 +128,7 @@ namespace utils { case 2: return "https://ipapi.co"; default: - throw std::logic_error{"invalid tz service"}; + throw logic_error{"Invalid tz service."}; } } @@ -131,9 +136,6 @@ namespace utils { std::pair fetch_timezone(int idx) { - if (idx < 0 || idx >= num_tz_services) - throw std::logic_error{"invalid service"}; - const char* service = get_tz_service_name(idx); static const char* urls[num_tz_services] = { @@ -142,6 +144,8 @@ namespace utils { "https://ipapi.co/csv" }; + network_guard net_guard; + std::string response = http::get(urls[idx]); switch (idx) { @@ -150,7 +154,7 @@ namespace utils { { auto tokens = csv_split(response); if (size(tokens) != 2) - throw std::runtime_error{"Could not parse response from "s + service}; + throw runtime_error{"Could not parse response from "s + service}; std::string name = tokens[0]; auto offset = std::chrono::seconds{std::stoi(tokens[1])}; return {name, duration_cast(offset)}; @@ -163,18 +167,18 @@ namespace utils { // returned as +HHMM, not seconds. auto lines = split(response, "\r\n"); if (size(lines) != 2) - throw std::runtime_error{"Could not parse response from "s + service}; + throw runtime_error{"Could not parse response from "s + service}; auto keys = csv_split(lines[0]); auto values = csv_split(lines[1]); if (size(keys) != size(values)) - throw std::runtime_error{"Incoherent response from "s + service}; + throw runtime_error{"Incoherent response from "s + service}; auto tz_it = std::ranges::find(keys, "timezone"); auto offset_it = std::ranges::find(keys, "utc_offset"); if (tz_it == keys.end() || offset_it == keys.end()) - throw std::runtime_error{"Could not find timezone or utc_offset fields" - " in response."}; + throw runtime_error{"Could not find timezone or utc_offset fields" + " in response."}; auto tz_idx = std::distance(keys.begin(), tz_it);; auto offset_idx = std::distance(keys.begin(), offset_it); @@ -182,7 +186,7 @@ namespace utils { std::string name = values[tz_idx]; std::string hhmm = values[offset_idx]; if (empty(hhmm)) - throw std::runtime_error{"Invalid UTC offset string."}; + throw runtime_error{"Invalid UTC offset string."}; char sign = hhmm[0]; std::string hh = hhmm.substr(1, 2); @@ -196,9 +200,35 @@ namespace utils { } default: - throw std::logic_error{"invalid tz service"}; + throw logic_error{"Invalid tz service."}; } } + + network_guard::init_guard::init_guard() + { + if (!nn::ac::Initialize()) + throw runtime_error{"Network error (nn::ac::Initialize() failed)"}; + } + + + network_guard::init_guard::~init_guard() + { + nn::ac::Finalize(); + } + + + network_guard::connect_guard::connect_guard() + { + if (!nn::ac::Connect()) + throw runtime_error{"Network error (nn::ac::Connect() failed)"}; + } + + + network_guard::connect_guard::~connect_guard() + { + nn::ac::Close(); + } + } // namespace utils