From 66cc4b3cc7c7170bd7ff0347ed377d317dcdce91 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sun, 6 Sep 2020 21:28:07 -0400 Subject: [PATCH] refactor (store) --- Abaddon.vcxproj | 2 + Abaddon.vcxproj.filters | 6 ++ abaddon.cpp | 16 +--- components/channels.cpp | 29 +++---- components/channels.hpp | 4 +- discord/discord.cpp | 165 ++++++++++++++-------------------------- discord/discord.hpp | 51 +++++-------- discord/store.cpp | 86 +++++++++++++++++++++ discord/store.hpp | 45 +++++++++++ 9 files changed, 233 insertions(+), 171 deletions(-) create mode 100644 discord/store.cpp create mode 100644 discord/store.hpp diff --git a/Abaddon.vcxproj b/Abaddon.vcxproj index ca01a0f..afe6d28 100644 --- a/Abaddon.vcxproj +++ b/Abaddon.vcxproj @@ -153,6 +153,7 @@ + @@ -168,6 +169,7 @@ + diff --git a/Abaddon.vcxproj.filters b/Abaddon.vcxproj.filters index c361054..917577c 100644 --- a/Abaddon.vcxproj.filters +++ b/Abaddon.vcxproj.filters @@ -54,6 +54,9 @@ Source Files + + Source Files + @@ -98,5 +101,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/abaddon.cpp b/abaddon.cpp index b389b20..706e315 100644 --- a/abaddon.cpp +++ b/abaddon.cpp @@ -134,7 +134,7 @@ void Abaddon::ActionMoveGuildUp(Snowflake id) { // get iter to target decltype(order)::iterator target_iter; for (auto it = order.begin(); it != order.end(); it++) { - if (it->first == id) { + if (*it == id) { target_iter = it; break; } @@ -143,11 +143,7 @@ void Abaddon::ActionMoveGuildUp(Snowflake id) { decltype(order)::iterator left = target_iter - 1; std::swap(*left, *target_iter); - std::vector new_sort; - for (const auto &x : order) - new_sort.push_back(x.first); - - m_discord.UpdateSettingsGuildPositions(new_sort); + m_discord.UpdateSettingsGuildPositions(order); } void Abaddon::ActionMoveGuildDown(Snowflake id) { @@ -155,7 +151,7 @@ void Abaddon::ActionMoveGuildDown(Snowflake id) { // get iter to target decltype(order)::iterator target_iter; for (auto it = order.begin(); it != order.end(); it++) { - if (it->first == id) { + if (*it == id) { target_iter = it; break; } @@ -164,11 +160,7 @@ void Abaddon::ActionMoveGuildDown(Snowflake id) { decltype(order)::iterator right = target_iter + 1; std::swap(*right, *target_iter); - std::vector new_sort; - for (const auto &x : order) - new_sort.push_back(x.first); - - m_discord.UpdateSettingsGuildPositions(new_sort); + m_discord.UpdateSettingsGuildPositions(order); } void Abaddon::ActionCopyGuildID(Snowflake id) { diff --git a/components/channels.cpp b/components/channels.cpp index fcbe8ef..7982d1b 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -39,7 +39,7 @@ Gtk::Widget *ChannelList::GetRoot() const { return m_main; } -void ChannelList::SetListingFromGuilds(const DiscordClient::Guilds_t &guilds) { +void ChannelList::SetListingFromGuilds(const DiscordClient::guilds_type &guilds) { std::scoped_lock guard(m_update_mutex); m_update_queue.push(guilds); m_update_dispatcher.emit(); @@ -47,7 +47,7 @@ void ChannelList::SetListingFromGuilds(const DiscordClient::Guilds_t &guilds) { void ChannelList::ClearListing() { std::scoped_lock guard(m_update_mutex); - m_update_queue.push(DiscordClient::Guilds_t()); + m_update_queue.push(DiscordClient::guilds_type()); m_update_dispatcher.emit(); } @@ -138,10 +138,11 @@ void ChannelList::AddPrivateChannels() { } void ChannelList::SetListingFromGuildsInternal() { - DiscordClient::Guilds_t *guilds; + DiscordClient::guilds_type guilds; { std::scoped_lock guard(m_update_mutex); - guilds = &m_update_queue.front(); + guilds = m_update_queue.front(); + m_update_queue.pop(); } auto children = m_list->get_children(); @@ -154,19 +155,13 @@ void ChannelList::SetListingFromGuildsInternal() { m_guild_count = 0; - if (guilds->empty()) { - std::scoped_lock guard(m_update_mutex); - m_update_queue.pop(); - return; - } - AddPrivateChannels(); // map each category to its channels std::unordered_map> cat_to_channels; std::unordered_map> orphan_channels; - for (const auto &[gid, guild] : *guilds) { + for (const auto &[gid, guild] : guilds) { for (const auto &chan : guild.Channels) { switch (chan.Type) { case ChannelType::GUILD_TEXT: { @@ -306,14 +301,10 @@ void ChannelList::SetListingFromGuildsInternal() { m_infos[guild_row] = std::move(info); }; - const auto &sorted_guilds = m_abaddon->GetDiscordClient().GetUserSortedGuilds(); - for (const auto &[id, guild] : sorted_guilds) { - add_guild(id, guild); - } - - { - std::scoped_lock guard(m_update_mutex); - m_update_queue.pop(); + const auto &discord = m_abaddon->GetDiscordClient(); + const auto &sorted_guilds = discord.GetUserSortedGuilds(); + for (const auto &id : sorted_guilds) { + add_guild(id, *discord.GetGuild(id)); } } diff --git a/components/channels.hpp b/components/channels.hpp index 83b242c..2747724 100644 --- a/components/channels.hpp +++ b/components/channels.hpp @@ -11,7 +11,7 @@ class ChannelList { public: ChannelList(); Gtk::Widget *GetRoot() const; - void SetListingFromGuilds(const DiscordClient::Guilds_t &guilds); + void SetListingFromGuilds(const DiscordClient::guilds_type &guilds); void ClearListing(); void SetAbaddon(Abaddon *ptr); @@ -50,7 +50,7 @@ protected: Glib::Dispatcher m_update_dispatcher; mutable std::mutex m_update_mutex; - std::queue m_update_queue; + std::queue m_update_queue; void AddPrivateChannels(); // retard moment void SetListingFromGuildsInternal(); void AttachMenuHandler(Gtk::ListBoxRow *row); diff --git a/discord/discord.cpp b/discord/discord.cpp index 11c429f..8f87950 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -14,9 +14,6 @@ void DiscordClient::SetAbaddon(Abaddon *ptr) { } void DiscordClient::Start() { - assert(!m_client_connected); - assert(!m_websocket.IsOpen()); - std::memset(&m_zstream, 0, sizeof(m_zstream)); inflateInit2(&m_zstream, MAX_WBITS + 32); @@ -26,7 +23,6 @@ void DiscordClient::Start() { } void DiscordClient::Stop() { - std::scoped_lock guard(m_mutex); if (!m_client_connected) return; inflateEnd(&m_zstream); @@ -34,61 +30,64 @@ void DiscordClient::Stop() { m_heartbeat_waiter.kill(); if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join(); m_client_connected = false; - m_websocket.Stop(); - m_guilds.clear(); + m_store.ClearAll(); + + m_websocket.Stop(); } bool DiscordClient::IsStarted() const { return m_client_connected; } -const DiscordClient::Guilds_t &DiscordClient::GetGuilds() const { - std::scoped_lock guard(m_mutex); - return m_guilds; +const Store::guilds_type &DiscordClient::GetGuilds() const { + return m_store.GetGuilds(); } const UserSettingsData &DiscordClient::GetUserSettings() const { - std::scoped_lock guard(m_mutex); - assert(m_ready_received); return m_user_settings; } const UserData &DiscordClient::GetUserData() const { - std::scoped_lock guard(m_mutex); - assert(m_ready_received); return m_user_data; } -std::vector> DiscordClient::GetUserSortedGuilds() const { - std::vector> sorted_guilds; +std::vector DiscordClient::GetUserSortedGuilds() const { + std::vector> sorted_guilds; if (m_user_settings.GuildPositions.size()) { std::unordered_set positioned_guilds(m_user_settings.GuildPositions.begin(), m_user_settings.GuildPositions.end()); // guilds not in the guild_positions object are at the top of the list, descending by guild ID std::set unpositioned_guilds; - for (const auto &[id, guild] : m_guilds) { + for (const auto &[id, guild] : m_store.GetGuilds()) { if (positioned_guilds.find(id) == positioned_guilds.end()) unpositioned_guilds.insert(id); } // unpositioned_guilds now has unpositioned guilds in ascending order - for (auto it = unpositioned_guilds.rbegin(); it != unpositioned_guilds.rend(); it++) - if (m_guilds.find(*it) != m_guilds.end()) - sorted_guilds.push_back(std::make_pair(*it, m_guilds.at(*it))); + for (auto it = unpositioned_guilds.rbegin(); it != unpositioned_guilds.rend(); it++) { + auto *data = m_store.GetGuild(*it); + if (data != nullptr) + sorted_guilds.push_back(std::make_pair(*it, data)); + } // now the rest go at the end in the order they are sorted for (const auto &id : m_user_settings.GuildPositions) { - if (m_guilds.find(id) != m_guilds.end()) - sorted_guilds.push_back(std::make_pair(id, m_guilds.at(id))); + auto *data = m_store.GetGuild(id); + if (data != nullptr) + sorted_guilds.push_back(std::make_pair(id, data)); } } else { // default sort is alphabetic - for (auto &it : m_guilds) - sorted_guilds.push_back(it); - AlphabeticalSort(sorted_guilds.begin(), sorted_guilds.end(), [](auto &pair) { return pair.second.Name; }); + for (auto &it : m_store.GetGuilds()) + sorted_guilds.push_back(std::make_pair(it.first, &it.second)); + AlphabeticalSort(sorted_guilds.begin(), sorted_guilds.end(), [](auto &pair) { return pair.second->Name; }); } - return sorted_guilds; + std::vector ret; + for (const auto &pair : sorted_guilds) + ret.push_back(pair.first); + + return ret; } std::set DiscordClient::GetMessagesForChannel(Snowflake id) const { @@ -97,14 +96,13 @@ std::set DiscordClient::GetMessagesForChannel(Snowflake id) const { return std::set(); std::set ret; - for (const auto &msg : it->second) - ret.insert(msg->ID); + for (const auto &msg_id : it->second) + ret.insert(m_store.GetMessage(msg_id)->ID); return ret; } void DiscordClient::UpdateSettingsGuildPositions(const std::vector &pos) { - assert(pos.size() == m_guilds.size()); nlohmann::json body; body["guild_positions"] = pos; m_http.MakePATCH("/users/@me/settings", body.dump(), [this, pos](const cpr::Response &r) { @@ -125,8 +123,9 @@ void DiscordClient::FetchMessagesInChannel(Snowflake id, std::functionsecond; - - return nullptr; + return m_store.GetUser(id); } const RoleData *DiscordClient::GetRole(Snowflake id) const { - if (m_roles.find(id) != m_roles.end()) - return &m_roles.at(id); + return m_store.GetRole(id); +} - return nullptr; +const GuildData *DiscordClient::GetGuild(Snowflake id) const { + return m_store.GetGuild(id); } Snowflake DiscordClient::GetMemberHoistedRole(Snowflake guild_id, Snowflake user_id, bool with_color) const { - auto *data = GetGuildMemberData(user_id, guild_id); + auto *data = m_store.GetGuildMemberData(guild_id, user_id); if (data == nullptr) return Snowflake::Invalid; std::vector roles; @@ -351,19 +342,19 @@ void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) { if (g.IsUnavailable) printf("guild (%lld) unavailable\n", g.ID); else { - StoreGuild(g.ID, g); + m_store.SetGuild(g.ID, g); for (auto &c : g.Channels) { c.GuildID = g.ID; - StoreChannel(c.ID, c); + m_store.SetChannel(c.ID, c); } for (auto &r : g.Roles) - StoreRole(r); + m_store.SetRole(r.ID, r); } } for (const auto &dm : data.PrivateChannels) { - StoreChannel(dm.ID, dm); + m_store.SetChannel(dm.ID, dm); } m_abaddon->DiscordNotifyReady(); @@ -373,8 +364,9 @@ void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) { void DiscordClient::HandleGatewayMessageCreate(const GatewayMessage &msg) { MessageData data = msg.Data; - StoreMessage(data.ID, data); - StoreUser(data.Author); + m_store.SetMessage(data.ID, data); + AddMessageToChannel(data.ID, data.ChannelID); + m_store.SetUser(data.Author.ID, data.Author); AddUserToGuild(data.Author.ID, data.GuildID); m_abaddon->DiscordNotifyMessageCreate(data.ID); } @@ -389,12 +381,14 @@ void DiscordClient::HandleGatewayMessageUpdate(const GatewayMessage &msg) { MessageData data; data.from_json_edited(msg.Data); - if (m_messages.find(data.ID) == m_messages.end()) return; + auto *current = m_store.GetMessage(data.ID); + if (current == nullptr) + return; - auto ¤t = m_messages.at(data.ID); - - if (data.Content != current.Content) { - current.Content = data.Content; + if (data.Content != current->Content) { + auto copy = *current; + copy.Content = data.Content; + m_store.SetMessage(copy.ID, copy); m_abaddon->DiscordNotifyMessageUpdateContent(data.ID, data.ChannelID); } } @@ -407,13 +401,9 @@ void DiscordClient::HandleGatewayGuildMemberListUpdate(const GatewayMessage &msg for (const auto &item : op.Items) { if (item->Type == "member") { auto member = static_cast(item.get()); - auto known = GetUser(member->User.ID); - if (known == nullptr) { - StoreUser(member->User); - known = GetUser(member->User.ID); - } + m_store.SetUser(member->User.ID, member->User); AddUserToGuild(member->User.ID, data.GuildID); - AddGuildMemberData(data.GuildID, member->User.ID, member->GetAsMemberData()); + m_store.SetGuildMemberData(data.GuildID, member->User.ID, member->GetAsMemberData()); } } } @@ -422,54 +412,18 @@ void DiscordClient::HandleGatewayGuildMemberListUpdate(const GatewayMessage &msg m_abaddon->DiscordNotifyGuildMemberListUpdate(data.GuildID); } -void DiscordClient::StoreGuild(Snowflake id, const GuildData &g) { - assert(id.IsValid() && id == g.ID); - m_guilds[id] = g; -} - -void DiscordClient::StoreMessage(Snowflake id, const MessageData &m) { - assert(id.IsValid()); - m_messages[id] = m; - auto it = m_chan_to_message_map.find(m.ChannelID); - if (it == m_chan_to_message_map.end()) - m_chan_to_message_map[m.ChannelID] = decltype(m_chan_to_message_map)::mapped_type(); - m_chan_to_message_map[m.ChannelID].insert(&m_messages[id]); -} - -void DiscordClient::StoreChannel(Snowflake id, const ChannelData &c) { - m_channels[id] = c; -} - -void DiscordClient::AddGuildMemberData(Snowflake guild_id, Snowflake user_id, const GuildMemberData &data) { - m_members[guild_id][user_id] = data; -} - -const GuildMemberData *DiscordClient::GetGuildMemberData(Snowflake user_id, Snowflake guild_id) const { - if (m_members.find(guild_id) == m_members.end()) - return nullptr; - - if (m_members.at(guild_id).find(user_id) == m_members.at(guild_id).end()) - return nullptr; - - return &m_members.at(guild_id).at(user_id); +void DiscordClient::AddMessageToChannel(Snowflake msg_id, Snowflake channel_id) { + m_chan_to_message_map[channel_id].insert(msg_id); } void DiscordClient::AddUserToGuild(Snowflake user_id, Snowflake guild_id) { m_guild_to_users[guild_id].insert(user_id); } -void DiscordClient::StoreUser(const UserData &u) { - m_users[u.ID] = u; -} - -void DiscordClient::StoreRole(const RoleData &r) { - m_roles[r.ID] = r; -} - std::set DiscordClient::GetPrivateChannels() const { auto ret = std::set(); - for (const auto &[id, chan] : m_channels) { + for (const auto &[id, chan] : m_store.GetChannels()) { if (chan.Type == ChannelType::DM || chan.Type == ChannelType::GROUP_DM) ret.insert(id); } @@ -496,7 +450,6 @@ void DiscordClient::HeartbeatThread() { } void DiscordClient::SendIdentify() { - assert(m_token.size()); IdentifyMessage msg; msg.Properties.OS = "OpenBSD"; msg.Properties.Device = GatewayIdentity; diff --git a/discord/discord.hpp b/discord/discord.hpp index f5aa07d..eb87f38 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -2,6 +2,7 @@ #include "websocket.hpp" #include "http.hpp" #include "objects.hpp" +#include "store.hpp" #include #include #include @@ -52,16 +53,17 @@ public: void Stop(); bool IsStarted() const; - using Channels_t = std::unordered_map; - using Guilds_t = std::unordered_map; - using Messages_t = std::unordered_map; - using Users_t = std::unordered_map; - using Roles_t = std::unordered_map; + using guilds_type = Store::guilds_type; + using channels_type = Store::channels_type; + using messages_type = Store::messages_type; + using users_type = Store::users_type; + using roles_type = Store::roles_type; + using members_type = Store::members_type; - const Guilds_t &GetGuilds() const; + const guilds_type &GetGuilds() const; const UserData &GetUserData() const; const UserSettingsData &GetUserSettings() const; - std::vector> GetUserSortedGuilds() const; + std::vector GetUserSortedGuilds() const; std::set GetMessagesForChannel(Snowflake id) const; std::set GetPrivateChannels() const; @@ -72,6 +74,7 @@ public: const ChannelData *GetChannel(Snowflake id) const; const UserData *GetUser(Snowflake id) const; const RoleData *GetRole(Snowflake id) const; + const GuildData *GetGuild(Snowflake id) const; Snowflake GetMemberHoistedRole(Snowflake guild_id, Snowflake user_id, bool with_color = false) const; std::unordered_set GetUsersInGuild(Snowflake id) const; @@ -99,46 +102,30 @@ private: bool CheckCode(const cpr::Response &r); - Abaddon *m_abaddon = nullptr; - HTTPClient m_http; - std::string m_token; - mutable std::mutex m_mutex; + void AddMessageToChannel(Snowflake msg_id, Snowflake channel_id); + std::unordered_map> m_chan_to_message_map; - void StoreGuild(Snowflake id, const GuildData &g); - Guilds_t m_guilds; - - void StoreMessage(Snowflake id, const MessageData &m); - Messages_t m_messages; - std::unordered_map> m_chan_to_message_map; - - void StoreChannel(Snowflake id, const ChannelData &c); - Channels_t m_channels; - - void AddGuildMemberData(Snowflake guild_id, Snowflake user_id, const GuildMemberData &data); - const GuildMemberData *GetGuildMemberData(Snowflake user_id, Snowflake guild_id) const; void AddUserToGuild(Snowflake user_id, Snowflake guild_id); - void StoreUser(const UserData &u); - Users_t m_users; std::unordered_map> m_guild_to_users; - std::unordered_map> m_members; - - void StoreRole(const RoleData &r); - Roles_t m_roles; UserData m_user_data; UserSettingsData m_user_settings; + Abaddon *m_abaddon = nullptr; + Store m_store; + HTTPClient m_http; Websocket m_websocket; std::atomic m_client_connected = false; std::atomic m_ready_received = false; + std::unordered_map m_event_map; void LoadEventMap(); std::thread m_heartbeat_thread; - int m_last_sequence = -1; - int m_heartbeat_msec = 0; + std::atomic m_last_sequence = -1; + std::atomic m_heartbeat_msec = 0; HeartbeatWaiter m_heartbeat_waiter; - bool m_heartbeat_acked = true; + std::atomic m_heartbeat_acked = true; }; diff --git a/discord/store.cpp b/discord/store.cpp new file mode 100644 index 0000000..454e1b9 --- /dev/null +++ b/discord/store.cpp @@ -0,0 +1,86 @@ +#include "store.hpp" + +void Store::SetUser(Snowflake id, const UserData &user) { + m_users[id] = user; +} + +void Store::SetChannel(Snowflake id, const ChannelData &channel) { + m_channels[id] = channel; +} + +void Store::SetGuild(Snowflake id, const GuildData &guild) { + m_guilds[id] = guild; +} + +void Store::SetRole(Snowflake id, const RoleData &role) { + m_roles[id] = role; +} + +void Store::SetMessage(Snowflake id, const MessageData &message) { + m_messages[id] = message; +} + +void Store::SetGuildMemberData(Snowflake guild_id, Snowflake user_id, const GuildMemberData &data) { + m_members[guild_id][user_id] = data; +} + +const UserData *Store::GetUser(Snowflake id) const { + auto it = m_users.find(id); + if (it == m_users.end()) + return nullptr; + return &it->second; +} + +const ChannelData *Store::GetChannel(Snowflake id) const { + auto it = m_channels.find(id); + if (it == m_channels.end()) + return nullptr; + return &it->second; +} + +const GuildData *Store::GetGuild(Snowflake id) const { + auto it = m_guilds.find(id); + if (it == m_guilds.end()) + return nullptr; + return &it->second; +} + +const RoleData *Store::GetRole(Snowflake id) const { + auto it = m_roles.find(id); + if (it == m_roles.end()) + return nullptr; + return &it->second; +} + +const MessageData *Store::GetMessage(Snowflake id) const { + auto it = m_messages.find(id); + if (it == m_messages.end()) + return nullptr; + return &it->second; +} + +const GuildMemberData *Store::GetGuildMemberData(Snowflake guild_id, Snowflake user_id) const { + auto git = m_members.find(guild_id); + if (git == m_members.end()) + return nullptr; + auto mit = git->second.find(user_id); + if (mit == git->second.end()) + return nullptr; + return &mit->second; +} + +const Store::channels_type &Store::GetChannels() const { + return m_channels; +} + +const Store::guilds_type &Store::GetGuilds() const { + return m_guilds; +} + +void Store::ClearAll() { + m_channels.clear(); + m_guilds.clear(); + m_messages.clear(); + m_roles.clear(); + m_users.clear(); +} diff --git a/discord/store.hpp b/discord/store.hpp new file mode 100644 index 0000000..c0cbf40 --- /dev/null +++ b/discord/store.hpp @@ -0,0 +1,45 @@ +#pragma once +#include "objects.hpp" +#include +#include + +#ifdef GetMessage // fuck you windows.h + #undef GetMessage +#endif + +class Store { +public: + void SetUser(Snowflake id, const UserData &user); + void SetChannel(Snowflake id, const ChannelData &channel); + void SetGuild(Snowflake id, const GuildData &guild); + void SetRole(Snowflake id, const RoleData &role); + void SetMessage(Snowflake id, const MessageData &message); + void SetGuildMemberData(Snowflake guild_id, Snowflake user_id, const GuildMemberData &data); + + const UserData *GetUser(Snowflake id) const; + const ChannelData *GetChannel(Snowflake id) const; + const GuildData *GetGuild(Snowflake id) const; + const RoleData *GetRole(Snowflake id) const; + const MessageData *GetMessage(Snowflake id) const; + const GuildMemberData *GetGuildMemberData(Snowflake guild_id, Snowflake user_id) const; + + using users_type = std::unordered_map; + using channels_type = std::unordered_map; + using guilds_type = std::unordered_map; + using roles_type = std::unordered_map; + using messages_type = std::unordered_map; + using members_type = std::unordered_map>; + + const channels_type &GetChannels() const; + const guilds_type &GetGuilds() const; + + void ClearAll(); + +private: + users_type m_users; + channels_type m_channels; + guilds_type m_guilds; + roles_type m_roles; + messages_type m_messages; + members_type m_members; +};