mirror of
https://github.com/uowuo/abaddon.git
synced 2025-03-04 03:03:16 -05:00
Merge pull request #260 from uowuo/settings
Refactor settings implementation
This commit is contained in:
commit
c45c090d84
@ -280,6 +280,7 @@ For example, memory_db would be set by adding `memory_db = true` under the line
|
||||
| `token` | string | | Discord token used to login, this can be set from the menu |
|
||||
| `prefetch` | boolean | false | if true, new messages will cause the avatar and image attachments to be automatically downloaded |
|
||||
| `autoconnect` | boolean | false | autoconnect to discord |
|
||||
| `keychain` | boolean | true | store token in system keychain (if compiled with support) |
|
||||
|
||||
#### http
|
||||
|
||||
|
260
src/settings.cpp
260
src/settings.cpp
@ -22,91 +22,134 @@ SettingsManager::SettingsManager(const std::string &filename)
|
||||
try {
|
||||
m_ok = m_file.load_from_file(m_filename, Glib::KEY_FILE_KEEP_COMMENTS);
|
||||
} catch (const Glib::Error &e) {
|
||||
fprintf(stderr, "error opening settings KeyFile: %s\n", e.what().c_str());
|
||||
spdlog::get("ui")->error("Error opening settings KeyFile: {}", e.what().c_str());
|
||||
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);
|
||||
|
||||
// semi-misleading name... only handles keychain (token is a normal setting)
|
||||
// DONT call AddSetting here
|
||||
void SettingsManager::HandleReadToken() {
|
||||
#ifdef WITH_KEYCHAIN
|
||||
keychain::Error error {};
|
||||
using namespace std::string_literals;
|
||||
|
||||
// convert to keychain if present in normal settings
|
||||
SMSTR("discord", "token", DiscordToken);
|
||||
if (!m_settings.UseKeychain) return;
|
||||
|
||||
if (!m_settings.DiscordToken.empty()) {
|
||||
keychain::Error set_error {};
|
||||
// Move to keychain if present in .ini
|
||||
std::string token = m_settings.DiscordToken;
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SettingsManager::HandleWriteToken() {
|
||||
#ifdef WITH_KEYCHAIN
|
||||
if (m_settings.UseKeychain) {
|
||||
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", "token", ""s, &Settings::DiscordToken);
|
||||
AddSetting("discord", "memory_db", false, &Settings::UseMemoryDB);
|
||||
AddSetting("discord", "prefetch", false, &Settings::Prefetch);
|
||||
AddSetting("discord", "autoconnect", false, &Settings::Autoconnect);
|
||||
AddSetting("discord", "keychain", true, &Settings::UseKeychain);
|
||||
|
||||
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
|
||||
SMSTR("discord", "token", DiscordToken);
|
||||
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"s, &Settings::VAD);
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
HandleReadToken();
|
||||
|
||||
m_read_settings = m_settings;
|
||||
}
|
||||
@ -121,72 +164,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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
125
src/settings.hpp
125
src/settings.hpp
@ -7,61 +7,48 @@ 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;
|
||||
bool UseKeychain;
|
||||
|
||||
// [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 +58,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;
|
||||
|
Loading…
Reference in New Issue
Block a user