diff --git a/abaddon.cpp b/abaddon.cpp index f0d94e4..2d57ea0 100644 --- a/abaddon.cpp +++ b/abaddon.cpp @@ -382,8 +382,8 @@ void Abaddon::ActionInsertMention(Snowflake id) { void Abaddon::ActionLeaveGuild(Snowflake id) { ConfirmDialog dlg(*m_main_window); - const auto *guild = m_discord.GetGuild(id); - if (guild != nullptr) + const auto guild = m_discord.GetGuild(id); + if (guild.has_value()) dlg.SetConfirmText("Are you sure you want to leave " + guild->Name + "?"); auto response = dlg.run(); if (response == Gtk::RESPONSE_OK) diff --git a/components/channels.cpp b/components/channels.cpp index 93b9015..a192159 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -283,11 +283,11 @@ void ChannelList::UpdateRemoveChannel(Snowflake id) { // this is total shit void ChannelList::UpdateChannelCategory(Snowflake id) { const auto *data = Abaddon::Get().GetDiscordClient().GetChannel(id); - const auto *guild = Abaddon::Get().GetDiscordClient().GetGuild(data->GuildID); + const auto guild = Abaddon::Get().GetDiscordClient().GetGuild(data->GuildID); auto git = m_guild_id_to_row.find(data->GuildID); if (git == m_guild_id_to_row.end()) return; auto *guild_row = git->second; - if (data == nullptr || guild == nullptr) return; + if (data == nullptr || !guild.has_value()) return; auto it = m_id_to_row.find(id); if (it == m_id_to_row.end()) return; auto row = dynamic_cast(it->second); @@ -343,7 +343,7 @@ void ChannelList::UpdateChannelCategory(Snowflake id) { // so is this void ChannelList::UpdateChannel(Snowflake id) { const auto *data = Abaddon::Get().GetDiscordClient().GetChannel(id); - const auto *guild = Abaddon::Get().GetDiscordClient().GetGuild(data->GuildID); + const auto guild = Abaddon::Get().GetDiscordClient().GetGuild(data->GuildID); const auto *guild_row = m_guild_id_to_row.at(data->GuildID); if (data->Type == ChannelType::GUILD_CATEGORY) { UpdateChannelCategory(id); @@ -402,7 +402,7 @@ void ChannelList::UpdateCreateChannel(Snowflake id) { UpdateCreateDMChannel(id); return; } - const auto *guild = discord.GetGuild(data->GuildID); + const auto guild = discord.GetGuild(data->GuildID); auto *guild_row = m_guild_id_to_row.at(data->GuildID); int pos = guild_row->get_index() + 1; @@ -437,8 +437,8 @@ void ChannelList::UpdateCreateChannel(Snowflake id) { void ChannelList::UpdateGuild(Snowflake id) { // the only thing changed is the row containing the guild item so just recreate it - const auto *data = Abaddon::Get().GetDiscordClient().GetGuild(id); - if (data == nullptr) return; + const auto data = Abaddon::Get().GetDiscordClient().GetGuild(id); + if (!data.has_value()) return; auto it = m_guild_id_to_row.find(id); if (it == m_guild_id_to_row.end()) return; auto *row = dynamic_cast(it->second); @@ -447,7 +447,7 @@ void ChannelList::UpdateGuild(Snowflake id) { const bool old_collapsed = row->IsUserCollapsed; const bool old_gindex = row->GuildIndex; delete row; - auto *new_row = Gtk::manage(new ChannelListRowGuild(data)); + auto *new_row = Gtk::manage(new ChannelListRowGuild(&*data)); new_row->IsUserCollapsed = old_collapsed; new_row->GuildIndex = old_gindex; m_guild_id_to_row[new_row->ID] = new_row; @@ -523,21 +523,24 @@ void ChannelList::InsertGuildAt(Snowflake id, int pos) { }; const auto &discord = Abaddon::Get().GetDiscordClient(); - const auto *guild_data = discord.GetGuild(id); - if (guild_data == nullptr) return; + const auto guild_data = discord.GetGuild(id); + if (!guild_data.has_value()) return; std::map orphan_channels; std::unordered_map> cat_to_channels; - for (const auto &channel : guild_data->Channels) { - if (channel.Type != ChannelType::GUILD_TEXT && channel.Type != ChannelType::GUILD_NEWS) continue; + if (guild_data->Channels.has_value()) + for (const auto &dc : *guild_data->Channels) { + const auto channel = discord.GetChannel(dc.ID); + if (channel == nullptr) continue; + if (channel->Type != ChannelType::GUILD_TEXT && channel->Type != ChannelType::GUILD_NEWS) continue; - if (channel.ParentID.IsValid()) - cat_to_channels[channel.ParentID].push_back(&channel); - else - orphan_channels[channel.Position] = &channel; - } + if (channel->ParentID.IsValid()) + cat_to_channels[channel->ParentID].push_back(&*channel); + else + orphan_channels[channel->Position] = &*channel; + } - auto *guild_row = Gtk::manage(new ChannelListRowGuild(guild_data)); + auto *guild_row = Gtk::manage(new ChannelListRowGuild(&*guild_data)); guild_row->show_all(); guild_row->IsUserCollapsed = true; guild_row->GuildIndex = m_guild_count++; @@ -558,9 +561,13 @@ void ChannelList::InsertGuildAt(Snowflake id, int pos) { // categories std::map> sorted_categories; - for (const auto &channel : guild_data->Channels) - if (channel.Type == ChannelType::GUILD_CATEGORY) - sorted_categories[channel.Position].push_back(&channel); + if (guild_data->Channels.has_value()) + for (const auto &dc : *guild_data->Channels) { + const auto channel = discord.GetChannel(dc.ID); + if (channel == nullptr) continue; + if (channel->Type == ChannelType::GUILD_CATEGORY) + sorted_categories[channel->Position].push_back(&*channel); + } for (auto &[pos, catvec] : sorted_categories) { std::sort(catvec.begin(), catvec.end(), [](const Channel *a, const Channel *b) { return a->ID < b->ID; }); @@ -619,7 +626,7 @@ void ChannelList::AddPrivateChannels() { } void ChannelList::UpdateListingInternal() { - std::unordered_set guilds = Abaddon::Get().GetDiscordClient().GetGuildsID(); + std::unordered_set guilds = Abaddon::Get().GetDiscordClient().GetGuilds(); auto children = m_list->get_children(); auto it = children.begin(); diff --git a/discord/discord.cpp b/discord/discord.cpp index ad68761..50446a7 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -52,22 +52,14 @@ bool DiscordClient::IsStoreValid() const { return m_store.IsValid(); } -std::unordered_set DiscordClient::GetGuildsID() const { - const auto &guilds = m_store.GetGuilds(); - std::unordered_set ret; - for (const auto &[gid, data] : guilds) - ret.insert(gid); - return ret; -} - -const Store::guilds_type &DiscordClient::GetGuilds() const { - return m_store.GetGuilds(); -} - const UserSettings &DiscordClient::GetUserSettings() const { return m_user_settings; } +std::unordered_set DiscordClient::GetGuilds() const { + return m_store.GetGuilds(); +} + const User &DiscordClient::GetUserData() const { return m_user_data; } @@ -76,7 +68,7 @@ std::vector DiscordClient::GetUserSortedGuilds() const { // sort order is unfolder'd guilds sorted by id descending, then guilds in folders in array order // todo: make sure folder'd guilds are sorted properly std::vector folder_order; - auto guilds = GetGuildsID(); + auto guilds = GetGuilds(); for (const auto &entry : m_user_settings.GuildFolders) { // can contain guilds not a part of for (const auto &id : entry.GuildIDs) { if (std::find(guilds.begin(), guilds.end(), id) != guilds.end()) @@ -181,7 +173,7 @@ std::optional DiscordClient::GetRole(Snowflake id) const { return m_store.GetRole(id); } -const Guild *DiscordClient::GetGuild(Snowflake id) const { +std::optional DiscordClient::GetGuild(Snowflake id) const { return m_store.GetGuild(id); } @@ -264,8 +256,8 @@ bool DiscordClient::HasChannelPermission(Snowflake user_id, Snowflake channel_id Permission DiscordClient::ComputePermissions(Snowflake member_id, Snowflake guild_id) const { const auto member = GetMember(member_id, guild_id); - const auto *guild = GetGuild(guild_id); - if (!member.has_value() || guild == nullptr) + const auto guild = GetGuild(guild_id); + if (!member.has_value() || !guild.has_value()) return Permission::NONE; if (guild->OwnerID == member_id) @@ -327,8 +319,8 @@ Permission DiscordClient::ComputeOverwrites(Permission base, Snowflake member_id } bool DiscordClient::CanManageMember(Snowflake guild_id, Snowflake actor, Snowflake target) const { - const auto *guild = GetGuild(guild_id); - if (guild != nullptr && guild->OwnerID == target) return false; + const auto guild = GetGuild(guild_id); + if (guild.has_value() && guild->OwnerID == target) return false; const auto actor_highest_id = GetMemberHighestRole(guild_id, actor); const auto target_highest_id = GetMemberHighestRole(guild_id, target); const auto actor_highest = GetRole(actor_highest_id); @@ -582,14 +574,15 @@ void DiscordClient::ProcessNewGuild(Guild &guild) { m_store.BeginTransaction(); m_store.SetGuild(guild.ID, guild); - for (auto &c : guild.Channels) { - c.GuildID = guild.ID; - m_store.SetChannel(c.ID, c); - m_guild_to_channels[guild.ID].insert(c.ID); - for (auto &p : c.PermissionOverwrites) { - m_store.SetPermissionOverwrite(c.ID, p.ID, p); + if (guild.Channels.has_value()) + for (auto &c : *guild.Channels) { + c.GuildID = guild.ID; + m_store.SetChannel(c.ID, c); + m_guild_to_channels[guild.ID].insert(c.ID); + for (auto &p : c.PermissionOverwrites) { + m_store.SetPermissionOverwrite(c.ID, p.ID, p); + } } - } for (auto &r : guild.Roles) m_store.SetRole(r.ID, r); @@ -702,8 +695,8 @@ void DiscordClient::HandleGatewayChannelCreate(const GatewayMessage &msg) { void DiscordClient::HandleGatewayGuildUpdate(const GatewayMessage &msg) { Snowflake id = msg.Data.at("id"); - auto *current = m_store.GetGuild(id); - if (current == nullptr) return; + auto current = m_store.GetGuild(id); + if (!current.has_value()) return; current->update_from_json(msg.Data); m_signal_guild_update.emit(id); } @@ -780,16 +773,17 @@ void DiscordClient::HandleGatewayGuildDelete(const GatewayMessage &msg) { if (unavailable) printf("guild %llu became unavailable\n", static_cast(id)); - auto *guild = m_store.GetGuild(id); - if (guild == nullptr) { + const auto guild = m_store.GetGuild(id); + if (!guild.has_value()) { m_store.ClearGuild(id); m_signal_guild_delete.emit(id); return; } m_store.ClearGuild(id); - for (const auto &c : guild->Channels) - m_store.ClearChannel(c.ID); + if (guild->Channels.has_value()) + for (const auto &c : *guild->Channels) + m_store.ClearChannel(c.ID); m_signal_guild_delete.emit(id); } diff --git a/discord/discord.hpp b/discord/discord.hpp index 73eb46c..b915d8c 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -69,8 +69,7 @@ public: using members_type = Store::members_type; using permission_overwrites_type = Store::permission_overwrites_type; - std::unordered_set GetGuildsID() const; - const guilds_type &GetGuilds() const; + std::unordered_set GetGuilds() const; const User &GetUserData() const; const UserSettings &GetUserSettings() const; std::vector GetUserSortedGuilds() const; @@ -86,7 +85,7 @@ public: std::optional GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const; std::optional GetUser(Snowflake id) const; std::optional GetRole(Snowflake id) const; - const Guild *GetGuild(Snowflake id) const; + std::optional GetGuild(Snowflake id) const; std::optional GetMember(Snowflake user_id, Snowflake guild_id) const; Snowflake GetMemberHoistedRole(Snowflake guild_id, Snowflake user_id, bool with_color = false) const; Snowflake GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const; diff --git a/discord/guild.cpp b/discord/guild.cpp index 054a2c3..31b4dd6 100644 --- a/discord/guild.cpp +++ b/discord/guild.cpp @@ -56,10 +56,10 @@ void from_json(const nlohmann::json &j, Guild &m) { JS_O("max_video_channel_users", m.MaxVideoChannelUsers); JS_O("approximate_member_count", tmp); if (tmp.has_value()) - m.ApproximateMemberCount = std::stoull(*tmp); + m.ApproximateMemberCount = std::stol(*tmp); JS_O("approximate_presence_count", tmp); if (tmp.has_value()) - m.ApproximatePresenceCount = std::stoull(*tmp); + m.ApproximatePresenceCount = std::stol(*tmp); } void Guild::update_from_json(const nlohmann::json &j) { diff --git a/discord/guild.hpp b/discord/guild.hpp index f0edf3f..d0863d5 100644 --- a/discord/guild.hpp +++ b/discord/guild.hpp @@ -10,53 +10,53 @@ // a bot is apparently only supposed to receive the `id` and `unavailable` as false // but user tokens seem to get the full objects (minus users) struct Guild { - Snowflake ID; // - std::string Name; // - std::string Icon; // null - std::string Splash; // null - std::string DiscoverySplash; // opt, null (docs wrong) - bool IsOwner = false; // opt - Snowflake OwnerID; // - int Permissions = 0; // opt - std::string PermissionsNew; // opt - std::string VoiceRegion; // opt - Snowflake AFKChannelID; // null - int AFKTimeout; // - bool IsEmbedEnabled = false; // opt, deprecated - Snowflake EmbedChannelID; // opt, null, deprecated - int VerificationLevel; // - int DefaultMessageNotifications; // - int ExplicitContentFilter; // - std::vector Roles; // - std::vector Emojis; // - std::vector Features; // - int MFALevel; // - Snowflake ApplicationID; // null - bool IsWidgetEnabled = false; // opt - Snowflake WidgetChannelID; // opt, null - Snowflake SystemChannelID; // null - int SystemChannelFlags; // - Snowflake RulesChannelID; // null - std::string JoinedAt; // opt* - bool IsLarge = false; // opt* - bool IsUnavailable = false; // opt* - int MemberCount = 0; // opt* + Snowflake ID; + std::string Name; + std::string Icon; // null + std::string Splash; // null + std::optional DiscoverySplash; // null + std::optional IsOwner; + Snowflake OwnerID; + std::optional Permissions; + std::optional PermissionsNew; + std::optional VoiceRegion; + Snowflake AFKChannelID; // null + int AFKTimeout; + std::optional IsEmbedEnabled; // deprecated + std::optional EmbedChannelID; // null, deprecated + int VerificationLevel; + int DefaultMessageNotifications; + int ExplicitContentFilter; + std::vector Roles; // only access id + std::vector Emojis; // only access id + std::vector Features; + int MFALevel; + Snowflake ApplicationID; // null + std::optional IsWidgetEnabled; + std::optional WidgetChannelID; // null + Snowflake SystemChannelID; // null + int SystemChannelFlags; + Snowflake RulesChannelID; // null + std::optional JoinedAt; // * + std::optional IsLarge; // * + std::optional IsUnavailable; // * + std::optional MemberCount; // * // std::vector VoiceStates; // opt* // std::vector Members; // opt* - incomplete anyways - std::vector Channels; // opt* + std::optional> Channels; // * // std::vector Presences; // opt* - int MaxPresences = 0; // opt, null - int MaxMembers = 0; // opt - std::string VanityURL; // null - std::string Description; // null - std::string BannerHash; // null - int PremiumTier; // - int PremiumSubscriptionCount = 0; // opt - std::string PreferredLocale; // + std::optional MaxPresences; // null + std::optional MaxMembers; + std::string VanityURL; // null + std::string Description; // null + std::string BannerHash; // null + int PremiumTier; + std::optional PremiumSubscriptionCount; + std::string PreferredLocale; Snowflake PublicUpdatesChannelID; // null - int MaxVideoChannelUsers = 0; // opt - int ApproximateMemberCount = 0; // opt - int ApproximatePresenceCount = 0; // opt + std::optional MaxVideoChannelUsers; + std::optional ApproximateMemberCount; + std::optional ApproximatePresenceCount; // undocumented // std::map GuildHashes; diff --git a/discord/store.cpp b/discord/store.cpp index a0ba612..12f729f 100644 --- a/discord/store.cpp +++ b/discord/store.cpp @@ -76,7 +76,59 @@ void Store::SetChannel(Snowflake id, const Channel &channel) { } void Store::SetGuild(Snowflake id, const Guild &guild) { - m_guilds[id] = guild; + Bind(m_set_guild_stmt, 1, id); + Bind(m_set_guild_stmt, 2, guild.Name); + Bind(m_set_guild_stmt, 3, guild.Icon); + Bind(m_set_guild_stmt, 4, guild.Splash); + Bind(m_set_guild_stmt, 5, guild.IsOwner); + Bind(m_set_guild_stmt, 6, guild.OwnerID); + Bind(m_set_guild_stmt, 7, guild.PermissionsNew); + Bind(m_set_guild_stmt, 8, guild.VoiceRegion); + Bind(m_set_guild_stmt, 9, guild.AFKChannelID); + Bind(m_set_guild_stmt, 10, guild.AFKTimeout); + Bind(m_set_guild_stmt, 11, guild.VerificationLevel); + Bind(m_set_guild_stmt, 12, guild.DefaultMessageNotifications); + std::vector snowflakes; + for (const auto &x : guild.Roles) snowflakes.push_back(x.ID); + Bind(m_set_guild_stmt, 13, nlohmann::json(snowflakes).dump()); + snowflakes.clear(); + for (const auto &x : guild.Emojis) snowflakes.push_back(x.ID); + Bind(m_set_guild_stmt, 14, nlohmann::json(snowflakes).dump()); + Bind(m_set_guild_stmt, 15, nlohmann::json(guild.Features).dump()); + Bind(m_set_guild_stmt, 16, guild.MFALevel); + Bind(m_set_guild_stmt, 17, guild.ApplicationID); + Bind(m_set_guild_stmt, 18, guild.IsWidgetEnabled); + Bind(m_set_guild_stmt, 19, guild.WidgetChannelID); + Bind(m_set_guild_stmt, 20, guild.SystemChannelFlags); + Bind(m_set_guild_stmt, 21, guild.RulesChannelID); + Bind(m_set_guild_stmt, 22, guild.JoinedAt); + Bind(m_set_guild_stmt, 23, guild.IsLarge); + Bind(m_set_guild_stmt, 24, guild.IsUnavailable); + Bind(m_set_guild_stmt, 25, guild.MemberCount); + if (guild.Channels.has_value()) { + snowflakes.clear(); + for (const auto &x : *guild.Channels) snowflakes.push_back(x.ID); + Bind(m_set_guild_stmt, 26, nlohmann::json(snowflakes).dump()); + } else + Bind(m_set_guild_stmt, 26, "[]"s); + Bind(m_set_guild_stmt, 27, guild.MaxPresences); + Bind(m_set_guild_stmt, 28, guild.MaxMembers); + Bind(m_set_guild_stmt, 29, guild.VanityURL); + Bind(m_set_guild_stmt, 30, guild.Description); + Bind(m_set_guild_stmt, 31, guild.BannerHash); + Bind(m_set_guild_stmt, 32, guild.PremiumTier); + Bind(m_set_guild_stmt, 33, guild.PremiumSubscriptionCount); + Bind(m_set_guild_stmt, 34, guild.PreferredLocale); + Bind(m_set_guild_stmt, 35, guild.PublicUpdatesChannelID); + Bind(m_set_guild_stmt, 36, guild.MaxVideoChannelUsers); + Bind(m_set_guild_stmt, 37, guild.ApproximateMemberCount); + Bind(m_set_guild_stmt, 38, guild.ApproximatePresenceCount); + Bind(m_set_guild_stmt, 39, guild.IsLazy); + + if (!RunInsert(m_set_guild_stmt)) + fprintf(stderr, "guild insert failed: %s\n", sqlite3_errstr(m_db_err)); + + m_guilds.insert(id); } void Store::SetRole(Snowflake id, const Role &role) { @@ -150,7 +202,7 @@ void Store::SetGuildMember(Snowflake guild_id, Snowflake user_id, const GuildMem Bind(m_set_member_stmt, 6, data.PremiumSince); Bind(m_set_member_stmt, 7, data.IsDeafened); Bind(m_set_member_stmt, 8, data.IsMuted); - + if (!RunInsert(m_set_member_stmt)) fprintf(stderr, "member insert failed: %s\n", sqlite3_errstr(m_db_err)); } @@ -216,6 +268,70 @@ std::optional Store::GetEmoji(Snowflake id) const { return ret; } +std::optional Store::GetGuild(Snowflake id) const { + Bind(m_get_guild_stmt, 1, id); + if (!FetchOne(m_get_guild_stmt)) { + if (m_db_err != SQLITE_DONE) + fprintf(stderr, "error while fetching guild: %s\n", sqlite3_errstr(m_db_err)); + Reset(m_get_guild_stmt); + return std::nullopt; + } + + Guild ret; + ret.ID = id; + Get(m_get_guild_stmt, 1, ret.Name); + Get(m_get_guild_stmt, 2, ret.Icon); + Get(m_get_guild_stmt, 3, ret.Splash); + Get(m_get_guild_stmt, 4, ret.IsOwner); + Get(m_get_guild_stmt, 5, ret.OwnerID); + Get(m_get_guild_stmt, 6, ret.PermissionsNew); + Get(m_get_guild_stmt, 7, ret.VoiceRegion); + Get(m_get_guild_stmt, 8, ret.AFKChannelID); + Get(m_get_guild_stmt, 9, ret.AFKTimeout); + Get(m_get_guild_stmt, 10, ret.VerificationLevel); + Get(m_get_guild_stmt, 11, ret.DefaultMessageNotifications); + std::string tmp; + Get(m_get_guild_stmt, 12, tmp); + for (const auto &id : nlohmann::json::parse(tmp).get>()) + ret.Roles.emplace_back().ID = id; + Get(m_get_guild_stmt, 13, tmp); + for (const auto &id : nlohmann::json::parse(tmp).get>()) + ret.Emojis.emplace_back().ID = id; + Get(m_get_guild_stmt, 14, tmp); + ret.Features = nlohmann::json::parse(tmp).get>(); + Get(m_get_guild_stmt, 15, ret.MFALevel); + Get(m_get_guild_stmt, 16, ret.ApplicationID); + Get(m_get_guild_stmt, 17, ret.IsWidgetEnabled); + Get(m_get_guild_stmt, 18, ret.WidgetChannelID); + Get(m_get_guild_stmt, 19, ret.SystemChannelFlags); + Get(m_get_guild_stmt, 20, ret.RulesChannelID); + Get(m_get_guild_stmt, 21, ret.JoinedAt); + Get(m_get_guild_stmt, 22, ret.IsLarge); + Get(m_get_guild_stmt, 23, ret.IsUnavailable); + Get(m_get_guild_stmt, 24, ret.MemberCount); + Get(m_get_guild_stmt, 25, tmp); + ret.Channels.emplace(); + for (const auto &id : nlohmann::json::parse(tmp).get>()) + ret.Channels->emplace_back().ID = id; + Get(m_get_guild_stmt, 26, ret.MaxPresences); + Get(m_get_guild_stmt, 27, ret.MaxMembers); + Get(m_get_guild_stmt, 28, ret.VanityURL); + Get(m_get_guild_stmt, 29, ret.Description); + Get(m_get_guild_stmt, 30, ret.BannerHash); + Get(m_get_guild_stmt, 31, ret.PremiumTier); + Get(m_get_guild_stmt, 32, ret.PremiumSubscriptionCount); + Get(m_get_guild_stmt, 33, ret.PreferredLocale); + Get(m_get_guild_stmt, 34, ret.PublicUpdatesChannelID); + Get(m_get_guild_stmt, 35, ret.MaxVideoChannelUsers); + Get(m_get_guild_stmt, 36, ret.ApproximateMemberCount); + Get(m_get_guild_stmt, 37, ret.ApproximatePresenceCount); + Get(m_get_guild_stmt, 38, ret.IsLazy); + + Reset(m_get_guild_stmt); + + return ret; +} + std::optional Store::GetGuildMember(Snowflake guild_id, Snowflake user_id) const { Bind(m_get_member_stmt, 1, guild_id); Bind(m_get_member_stmt, 2, user_id); @@ -386,20 +502,6 @@ const Channel *Store::GetChannel(Snowflake id) const { return &it->second; } -Guild *Store::GetGuild(Snowflake id) { - auto it = m_guilds.find(id); - if (it == m_guilds.end()) - return nullptr; - return &it->second; -} - -const Guild *Store::GetGuild(Snowflake id) const { - auto it = m_guilds.find(id); - if (it == m_guilds.end()) - return nullptr; - return &it->second; -} - void Store::ClearGuild(Snowflake id) { m_guilds.erase(id); } @@ -412,13 +514,12 @@ const Store::channels_type &Store::GetChannels() const { return m_channels; } -const Store::guilds_type &Store::GetGuilds() const { +const std::unordered_set &Store::GetGuilds() const { return m_guilds; } void Store::ClearAll() { m_channels.clear(); m_guilds.clear(); - m_members.clear(); } void Store::BeginTransaction() { @@ -521,6 +622,50 @@ premium_since TEXT, deaf BOOL NOT NULL, mute BOOL NOT NULL ) +)"; + + constexpr char *create_guilds = R"( +CREATE TABLE IF NOT EXISTS guilds ( +id INTEGER PRIMARY KEY, +name TEXT NOT NULL, +icon TEXT NOT NULL, +splash TEXT, +owner BOOL, +owner_id INTEGER NOT NULL, +permissions INTEGER, /* new */ +voice_region TEXT, +afk_id INTEGER, +afk_timeout INTEGER NOT NULL, +verification INTEGER NOT NULL, +notifications INTEGER NOT NULL, +roles TEXT NOT NULL, /* json */ +emojis TEXT NOT NULL, /* json */ +features TEXT NOT NULL, /* json */ +mfa INTEGER NOT NULL, +application INTEGER, +widget BOOL, +widget_channel INTEGER, +system_flags INTEGER NOT NULL, +rules_channel INTEGER, +joined_at TEXT, +large BOOL, +unavailable BOOL, +member_count INTEGER, +channels TEXT NOT NULL, /* json */ +max_presences INTEGER, +max_members INTEGER, +vanity TEXT, +description TEXT, +banner_hash TEXT, +premium_tier INTEGER NOT NULL, +premium_count INTEGER, +locale TEXT NOT NULL, +public_updates_id INTEGER, +max_video_users INTEGER, +approx_members INTEGER, +approx_presences INTEGER, +lazy BOOL +) )"; m_db_err = sqlite3_exec(m_db, create_users, nullptr, nullptr, nullptr); @@ -559,6 +704,12 @@ mute BOOL NOT NULL return false; } + m_db_err = sqlite3_exec(m_db, create_guilds, nullptr, nullptr, nullptr); + if (m_db_err != SQLITE_OK) { + fprintf(stderr, "failed to create guilds table: %s\n", sqlite3_errstr(m_db_err)); + return false; + } + return true; } @@ -621,6 +772,16 @@ REPLACE INTO members VALUES ( constexpr const char *get_member = R"( SELECT * FROM members WHERE user_id = ? AND guild_id = ? +)"; + + constexpr const char *set_guild = R"( +REPLACE INTO guilds VALUES ( +?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? +) +)"; + + constexpr const char *get_guild = R"( +SELECT * FROM guilds WHERE id = ? )"; m_db_err = sqlite3_prepare_v2(m_db, set_user, -1, &m_set_user_stmt, nullptr); @@ -695,6 +856,18 @@ SELECT * FROM members WHERE user_id = ? AND guild_id = ? return false; } + m_db_err = sqlite3_prepare_v2(m_db, set_guild, -1, &m_set_guild_stmt, nullptr); + if (m_db_err != SQLITE_OK) { + fprintf(stderr, "failed to prepare set guild statement: %s\n", sqlite3_errstr(m_db_err)); + return false; + } + + m_db_err = sqlite3_prepare_v2(m_db, get_guild, -1, &m_get_guild_stmt, nullptr); + if (m_db_err != SQLITE_OK) { + fprintf(stderr, "failed to prepare get guild statement: %s\n", sqlite3_errstr(m_db_err)); + return false; + } + return true; } @@ -711,6 +884,8 @@ void Store::Cleanup() { sqlite3_finalize(m_get_emote_stmt); sqlite3_finalize(m_set_member_stmt); sqlite3_finalize(m_get_member_stmt); + sqlite3_finalize(m_set_guild_stmt); + sqlite3_finalize(m_get_guild_stmt); } void Store::Bind(sqlite3_stmt *stmt, int index, int num) const { diff --git a/discord/store.hpp b/discord/store.hpp index 437cae9..6d1987f 100644 --- a/discord/store.hpp +++ b/discord/store.hpp @@ -2,6 +2,7 @@ #include "../util.hpp" #include "objects.hpp" #include +#include #include #include #include @@ -29,15 +30,14 @@ public: // slap const on everything even tho its not *really* const Channel *GetChannel(Snowflake id); - Guild *GetGuild(Snowflake id); std::optional GetEmoji(Snowflake id) const; + std::optional GetGuild(Snowflake id) const; std::optional GetGuildMember(Snowflake guild_id, Snowflake user_id) const; std::optional GetMessage(Snowflake id) const; std::optional GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const; std::optional GetRole(Snowflake id) const; std::optional GetUser(Snowflake id) const; const Channel *GetChannel(Snowflake id) const; - const Guild *GetGuild(Snowflake id) const; void ClearGuild(Snowflake id); void ClearChannel(Snowflake id); @@ -52,7 +52,7 @@ public: using emojis_type = std::unordered_map; const channels_type &GetChannels() const; - const guilds_type &GetGuilds() const; + const std::unordered_set &GetGuilds() const; void ClearAll(); @@ -61,8 +61,7 @@ public: private: channels_type m_channels; - guilds_type m_guilds; - members_type m_members; + std::unordered_set m_guilds; bool CreateTables(); bool CreateStatements(); @@ -101,6 +100,8 @@ private: mutable sqlite3_stmt *m_get_emote_stmt; mutable sqlite3_stmt *m_set_member_stmt; mutable sqlite3_stmt *m_get_member_stmt; + mutable sqlite3_stmt *m_set_guild_stmt; + mutable sqlite3_stmt *m_get_guild_stmt; }; template