refactor settings

This commit is contained in:
ouwou 2024-01-01 22:35:54 -05:00
parent 9b2475538a
commit bc9bb3d754
2 changed files with 214 additions and 167 deletions

View File

@ -26,87 +26,127 @@ SettingsManager::SettingsManager(const std::string &filename)
m_ok = false;
}
DefineSettings();
if (m_ok) ReadSettings();
}
void SettingsManager::ReadSettings() {
#define SMBOOL(section, key, var) \
try { \
m_settings.var = m_file.get_boolean(section, key); \
} catch (...) {}
#define SMSTR(section, key, var) \
try { \
m_settings.var = m_file.get_string(section, key); \
} catch (...) {}
#define SMINT(section, key, var) \
try { \
m_settings.var = m_file.get_integer(section, key); \
} catch (...) {}
#define SMFLT(section, key, var) \
try { \
m_settings.var = m_file.get_double(section, key); \
} catch (...) {}
SMSTR("discord", "api_base", APIBaseURL);
SMSTR("discord", "gateway", GatewayURL);
SMBOOL("discord", "memory_db", UseMemoryDB);
SMBOOL("discord", "prefetch", Prefetch);
SMBOOL("discord", "autoconnect", Autoconnect);
SMSTR("gui", "css", MainCSS);
SMBOOL("gui", "animated_guild_hover_only", AnimatedGuildHoverOnly);
SMBOOL("gui", "animations", ShowAnimations);
SMBOOL("gui", "custom_emojis", ShowCustomEmojis);
SMBOOL("gui", "member_list_discriminator", ShowMemberListDiscriminators);
SMBOOL("gui", "owner_crown", ShowOwnerCrown);
SMBOOL("gui", "save_state", SaveState);
SMBOOL("gui", "stock_emojis", ShowStockEmojis);
SMBOOL("gui", "unreads", Unreads);
SMBOOL("gui", "alt_menu", AltMenu);
SMBOOL("gui", "hide_to_tray", HideToTray);
SMBOOL("gui", "show_deleted_indicator", ShowDeletedIndicator);
SMFLT("gui", "font_scale", FontScale);
SMINT("http", "concurrent", CacheHTTPConcurrency);
SMSTR("http", "user_agent", UserAgent);
SMSTR("style", "expandercolor", ChannelsExpanderColor);
SMSTR("style", "nsfwchannelcolor", NSFWChannelColor);
SMSTR("style", "mentionbadgecolor", MentionBadgeColor);
SMSTR("style", "mentionbadgetextcolor", MentionBadgeTextColor);
SMSTR("style", "unreadcolor", UnreadIndicatorColor);
SMBOOL("notifications", "enabled", NotificationsEnabled);
SMBOOL("notifications", "playsound", NotificationsPlaySound);
SMSTR("voice", "vad", VAD);
SMBOOL("windows", "hideconsole", HideConsole);
void SettingsManager::HandleReadToken() {
#ifdef WITH_KEYCHAIN
keychain::Error error {};
// Move to keychain if present
// convert to keychain if present in normal settings
SMSTR("discord", "token", DiscordToken);
std::string token;
try {
token = m_file.get_string("discord", "token");
} catch (...) {}
if (!m_settings.DiscordToken.empty()) {
keychain::Error set_error {};
keychain::setPassword(KeychainPackage, KeychainService, KeychainUser, m_settings.DiscordToken, set_error);
if (set_error) {
printf("keychain error setting token: %s\n", set_error.message.c_str());
if (!token.empty()) {
keychain::Error error {};
keychain::setPassword(KeychainPackage, KeychainService, KeychainUser, token, error);
if (error) {
spdlog::get("ui")->error("Keychain error setting token: {}", error.message);
} else {
m_file.remove_key("discord", "token");
}
}
keychain::Error error {};
m_settings.DiscordToken = keychain::getPassword(KeychainPackage, KeychainService, KeychainUser, error);
if (error && error.type != keychain::ErrorType::NotFound) {
printf("keychain error reading token: %s (%d)\n", error.message.c_str(), error.code);
spdlog::get("ui")->error("Keychain error reading token: {} ({})", error.message, error.code);
}
#else
SMSTR("discord", "token", DiscordToken);
AddSetting("discord", "token", "", &Settings::DiscordToken);
#endif
}
void SettingsManager::HandleWriteToken() {
#ifdef WITH_KEYCHAIN
keychain::Error error {};
keychain::setPassword(KeychainPackage, KeychainService, KeychainUser, m_settings.DiscordToken, error);
if (error) {
spdlog::get("ui")->error("Keychain error setting token: {}", error.message);
}
#endif
// else it will get enumerated over as part of definitions
}
void SettingsManager::DefineSettings() {
using namespace std::string_literals;
AddSetting("discord", "api_base", "https://discord.com/api/v9"s, &Settings::APIBaseURL);
AddSetting("discord", "gateway", "wss://gateway.discord.gg/?v=9&encoding=json&compress=zlib-stream"s, &Settings::GatewayURL);
AddSetting("discord", "memory_db", false, &Settings::UseMemoryDB);
AddSetting("discord", "prefetch", false, &Settings::Prefetch);
AddSetting("discord", "autoconnect", false, &Settings::Autoconnect);
AddSetting("gui", "css", "main.css"s, &Settings::MainCSS);
AddSetting("gui", "animated_guild_hover_only", true, &Settings::AnimatedGuildHoverOnly);
AddSetting("gui", "animations", true, &Settings::ShowAnimations);
AddSetting("gui", "custom_emojis", true, &Settings::ShowCustomEmojis);
AddSetting("gui", "owner_crown", true, &Settings::ShowOwnerCrown);
AddSetting("gui", "save_state", true, &Settings::SaveState);
AddSetting("gui", "stock_emojis", false, &Settings::ShowStockEmojis);
AddSetting("gui", "unreads", true, &Settings::Unreads);
AddSetting("gui", "alt_menu", false, &Settings::AltMenu);
AddSetting("gui", "hide_to_try", false, &Settings::HideToTray);
AddSetting("gui", "show_deleted_indicator", true, &Settings::ShowDeletedIndicator);
AddSetting("gui", "font_scale", -1.0, &Settings::FontScale);
AddSetting("http", "concurrent", 20, &Settings::CacheHTTPConcurrency);
AddSetting("http", "user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36"s, &Settings::UserAgent);
AddSetting("style", "expandercolor", "rgba(255, 83, 112, 0)"s, &Settings::ChannelsExpanderColor);
AddSetting("style", "nsfwchannelcolor", "#970d0d"s, &Settings::NSFWChannelColor);
AddSetting("style", "mentionbadgecolor", "rgba(184, 37, 37, 0)"s, &Settings::MentionBadgeColor);
AddSetting("style", "mentionbadgetextcolor", "rgba(251, 251, 251, 0)"s, &Settings::MentionBadgeTextColor);
AddSetting("style", "unreadcolor", "rgba(255, 255, 255, 0)"s, &Settings::UnreadIndicatorColor);
#ifdef _WIN32
AddSetting("notifications", "enabled", false, &Settings::NotificationsEnabled);
AddSetting("notifications", "playsound", false, &Settings::NotificationsPlaySound);
AddSetting("windows", "hideconsole", false, &Settings::HideConsole);
#else
AddSetting("notifications", "enabled", true, &Settings::NotificationsEnabled);
AddSetting("notifications", "playsound", true, &Settings::NotificationsPlaySound);
#endif
#undef SMBOOL
#undef SMSTR
#undef SMINT
#undef SMFLT
#ifdef WITH_RNNOISE
AddSetting("voice", "vad", "rnnoise"s, &Settings::VAD);
#else
AddSetting("voice", "vad", "gate", &Settings::VAD);
#endif
HandleReadToken();
}
void SettingsManager::ReadSettings() {
for (auto &[k, setting] : m_definitions) {
switch (setting.Type) {
case SettingDefinition::TypeString:
try {
m_settings.*(setting.Ptr.String) = m_file.get_string(setting.Section, setting.Name);
} catch (...) {}
break;
case SettingDefinition::TypeBool:
try {
m_settings.*(setting.Ptr.Bool) = m_file.get_boolean(setting.Section, setting.Name);
} catch (...) {}
break;
case SettingDefinition::TypeDouble:
try {
m_settings.*(setting.Ptr.Double) = m_file.get_double(setting.Section, setting.Name);
} catch (...) {}
break;
case SettingDefinition::TypeInt:
try {
m_settings.*(setting.Ptr.Int) = m_file.get_integer(setting.Section, setting.Name);
} catch (...) {}
break;
}
}
m_read_settings = m_settings;
}
@ -121,72 +161,39 @@ SettingsManager::Settings &SettingsManager::GetSettings() {
void SettingsManager::Close() {
if (m_ok) {
// save anything that changed
// (futureproofing since only DiscordToken can actually change)
#define SMSTR(section, key, var) \
if (m_settings.var != m_read_settings.var) \
m_file.set_string(section, key, m_settings.var);
#define SMBOOL(section, key, var) \
if (m_settings.var != m_read_settings.var) \
m_file.set_boolean(section, key, m_settings.var);
#define SMINT(section, key, var) \
if (m_settings.var != m_read_settings.var) \
m_file.set_integer(section, key, m_settings.var);
#define SMFLT(section, key, var) \
if (m_settings.var != m_read_settings.var) \
m_file.set_double(section, key, m_settings.var);
SMSTR("discord", "api_base", APIBaseURL);
SMSTR("discord", "gateway", GatewayURL);
SMBOOL("discord", "memory_db", UseMemoryDB);
SMBOOL("discord", "prefetch", Prefetch);
SMBOOL("discord", "autoconnect", Autoconnect);
SMSTR("gui", "css", MainCSS);
SMBOOL("gui", "animated_guild_hover_only", AnimatedGuildHoverOnly);
SMBOOL("gui", "animations", ShowAnimations);
SMBOOL("gui", "custom_emojis", ShowCustomEmojis);
SMBOOL("gui", "member_list_discriminator", ShowMemberListDiscriminators);
SMBOOL("gui", "owner_crown", ShowOwnerCrown);
SMBOOL("gui", "save_state", SaveState);
SMBOOL("gui", "stock_emojis", ShowStockEmojis);
SMBOOL("gui", "unreads", Unreads);
SMBOOL("gui", "alt_menu", AltMenu);
SMBOOL("gui", "hide_to_tray", HideToTray);
SMBOOL("gui", "show_deleted_indicator", ShowDeletedIndicator);
SMFLT("gui", "font_scale", FontScale);
SMINT("http", "concurrent", CacheHTTPConcurrency);
SMSTR("http", "user_agent", UserAgent);
SMSTR("style", "expandercolor", ChannelsExpanderColor);
SMSTR("style", "nsfwchannelcolor", NSFWChannelColor);
SMSTR("style", "mentionbadgecolor", MentionBadgeColor);
SMSTR("style", "mentionbadgetextcolor", MentionBadgeTextColor);
SMSTR("style", "unreadcolor", UnreadIndicatorColor);
SMBOOL("notifications", "enabled", NotificationsEnabled);
SMBOOL("notifications", "playsound", NotificationsPlaySound);
SMSTR("voice", "vad", VAD);
SMBOOL("windows", "hideconsole", HideConsole);
#ifdef WITH_KEYCHAIN
keychain::Error error {};
keychain::setPassword(KeychainPackage, KeychainService, KeychainUser, m_settings.DiscordToken, error);
if (error) {
printf("keychain error setting token: %s\n", error.message.c_str());
for (auto &[k, setting] : m_definitions) {
switch (setting.Type) {
case SettingDefinition::TypeString:
if (m_settings.*(setting.Ptr.String) != m_read_settings.*(setting.Ptr.String)) {
m_file.set_string(setting.Section, setting.Name, m_settings.*(setting.Ptr.String));
}
break;
case SettingDefinition::TypeBool:
if (m_settings.*(setting.Ptr.Bool) != m_read_settings.*(setting.Ptr.Bool)) {
m_file.set_boolean(setting.Section, setting.Name, m_settings.*(setting.Ptr.Bool));
}
break;
case SettingDefinition::TypeDouble:
if (m_settings.*(setting.Ptr.Double) != m_read_settings.*(setting.Ptr.Double)) {
m_file.set_double(setting.Section, setting.Name, m_settings.*(setting.Ptr.Double));
}
break;
case SettingDefinition::TypeInt:
if (m_settings.*(setting.Ptr.Int) != m_read_settings.*(setting.Ptr.Int)) {
m_file.set_integer(setting.Section, setting.Name, m_settings.*(setting.Ptr.Int));
}
break;
}
}
#else
SMSTR("discord", "token", DiscordToken);
#endif
#undef SMSTR
#undef SMBOOL
#undef SMINT
#undef SMFLT
HandleWriteToken();
try {
if (!m_file.save_to_file(m_filename))
fputs("failed to save settings KeyFile", stderr);
if (!m_file.save_to_file(m_filename)) {
spdlog::get("ui")->error("Failed to save settings KeyFile");
}
} catch (const Glib::Error &e) {
fprintf(stderr, "failed to save settings KeyFile: %s\n", e.what().c_str());
spdlog::get("ui")->error("Failed to save settings Keyfile: {}", e.what().c_str());
}
}
}
}

View File

@ -7,61 +7,47 @@ class SettingsManager {
public:
struct Settings {
// [discord]
std::string APIBaseURL { "https://discord.com/api/v9" };
std::string GatewayURL { "wss://gateway.discord.gg/?v=9&encoding=json&compress=zlib-stream" };
std::string APIBaseURL;
std::string GatewayURL;
std::string DiscordToken;
bool UseMemoryDB { false };
bool Prefetch { false };
bool Autoconnect { false };
bool UseMemoryDB;
bool Prefetch;
bool Autoconnect;
// [gui]
std::string MainCSS { "main.css" };
bool AnimatedGuildHoverOnly { true };
bool ShowAnimations { true };
bool ShowCustomEmojis { true };
bool ShowMemberListDiscriminators { true };
bool ShowOwnerCrown { true };
bool SaveState { true };
#ifdef _WIN32
bool ShowStockEmojis { false };
#else
bool ShowStockEmojis { true };
#endif
bool Unreads { true };
bool AltMenu { false };
bool HideToTray { false };
bool ShowDeletedIndicator { true };
double FontScale { -1.0 };
std::string MainCSS;
bool AnimatedGuildHoverOnly;
bool ShowAnimations;
bool ShowCustomEmojis;
bool ShowOwnerCrown;
bool SaveState;
bool ShowStockEmojis;
bool Unreads;
bool AltMenu;
bool HideToTray;
bool ShowDeletedIndicator;
double FontScale;
// [http]
int CacheHTTPConcurrency { 20 };
std::string UserAgent { "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36" };
int CacheHTTPConcurrency;
std::string UserAgent;
// [style]
std::string ChannelsExpanderColor { "rgba(255, 83, 112, 0)" };
std::string NSFWChannelColor { "#970d0d" };
std::string MentionBadgeColor { "rgba(184, 37, 37, 0)" };
std::string MentionBadgeTextColor { "rgba(251, 251, 251, 0)" };
std::string UnreadIndicatorColor { "rgba(255, 255, 255, 0)" };
std::string ChannelsExpanderColor;
std::string NSFWChannelColor;
std::string MentionBadgeColor;
std::string MentionBadgeTextColor;
std::string UnreadIndicatorColor;
// [notifications]
#ifdef _WIN32
bool NotificationsEnabled { false };
bool NotificationsPlaySound { false };
#else
bool NotificationsEnabled { true };
bool NotificationsPlaySound { true };
#endif
bool NotificationsEnabled;
bool NotificationsPlaySound;
// [voice]
#ifdef WITH_RNNOISE
std::string VAD { "rnnoise" };
#else
std::string VAD { "gate" };
#endif
std::string VAD;
// [windows]
bool HideConsole { false };
bool HideConsole;
};
SettingsManager(const std::string &filename);
@ -71,8 +57,62 @@ public:
Settings &GetSettings();
private:
void HandleReadToken();
void HandleWriteToken();
void DefineSettings();
void ReadSettings();
// a little weird because i dont want to have to change every line where settings are used
// why this way: i dont want to have to define a setting in multiple places and the old way was ugly
struct SettingDefinition {
using StringPtr = std::string Settings::*;
using BoolPtr = bool Settings::*;
using DoublePtr = double Settings::*;
using IntPtr = int Settings::*;
std::string Section;
std::string Name;
enum SettingType {
TypeString,
TypeBool,
TypeDouble,
TypeInt,
} Type;
union {
StringPtr String;
BoolPtr Bool;
DoublePtr Double;
IntPtr Int;
} Ptr;
};
std::unordered_map<std::string, SettingDefinition> m_definitions;
template<typename FieldType>
void AddSetting(const char *section, const char *name, FieldType default_value, FieldType Settings::*ptr) {
m_settings.*ptr = default_value;
SettingDefinition definition;
definition.Section = section;
definition.Name = name;
if constexpr (std::is_same<FieldType, std::string>::value) {
definition.Type = SettingDefinition::TypeString;
definition.Ptr.String = ptr;
} else if constexpr (std::is_same<FieldType, bool>::value) {
definition.Type = SettingDefinition::TypeBool;
definition.Ptr.Bool = ptr;
} else if constexpr (std::is_same<FieldType, double>::value) {
definition.Type = SettingDefinition::TypeDouble;
definition.Ptr.Double = ptr;
} else if constexpr (std::is_same<FieldType, int>::value) {
definition.Type = SettingDefinition::TypeInt;
definition.Ptr.Int = ptr;
}
m_definitions[name] = definition;
}
bool m_ok;
std::string m_filename;
Glib::KeyFile m_file;