reduce db access + refactor

This commit is contained in:
ouwou
2021-06-10 15:27:32 -04:00
parent c73b08e341
commit efc97aa2b0
13 changed files with 252 additions and 217 deletions

View File

@@ -181,7 +181,7 @@ void Abaddon::DiscordOnReady() {
} }
void Abaddon::DiscordOnMessageCreate(const Message &message) { void Abaddon::DiscordOnMessageCreate(const Message &message) {
m_main_window->UpdateChatNewMessage(message.ID); // todo ill fix you later :^) m_main_window->UpdateChatNewMessage(message);
} }
void Abaddon::DiscordOnMessageDelete(Snowflake id, Snowflake channel_id) { void Abaddon::DiscordOnMessageDelete(Snowflake id, Snowflake channel_id) {
@@ -236,7 +236,7 @@ void Abaddon::DiscordOnGuildJoinRequestCreate(const GuildJoinRequestCreateData &
} }
void Abaddon::DiscordOnMessageSent(const Message &data) { void Abaddon::DiscordOnMessageSent(const Message &data) {
m_main_window->UpdateChatNewMessage(data.ID); m_main_window->UpdateChatNewMessage(data);
} }
void Abaddon::DiscordOnDisconnect(bool is_reconnecting, GatewayCloseCode close_code) { void Abaddon::DiscordOnDisconnect(bool is_reconnecting, GatewayCloseCode close_code) {
@@ -475,7 +475,7 @@ void Abaddon::ActionChannelOpened(Snowflake id) {
} }
m_main_window->UpdateChatActiveChannel(id); m_main_window->UpdateChatActiveChannel(id);
if (m_channels_requested.find(id) == m_channels_requested.end()) { if (m_channels_requested.find(id) == m_channels_requested.end()) {
m_discord.FetchMessagesInChannel(id, [this, id](const std::vector<Snowflake> &msgs) { m_discord.FetchMessagesInChannel(id, [this, id](const std::vector<Message> &msgs) {
m_main_window->UpdateChatWindowContents(); m_main_window->UpdateChatWindowContents();
m_channels_requested.insert(id); m_channels_requested.insert(id);
}); });
@@ -500,20 +500,23 @@ void Abaddon::ActionChatLoadHistory(Snowflake id) {
return; return;
Snowflake before_id = m_main_window->GetChatOldestListedMessage(); Snowflake before_id = m_main_window->GetChatOldestListedMessage();
auto knownset = m_discord.GetMessagesForChannel(id); auto knownset = m_discord.GetMessageIDsForChannel(id);
std::vector<Snowflake> knownvec(knownset.begin(), knownset.end()); std::vector<Snowflake> knownvec(knownset.begin(), knownset.end());
std::sort(knownvec.begin(), knownvec.end()); std::sort(knownvec.begin(), knownvec.end());
auto latest = std::find_if(knownvec.begin(), knownvec.end(), [&before_id](Snowflake x) -> bool { return x == before_id; }); auto latest = std::find_if(knownvec.begin(), knownvec.end(), [&before_id](Snowflake x) -> bool { return x == before_id; });
int distance = std::distance(knownvec.begin(), latest); int distance = std::distance(knownvec.begin(), latest);
if (distance >= 50) { if (distance >= 50) {
m_main_window->UpdateChatPrependHistory(std::vector<Snowflake>(knownvec.begin() + distance - 50, knownvec.begin() + distance)); std::vector<Message> msgs;
for (auto it = knownvec.begin() + distance - 50; it != knownvec.begin() + distance; it++)
msgs.push_back(*m_discord.GetMessage(*it));
m_main_window->UpdateChatPrependHistory(msgs);
return; return;
} }
m_channels_history_loading.insert(id); m_channels_history_loading.insert(id);
m_discord.FetchMessagesInChannelBefore(id, before_id, [this, id](const std::vector<Snowflake> &msgs) { m_discord.FetchMessagesInChannelBefore(id, before_id, [this, id](const std::vector<Message> &msgs) {
m_channels_history_loading.erase(id); m_channels_history_loading.erase(id);
if (msgs.size() == 0) { if (msgs.size() == 0) {

View File

@@ -44,16 +44,14 @@ void ChatList::SetActiveChannel(Snowflake id) {
m_active_channel = id; m_active_channel = id;
} }
void ChatList::ProcessNewMessage(Snowflake id, bool prepend) { void ChatList::ProcessNewMessage(const Message &data, bool prepend) {
auto &discord = Abaddon::Get().GetDiscordClient(); auto &discord = Abaddon::Get().GetDiscordClient();
if (!discord.IsStarted()) return; if (!discord.IsStarted()) return;
const auto data = discord.GetMessage(id);
if (!data.has_value()) return;
// delete preview message when gateway sends it back // delete preview message when gateway sends it back
if (!data->IsPending && data->Nonce.has_value() && data->Author.ID == discord.GetUserData().ID) { if (!data.IsPending && data.Nonce.has_value() && data.Author.ID == discord.GetUserData().ID) {
for (auto [id, widget] : m_id_to_widget) { for (auto [id, widget] : m_id_to_widget) {
if (dynamic_cast<ChatMessageItemContainer *>(widget)->Nonce == *data->Nonce) { if (dynamic_cast<ChatMessageItemContainer *>(widget)->Nonce == *data.Nonce) {
RemoveMessageAndHeader(widget); RemoveMessageAndHeader(widget);
m_id_to_widget.erase(id); m_id_to_widget.erase(id);
break; break;
@@ -70,8 +68,8 @@ void ChatList::ProcessNewMessage(Snowflake id, bool prepend) {
last_row = dynamic_cast<ChatMessageHeader *>(m_list.get_row_at_index(m_num_rows - 1)); last_row = dynamic_cast<ChatMessageHeader *>(m_list.get_row_at_index(m_num_rows - 1));
if (last_row != nullptr) { if (last_row != nullptr) {
const uint64_t diff = std::max(id, last_row->NewestID) - std::min(id, last_row->NewestID); const uint64_t diff = std::max(data.ID, last_row->NewestID) - std::min(data.ID, last_row->NewestID);
if (last_row->UserID == data->Author.ID && (prepend || (diff < SnowflakeSplitDifference * Snowflake::SecondsInterval))) if (last_row->UserID == data.Author.ID && (prepend || (diff < SnowflakeSplitDifference * Snowflake::SecondsInterval)))
should_attach = true; should_attach = true;
} }
} }
@@ -91,11 +89,11 @@ void ChatList::ProcessNewMessage(Snowflake id, bool prepend) {
header = last_row; header = last_row;
} else { } else {
const auto guild_id = *discord.GetChannel(m_active_channel)->GuildID; const auto guild_id = *discord.GetChannel(m_active_channel)->GuildID;
const auto user_id = data->Author.ID; const auto user_id = data.Author.ID;
const auto user = discord.GetUser(user_id); const auto user = discord.GetUser(user_id);
if (!user.has_value()) return; if (!user.has_value()) return;
header = Gtk::manage(new ChatMessageHeader(&*data)); header = Gtk::manage(new ChatMessageHeader(data));
header->signal_action_insert_mention().connect([this, user_id]() { header->signal_action_insert_mention().connect([this, user_id]() {
m_signal_action_insert_mention.emit(user_id); m_signal_action_insert_mention.emit(user_id);
}); });
@@ -107,22 +105,22 @@ void ChatList::ProcessNewMessage(Snowflake id, bool prepend) {
m_num_rows++; m_num_rows++;
} }
auto *content = ChatMessageItemContainer::FromMessage(id); auto *content = ChatMessageItemContainer::FromMessage(data);
if (content != nullptr) { if (content != nullptr) {
header->AddContent(content, prepend); header->AddContent(content, prepend);
m_id_to_widget[id] = content; m_id_to_widget[data.ID] = content;
if (!data->IsPending) { if (!data.IsPending) {
content->signal_action_delete().connect([this, id] { content->signal_action_delete().connect([this, id = data.ID] {
m_signal_action_message_delete.emit(m_active_channel, id); m_signal_action_message_delete.emit(m_active_channel, id);
}); });
content->signal_action_edit().connect([this, id] { content->signal_action_edit().connect([this, id = data.ID] {
m_signal_action_message_edit.emit(m_active_channel, id); m_signal_action_message_edit.emit(m_active_channel, id);
}); });
content->signal_action_reaction_add().connect([this, id](const Glib::ustring &param) { content->signal_action_reaction_add().connect([this, id = data.ID](const Glib::ustring &param) {
m_signal_action_reaction_add.emit(id, param); m_signal_action_reaction_add.emit(id, param);
}); });
content->signal_action_reaction_remove().connect([this, id](const Glib::ustring &param) { content->signal_action_reaction_remove().connect([this, id = data.ID](const Glib::ustring &param) {
m_signal_action_reaction_remove.emit(id, param); m_signal_action_reaction_remove.emit(id, param);
}); });
content->signal_action_channel_click().connect([this](const Snowflake &id) { content->signal_action_channel_click().connect([this](const Snowflake &id) {

View File

@@ -13,7 +13,7 @@ public:
void SetMessages(Iter begin, Iter end); void SetMessages(Iter begin, Iter end);
template<typename Iter> template<typename Iter>
void PrependMessages(Iter begin, Iter end); void PrependMessages(Iter begin, Iter end);
void ProcessNewMessage(Snowflake id, bool prepend); void ProcessNewMessage(const Message &data, bool prepend);
void DeleteMessage(Snowflake id); void DeleteMessage(Snowflake id);
void RefetchMessage(Snowflake id); void RefetchMessage(Snowflake id);
Snowflake GetOldestListedMessage(); Snowflake GetOldestListedMessage();

View File

@@ -43,32 +43,29 @@ ChatMessageItemContainer::ChatMessageItemContainer() {
m_link_menu.show_all(); m_link_menu.show_all();
} }
ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(Snowflake id) { ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(const Message &data) {
const auto data = Abaddon::Get().GetDiscordClient().GetMessage(id);
if (!data.has_value()) return nullptr;
auto *container = Gtk::manage(new ChatMessageItemContainer); auto *container = Gtk::manage(new ChatMessageItemContainer);
container->ID = data->ID; container->ID = data.ID;
container->ChannelID = data->ChannelID; container->ChannelID = data.ChannelID;
if (data->Nonce.has_value()) if (data.Nonce.has_value())
container->Nonce = *data->Nonce; container->Nonce = *data.Nonce;
if (data->Content.size() > 0 || data->Type != MessageType::DEFAULT) { if (data.Content.size() > 0 || data.Type != MessageType::DEFAULT) {
container->m_text_component = container->CreateTextComponent(&*data); container->m_text_component = container->CreateTextComponent(data);
container->AttachEventHandlers(*container->m_text_component); container->AttachEventHandlers(*container->m_text_component);
container->m_main->add(*container->m_text_component); container->m_main->add(*container->m_text_component);
} }
if ((data->MessageReference.has_value() || data->Interaction.has_value()) && data->Type != MessageType::CHANNEL_FOLLOW_ADD) { if ((data.MessageReference.has_value() || data.Interaction.has_value()) && data.Type != MessageType::CHANNEL_FOLLOW_ADD) {
auto *widget = container->CreateReplyComponent(*data); auto *widget = container->CreateReplyComponent(data);
container->m_main->add(*widget); container->m_main->add(*widget);
container->m_main->child_property_position(*widget) = 0; // eek container->m_main->child_property_position(*widget) = 0; // eek
} }
// there should only ever be 1 embed (i think?) // there should only ever be 1 embed (i think?)
if (data->Embeds.size() == 1) { if (data.Embeds.size() == 1) {
const auto &embed = data->Embeds[0]; const auto &embed = data.Embeds[0];
if (IsEmbedImageOnly(embed)) { if (IsEmbedImageOnly(embed)) {
auto *widget = container->CreateImageComponent(*embed.Thumbnail->ProxyURL, *embed.Thumbnail->URL, *embed.Thumbnail->Width, *embed.Thumbnail->Height); auto *widget = container->CreateImageComponent(*embed.Thumbnail->ProxyURL, *embed.Thumbnail->URL, *embed.Thumbnail->Width, *embed.Thumbnail->Height);
container->AttachEventHandlers(*widget); container->AttachEventHandlers(*widget);
@@ -82,7 +79,7 @@ ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(Snowflake id) {
// i dont think attachments can be edited // i dont think attachments can be edited
// also this can definitely be done much better holy shit // also this can definitely be done much better holy shit
for (const auto &a : data->Attachments) { for (const auto &a : data.Attachments) {
if (IsURLViewableImage(a.ProxyURL) && a.Width.has_value() && a.Height.has_value()) { if (IsURLViewableImage(a.ProxyURL) && a.Width.has_value() && a.Height.has_value()) {
auto *widget = container->CreateImageComponent(a.ProxyURL, a.URL, *a.Width, *a.Height); auto *widget = container->CreateImageComponent(a.ProxyURL, a.URL, *a.Width, *a.Height);
container->m_main->add(*widget); container->m_main->add(*widget);
@@ -93,8 +90,8 @@ ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(Snowflake id) {
} }
// only 1? // only 1?
if (data->Stickers.has_value()) { if (data.Stickers.has_value()) {
const auto &sticker = data->Stickers.value()[0]; const auto &sticker = data.Stickers.value()[0];
// todo: lottie, proper apng // todo: lottie, proper apng
if (sticker.FormatType == StickerFormatType::PNG || sticker.FormatType == StickerFormatType::APNG) { if (sticker.FormatType == StickerFormatType::PNG || sticker.FormatType == StickerFormatType::APNG) {
auto *widget = container->CreateStickerComponent(sticker); auto *widget = container->CreateStickerComponent(sticker);
@@ -102,8 +99,8 @@ ChatMessageItemContainer *ChatMessageItemContainer::FromMessage(Snowflake id) {
} }
} }
if (data->Reactions.has_value() && data->Reactions->size() > 0) { if (data.Reactions.has_value() && data.Reactions->size() > 0) {
container->m_reactions_component = container->CreateReactionsComponent(*data); container->m_reactions_component = container->CreateReactionsComponent(data);
container->m_main->add(*container->m_reactions_component); container->m_main->add(*container->m_reactions_component);
} }
@@ -183,10 +180,10 @@ void ChatMessageItemContainer::AddClickHandler(Gtk::Widget *widget, std::string
// clang-format on // clang-format on
} }
Gtk::TextView *ChatMessageItemContainer::CreateTextComponent(const Message *data) { Gtk::TextView *ChatMessageItemContainer::CreateTextComponent(const Message &data) {
auto *tv = Gtk::manage(new Gtk::TextView); auto *tv = Gtk::manage(new Gtk::TextView);
if (data->IsPending) if (data.IsPending)
tv->get_style_context()->add_class("pending"); tv->get_style_context()->add_class("pending");
tv->get_style_context()->add_class("message-text"); tv->get_style_context()->add_class("message-text");
tv->set_can_focus(false); tv->set_can_focus(false);
@@ -1065,9 +1062,9 @@ void ChatMessageItemContainer::AttachEventHandlers(Gtk::Widget &widget) {
widget.signal_button_press_event().connect(on_button_press_event, false); widget.signal_button_press_event().connect(on_button_press_event, false);
} }
ChatMessageHeader::ChatMessageHeader(const Message *data) { ChatMessageHeader::ChatMessageHeader(const Message &data) {
UserID = data->Author.ID; UserID = data.Author.ID;
ChannelID = data->ChannelID; ChannelID = data.ChannelID;
m_main_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)); m_main_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
m_content_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); m_content_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
@@ -1086,7 +1083,7 @@ ChatMessageHeader::ChatMessageHeader(const Message *data) {
m_static_avatar = pb->scale_simple(AvatarSize, AvatarSize, Gdk::INTERP_BILINEAR); m_static_avatar = pb->scale_simple(AvatarSize, AvatarSize, Gdk::INTERP_BILINEAR);
m_avatar->property_pixbuf() = m_static_avatar; m_avatar->property_pixbuf() = m_static_avatar;
}; };
img.LoadFromURL(author->GetAvatarURL(data->GuildID), sigc::track_obj(cb, *this)); img.LoadFromURL(author->GetAvatarURL(data.GuildID), sigc::track_obj(cb, *this));
if (author->HasAnimatedAvatar()) { if (author->HasAnimatedAvatar()) {
auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) { auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
@@ -1103,7 +1100,7 @@ ChatMessageHeader::ChatMessageHeader(const Message *data) {
m_avatar->set_valign(Gtk::ALIGN_START); m_avatar->set_valign(Gtk::ALIGN_START);
m_avatar->set_margin_right(10); m_avatar->set_margin_right(10);
m_author->set_markup(data->Author.GetEscapedBoldName()); m_author->set_markup(data.Author.GetEscapedBoldName());
m_author->set_single_line_mode(true); m_author->set_single_line_mode(true);
m_author->set_line_wrap(false); m_author->set_line_wrap(false);
m_author->set_ellipsize(Pango::ELLIPSIZE_END); m_author->set_ellipsize(Pango::ELLIPSIZE_END);
@@ -1112,7 +1109,7 @@ ChatMessageHeader::ChatMessageHeader(const Message *data) {
m_meta_ev->signal_button_press_event().connect(sigc::mem_fun(*this, &ChatMessageHeader::on_author_button_press)); m_meta_ev->signal_button_press_event().connect(sigc::mem_fun(*this, &ChatMessageHeader::on_author_button_press));
if (author->IsBot || data->WebhookID.has_value()) { if (author->IsBot || data.WebhookID.has_value()) {
m_extra = Gtk::manage(new Gtk::Label); m_extra = Gtk::manage(new Gtk::Label);
m_extra->get_style_context()->add_class("message-container-extra"); m_extra->get_style_context()->add_class("message-container-extra");
m_extra->set_single_line_mode(true); m_extra->set_single_line_mode(true);
@@ -1122,10 +1119,10 @@ ChatMessageHeader::ChatMessageHeader(const Message *data) {
} }
if (author->IsBot) if (author->IsBot)
m_extra->set_markup("<b>BOT</b>"); m_extra->set_markup("<b>BOT</b>");
else if (data->WebhookID.has_value()) else if (data.WebhookID.has_value())
m_extra->set_markup("<b>Webhook</b>"); m_extra->set_markup("<b>Webhook</b>");
m_timestamp->set_text(data->ID.GetLocalTimestamp()); m_timestamp->set_text(data.ID.GetLocalTimestamp());
m_timestamp->set_hexpand(true); m_timestamp->set_hexpand(true);
m_timestamp->set_halign(Gtk::ALIGN_END); m_timestamp->set_halign(Gtk::ALIGN_END);
m_timestamp->set_ellipsize(Pango::ELLIPSIZE_END); m_timestamp->set_ellipsize(Pango::ELLIPSIZE_END);

View File

@@ -10,7 +10,7 @@ public:
std::string Nonce; std::string Nonce;
ChatMessageItemContainer(); ChatMessageItemContainer();
static ChatMessageItemContainer *FromMessage(Snowflake id); static ChatMessageItemContainer *FromMessage(const Message &data);
// attributes = edited, deleted // attributes = edited, deleted
void UpdateAttributes(); void UpdateAttributes();
@@ -20,7 +20,7 @@ public:
protected: protected:
void AddClickHandler(Gtk::Widget *widget, std::string); void AddClickHandler(Gtk::Widget *widget, std::string);
Gtk::TextView *CreateTextComponent(const Message *data); // Message.Content Gtk::TextView *CreateTextComponent(const Message &data); // Message.Content
void UpdateTextComponent(Gtk::TextView *tv); void UpdateTextComponent(Gtk::TextView *tv);
Gtk::Widget *CreateEmbedComponent(const EmbedData &data); // Message.Embeds[0] Gtk::Widget *CreateEmbedComponent(const EmbedData &data); // Message.Embeds[0]
Gtk::Widget *CreateImageComponent(const std::string &proxy_url, const std::string &url, int inw, int inh); Gtk::Widget *CreateImageComponent(const std::string &proxy_url, const std::string &url, int inw, int inh);
@@ -111,7 +111,7 @@ public:
Snowflake ChannelID; Snowflake ChannelID;
Snowflake NewestID = 0; Snowflake NewestID = 0;
ChatMessageHeader(const Message *data); ChatMessageHeader(const Message &data);
void AddContent(Gtk::Widget *widget, bool prepend); void AddContent(Gtk::Widget *widget, bool prepend);
void UpdateNameColor(); void UpdateNameColor();
std::vector<Gtk::Widget*> GetChildContent(); std::vector<Gtk::Widget*> GetChildContent();

View File

@@ -99,10 +99,10 @@ Gtk::Widget *ChatWindow::GetRoot() const {
} }
void ChatWindow::Clear() { void ChatWindow::Clear() {
SetMessages(std::set<Snowflake>()); m_chat->Clear();
} }
void ChatWindow::SetMessages(const std::set<Snowflake> &msgs) { void ChatWindow::SetMessages(const std::vector<Message> &msgs) {
m_chat->SetMessages(msgs.begin(), msgs.end()); m_chat->SetMessages(msgs.begin(), msgs.end());
} }
@@ -115,8 +115,8 @@ void ChatWindow::SetActiveChannel(Snowflake id) {
StopReplying(); StopReplying();
} }
void ChatWindow::AddNewMessage(Snowflake id) { void ChatWindow::AddNewMessage(const Message &data) {
m_chat->ProcessNewMessage(id, false); m_chat->ProcessNewMessage(data, false);
} }
void ChatWindow::DeleteMessage(Snowflake id) { void ChatWindow::DeleteMessage(Snowflake id) {
@@ -127,8 +127,8 @@ void ChatWindow::UpdateMessage(Snowflake id) {
m_chat->RefetchMessage(id); m_chat->RefetchMessage(id);
} }
void ChatWindow::AddNewHistory(const std::vector<Snowflake> &id) { void ChatWindow::AddNewHistory(const std::vector<Message> &msgs) {
m_chat->PrependMessages(id.begin(), id.end()); m_chat->PrependMessages(msgs.crbegin(), msgs.crend());
} }
void ChatWindow::InsertChatInput(std::string text) { void ChatWindow::InsertChatInput(std::string text) {

View File

@@ -19,12 +19,12 @@ public:
Snowflake GetActiveChannel() const; Snowflake GetActiveChannel() const;
void Clear(); void Clear();
void SetMessages(const std::set<Snowflake> &msgs); // clear contents and replace with given set void SetMessages(const std::vector<Message> &msgs); // clear contents and replace with given set
void SetActiveChannel(Snowflake id); void SetActiveChannel(Snowflake id);
void AddNewMessage(Snowflake id); // append new message to bottom void AddNewMessage(const Message &data); // append new message to bottom
void DeleteMessage(Snowflake id); // add [deleted] indicator void DeleteMessage(Snowflake id); // add [deleted] indicator
void UpdateMessage(Snowflake id); // add [edited] indicator void UpdateMessage(Snowflake id); // add [edited] indicator
void AddNewHistory(const std::vector<Snowflake> &id); // prepend messages void AddNewHistory(const std::vector<Message> &msgs); // prepend messages
void InsertChatInput(std::string text); void InsertChatInput(std::string text);
Snowflake GetOldestListedMessage(); // oldest message that is currently in the ListBox Snowflake GetOldestListedMessage(); // oldest message that is currently in the ListBox
void UpdateReactions(Snowflake id); void UpdateReactions(Snowflake id);

View File

@@ -46,7 +46,6 @@ void DiscordClient::Stop() {
m_client_connected = false; m_client_connected = false;
m_store.ClearAll(); m_store.ClearAll();
m_chan_to_message_map.clear();
m_guild_to_users.clear(); m_guild_to_users.clear();
m_websocket.Stop(); m_websocket.Stop();
@@ -99,16 +98,12 @@ std::vector<Snowflake> DiscordClient::GetUserSortedGuilds() const {
return ret; return ret;
} }
std::set<Snowflake> DiscordClient::GetMessagesForChannel(Snowflake id) const { std::vector<Message> DiscordClient::GetMessagesForChannel(Snowflake id, size_t limit) const {
auto it = m_chan_to_message_map.find(id); return m_store.GetLastMessages(id, limit);
if (it == m_chan_to_message_map.end()) }
return std::set<Snowflake>();
std::set<Snowflake> ret; std::vector<Snowflake> DiscordClient::GetMessageIDsForChannel(Snowflake id) const {
for (const auto &msg_id : it->second) return m_store.GetChannelMessageIDs(id);
ret.insert(m_store.GetMessage(msg_id)->ID);
return ret;
} }
void DiscordClient::FetchInvite(std::string code, sigc::slot<void(std::optional<InviteData>)> callback) { void DiscordClient::FetchInvite(std::string code, sigc::slot<void(std::optional<InviteData>)> callback) {
@@ -123,49 +118,44 @@ void DiscordClient::FetchInvite(std::string code, sigc::slot<void(std::optional<
}); });
} }
void DiscordClient::FetchMessagesInChannel(Snowflake id, std::function<void(const std::vector<Snowflake> &)> cb) { void DiscordClient::FetchMessagesInChannel(Snowflake id, sigc::slot<void(const std::vector<Message> &)> cb) {
std::string path = "/channels/" + std::to_string(id) + "/messages?limit=50"; std::string path = "/channels/" + std::to_string(id) + "/messages?limit=50";
m_http.MakeGET(path, [this, id, cb](const http::response_type &r) { m_http.MakeGET(path, [this, id, cb](const http::response_type &r) {
if (!CheckCode(r)) return; if (!CheckCode(r)) return;
std::vector<Message> msgs; std::vector<Message> msgs;
std::vector<Snowflake> ids;
nlohmann::json::parse(r.text).get_to(msgs); nlohmann::json::parse(r.text).get_to(msgs);
m_store.BeginTransaction(); m_store.BeginTransaction();
for (auto &msg : msgs) { for (auto &msg : msgs) {
StoreMessageData(msg); StoreMessageData(msg);
AddMessageToChannel(msg.ID, id);
AddUserToGuild(msg.Author.ID, *msg.GuildID); AddUserToGuild(msg.Author.ID, *msg.GuildID);
ids.push_back(msg.ID);
} }
m_store.EndTransaction(); m_store.EndTransaction();
cb(ids); cb(msgs);
}); });
} }
void DiscordClient::FetchMessagesInChannelBefore(Snowflake channel_id, Snowflake before_id, std::function<void(const std::vector<Snowflake> &)> cb) { void DiscordClient::FetchMessagesInChannelBefore(Snowflake channel_id, Snowflake before_id, sigc::slot<void(const std::vector<Message> &)> cb) {
std::string path = "/channels/" + std::to_string(channel_id) + "/messages?limit=50&before=" + std::to_string(before_id); std::string path = "/channels/" + std::to_string(channel_id) + "/messages?limit=50&before=" + std::to_string(before_id);
m_http.MakeGET(path, [this, channel_id, cb](http::response_type r) { m_http.MakeGET(path, [this, channel_id, cb](http::response_type r) {
if (!CheckCode(r)) return; if (!CheckCode(r)) return;
std::vector<Message> msgs; std::vector<Message> msgs;
std::vector<Snowflake> ids;
nlohmann::json::parse(r.text).get_to(msgs); nlohmann::json::parse(r.text).get_to(msgs);
m_store.BeginTransaction(); m_store.BeginTransaction();
for (auto &msg : msgs) { for (auto &msg : msgs) {
StoreMessageData(msg); StoreMessageData(msg);
AddMessageToChannel(msg.ID, channel_id);
AddUserToGuild(msg.Author.ID, *msg.GuildID); AddUserToGuild(msg.Author.ID, *msg.GuildID);
ids.push_back(msg.ID);
} }
m_store.EndTransaction(); m_store.EndTransaction();
cb(ids); std::sort(msgs.begin(), msgs.end(), [](const Message &a, const Message &b) { return a.ID < b.ID; });
cb(msgs);
}); });
} }
@@ -1119,7 +1109,6 @@ std::string DiscordClient::GetGatewayURL() {
DiscordError DiscordClient::GetCodeFromResponse(const http::response_type &response) { DiscordError DiscordClient::GetCodeFromResponse(const http::response_type &response) {
try { try {
// pull me somewhere else?
const auto data = nlohmann::json::parse(response.text); const auto data = nlohmann::json::parse(response.text);
return data.at("code").get<DiscordError>(); return data.at("code").get<DiscordError>();
} catch (...) {} } catch (...) {}
@@ -1201,7 +1190,6 @@ void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) {
void DiscordClient::HandleGatewayMessageCreate(const GatewayMessage &msg) { void DiscordClient::HandleGatewayMessageCreate(const GatewayMessage &msg) {
Message data = msg.Data; Message data = msg.Data;
StoreMessageData(data); StoreMessageData(data);
AddMessageToChannel(data.ID, data.ChannelID);
AddUserToGuild(data.Author.ID, *data.GuildID); AddUserToGuild(data.Author.ID, *data.GuildID);
m_signal_message_create.emit(data); m_signal_message_create.emit(data);
} }
@@ -1699,10 +1687,6 @@ void DiscordClient::HandleGatewayGuildDelete(const GatewayMessage &msg) {
m_signal_guild_delete.emit(id); m_signal_guild_delete.emit(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) { void DiscordClient::AddUserToGuild(Snowflake user_id, Snowflake guild_id) {
m_guild_to_users[guild_id].insert(user_id); m_guild_to_users[guild_id].insert(user_id);
} }
@@ -1792,7 +1776,6 @@ void DiscordClient::HandleSocketClose(uint16_t code) {
m_client_connected = false; m_client_connected = false;
m_store.ClearAll(); m_store.ClearAll();
m_chan_to_message_map.clear();
m_guild_to_users.clear(); m_guild_to_users.clear();
m_signal_disconnected.emit(m_reconnecting, close_code); m_signal_disconnected.emit(m_reconnecting, close_code);

View File

@@ -68,13 +68,14 @@ public:
const UserData &GetUserData() const; const UserData &GetUserData() const;
const UserSettings &GetUserSettings() const; const UserSettings &GetUserSettings() const;
std::vector<Snowflake> GetUserSortedGuilds() const; std::vector<Snowflake> GetUserSortedGuilds() const;
std::set<Snowflake> GetMessagesForChannel(Snowflake id) const; std::vector<Message> GetMessagesForChannel(Snowflake id, size_t limit = 50) const;
std::vector<Snowflake> GetMessageIDsForChannel(Snowflake id) const;
std::set<Snowflake> GetPrivateChannels() const; std::set<Snowflake> GetPrivateChannels() const;
EPremiumType GetSelfPremiumType() const; EPremiumType GetSelfPremiumType() const;
void FetchMessagesInChannel(Snowflake id, std::function<void(const std::vector<Snowflake> &)> cb); void FetchMessagesInChannel(Snowflake id, sigc::slot<void(const std::vector<Message> &)> cb);
void FetchMessagesInChannelBefore(Snowflake channel_id, Snowflake before_id, std::function<void(const std::vector<Snowflake> &)> cb); void FetchMessagesInChannelBefore(Snowflake channel_id, Snowflake before_id, sigc::slot<void(const std::vector<Message> &)> cb);
std::optional<Message> GetMessage(Snowflake id) const; std::optional<Message> GetMessage(Snowflake id) const;
std::optional<ChannelData> GetChannel(Snowflake id) const; std::optional<ChannelData> GetChannel(Snowflake id) const;
std::optional<EmojiData> GetEmoji(Snowflake id) const; std::optional<EmojiData> GetEmoji(Snowflake id) const;
@@ -247,9 +248,6 @@ private:
std::string m_token; std::string m_token;
void AddMessageToChannel(Snowflake msg_id, Snowflake channel_id);
std::unordered_map<Snowflake, std::unordered_set<Snowflake>> m_chan_to_message_map;
void AddUserToGuild(Snowflake user_id, Snowflake guild_id); void AddUserToGuild(Snowflake user_id, Snowflake guild_id);
std::unordered_map<Snowflake, std::unordered_set<Snowflake>> m_guild_to_users; std::unordered_map<Snowflake, std::unordered_set<Snowflake>> m_guild_to_users;

View File

@@ -315,6 +315,82 @@ void Store::SetUser(Snowflake id, const UserData &user) {
} }
} }
Message Store::GetMessageBound(sqlite3_stmt *stmt) const {
Message ret;
Get(stmt, 0, ret.ID);
Get(stmt, 1, ret.ChannelID);
Get(stmt, 2, ret.GuildID);
Get(stmt, 3, ret.Author.ID); // yike
Get(stmt, 4, ret.Content);
Get(stmt, 5, ret.Timestamp);
Get(stmt, 6, ret.EditedTimestamp);
Get(stmt, 7, ret.IsTTS);
Get(stmt, 8, ret.DoesMentionEveryone);
std::string tmps;
Get(stmt, 9, tmps);
nlohmann::json::parse(tmps).get_to(ret.Mentions);
Get(stmt, 10, tmps);
nlohmann::json::parse(tmps).get_to(ret.Attachments);
Get(stmt, 11, tmps);
nlohmann::json::parse(tmps).get_to(ret.Embeds);
Get(stmt, 12, ret.IsPinned);
Get(stmt, 13, ret.WebhookID);
uint64_t tmpi;
Get(stmt, 14, tmpi);
ret.Type = static_cast<MessageType>(tmpi);
Get(stmt, 15, tmps);
if (tmps != "")
ret.Application = nlohmann::json::parse(tmps).get<MessageApplicationData>();
Get(stmt, 16, tmps);
if (tmps != "")
ret.MessageReference = nlohmann::json::parse(tmps).get<MessageReferenceData>();
Get(stmt, 17, tmpi);
ret.Flags = static_cast<MessageFlags>(tmpi);
Get(stmt, 18, tmps);
if (tmps != "")
ret.Stickers = nlohmann::json::parse(tmps).get<std::vector<StickerData>>();
Get(stmt, 19, tmps);
if (tmps != "")
ret.Reactions = nlohmann::json::parse(tmps).get<std::vector<ReactionData>>();
bool tmpb = false;
Get(stmt, 20, tmpb);
if (tmpb) ret.SetDeleted();
Get(stmt, 21, tmpb);
if (tmpb) ret.SetEdited();
Get(stmt, 22, ret.IsPending);
Get(stmt, 23, ret.Nonce);
// interaction data from join
if (!IsNull(stmt, 24)) {
auto &interaction = ret.Interaction.emplace();
Get(stmt, 24, interaction.ID);
Get(stmt, 25, interaction.Name);
Get(stmt, 26, interaction.Type);
Get(stmt, 27, interaction.User.ID);
}
Reset(stmt);
if (ret.MessageReference.has_value() && ret.MessageReference->MessageID.has_value()) {
auto ref = GetMessage(*ret.MessageReference->MessageID);
if (ref.has_value())
ret.ReferencedMessage = std::make_unique<Message>(std::move(*ref));
else
ret.ReferencedMessage = nullptr;
}
return ret;
}
void Store::SetMessageInteractionPair(Snowflake message_id, const MessageInteractionData &interaction) { void Store::SetMessageInteractionPair(Snowflake message_id, const MessageInteractionData &interaction) {
Bind(m_set_msg_interaction_stmt, 1, message_id); Bind(m_set_msg_interaction_stmt, 1, message_id);
Bind(m_set_msg_interaction_stmt, 2, interaction.ID); Bind(m_set_msg_interaction_stmt, 2, interaction.ID);
@@ -362,6 +438,31 @@ std::vector<BanData> Store::GetBans(Snowflake guild_id) const {
return ret; return ret;
} }
std::vector<Message> Store::GetLastMessages(Snowflake id, size_t num) const {
auto ids = GetChannelMessageIDs(id);
std::vector<Message> ret;
for (auto it = ids.cend() - std::min(ids.size(), num); it != ids.cend(); it++)
ret.push_back(*GetMessage(*it));
return ret;
}
std::vector<Snowflake> Store::GetChannelMessageIDs(Snowflake id) const {
std::vector<Snowflake> ret;
Bind(m_get_msg_ids_stmt, 1, id);
while (FetchOne(m_get_msg_ids_stmt)) {
Snowflake x;
Get(m_get_msg_ids_stmt, 0, x);
ret.push_back(x);
}
Reset(m_get_msg_ids_stmt);
if (m_db_err != SQLITE_DONE)
fprintf(stderr, "error while fetching ids: %s\n", sqlite3_errstr(m_db_err));
return ret;
}
std::optional<ChannelData> Store::GetChannel(Snowflake id) const { std::optional<ChannelData> Store::GetChannel(Snowflake id) const {
Bind(m_get_chan_stmt, 1, id); Bind(m_get_chan_stmt, 1, id);
if (!FetchOne(m_get_chan_stmt)) { if (!FetchOne(m_get_chan_stmt)) {
@@ -537,77 +638,7 @@ std::optional<Message> Store::GetMessage(Snowflake id) const {
return std::nullopt; return std::nullopt;
} }
Message ret; auto ret = GetMessageBound(m_get_msg_stmt);
ret.ID = id;
Get(m_get_msg_stmt, 1, ret.ChannelID);
Get(m_get_msg_stmt, 2, ret.GuildID);
Get(m_get_msg_stmt, 3, ret.Author.ID); // yike
Get(m_get_msg_stmt, 4, ret.Content);
Get(m_get_msg_stmt, 5, ret.Timestamp);
Get(m_get_msg_stmt, 6, ret.EditedTimestamp);
Get(m_get_msg_stmt, 7, ret.IsTTS);
Get(m_get_msg_stmt, 8, ret.DoesMentionEveryone);
std::string tmps;
Get(m_get_msg_stmt, 9, tmps);
nlohmann::json::parse(tmps).get_to(ret.Mentions);
Get(m_get_msg_stmt, 10, tmps);
nlohmann::json::parse(tmps).get_to(ret.Attachments);
Get(m_get_msg_stmt, 11, tmps);
nlohmann::json::parse(tmps).get_to(ret.Embeds);
Get(m_get_msg_stmt, 12, ret.IsPinned);
Get(m_get_msg_stmt, 13, ret.WebhookID);
uint64_t tmpi;
Get(m_get_msg_stmt, 14, tmpi);
ret.Type = static_cast<MessageType>(tmpi);
Get(m_get_msg_stmt, 15, tmps);
if (tmps != "")
ret.Application = nlohmann::json::parse(tmps).get<MessageApplicationData>();
Get(m_get_msg_stmt, 16, tmps);
if (tmps != "")
ret.MessageReference = nlohmann::json::parse(tmps).get<MessageReferenceData>();
Get(m_get_msg_stmt, 17, tmpi);
ret.Flags = static_cast<MessageFlags>(tmpi);
Get(m_get_msg_stmt, 18, tmps);
if (tmps != "")
ret.Stickers = nlohmann::json::parse(tmps).get<std::vector<StickerData>>();
Get(m_get_msg_stmt, 19, tmps);
if (tmps != "")
ret.Reactions = nlohmann::json::parse(tmps).get<std::vector<ReactionData>>();
bool tmpb = false;
Get(m_get_msg_stmt, 20, tmpb);
if (tmpb) ret.SetDeleted();
Get(m_get_msg_stmt, 21, tmpb);
if (tmpb) ret.SetEdited();
Get(m_get_msg_stmt, 22, ret.IsPending);
Get(m_get_msg_stmt, 23, ret.Nonce);
// interaction data from join
if (!IsNull(m_get_msg_stmt, 24)) {
auto &interaction = ret.Interaction.emplace();
Get(m_get_msg_stmt, 24, interaction.ID);
Get(m_get_msg_stmt, 25, interaction.Name);
Get(m_get_msg_stmt, 26, interaction.Type);
Get(m_get_msg_stmt, 27, interaction.User.ID);
}
Reset(m_get_msg_stmt);
if (ret.MessageReference.has_value() && ret.MessageReference->MessageID.has_value()) {
auto ref = GetMessage(*ret.MessageReference->MessageID);
if (ref.has_value())
ret.ReferencedMessage = std::make_unique<Message>(std::move(*ref));
else
ret.ReferencedMessage = nullptr;
}
return std::optional<Message>(std::move(ret)); return std::optional<Message>(std::move(ret));
} }
@@ -731,7 +762,7 @@ void Store::EndTransaction() {
} }
bool Store::CreateTables() { bool Store::CreateTables() {
constexpr const char *create_users = R"( const char *create_users = R"(
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
username TEXT NOT NULL, username TEXT NOT NULL,
@@ -749,7 +780,7 @@ bool Store::CreateTables() {
) )
)"; )";
constexpr const char *create_permissions = R"( const char *create_permissions = R"(
CREATE TABLE IF NOT EXISTS permissions ( CREATE TABLE IF NOT EXISTS permissions (
id INTEGER NOT NULL, id INTEGER NOT NULL,
channel_id INTEGER NOT NULL, channel_id INTEGER NOT NULL,
@@ -760,7 +791,7 @@ bool Store::CreateTables() {
) )
)"; )";
constexpr const char *create_messages = R"( const char *create_messages = R"(
CREATE TABLE IF NOT EXISTS messages ( CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
channel_id INTEGER NOT NULL, channel_id INTEGER NOT NULL,
@@ -789,7 +820,7 @@ bool Store::CreateTables() {
) )
)"; )";
constexpr const char *create_roles = R"( const char *create_roles = R"(
CREATE TABLE IF NOT EXISTS roles ( CREATE TABLE IF NOT EXISTS roles (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
name TEXT NOT NULL, name TEXT NOT NULL,
@@ -802,7 +833,7 @@ bool Store::CreateTables() {
) )
)"; )";
constexpr const char *create_emojis = R"( const char *create_emojis = R"(
CREATE TABLE IF NOT EXISTS emojis ( CREATE TABLE IF NOT EXISTS emojis (
id INTEGER PRIMARY KEY, /*though nullable, only custom emojis (with non-null ids) are stored*/ id INTEGER PRIMARY KEY, /*though nullable, only custom emojis (with non-null ids) are stored*/
name TEXT NOT NULL, /*same as id*/ name TEXT NOT NULL, /*same as id*/
@@ -815,7 +846,7 @@ bool Store::CreateTables() {
) )
)"; )";
constexpr const char *create_members = R"( const char *create_members = R"(
CREATE TABLE IF NOT EXISTS members ( CREATE TABLE IF NOT EXISTS members (
user_id INTEGER NOT NULL, user_id INTEGER NOT NULL,
guild_id INTEGER NOT NULL, guild_id INTEGER NOT NULL,
@@ -830,7 +861,7 @@ bool Store::CreateTables() {
) )
)"; )";
constexpr const char *create_guilds = R"( const char *create_guilds = R"(
CREATE TABLE IF NOT EXISTS guilds ( CREATE TABLE IF NOT EXISTS guilds (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
name TEXT NOT NULL, name TEXT NOT NULL,
@@ -874,7 +905,7 @@ bool Store::CreateTables() {
) )
)"; )";
constexpr const char *create_channels = R"( const char *create_channels = R"(
CREATE TABLE IF NOT EXISTS channels ( CREATE TABLE IF NOT EXISTS channels (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
type INTEGER NOT NULL, type INTEGER NOT NULL,
@@ -897,7 +928,7 @@ bool Store::CreateTables() {
) )
)"; )";
constexpr const char *create_bans = R"( const char *create_bans = R"(
CREATE TABLE IF NOT EXISTS bans ( CREATE TABLE IF NOT EXISTS bans (
guild_id INTEGER NOT NULL, guild_id INTEGER NOT NULL,
user_id INTEGER NOT NULL, user_id INTEGER NOT NULL,
@@ -906,7 +937,7 @@ bool Store::CreateTables() {
) )
)"; )";
constexpr const char *create_interactions = R"( const char *create_interactions = R"(
CREATE TABLE IF NOT EXISTS message_interactions ( CREATE TABLE IF NOT EXISTS message_interactions (
message_id INTEGER NOT NULL, message_id INTEGER NOT NULL,
interaction_id INTEGER NOT NULL, interaction_id INTEGER NOT NULL,
@@ -981,33 +1012,33 @@ bool Store::CreateTables() {
} }
bool Store::CreateStatements() { bool Store::CreateStatements() {
constexpr const char *set_user = R"( const char *set_user = R"(
REPLACE INTO users VALUES ( REPLACE INTO users VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
) )
)"; )";
constexpr const char *get_user = R"( const char *get_user = R"(
SELECT * FROM users WHERE id = ? SELECT * FROM users WHERE id = ?
)"; )";
constexpr const char *set_perm = R"( const char *set_perm = R"(
REPLACE INTO permissions VALUES ( REPLACE INTO permissions VALUES (
?, ?, ?, ?, ? ?, ?, ?, ?, ?
) )
)"; )";
constexpr const char *get_perm = R"( const char *get_perm = R"(
SELECT * FROM permissions WHERE id = ? AND channel_id = ? SELECT * FROM permissions WHERE id = ? AND channel_id = ?
)"; )";
constexpr const char *set_msg = R"( const char *set_msg = R"(
REPLACE INTO messages VALUES ( REPLACE INTO messages VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
) )
)"; )";
constexpr const char *get_msg = R"( const char *get_msg = R"(
SELECT messages.*, SELECT messages.*,
message_interactions.interaction_id as interaction_id, message_interactions.interaction_id as interaction_id,
message_interactions.name as interaction_name, message_interactions.name as interaction_name,
@@ -1020,80 +1051,93 @@ bool Store::CreateStatements() {
WHERE id = ? WHERE id = ?
)"; )";
constexpr const char *set_role = R"( const char *set_role = R"(
REPLACE INTO roles VALUES ( REPLACE INTO roles VALUES (
?, ?, ?, ?, ?, ?, ?, ? ?, ?, ?, ?, ?, ?, ?, ?
) )
)"; )";
constexpr const char *get_role = R"( const char *get_role = R"(
SELECT * FROM roles WHERE id = ? SELECT * FROM roles WHERE id = ?
)"; )";
constexpr const char *set_emoji = R"( const char *set_emoji = R"(
REPLACE INTO emojis VALUES ( REPLACE INTO emojis VALUES (
?, ?, ?, ?, ?, ?, ?, ? ?, ?, ?, ?, ?, ?, ?, ?
) )
)"; )";
constexpr const char *get_emoji = R"( const char *get_emoji = R"(
SELECT * FROM emojis WHERE id = ? SELECT * FROM emojis WHERE id = ?
)"; )";
constexpr const char *set_member = R"( const char *set_member = R"(
REPLACE INTO members VALUES ( REPLACE INTO members VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ? ?, ?, ?, ?, ?, ?, ?, ?, ?
) )
)"; )";
constexpr const char *get_member = R"( const char *get_member = R"(
SELECT * FROM members WHERE user_id = ? AND guild_id = ? SELECT * FROM members WHERE user_id = ? AND guild_id = ?
)"; )";
constexpr const char *set_guild = R"( const char *set_guild = R"(
REPLACE INTO guilds VALUES ( REPLACE INTO guilds VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
) )
)"; )";
constexpr const char *get_guild = R"( const char *get_guild = R"(
SELECT * FROM guilds WHERE id = ? SELECT * FROM guilds WHERE id = ?
)"; )";
constexpr const char *set_chan = R"( const char *set_chan = R"(
REPLACE INTO channels VALUES ( REPLACE INTO channels VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
) )
)"; )";
constexpr const char *get_chan = R"( const char *get_chan = R"(
SELECT * FROM channels WHERE id = ? SELECT * FROM channels WHERE id = ?
)"; )";
constexpr const char *set_ban = R"( const char *set_ban = R"(
REPLACE INTO bans VALUES ( REPLACE INTO bans VALUES (
?, ?, ? ?, ?, ?
) )
)"; )";
constexpr const char *get_ban = R"( const char *get_ban = R"(
SELECT * FROM bans WHERE guild_id = ? AND user_id = ? SELECT * FROM bans WHERE guild_id = ? AND user_id = ?
)"; )";
constexpr const char *clear_ban = R"( const char *clear_ban = R"(
DELETE FROM bans WHERE guild_id = ? AND user_id = ? DELETE FROM bans WHERE guild_id = ? AND user_id = ?
)"; )";
constexpr const char *get_bans = R"( const char *get_bans = R"(
SELECT * FROM bans WHERE guild_id = ? SELECT * FROM bans WHERE guild_id = ?
)"; )";
constexpr const char *set_interaction = R"( const char *set_interaction = R"(
REPLACE INTO message_interactions VALUES ( REPLACE INTO message_interactions VALUES (
?, ?, ?, ?, ? ?, ?, ?, ?, ?
) )
)"; )";
const char *get_last_msgs = R"(
SELECT * FROM (
SELECT * FROM messages
WHERE channel_id = ?
ORDER BY id DESC
LIMIT ?
) T1 ORDER BY id ASC
)";
const char *get_msg_ids = R"(
SELECT id FROM messages WHERE channel_id = ? ORDER BY id ASC
)";
m_db_err = sqlite3_prepare_v2(m_db, set_user, -1, &m_set_user_stmt, nullptr); m_db_err = sqlite3_prepare_v2(m_db, set_user, -1, &m_set_user_stmt, nullptr);
if (m_db_err != SQLITE_OK) { if (m_db_err != SQLITE_OK) {
fprintf(stderr, "failed to prepare set user statement: %s\n", sqlite3_errstr(m_db_err)); fprintf(stderr, "failed to prepare set user statement: %s\n", sqlite3_errstr(m_db_err));
@@ -1220,6 +1264,18 @@ bool Store::CreateStatements() {
return false; return false;
} }
m_db_err = sqlite3_prepare_v2(m_db, get_last_msgs, -1, &m_get_last_msgs_stmt, nullptr);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "failed to prepare get last messages statement: %s\n", sqlite3_errstr(m_db_err));
return false;
}
m_db_err = sqlite3_prepare_v2(m_db, get_msg_ids, -1, &m_get_msg_ids_stmt, nullptr);
if (m_db_err != SQLITE_OK) {
fprintf(stderr, "failed to prepare get msg ids statement: %s\n", sqlite3_errstr(m_db_err));
return false;
}
return true; return true;
} }
@@ -1245,6 +1301,8 @@ void Store::Cleanup() {
sqlite3_finalize(m_clear_ban_stmt); sqlite3_finalize(m_clear_ban_stmt);
sqlite3_finalize(m_get_bans_stmt); sqlite3_finalize(m_get_bans_stmt);
sqlite3_finalize(m_set_msg_interaction_stmt); sqlite3_finalize(m_set_msg_interaction_stmt);
sqlite3_finalize(m_get_last_msgs_stmt);
sqlite3_finalize(m_get_msg_ids_stmt);
} }
void Store::Bind(sqlite3_stmt *stmt, int index, int num) const { void Store::Bind(sqlite3_stmt *stmt, int index, int num) const {

View File

@@ -41,6 +41,9 @@ public:
std::optional<BanData> GetBan(Snowflake guild_id, Snowflake user_id) const; std::optional<BanData> GetBan(Snowflake guild_id, Snowflake user_id) const;
std::vector<BanData> GetBans(Snowflake guild_id) const; std::vector<BanData> GetBans(Snowflake guild_id) const;
std::vector<Message> GetLastMessages(Snowflake id, size_t num) const;
std::vector<Snowflake> GetChannelMessageIDs(Snowflake id) const;
void ClearGuild(Snowflake id); void ClearGuild(Snowflake id);
void ClearChannel(Snowflake id); void ClearChannel(Snowflake id);
void ClearBan(Snowflake guild_id, Snowflake user_id); void ClearBan(Snowflake guild_id, Snowflake user_id);
@@ -63,6 +66,8 @@ public:
void EndTransaction(); void EndTransaction();
private: private:
Message GetMessageBound(sqlite3_stmt *stmt) const;
void SetMessageInteractionPair(Snowflake message_id, const MessageInteractionData &interaction); void SetMessageInteractionPair(Snowflake message_id, const MessageInteractionData &interaction);
std::unordered_set<Snowflake> m_channels; std::unordered_set<Snowflake> m_channels;
@@ -126,6 +131,8 @@ private:
mutable sqlite3_stmt *m_clear_ban_stmt; mutable sqlite3_stmt *m_clear_ban_stmt;
mutable sqlite3_stmt *m_get_bans_stmt; mutable sqlite3_stmt *m_get_bans_stmt;
mutable sqlite3_stmt *m_set_msg_interaction_stmt; mutable sqlite3_stmt *m_set_msg_interaction_stmt;
mutable sqlite3_stmt *m_get_last_msgs_stmt;
mutable sqlite3_stmt *m_get_msg_ids_stmt;
}; };
template<typename T> template<typename T>

View File

@@ -199,17 +199,8 @@ void MainWindow::UpdateChannelsUpdateGuild(Snowflake id) {
void MainWindow::UpdateChatWindowContents() { void MainWindow::UpdateChatWindowContents() {
auto &discord = Abaddon::Get().GetDiscordClient(); auto &discord = Abaddon::Get().GetDiscordClient();
auto allmsgs = discord.GetMessagesForChannel(m_chat.GetActiveChannel()); auto msgs = discord.GetMessagesForChannel(m_chat.GetActiveChannel(), 50);
if (allmsgs.size() > 50) { m_chat.SetMessages(msgs);
std::vector<Snowflake> msgvec(allmsgs.begin(), allmsgs.end());
std::vector<Snowflake> cutvec(msgvec.end() - 50, msgvec.end());
std::set<Snowflake> msgs;
for (const auto s : cutvec)
msgs.insert(s);
m_chat.SetMessages(msgs);
} else {
m_chat.SetMessages(allmsgs);
}
m_members.UpdateMemberList(); m_members.UpdateMemberList();
} }
@@ -225,9 +216,9 @@ Snowflake MainWindow::GetChatActiveChannel() const {
return m_chat.GetActiveChannel(); return m_chat.GetActiveChannel();
} }
void MainWindow::UpdateChatNewMessage(Snowflake id) { void MainWindow::UpdateChatNewMessage(const Message &data) {
if (Abaddon::Get().GetDiscordClient().GetMessage(id)->ChannelID == GetChatActiveChannel()) { if (data.ChannelID == GetChatActiveChannel()) {
m_chat.AddNewMessage(id); m_chat.AddNewMessage(data);
} }
} }
@@ -241,8 +232,8 @@ void MainWindow::UpdateChatMessageUpdated(Snowflake id, Snowflake channel_id) {
m_chat.UpdateMessage(id); m_chat.UpdateMessage(id);
} }
void MainWindow::UpdateChatPrependHistory(const std::vector<Snowflake> &msgs) { void MainWindow::UpdateChatPrependHistory(const std::vector<Message> &msgs) {
m_chat.AddNewHistory(msgs); m_chat.AddNewHistory(msgs); // given vector should be sorted ascending
} }
void MainWindow::InsertChatInput(std::string text) { void MainWindow::InsertChatInput(std::string text) {

View File

@@ -21,10 +21,10 @@ public:
void UpdateChatWindowContents(); void UpdateChatWindowContents();
void UpdateChatActiveChannel(Snowflake id); void UpdateChatActiveChannel(Snowflake id);
Snowflake GetChatActiveChannel() const; Snowflake GetChatActiveChannel() const;
void UpdateChatNewMessage(Snowflake id); void UpdateChatNewMessage(const Message &data);
void UpdateChatMessageDeleted(Snowflake id, Snowflake channel_id); void UpdateChatMessageDeleted(Snowflake id, Snowflake channel_id);
void UpdateChatMessageUpdated(Snowflake id, Snowflake channel_id); void UpdateChatMessageUpdated(Snowflake id, Snowflake channel_id);
void UpdateChatPrependHistory(const std::vector<Snowflake> &msgs); void UpdateChatPrependHistory(const std::vector<Message> &msgs);
void InsertChatInput(std::string text); void InsertChatInput(std::string text);
Snowflake GetChatOldestListedMessage(); Snowflake GetChatOldestListedMessage();
void UpdateChatReactionAdd(Snowflake id, const Glib::ustring &param); void UpdateChatReactionAdd(Snowflake id, const Glib::ustring &param);