From 43f87b4bcaa6d160cf7c4856109af06ea4873cf3 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sun, 4 Oct 2020 02:28:48 -0400 Subject: [PATCH] allow limiting concurrent http requests add Semaphore update SettingsManager a little --- abaddon.cpp | 6 +++++- abaddon.hpp | 2 ++ filecache.cpp | 18 +++++++++++++++--- filecache.hpp | 3 +++ settings.cpp | 6 +++--- settings.hpp | 14 ++++++++++++-- util.hpp | 27 +++++++++++++++++++++++++++ 7 files changed, 67 insertions(+), 9 deletions(-) diff --git a/abaddon.cpp b/abaddon.cpp index 0f8a679..2c8a839 100644 --- a/abaddon.cpp +++ b/abaddon.cpp @@ -85,7 +85,7 @@ int Abaddon::StartGTK() { } void Abaddon::LoadFromSettings() { - std::string token = m_settings.GetSetting("discord", "token"); + std::string token = m_settings.GetSettingString("discord", "token"); if (token.size()) { m_discord_token = token; m_discord.UpdateToken(m_discord_token); @@ -150,6 +150,10 @@ void Abaddon::DiscordOnGuildDelete(Snowflake guild_id) { m_main_window->UpdateChannelListing(); } +const SettingsManager &Abaddon::GetSettings() const { + return m_settings; +} + void Abaddon::ActionConnect() { if (!m_discord.IsStarted()) StartDiscord(); diff --git a/abaddon.hpp b/abaddon.hpp index 96728c6..3ca4151 100644 --- a/abaddon.hpp +++ b/abaddon.hpp @@ -61,6 +61,8 @@ public: void DiscordOnGuildCreate(Snowflake guild_id); void DiscordOnGuildDelete(Snowflake guild_id); + const SettingsManager &GetSettings() const; + private: DiscordClient m_discord; std::string m_discord_token; diff --git a/filecache.cpp b/filecache.cpp index f89bb3f..9e4b0b4 100644 --- a/filecache.cpp +++ b/filecache.cpp @@ -1,5 +1,8 @@ +#include "abaddon.hpp" #include "filecache.hpp" +constexpr static const int MaxConcurrentCacheHTTP = 10; + Cache::Cache() { m_tmp_path = std::filesystem::temp_directory_path() / "abaddon-cache"; std::filesystem::create_directories(m_tmp_path); @@ -29,16 +32,25 @@ void Cache::RespondFromPath(std::filesystem::path path, callback_type cb) { void Cache::GetFileFromURL(std::string url, callback_type cb) { auto cache_path = m_tmp_path / SanitizeString(url); if (std::filesystem::exists(cache_path)) { - m_futures.push_back(std::async(std::launch::async, [this, cache_path, cb]() { - RespondFromPath(cache_path, cb); })); + m_futures.push_back(std::async(std::launch::async, [this, cache_path, cb]() { RespondFromPath(cache_path, cb); })); return; } + // needs to be initialized like this or else ::Get() is called recursively + if (!m_semaphore) + m_semaphore = std::make_unique(Abaddon::Get().GetSettings().GetSettingInt("http", "concurrent", MaxConcurrentCacheHTTP)); + if (m_callbacks.find(url) != m_callbacks.end()) { m_callbacks[url].push_back(cb); } else { - m_futures.push_back(cpr::GetCallback(std::bind(&Cache::OnResponse, this, std::placeholders::_1), cpr::Url { url })); m_callbacks[url].push_back(cb); + auto future = std::async(std::launch::async, [this, url]() { + m_semaphore->wait(); + const auto &r = cpr::Get(cpr::Url { url }); + m_semaphore->notify(); + OnResponse(r); + }); + m_futures.push_back(std::move(future)); } } diff --git a/filecache.hpp b/filecache.hpp index b54f842..eed355a 100644 --- a/filecache.hpp +++ b/filecache.hpp @@ -5,6 +5,7 @@ #include #include #include +#include "util.hpp" // todo throttle requests and keep track of active requests to stop redundant requests @@ -23,6 +24,8 @@ private: void RespondFromPath(std::filesystem::path path, callback_type cb); void OnResponse(const cpr::Response &r); + std::unique_ptr m_semaphore; + std::unordered_map> m_callbacks; std::vector> m_futures; std::filesystem::path m_tmp_path; diff --git a/settings.cpp b/settings.cpp index 494f1ba..daff887 100644 --- a/settings.cpp +++ b/settings.cpp @@ -14,12 +14,12 @@ SettingsManager::SettingsManager(std::string filename) m_ok = rc == SI_OK; } -std::string SettingsManager::GetSetting(std::string section, std::string key, std::string fallback) { +std::string SettingsManager::GetSettingString(std::string section, std::string key, std::string fallback) const { return m_ini.GetValue(section.c_str(), key.c_str(), fallback.c_str()); } -void SettingsManager::SetSetting(std::string section, std::string key, std::string value) { - m_ini.SetValue(section.c_str(), key.c_str(), value.c_str()); +int SettingsManager::GetSettingInt(std::string section, std::string key, int fallback) const { + return std::stoul(GetSettingString(section, key, std::to_string(fallback))); } bool SettingsManager::IsValid() const { diff --git a/settings.hpp b/settings.hpp index e6a5b99..7c914f4 100644 --- a/settings.hpp +++ b/settings.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include class SettingsManager { @@ -7,8 +8,17 @@ public: SettingsManager(std::string filename); void Close(); - std::string GetSetting(std::string section, std::string key, std::string fallback = ""); - void SetSetting(std::string section, std::string key, std::string value); + std::string GetSettingString(std::string section, std::string key, std::string fallback = "") const; + int GetSettingInt(std::string section, std::string key, int fallback) const; + + template + void SetSetting(std::string section, std::string key, T value) { + static_assert(std::is_convertible::value); + if constexpr (std::is_same::value) + m_ini.SetValue(section.c_str(), key.c_str(), value.c_str()); + else + m_ini.SetValue(section.c_str(), key.c_str(), std::to_string(value).c_str()); + } bool IsValid() const; private: diff --git a/util.hpp b/util.hpp index bf6d9ee..5585013 100644 --- a/util.hpp +++ b/util.hpp @@ -8,7 +8,34 @@ #include #include #include +#include +#include +#include +class Semaphore { +public: + Semaphore(int count = 0) + : m_count(count) {} + + inline void notify() { + std::unique_lock lock(m_mutex); + m_count++; + lock.unlock(); + m_cv.notify_one(); + } + + inline void wait() { + std::unique_lock lock(m_mutex); + while (m_count == 0) + m_cv.wait(lock); + m_count--; + } + +private: + std::mutex m_mutex; + std::condition_variable m_cv; + int m_count; +}; // gtkmm doesnt seem to work #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN