allow limiting concurrent http requests

add Semaphore
update SettingsManager a little
This commit is contained in:
ouwou 2020-10-04 02:28:48 -04:00
parent bbe36a8246
commit 43f87b4bca
7 changed files with 67 additions and 9 deletions

View File

@ -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();

View File

@ -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;

View File

@ -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<Semaphore>(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));
}
}

View File

@ -5,6 +5,7 @@
#include <filesystem>
#include <vector>
#include <unordered_map>
#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<Semaphore> m_semaphore;
std::unordered_map<std::string, std::vector<callback_type>> m_callbacks;
std::vector<std::future<void>> m_futures;
std::filesystem::path m_tmp_path;

View File

@ -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 {

View File

@ -1,5 +1,6 @@
#pragma once
#include <string>
#include <type_traits>
#include <SimpleIni.h>
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<typename T>
void SetSetting(std::string section, std::string key, T value) {
static_assert(std::is_convertible<T, std::string>::value);
if constexpr (std::is_same<T, std::string>::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:

View File

@ -8,7 +8,34 @@
#include <sstream>
#include <string>
#include <iomanip>
#include <regex>
#include <mutex>
#include <condition_variable>
class Semaphore {
public:
Semaphore(int count = 0)
: m_count(count) {}
inline void notify() {
std::unique_lock<std::mutex> lock(m_mutex);
m_count++;
lock.unlock();
m_cv.notify_one();
}
inline void wait() {
std::unique_lock<std::mutex> 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