/* Copyright 2020, Michele Santullo * This file is part of orotool. * * Orotool is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Orotool is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Orotool. If not, see . */ #include "app_config.hpp" #include "orotool_config.hpp" #include "duckhandy/int_conv.hpp" #include #include #include #include #include #include #include #include #include namespace duck { namespace { constexpr const std::size_t g_min_update_timeout = 60; constexpr const char g_db_path_sect[] = "system"; constexpr const char g_db_path[] = "db_path"; constexpr const char g_worker_threads_sect[] = "system"; constexpr const char g_worker_threads[] = "worker_threads"; constexpr const char g_backend_sect[] = "system"; constexpr const char g_backend[] = "backend"; constexpr const char g_fetch_extra_delay_sect[] = "options"; constexpr const char g_fetch_extra_delay[] = "fetch_extra_delay"; constexpr const char g_fetch_extra_delay_def[] = "30"; constexpr const char g_api_key_sect[] = "options"; constexpr const char g_api_key[] = "api_key"; constexpr const char g_api_key_def[] = ""; constexpr const char g_store_raw_json_sect[] = "options"; constexpr const char g_store_raw_json[] = "store_raw_json"; constexpr const char g_store_raw_json_def[] = "false"; constexpr const char g_enable_webserver_sect[] = "webserver"; constexpr const char g_enable_webserver[] = "enabled"; constexpr const char g_enable_webserver_def[] = "no"; constexpr const char g_json_store_mode_sect[] = "options"; constexpr const char g_json_store_mode[] = "json_store_mode"; constexpr const char g_json_store_mode_def[] = "plain"; constexpr const char g_items_time_sect[] = "timing"; constexpr const char g_items_time[] = "items"; constexpr const char g_items_time_def[] = "604800"; constexpr const char g_icons_time_sect[] = "timing"; constexpr const char g_icons_time[] = "icons"; constexpr const char g_icons_time_def[] = "604800"; constexpr const char g_shops_time_sect[] = "timing"; constexpr const char g_shops_time[] = "shops"; constexpr const char g_shops_time_def[] = "600"; constexpr const char g_creators_time_sect[] = "timing"; constexpr const char g_creators_time[] = "creators"; constexpr const char g_creators_time_def[] = "600"; constexpr const char g_max_conn_retries_sect[] = "options"; constexpr const char g_max_conn_retries[] = "max_connection_retries"; constexpr const char g_max_conn_retries_def[] = "0"; constexpr const char g_err_retry_timeout_sect[] = "options"; constexpr const char g_err_retry_timeout[] = "error_retry_timeout"; constexpr const char g_err_retry_timeout_def[] = "600"; bool equal (std::string_view a, std::string_view b) { return a.size() == b.size() and std::equal( a.begin(), a.end(), b.begin(), [](auto c1, auto c2) {return std::tolower(c1) == std::tolower(c2); } ); } bool to_bool (std::string_view a) { std::array yes_list { "true", "1", "yes", "on", "ok", "enable", "enabled", "sure", "aye", "one" }; return ( std::find_if( yes_list.begin(), yes_list.end(), [a](std::string_view b) -> bool { return equal(a, b); } ) != yes_list.end() ); } std::string whole_ini() { std::ifstream input(g_config_file_path); input >> std::noskipws; return { std::istream_iterator(input), std::istream_iterator() }; } std::string_view value_ifp ( const kamokan::IniFile& ini, std::string_view section, std::string_view key, std::string_view def, bool allow_empty ) { const auto& map = ini.parsed(); auto it_section = map.find(section); if (map.end() == it_section) return def; auto it_setting = it_section->second.find(key); if (it_section->second.end() == it_setting) return def; if (not allow_empty and it_setting->second.empty()) return def; else return it_setting->second; } void print_setting_read_err ( std::string_view section, std::string_view name, const std::logic_error& err ) { std::cerr << "Error reading setting [" << section << "] \"" << name << "\": " << err.what() << '\n'; } } //unnamed namespace AppConfig::AppConfig() : m_ini(whole_ini()) { } AppConfig::~AppConfig() noexcept = default; std::string_view AppConfig::db_path() const { return value_ifp(m_ini, g_db_path_sect, g_db_path, g_def_sqlite_db_name, false); } std::string_view AppConfig::api_key() const { return value_ifp(m_ini, g_api_key_sect, g_api_key, g_api_key_def, true); } std::size_t AppConfig::worker_threads() const { std::string_view val = value_ifp(m_ini, g_worker_threads_sect, g_worker_threads, g_def_worker_threads, false); if (val == "max") { return std::max(3U, std::thread::hardware_concurrency()) - 1; } else { try { const std::size_t num = std::stoul(std::string(val.data(), val.size())); const std::size_t hard_max = 4U * std::thread::hardware_concurrency(); return std::max(2U, std::min(num, hard_max)); } catch (const std::logic_error& err) { print_setting_read_err(g_worker_threads_sect, g_worker_threads, err); return std::stoul(g_def_worker_threads); } } } std::size_t AppConfig::fetch_extra_delay() const { std::string_view val = value_ifp(m_ini, g_fetch_extra_delay_sect, g_fetch_extra_delay, g_fetch_extra_delay_def, false); try { const std::size_t num = std::stoul(std::string(val.data(), val.size())); return std::min(3600 * 6, num); } catch (const std::logic_error& err) { print_setting_read_err(g_fetch_extra_delay_sect, g_fetch_extra_delay, err); return std::stoul(g_fetch_extra_delay_def); } } std::string_view AppConfig::backend() const { return value_ifp(m_ini, g_backend_sect, g_backend, g_def_backend_name, false); } bool AppConfig::store_raw_json() const { std::string_view val = value_ifp(m_ini, g_store_raw_json_sect, g_store_raw_json, g_store_raw_json_def, false); return to_bool(val); } bool AppConfig::enable_webserver() const { std::string_view val = value_ifp(m_ini, g_enable_webserver_sect, g_enable_webserver, g_enable_webserver_def, false); return to_bool(val); } std::size_t AppConfig::items_timeout() const { std::string_view val = value_ifp(m_ini, g_items_time_sect, g_items_time, g_items_time_def, false); return std::max(dhandy::int_conv(val), g_min_update_timeout); } std::size_t AppConfig::icons_timeout() const { std::string_view val = value_ifp(m_ini, g_icons_time_sect, g_icons_time, g_icons_time_def, false); return std::max(dhandy::int_conv(val), g_min_update_timeout); } std::size_t AppConfig::shops_timeout() const { std::string_view val = value_ifp(m_ini, g_shops_time_sect, g_shops_time, g_shops_time_def, false); return std::max(dhandy::int_conv(val), g_min_update_timeout); } std::size_t AppConfig::creators_timeout() const { std::string_view val = value_ifp(m_ini, g_creators_time_sect, g_creators_time, g_creators_time_def, false); return std::max(dhandy::int_conv(val), g_min_update_timeout); } oro::SourceFormat AppConfig::json_store_mode() const { std::string_view val = value_ifp(m_ini, g_json_store_mode_sect, g_json_store_mode, g_json_store_mode_def, false); if (equal(val, "plain")) { return oro::SourceFormat::Plain; } else if (equal(val, "xz")) { #if defined(OROTOOL_WITH_LZMA) return oro::SourceFormat::Base64_xz; #else throw std::runtime_error( std::string("This version of ") + g_project_name + " was compiled without lzma support so " + g_json_store_mode + " can't be set to xz" ); #endif } else { throw std::runtime_error( "Invalid value \"" + std::string(val) + "\" for option [" + g_json_store_mode_sect + "] " + g_json_store_mode ); } } std::size_t AppConfig::error_retry_timeout() const { std::string_view val = value_ifp(m_ini, g_err_retry_timeout_sect, g_err_retry_timeout, g_err_retry_timeout_def, false); return std::max(dhandy::int_conv(val), g_min_update_timeout); } unsigned int AppConfig::max_connection_retries() const { std::string_view val = value_ifp(m_ini, g_max_conn_retries_sect, g_max_conn_retries, g_max_conn_retries_def, false); return dhandy::int_conv(val); } } //namespace duck