diff options
author | ouwou <26526779+ouwou@users.noreply.github.com> | 2020-12-10 03:50:40 -0500 |
---|---|---|
committer | ouwou <26526779+ouwou@users.noreply.github.com> | 2020-12-10 03:50:40 -0500 |
commit | 850b87c1ec0ac1abfc9a3ed5c566bbe98fba9e7c (patch) | |
tree | f2e990e7a1a84ffa3f2e825ac7e1380826d7de9e | |
parent | e04545287519123982b7baa9c29dc175d4e35405 (diff) | |
download | abaddon-portaudio-850b87c1ec0ac1abfc9a3ed5c566bbe98fba9e7c.tar.gz abaddon-portaudio-850b87c1ec0ac1abfc9a3ed5c566bbe98fba9e7c.zip |
cache channels
-rw-r--r-- | abaddon.cpp | 10 | ||||
-rw-r--r-- | components/channels.cpp | 117 | ||||
-rw-r--r-- | components/chatmessage.cpp | 16 | ||||
-rw-r--r-- | components/chatwindow.cpp | 2 | ||||
-rw-r--r-- | components/memberlist.cpp | 10 | ||||
-rw-r--r-- | discord/channel.hpp | 36 | ||||
-rw-r--r-- | discord/discord.cpp | 45 | ||||
-rw-r--r-- | discord/discord.hpp | 2 | ||||
-rw-r--r-- | discord/guild.cpp | 14 | ||||
-rw-r--r-- | discord/store.cpp | 270 | ||||
-rw-r--r-- | discord/store.hpp | 12 |
11 files changed, 330 insertions, 204 deletions
diff --git a/abaddon.cpp b/abaddon.cpp index 74355ea..ce9deeb 100644 --- a/abaddon.cpp +++ b/abaddon.cpp @@ -293,18 +293,18 @@ void Abaddon::ActionJoinGuildDialog() { void Abaddon::ActionChannelOpened(Snowflake id) { if (id == m_main_window->GetChatActiveChannel()) return; - auto *channel = m_discord.GetChannel(id); + const auto channel = m_discord.GetChannel(id); if (channel->Type != ChannelType::DM && channel->Type != ChannelType::GROUP_DM) m_discord.SendLazyLoad(id); if (channel->Type == ChannelType::GUILD_TEXT || channel->Type == ChannelType::GUILD_NEWS) - m_main_window->set_title(std::string(APP_TITLE) + " - #" + channel->Name); + m_main_window->set_title(std::string(APP_TITLE) + " - #" + *channel->Name); else { std::string display; - if (channel->Recipients.size() > 1) - display = std::to_string(channel->Recipients.size()) + " users"; + if (channel->Recipients->size() > 1) + display = std::to_string(channel->Recipients->size()) + " users"; else - display = channel->Recipients[0].Username; + display = channel->Recipients.value()[0].Username; m_main_window->set_title(std::string(APP_TITLE) + " - " + display); } m_main_window->UpdateChatActiveChannel(id); diff --git a/components/channels.cpp b/components/channels.cpp index a192159..0c28be4 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -55,14 +55,15 @@ ChannelListRowDMChannel::ChannelListRowDMChannel(const Channel *data) { get_style_context()->add_class("channel-row"); m_lbl->get_style_context()->add_class("channel-row-label"); + const auto top_recipient = Abaddon::Get().GetDiscordClient().GetUser(data->Recipients.value()[0].ID); if (data->Type == ChannelType::DM) { - if (data->Recipients[0].HasAvatar()) { - auto buf = Abaddon::Get().GetImageManager().GetFromURLIfCached(data->Recipients[0].GetAvatarURL("png", "16")); + if (top_recipient->HasAvatar()) { + auto buf = Abaddon::Get().GetImageManager().GetFromURLIfCached(top_recipient->GetAvatarURL("png", "16")); if (buf) m_icon = Gtk::manage(new Gtk::Image(buf)); else { m_icon = Gtk::manage(new Gtk::Image(Abaddon::Get().GetImageManager().GetPlaceholder(24))); - Abaddon::Get().GetImageManager().LoadFromURL(data->Recipients[0].GetAvatarURL("png", "16"), sigc::mem_fun(*this, &ChannelListRowDMChannel::OnImageLoad)); + Abaddon::Get().GetImageManager().LoadFromURL(top_recipient->GetAvatarURL("png", "16"), sigc::mem_fun(*this, &ChannelListRowDMChannel::OnImageLoad)); } } else { m_icon = Gtk::manage(new Gtk::Image(Abaddon::Get().GetImageManager().GetPlaceholder(24))); @@ -71,9 +72,9 @@ ChannelListRowDMChannel::ChannelListRowDMChannel(const Channel *data) { auto buf = m_lbl->get_buffer(); if (data->Type == ChannelType::DM) - buf->set_text(data->Recipients[0].Username); + buf->set_text(top_recipient->Username); else if (data->Type == ChannelType::GROUP_DM) - buf->set_text(std::to_string(data->Recipients.size()) + " users"); + buf->set_text(std::to_string(data->Recipients->size()) + " users"); Abaddon::Get().GetEmojis().ReplaceEmojis(buf, ChannelEmojiSize); m_box->set_halign(Gtk::ALIGN_START); @@ -143,7 +144,7 @@ ChannelListRowCategory::ChannelListRowCategory(const Channel *data) { m_lbl->get_style_context()->add_class("channel-row-label"); auto buf = m_lbl->get_buffer(); - buf->set_text(data->Name); + buf->set_text(*data->Name); Abaddon::Get().GetEmojis().ReplaceEmojis(buf, ChannelEmojiSize); m_box->set_halign(Gtk::ALIGN_START); m_box->pack_start(*m_arrow); @@ -173,7 +174,7 @@ ChannelListRowChannel::ChannelListRowChannel(const Channel *data) { m_lbl->get_style_context()->add_class("channel-row-label"); auto buf = m_lbl->get_buffer(); - buf->set_text("#" + data->Name); + buf->set_text("#" + *data->Name); Abaddon::Get().GetEmojis().ReplaceEmojis(buf, ChannelEmojiSize); m_box->set_halign(Gtk::ALIGN_START); m_box->pack_start(*m_lbl); @@ -216,8 +217,8 @@ ChannelList::ChannelList() { auto &discord = Abaddon::Get().GetDiscordClient(); discord.signal_message_create().connect(sigc::track_obj([this, &discord](Snowflake message_id) { const auto message = discord.GetMessage(message_id); - const auto *channel = discord.GetChannel(message->ChannelID); - if (channel == nullptr) return; + const auto channel = discord.GetChannel(message->ChannelID); + if (!channel.has_value()) return; if (channel->Type == ChannelType::DM || channel->Type == ChannelType::GROUP_DM) CheckBumpDM(message->ChannelID); // clang-format off @@ -282,12 +283,12 @@ 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); - auto git = m_guild_id_to_row.find(data->GuildID); + const auto data = Abaddon::Get().GetDiscordClient().GetChannel(id); + 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.has_value()) return; + if (!data.has_value() || !guild.has_value()) return; auto it = m_id_to_row.find(id); if (it == m_id_to_row.end()) return; auto row = dynamic_cast<ChannelListRowCategory *>(it->second); @@ -315,7 +316,7 @@ void ChannelList::UpdateChannelCategory(Snowflake id) { pos = x->second->get_index(); } - auto *new_row = Gtk::manage(new ChannelListRowCategory(data)); + auto *new_row = Gtk::manage(new ChannelListRowCategory(&*data)); new_row->IsUserCollapsed = old_collapsed; if (visible) new_row->show(); @@ -326,9 +327,9 @@ void ChannelList::UpdateChannelCategory(Snowflake id) { m_list->insert(*new_row, pos); int i = 1; for (const auto &[idx, child_id] : child_rows) { - const auto *channel = Abaddon::Get().GetDiscordClient().GetChannel(child_id); - if (channel != nullptr) { - auto *new_child = Gtk::manage(new ChannelListRowChannel(channel)); + const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(child_id); + if (channel.has_value()) { + auto *new_child = Gtk::manage(new ChannelListRowChannel(&*channel)); new_row->Children.insert(new_child); new_child->Parent = new_row; AttachChannelMenuHandler(new_child); @@ -342,9 +343,9 @@ 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_row = m_guild_id_to_row.at(data->GuildID); + const auto data = Abaddon::Get().GetDiscordClient().GetChannel(id); + 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); return; @@ -370,13 +371,13 @@ void ChannelList::UpdateChannel(Snowflake id) { pos = x->second->get_index(); } - auto *new_row = Gtk::manage(new ChannelListRowChannel(data)); + auto *new_row = Gtk::manage(new ChannelListRowChannel(&*data)); new_row->IsUserCollapsed = old_collapsed; m_id_to_row[id] = new_row; - if (data->ParentID.IsValid()) { - new_row->Parent = m_id_to_row.at(data->ParentID); + if (data->ParentID->IsValid()) { + new_row->Parent = m_id_to_row.at(*data->ParentID); } else { - new_row->Parent = m_guild_id_to_row.at(data->GuildID); + new_row->Parent = m_guild_id_to_row.at(*data->GuildID); } new_row->Parent->Children.insert(new_row); @@ -387,7 +388,8 @@ void ChannelList::UpdateChannel(Snowflake id) { } void ChannelList::UpdateCreateDMChannel(Snowflake id) { - auto *dm_row = Gtk::manage(new ChannelListRowDMChannel(Abaddon::Get().GetDiscordClient().GetChannel(id))); + const auto chan = Abaddon::Get().GetDiscordClient().GetChannel(id); + auto *dm_row = Gtk::manage(new ChannelListRowDMChannel(&*chan)); dm_row->IsUserCollapsed = false; m_list->insert(*dm_row, m_dm_header_row->get_index() + 1); m_dm_header_row->Children.insert(dm_row); @@ -397,13 +399,13 @@ void ChannelList::UpdateCreateDMChannel(Snowflake id) { void ChannelList::UpdateCreateChannel(Snowflake id) { const auto &discord = Abaddon::Get().GetDiscordClient(); - const auto *data = discord.GetChannel(id); + const auto data = discord.GetChannel(id); if (data->Type == ChannelType::DM || data->Type == ChannelType::GROUP_DM) { UpdateCreateDMChannel(id); return; } - const auto guild = discord.GetGuild(data->GuildID); - auto *guild_row = m_guild_id_to_row.at(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; const auto sorted = guild->GetSortedChannels(); @@ -420,9 +422,9 @@ void ChannelList::UpdateCreateChannel(Snowflake id) { ChannelListRow *row; if (data->Type == ChannelType::GUILD_TEXT || data->Type == ChannelType::GUILD_NEWS) { - row = Gtk::manage(new ChannelListRowChannel(data)); + row = Gtk::manage(new ChannelListRowChannel(&*data)); } else if (data->Type == ChannelType::GUILD_CATEGORY) { - row = Gtk::manage(new ChannelListRowCategory(data)); + row = Gtk::manage(new ChannelListRowCategory(&*data)); } else return; row->IsUserCollapsed = false; @@ -526,18 +528,18 @@ void ChannelList::InsertGuildAt(Snowflake id, int pos) { const auto guild_data = discord.GetGuild(id); if (!guild_data.has_value()) return; - std::map<int, const Channel *> orphan_channels; - std::unordered_map<Snowflake, std::vector<const Channel *>> cat_to_channels; + std::map<int, Channel> orphan_channels; + std::unordered_map<Snowflake, std::vector<Channel>> cat_to_channels; 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.has_value()) 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); + if (channel->ParentID->IsValid()) + cat_to_channels[*channel->ParentID].push_back(*channel); else - orphan_channels[channel->Position] = &*channel; + orphan_channels[*channel->Position] = *channel; } auto *guild_row = Gtk::manage(new ChannelListRowGuild(&*guild_data)); @@ -550,7 +552,7 @@ void ChannelList::InsertGuildAt(Snowflake id, int pos) { // add channels with no parent category for (const auto &[pos, channel] : orphan_channels) { - auto *chan_row = Gtk::manage(new ChannelListRowChannel(channel)); + auto *chan_row = Gtk::manage(new ChannelListRowChannel(&channel)); chan_row->IsUserCollapsed = false; AttachChannelMenuHandler(chan_row); insert_and_adjust(*chan_row); @@ -560,19 +562,19 @@ void ChannelList::InsertGuildAt(Snowflake id, int pos) { } // categories - std::map<int, std::vector<const Channel *>> sorted_categories; + std::map<int, std::vector<Channel>> sorted_categories; 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.has_value()) continue; if (channel->Type == ChannelType::GUILD_CATEGORY) - sorted_categories[channel->Position].push_back(&*channel); + 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; }); + std::sort(catvec.begin(), catvec.end(), [](const Channel &a, const Channel &b) { return a.ID < b.ID; }); for (const auto cat : catvec) { - auto *cat_row = Gtk::manage(new ChannelListRowCategory(cat)); + auto *cat_row = Gtk::manage(new ChannelListRowCategory(&cat)); cat_row->IsUserCollapsed = false; AttachChannelMenuHandler(cat_row); insert_and_adjust(*cat_row); @@ -581,14 +583,14 @@ void ChannelList::InsertGuildAt(Snowflake id, int pos) { m_id_to_row[cat_row->ID] = cat_row; // child channels - if (cat_to_channels.find(cat->ID) == cat_to_channels.end()) continue; - std::map<int, const Channel *> sorted_channels; + if (cat_to_channels.find(cat.ID) == cat_to_channels.end()) continue; + std::map<int, Channel> sorted_channels; - for (const auto channel : cat_to_channels.at(cat->ID)) - sorted_channels[channel->Position] = channel; + for (const auto channel : cat_to_channels.at(cat.ID)) + sorted_channels[*channel.Position] = channel; for (const auto &[pos, channel] : sorted_channels) { - auto *chan_row = Gtk::manage(new ChannelListRowChannel(channel)); + auto *chan_row = Gtk::manage(new ChannelListRowChannel(&channel)); chan_row->IsUserCollapsed = false; AttachChannelMenuHandler(chan_row); insert_and_adjust(*chan_row); @@ -601,13 +603,15 @@ void ChannelList::InsertGuildAt(Snowflake id, int pos) { } void ChannelList::AddPrivateChannels() { - auto dms_ = Abaddon::Get().GetDiscordClient().GetPrivateChannels(); - std::vector<const Channel *> dms; const auto &discord = Abaddon::Get().GetDiscordClient(); - for (const auto &x : dms_) - dms.push_back(discord.GetChannel(x)); - std::sort(dms.begin(), dms.end(), [&](const Channel *a, const Channel *b) -> bool { - return a->LastMessageID > b->LastMessageID; + auto dms_ = discord.GetPrivateChannels(); + std::vector<Channel> dms; + for (const auto &x : dms_) { + const auto chan = discord.GetChannel(x); + dms.push_back(*chan); + } + std::sort(dms.begin(), dms.end(), [&](const Channel &a, const Channel &b) -> bool { + return a.LastMessageID > b.LastMessageID; }); m_dm_header_row = Gtk::manage(new ChannelListRowDMHeader); @@ -616,9 +620,9 @@ void ChannelList::AddPrivateChannels() { m_list->add(*m_dm_header_row); for (const auto &dm : dms) { - auto *dm_row = Gtk::manage(new ChannelListRowDMChannel(dm)); + auto *dm_row = Gtk::manage(new ChannelListRowDMChannel(&dm)); dm_row->Parent = m_dm_header_row; - m_dm_id_to_row[dm->ID] = dm_row; + m_dm_id_to_row[dm.ID] = dm_row; dm_row->IsUserCollapsed = false; m_list->add(*dm_row); m_dm_header_row->Children.insert(dm_row); @@ -707,7 +711,8 @@ void ChannelList::CheckBumpDM(Snowflake channel_id) { const bool selected = row->is_selected(); row->Parent->Children.erase(row); delete row; - auto *dm_row = Gtk::manage(new ChannelListRowDMChannel(Abaddon::Get().GetDiscordClient().GetChannel(channel_id))); + const auto chan = Abaddon::Get().GetDiscordClient().GetChannel(channel_id); + auto *dm_row = Gtk::manage(new ChannelListRowDMChannel(&*chan)); dm_row->Parent = m_dm_header_row; m_dm_header_row->Children.insert(dm_row); m_dm_id_to_row[channel_id] = dm_row; diff --git a/components/chatmessage.cpp b/components/chatmessage.cpp index 257f2c4..a2b4f69 100644 --- a/components/chatmessage.cpp +++ b/components/chatmessage.cpp @@ -422,8 +422,8 @@ void ChatMessageItemContainer::HandleUserMentions(Gtk::TextView *tv) { if (!match.fetch_pos(0, mstart, mend)) break; const Glib::ustring user_id = match.fetch(1); const auto user = discord.GetUser(user_id); - const auto *channel = discord.GetChannel(ChannelID); - if (!user.has_value() || channel == nullptr) { + const auto channel = discord.GetChannel(ChannelID); + if (!user.has_value() || !channel.has_value()) { startpos = mend; continue; } @@ -433,7 +433,7 @@ void ChatMessageItemContainer::HandleUserMentions(Gtk::TextView *tv) { if (channel->Type == ChannelType::DM || channel->Type == ChannelType::GROUP_DM) replacement = "<b>@" + Glib::Markup::escape_text(user->Username) + "#" + user->Discriminator + "</b>"; else { - const auto role_id = user->GetHoistedRole(channel->GuildID, true); + const auto role_id = user->GetHoistedRole(*channel->GuildID, true); const auto role = discord.GetRole(role_id); if (!role.has_value()) replacement = "<b>@" + Glib::Markup::escape_text(user->Username) + "#" + user->Discriminator + "</b>"; @@ -533,8 +533,8 @@ void ChatMessageItemContainer::HandleChannelMentions(Gtk::TextView *tv) { int mstart, mend; match.fetch_pos(0, mstart, mend); std::string channel_id = match.fetch(1); - const auto *chan = discord.GetChannel(channel_id); - if (chan == nullptr) { + const auto chan = discord.GetChannel(channel_id); + if (!chan.has_value()) { startpos = mend; continue; } @@ -548,8 +548,8 @@ void ChatMessageItemContainer::HandleChannelMentions(Gtk::TextView *tv) { const auto erase_from = buf->get_iter_at_offset(chars_start); const auto erase_to = buf->get_iter_at_offset(chars_end); auto it = buf->erase(erase_from, erase_to); - const std::string replacement = "#" + chan->Name; - it = buf->insert_with_tag(it, "#" + chan->Name, tag); + const std::string replacement = "#" + *chan->Name; + it = buf->insert_with_tag(it, "#" + *chan->Name, tag); // rescan the whole thing so i dont have to deal with fixing match positions text = GetText(buf); @@ -823,7 +823,7 @@ ChatMessageHeader::ChatMessageHeader(const Message *data) { void ChatMessageHeader::UpdateNameColor() { const auto &discord = Abaddon::Get().GetDiscordClient(); const auto guild_id = discord.GetChannel(ChannelID)->GuildID; - const auto role_id = discord.GetMemberHoistedRole(guild_id, UserID, true); + const auto role_id = discord.GetMemberHoistedRole(*guild_id, UserID, true); const auto user = discord.GetUser(UserID); if (!user.has_value()) return; const auto role = discord.GetRole(role_id); diff --git a/components/chatwindow.cpp b/components/chatwindow.cpp index 28d3fce..ea8da69 100644 --- a/components/chatwindow.cpp +++ b/components/chatwindow.cpp @@ -178,7 +178,7 @@ void ChatWindow::ProcessNewMessage(Snowflake id, bool prepend) { if (should_attach) { header = last_row; } else { - const auto guild_id = client.GetChannel(m_active_channel)->GuildID; + const auto guild_id = *client.GetChannel(m_active_channel)->GuildID; const auto user_id = data->Author.ID; const auto user = client.GetUser(user_id); if (!user.has_value()) return; diff --git a/components/memberlist.cpp b/components/memberlist.cpp index 04bdf8a..cf5e504 100644 --- a/components/memberlist.cpp +++ b/components/memberlist.cpp @@ -75,8 +75,8 @@ void MemberList::SetActiveChannel(Snowflake id) { m_chan_id = id; m_guild_id = Snowflake::Invalid; if (m_chan_id.IsValid()) { - auto *chan = Abaddon::Get().GetDiscordClient().GetChannel(id); - if (chan != nullptr) m_guild_id = chan->GuildID; + const auto chan = Abaddon::Get().GetDiscordClient().GetChannel(id); + if (chan.has_value()) m_guild_id = *chan->GuildID; } } @@ -99,11 +99,11 @@ void MemberList::UpdateMemberListInternal() { if (!m_chan_id.IsValid()) return; auto &discord = Abaddon::Get().GetDiscordClient(); - auto *chan = discord.GetChannel(m_chan_id); - if (chan == nullptr) return; + const auto chan = discord.GetChannel(m_chan_id); + if (!chan.has_value()) return; std::unordered_set<Snowflake> ids; if (chan->Type == ChannelType::DM || chan->Type == ChannelType::GROUP_DM) { - for (const auto &user : chan->Recipients) + for (const auto &user : *chan->Recipients) ids.insert(user.ID); ids.insert(discord.GetUserData().ID); } else { diff --git a/discord/channel.hpp b/discord/channel.hpp index 178f8b6..5f8e5e3 100644 --- a/discord/channel.hpp +++ b/discord/channel.hpp @@ -17,24 +17,24 @@ enum class ChannelType : int { }; struct Channel { - Snowflake ID; // - ChannelType Type; // - Snowflake GuildID; // opt - int Position = -1; // opt - std::vector<PermissionOverwrite> PermissionOverwrites; // opt - std::string Name; // opt, null (null for dm's) - std::string Topic; // opt, null - bool IsNSFW = false; // opt - Snowflake LastMessageID; // opt, null - int Bitrate = 0; // opt - int UserLimit = 0; // opt - int RateLimitPerUser = 0; // opt - std::vector<User> Recipients; // opt - std::string Icon; // opt, null - Snowflake OwnerID; // opt - Snowflake ApplicationID; // opt - Snowflake ParentID; // opt, null - std::string LastPinTimestamp; // opt, can be null even tho docs say otherwise + Snowflake ID; + ChannelType Type; + std::optional<Snowflake> GuildID; + std::optional<int> Position; + std::optional<std::vector<PermissionOverwrite>> PermissionOverwrites; // shouldnt be accessed + std::optional<std::string> Name; // null for dm's + std::optional<std::string> Topic; // null + std::optional<bool> IsNSFW; + std::optional<Snowflake> LastMessageID; // null + std::optional<int> Bitrate; + std::optional<int> UserLimit; + std::optional<int> RateLimitPerUser; + std::optional<std::vector<User>> Recipients; // only access id + std::optional<std::string> Icon; // null + std::optional<Snowflake> OwnerID; + std::optional<Snowflake> ApplicationID; + std::optional<Snowflake> ParentID; // null + std::optional<std::string> LastPinTimestamp; // null friend void from_json(const nlohmann::json &j, Channel &m); void update_from_json(const nlohmann::json &j); diff --git a/discord/discord.cpp b/discord/discord.cpp index 50446a7..c86cc3b 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -161,7 +161,7 @@ std::optional<Message> DiscordClient::GetMessage(Snowflake id) const { return m_store.GetMessage(id); } -const Channel *DiscordClient::GetChannel(Snowflake id) const { +std::optional<Channel> DiscordClient::GetChannel(Snowflake id) const { return m_store.GetChannel(id); } @@ -247,9 +247,9 @@ bool DiscordClient::HasGuildPermission(Snowflake user_id, Snowflake guild_id, Pe } bool DiscordClient::HasChannelPermission(Snowflake user_id, Snowflake channel_id, Permission perm) const { - const auto *channel = m_store.GetChannel(channel_id); - if (channel == nullptr) return false; - const auto base = ComputePermissions(user_id, channel->GuildID); + const auto channel = m_store.GetChannel(channel_id); + if (!channel.has_value()) return false; + const auto base = ComputePermissions(user_id, *channel->GuildID); const auto overwrites = ComputeOverwrites(base, user_id, channel_id); return (overwrites & perm) == perm; } @@ -284,13 +284,13 @@ Permission DiscordClient::ComputeOverwrites(Permission base, Snowflake member_id if ((base & Permission::ADMINISTRATOR) == Permission::ADMINISTRATOR) return Permission::ALL; - const auto *channel = GetChannel(channel_id); - const auto member = GetMember(member_id, channel->GuildID); - if (!member.has_value() || channel == nullptr) + const auto channel = GetChannel(channel_id); + const auto member = GetMember(member_id, *channel->GuildID); + if (!member.has_value() || !channel.has_value()) return Permission::NONE; Permission perms = base; - const auto overwrite_everyone = GetPermissionOverwrite(channel_id, channel->GuildID); + const auto overwrite_everyone = GetPermissionOverwrite(channel_id, *channel->GuildID); if (overwrite_everyone.has_value()) { perms &= ~overwrite_everyone->Deny; perms |= overwrite_everyone->Allow; @@ -359,7 +359,7 @@ void DiscordClient::SendLazyLoad(Snowflake id) { std::make_pair(100, 199) }; msg.Channels = c; - msg.GuildID = GetChannel(id)->GuildID; + msg.GuildID = *GetChannel(id)->GuildID; msg.ShouldGetActivities = false; msg.ShouldGetTyping = false; @@ -401,8 +401,9 @@ void DiscordClient::CreateDM(Snowflake user_id) { std::optional<Snowflake> DiscordClient::FindDM(Snowflake user_id) { const auto &channels = m_store.GetChannels(); - for (const auto &[id, channel] : channels) { - if (channel.Recipients.size() == 1 && channel.Recipients[0].ID == user_id) + for (const auto &id : channels) { + const auto channel = m_store.GetChannel(id); + if (channel->Recipients->size() == 1 && channel->Recipients.value()[0].ID == user_id) return id; } @@ -579,7 +580,7 @@ void DiscordClient::ProcessNewGuild(Guild &guild) { c.GuildID = guild.ID; m_store.SetChannel(c.ID, c); m_guild_to_channels[guild.ID].insert(c.ID); - for (auto &p : c.PermissionOverwrites) { + for (auto &p : *c.PermissionOverwrites) { m_store.SetPermissionOverwrite(c.ID, p.ID, p); } } @@ -602,7 +603,7 @@ void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) { m_store.BeginTransaction(); for (const auto &dm : data.PrivateChannels) { m_store.SetChannel(dm.ID, dm); - for (const auto &recipient : dm.Recipients) + for (const auto &recipient : *dm.Recipients) m_store.SetUser(recipient.ID, recipient); } m_store.EndTransaction(); @@ -665,8 +666,8 @@ void DiscordClient::HandleGatewayPresenceUpdate(const GatewayMessage &msg) { void DiscordClient::HandleGatewayChannelDelete(const GatewayMessage &msg) { const auto id = msg.Data.at("id").get<Snowflake>(); - const auto *channel = GetChannel(id); - auto it = m_guild_to_channels.find(channel->GuildID); + const auto channel = GetChannel(id); + auto it = m_guild_to_channels.find(*channel->GuildID); if (it != m_guild_to_channels.end()) it->second.erase(id); m_store.ClearChannel(id); @@ -675,9 +676,10 @@ void DiscordClient::HandleGatewayChannelDelete(const GatewayMessage &msg) { void DiscordClient::HandleGatewayChannelUpdate(const GatewayMessage &msg) { const auto id = msg.Data.at("id").get<Snowflake>(); - auto *cur = m_store.GetChannel(id); - if (cur != nullptr) { + auto cur = m_store.GetChannel(id); + if (cur.has_value()) { cur->update_from_json(msg.Data); + m_store.SetChannel(id, *cur); m_signal_channel_update.emit(id); } } @@ -686,8 +688,8 @@ void DiscordClient::HandleGatewayChannelCreate(const GatewayMessage &msg) { Channel data = msg.Data; m_store.BeginTransaction(); m_store.SetChannel(data.ID, data); - m_guild_to_channels[data.GuildID].insert(data.ID); - for (const auto &p : data.PermissionOverwrites) + m_guild_to_channels[*data.GuildID].insert(data.ID); + for (const auto &p : *data.PermissionOverwrites) m_store.SetPermissionOverwrite(data.ID, p.ID, p); m_store.EndTransaction(); m_signal_channel_create.emit(data.ID); @@ -799,8 +801,9 @@ void DiscordClient::AddUserToGuild(Snowflake user_id, Snowflake guild_id) { std::set<Snowflake> DiscordClient::GetPrivateChannels() const { auto ret = std::set<Snowflake>(); - for (const auto &[id, chan] : m_store.GetChannels()) { - if (chan.Type == ChannelType::DM || chan.Type == ChannelType::GROUP_DM) + for (const auto &id : m_store.GetChannels()) { + const auto chan = m_store.GetChannel(id); + if (chan->Type == ChannelType::DM || chan->Type == ChannelType::GROUP_DM) ret.insert(id); } diff --git a/discord/discord.hpp b/discord/discord.hpp index b915d8c..17187d5 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -80,7 +80,7 @@ public: void FetchMessagesInChannel(Snowflake id, std::function<void(const std::vector<Snowflake> &)> cb); void FetchMessagesInChannelBefore(Snowflake channel_id, Snowflake before_id, std::function<void(const std::vector<Snowflake> &)> cb); std::optional<Message> GetMessage(Snowflake id) const; - const Channel *GetChannel(Snowflake id) const; + std::optional<Channel> GetChannel(Snowflake id) const; std::optional<Emoji> GetEmoji(Snowflake id) const; std::optional<PermissionOverwrite> GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const; std::optional<User> GetUser(Snowflake id) const; diff --git a/discord/guild.cpp b/discord/guild.cpp index 31b4dd6..2663aac 100644 --- a/discord/guild.cpp +++ b/discord/guild.cpp @@ -136,14 +136,14 @@ std::vector<Snowflake> Guild::GetSortedChannels(Snowflake ignore) const { std::map<int, std::vector<const Channel *>> position_to_categories; std::map<int, std::vector<const Channel *>> orphan_channels; for (const auto &channel_id : channels) { - const auto *data = discord.GetChannel(channel_id); - if (data == nullptr) continue; - if (!data->ParentID.IsValid() && (data->Type == ChannelType::GUILD_TEXT || data->Type == ChannelType::GUILD_NEWS)) - orphan_channels[data->Position].push_back(data); - else if (data->ParentID.IsValid() && (data->Type == ChannelType::GUILD_TEXT || data->Type == ChannelType::GUILD_NEWS)) - category_to_channels[data->ParentID].push_back(data); + const auto data = discord.GetChannel(channel_id); + if (!data.has_value()) continue; + if (!data->ParentID->IsValid() && (data->Type == ChannelType::GUILD_TEXT || data->Type == ChannelType::GUILD_NEWS)) + orphan_channels[*data->Position].push_back(&*data); + else if (data->ParentID->IsValid() && (data->Type == ChannelType::GUILD_TEXT || data->Type == ChannelType::GUILD_NEWS)) + category_to_channels[*data->ParentID].push_back(&*data); else if (data->Type == ChannelType::GUILD_CATEGORY) - position_to_categories[data->Position].push_back(data); + position_to_categories[*data->Position].push_back(&*data); } for (auto &[pos, channels] : orphan_channels) { diff --git a/discord/store.cpp b/discord/store.cpp index 12f729f..e5dcd19 100644 --- a/discord/store.cpp +++ b/discord/store.cpp @@ -51,28 +51,60 @@ bool Store::IsValid() const { return m_db_err == SQLITE_OK; } -void Store::SetUser(Snowflake id, const User &user) { - Bind(m_set_user_stmt, 1, id); - Bind(m_set_user_stmt, 2, user.Username); - Bind(m_set_user_stmt, 3, user.Discriminator); - Bind(m_set_user_stmt, 4, user.Avatar); - Bind(m_set_user_stmt, 5, user.IsBot); - Bind(m_set_user_stmt, 6, user.IsSystem); - Bind(m_set_user_stmt, 7, user.IsMFAEnabled); - Bind(m_set_user_stmt, 8, user.Locale); - Bind(m_set_user_stmt, 9, user.IsVerified); - Bind(m_set_user_stmt, 10, user.Email); - Bind(m_set_user_stmt, 11, user.Flags); - Bind(m_set_user_stmt, 12, user.PremiumType); - Bind(m_set_user_stmt, 13, user.PublicFlags); - - if (!RunInsert(m_set_user_stmt)) { - fprintf(stderr, "user insert failed: %s\n", sqlite3_errstr(m_db_err)); +void Store::SetChannel(Snowflake id, const Channel &chan) { + Bind(m_set_chan_stmt, 1, id); + Bind(m_set_chan_stmt, 2, static_cast<int>(chan.Type)); + Bind(m_set_chan_stmt, 3, chan.GuildID); + Bind(m_set_chan_stmt, 4, chan.Position); + Bind(m_set_chan_stmt, 5, nullptr); // unused + Bind(m_set_chan_stmt, 6, chan.Name); + Bind(m_set_chan_stmt, 7, chan.Topic); + Bind(m_set_chan_stmt, 8, chan.IsNSFW); + Bind(m_set_chan_stmt, 9, chan.LastMessageID); + Bind(m_set_chan_stmt, 10, chan.Bitrate); + Bind(m_set_chan_stmt, 11, chan.UserLimit); + Bind(m_set_chan_stmt, 12, chan.RateLimitPerUser); + if (chan.Recipients.has_value()) { + std::vector<Snowflake> ids; + for (const auto &u : *chan.Recipients) + ids.push_back(u.ID); + Bind(m_set_chan_stmt, 13, nlohmann::json(ids).dump()); + } else { + Bind(m_set_chan_stmt, 13, nullptr); } + Bind(m_set_chan_stmt, 14, chan.Icon); + Bind(m_set_chan_stmt, 15, chan.OwnerID); + Bind(m_set_chan_stmt, 16, chan.ApplicationID); + Bind(m_set_chan_stmt, 17, chan.ParentID); + Bind(m_set_chan_stmt, 18, chan.LastPinTimestamp); + + if (!RunInsert(m_set_chan_stmt)) + fprintf(stderr, "channel insert failed: %s\n", sqlite3_errstr(m_db_err)); + + m_channels.insert(id); } -void Store::SetChannel(Snowflake id, const Channel &channel) { - m_channels[id] = channel; +void Store::SetEmoji(Snowflake id, const Emoji &emoji) { + Bind(m_set_emote_stmt, 1, id); + Bind(m_set_emote_stmt, 2, emoji.Name); + + if (emoji.Roles.has_value()) + Bind(m_set_emote_stmt, 3, nlohmann::json(*emoji.Roles).dump()); + else + Bind(m_set_emote_stmt, 3, nullptr); + + if (emoji.Creator.has_value()) + Bind(m_set_emote_stmt, 4, emoji.Creator->ID); + else + Bind(m_set_emote_stmt, 4, nullptr); + + Bind(m_set_emote_stmt, 5, emoji.NeedsColons); + Bind(m_set_emote_stmt, 6, emoji.IsManaged); + Bind(m_set_emote_stmt, 7, emoji.IsAnimated); + Bind(m_set_emote_stmt, 8, emoji.IsAvailable); + + if (!RunInsert(m_set_emote_stmt)) + fprintf(stderr, "emoji insert failed: %s\n", sqlite3_errstr(m_db_err)); } void Store::SetGuild(Snowflake id, const Guild &guild) { @@ -131,18 +163,18 @@ void Store::SetGuild(Snowflake id, const Guild &guild) { m_guilds.insert(id); } -void Store::SetRole(Snowflake id, const Role &role) { - Bind(m_set_role_stmt, 1, id); - Bind(m_set_role_stmt, 2, role.Name); - Bind(m_set_role_stmt, 3, role.Color); - Bind(m_set_role_stmt, 4, role.IsHoisted); - Bind(m_set_role_stmt, 5, role.Position); - Bind(m_set_role_stmt, 6, static_cast<uint64_t>(role.Permissions)); - Bind(m_set_role_stmt, 7, role.IsManaged); - Bind(m_set_role_stmt, 8, role.IsMentionable); +void Store::SetGuildMember(Snowflake guild_id, Snowflake user_id, const GuildMember &data) { + Bind(m_set_member_stmt, 1, user_id); + Bind(m_set_member_stmt, 2, guild_id); + Bind(m_set_member_stmt, 3, data.Nickname); + Bind(m_set_member_stmt, 4, nlohmann::json(data.Roles).dump()); + Bind(m_set_member_stmt, 5, data.JoinedAt); + 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_role_stmt)) - fprintf(stderr, "role insert failed: %s\n", sqlite3_errstr(m_db_err)); + if (!RunInsert(m_set_member_stmt)) + fprintf(stderr, "member insert failed: %s\n", sqlite3_errstr(m_db_err)); } void Store::SetMessage(Snowflake id, const Message &message) { @@ -193,20 +225,6 @@ void Store::SetMessage(Snowflake id, const Message &message) { fprintf(stderr, "message insert failed: %s\n", sqlite3_errstr(m_db_err)); } -void Store::SetGuildMember(Snowflake guild_id, Snowflake user_id, const GuildMember &data) { - Bind(m_set_member_stmt, 1, user_id); - Bind(m_set_member_stmt, 2, guild_id); - Bind(m_set_member_stmt, 3, data.Nickname); - Bind(m_set_member_stmt, 4, nlohmann::json(data.Roles).dump()); - Bind(m_set_member_stmt, 5, data.JoinedAt); - 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)); -} - void Store::SetPermissionOverwrite(Snowflake channel_id, Snowflake id, const PermissionOverwrite &perm) { Bind(m_set_perm_stmt, 1, perm.ID); Bind(m_set_perm_stmt, 2, channel_id); @@ -218,27 +236,82 @@ void Store::SetPermissionOverwrite(Snowflake channel_id, Snowflake id, const Per fprintf(stderr, "permission insert failed: %s\n", sqlite3_errstr(m_db_err)); } -void Store::SetEmoji(Snowflake id, const Emoji &emoji) { - Bind(m_set_emote_stmt, 1, id); - Bind(m_set_emote_stmt, 2, emoji.Name); +void Store::SetRole(Snowflake id, const Role &role) { + Bind(m_set_role_stmt, 1, id); + Bind(m_set_role_stmt, 2, role.Name); + Bind(m_set_role_stmt, 3, role.Color); + Bind(m_set_role_stmt, 4, role.IsHoisted); + Bind(m_set_role_stmt, 5, role.Position); + Bind(m_set_role_stmt, 6, static_cast<uint64_t>(role.Permissions)); + Bind(m_set_role_stmt, 7, role.IsManaged); + Bind(m_set_role_stmt, 8, role.IsMentionable); - if (emoji.Roles.has_value()) - Bind(m_set_emote_stmt, 3, nlohmann::json(*emoji.Roles).dump()); - else - Bind(m_set_emote_stmt, 3, nullptr); + if (!RunInsert(m_set_role_stmt)) + fprintf(stderr, "role insert failed: %s\n", sqlite3_errstr(m_db_err)); +} - if (emoji.Creator.has_value()) - Bind(m_set_emote_stmt, 4, emoji.Creator->ID); - else - Bind(m_set_emote_stmt, 4, nullptr); +void Store::SetUser(Snowflake id, const User &user) { + Bind(m_set_user_stmt, 1, id); + Bind(m_set_user_stmt, 2, user.Username); + Bind(m_set_user_stmt, 3, user.Discriminator); + Bind(m_set_user_stmt, 4, user.Avatar); + Bind(m_set_user_stmt, 5, user.IsBot); + Bind(m_set_user_stmt, 6, user.IsSystem); + Bind(m_set_user_stmt, 7, user.IsMFAEnabled); + Bind(m_set_user_stmt, 8, user.Locale); + Bind(m_set_user_stmt, 9, user.IsVerified); + Bind(m_set_user_stmt, 10, user.Email); + Bind(m_set_user_stmt, 11, user.Flags); + Bind(m_set_user_stmt, 12, user.PremiumType); + Bind(m_set_user_stmt, 13, user.PublicFlags); - Bind(m_set_emote_stmt, 5, emoji.NeedsColons); - Bind(m_set_emote_stmt, 6, emoji.IsManaged); - Bind(m_set_emote_stmt, 7, emoji.IsAnimated); - Bind(m_set_emote_stmt, 8, emoji.IsAvailable); + if (!RunInsert(m_set_user_stmt)) { + fprintf(stderr, "user insert failed: %s\n", sqlite3_errstr(m_db_err)); + } +} - if (!RunInsert(m_set_emote_stmt)) - fprintf(stderr, "emoji insert failed: %s\n", sqlite3_errstr(m_db_err)); +std::optional<Channel> Store::GetChannel(Snowflake id) const { + Bind(m_get_chan_stmt, 1, id); + if (!FetchOne(m_get_chan_stmt)) { + if (m_db_err != SQLITE_DONE) + fprintf(stderr, "error while fetching channel: %s\n", sqlite3_errstr(m_db_err)); + Reset(m_get_chan_stmt); + return std::nullopt; + } + + Channel ret; + ret.ID = id; + int tmpi; + Get(m_get_chan_stmt, 1, tmpi); + ret.Type = static_cast<ChannelType>(tmpi); + Get(m_get_chan_stmt, 2, ret.GuildID); + Get(m_get_chan_stmt, 3, ret.Position); + ret.PermissionOverwrites = std::nullopt; + Get(m_get_chan_stmt, 5, ret.Name); + Get(m_get_chan_stmt, 6, ret.Topic); + Get(m_get_chan_stmt, 7, ret.IsNSFW); + Get(m_get_chan_stmt, 8, ret.LastMessageID); + Get(m_get_chan_stmt, 9, ret.Bitrate); + Get(m_get_chan_stmt, 10, ret.UserLimit); + Get(m_get_chan_stmt, 11, ret.RateLimitPerUser); + if (!IsNull(m_get_chan_stmt, 12)) { + std::string tmps; + Get(m_get_chan_stmt, 12, tmps); + // dummy users + ret.Recipients = std::vector<User>(); + auto ids = nlohmann::json::parse(tmps).get<std::vector<Snowflake>>(); + for (const auto &id : ids) + ret.Recipients->emplace_back().ID = id; + } + Get(m_get_chan_stmt, 13, ret.Icon); + Get(m_get_chan_stmt, 14, ret.OwnerID); + Get(m_get_chan_stmt, 15, ret.ApplicationID); + Get(m_get_chan_stmt, 16, ret.ParentID); + Get(m_get_chan_stmt, 17, ret.LastPinTimestamp); + + Reset(m_get_chan_stmt); + + return ret; } std::optional<Emoji> Store::GetEmoji(Snowflake id) const { @@ -488,20 +561,6 @@ std::optional<User> Store::GetUser(Snowflake id) const { return ret; } -Channel *Store::GetChannel(Snowflake id) { - auto it = m_channels.find(id); - if (it == m_channels.end()) - return nullptr; - return &it->second; -} - -const Channel *Store::GetChannel(Snowflake id) const { - auto it = m_channels.find(id); - if (it == m_channels.end()) - return nullptr; - return &it->second; -} - void Store::ClearGuild(Snowflake id) { m_guilds.erase(id); } @@ -510,7 +569,7 @@ void Store::ClearChannel(Snowflake id) { m_channels.erase(id); } -const Store::channels_type &Store::GetChannels() const { +const std::unordered_set<Snowflake> &Store::GetChannels() const { return m_channels; } @@ -668,6 +727,29 @@ lazy BOOL ) )"; + constexpr char *create_channels = R"( +CREATE TABLE IF NOT EXISTS channels ( +id INTEGER PRIMARY KEY, +type INTEGER NOT NULL, +guild_id INTEGER, +position INTEGER, +overwrites TEXT, /* json */ +name TEXT, +topic TEXT, +is_nsfw BOOL, +last_message_id INTEGER, +bitrate INTEGER, +user_limit INTEGER, +rate_limit INTEGER, +recipients TEXT, /* json */ +icon TEXT, +owner_id INTEGER, +application_id INTEGER, +parent_id INTEGER, +last_pin_timestamp TEXT +) +)"; + m_db_err = sqlite3_exec(m_db, create_users, nullptr, nullptr, nullptr); if (m_db_err != SQLITE_OK) { fprintf(stderr, "failed to create user table: %s\n", sqlite3_errstr(m_db_err)); @@ -710,6 +792,12 @@ lazy BOOL return false; } + m_db_err = sqlite3_exec(m_db, create_channels, nullptr, nullptr, nullptr); + if (m_db_err != SQLITE_OK) { + fprintf(stderr, "failed to create channels table: %s\n", sqlite3_errstr(m_db_err)); + return false; + } + return true; } @@ -776,7 +864,7 @@ SELECT * FROM members WHERE user_id = ? AND guild_id = ? constexpr const char *set_guild = R"( REPLACE INTO guilds VALUES ( -?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) )"; @@ -784,6 +872,16 @@ REPLACE INTO guilds VALUES ( SELECT * FROM guilds WHERE id = ? )"; + constexpr const char *set_chan = R"( +REPLACE INTO channels VALUES ( + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? +) +)"; + + constexpr const char *get_chan = R"( +SELECT * FROM channels WHERE id = ? +)"; + m_db_err = sqlite3_prepare_v2(m_db, set_user, -1, &m_set_user_stmt, nullptr); if (m_db_err != SQLITE_OK) { fprintf(stderr, "failed to prepare set user statement: %s\n", sqlite3_errstr(m_db_err)); @@ -868,6 +966,18 @@ SELECT * FROM guilds WHERE id = ? return false; } + m_db_err = sqlite3_prepare_v2(m_db, set_chan, -1, &m_set_chan_stmt, nullptr); + if (m_db_err != SQLITE_OK) { + fprintf(stderr, "failed to prepare set channel statement: %s\n", sqlite3_errstr(m_db_err)); + return false; + } + + m_db_err = sqlite3_prepare_v2(m_db, get_chan, -1, &m_get_chan_stmt, nullptr); + if (m_db_err != SQLITE_OK) { + fprintf(stderr, "failed to prepare get channel statement: %s\n", sqlite3_errstr(m_db_err)); + return false; + } + return true; } @@ -886,6 +996,8 @@ void Store::Cleanup() { sqlite3_finalize(m_get_member_stmt); sqlite3_finalize(m_set_guild_stmt); sqlite3_finalize(m_get_guild_stmt); + sqlite3_finalize(m_set_chan_stmt); + sqlite3_finalize(m_get_chan_stmt); } void Store::Bind(sqlite3_stmt *stmt, int index, int num) const { @@ -959,6 +1071,10 @@ void Store::Get(sqlite3_stmt *stmt, int index, Snowflake &out) const { out = static_cast<uint64_t>(num); } +bool Store::IsNull(sqlite3_stmt *stmt, int index) const { + return sqlite3_column_type(stmt, index) == SQLITE_NULL; +} + void Store::Reset(sqlite3_stmt *stmt) const { sqlite3_reset(stmt); sqlite3_clear_bindings(stmt); diff --git a/discord/store.hpp b/discord/store.hpp index 6d1987f..b08be07 100644 --- a/discord/store.hpp +++ b/discord/store.hpp @@ -19,7 +19,7 @@ public: bool IsValid() const; void SetUser(Snowflake id, const User &user); - void SetChannel(Snowflake id, const Channel &channel); + void SetChannel(Snowflake id, const Channel &chan); void SetGuild(Snowflake id, const Guild &guild); void SetRole(Snowflake id, const Role &role); void SetMessage(Snowflake id, const Message &message); @@ -29,7 +29,7 @@ public: // slap const on everything even tho its not *really* const - Channel *GetChannel(Snowflake id); + std::optional<Channel> GetChannel(Snowflake id) const; std::optional<Emoji> GetEmoji(Snowflake id) const; std::optional<Guild> GetGuild(Snowflake id) const; std::optional<GuildMember> GetGuildMember(Snowflake guild_id, Snowflake user_id) const; @@ -37,7 +37,6 @@ public: std::optional<PermissionOverwrite> GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const; std::optional<Role> GetRole(Snowflake id) const; std::optional<User> GetUser(Snowflake id) const; - const Channel *GetChannel(Snowflake id) const; void ClearGuild(Snowflake id); void ClearChannel(Snowflake id); @@ -51,7 +50,7 @@ public: using permission_overwrites_type = std::unordered_map<Snowflake, std::unordered_map<Snowflake, PermissionOverwrite>>; // [channel][user/role] using emojis_type = std::unordered_map<Snowflake, Emoji>; - const channels_type &GetChannels() const; + const std::unordered_set<Snowflake> &GetChannels() const; const std::unordered_set<Snowflake> &GetGuilds() const; void ClearAll(); @@ -60,7 +59,7 @@ public: void EndTransaction(); private: - channels_type m_channels; + std::unordered_set<Snowflake> m_channels; std::unordered_set<Snowflake> m_guilds; bool CreateTables(); @@ -83,6 +82,7 @@ private: void Get(sqlite3_stmt *stmt, int index, std::string &out) const; void Get(sqlite3_stmt *stmt, int index, bool &out) const; void Get(sqlite3_stmt *stmt, int index, Snowflake &out) const; + bool IsNull(sqlite3_stmt *stmt, int index) const; void Reset(sqlite3_stmt *stmt) const; std::filesystem::path m_db_path; @@ -102,6 +102,8 @@ private: mutable sqlite3_stmt *m_get_member_stmt; mutable sqlite3_stmt *m_set_guild_stmt; mutable sqlite3_stmt *m_get_guild_stmt; + mutable sqlite3_stmt *m_set_chan_stmt; + mutable sqlite3_stmt *m_get_chan_stmt; }; template<typename T> |