summaryrefslogtreecommitdiff
path: root/discord/discord.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'discord/discord.cpp')
-rw-r--r--discord/discord.cpp237
1 files changed, 234 insertions, 3 deletions
diff --git a/discord/discord.cpp b/discord/discord.cpp
index 6d76825..7a33c05 100644
--- a/discord/discord.cpp
+++ b/discord/discord.cpp
@@ -127,7 +127,23 @@ void DiscordClient::FetchInvite(std::string code, sigc::slot<void(std::optional<
void DiscordClient::FetchMessagesInChannel(Snowflake id, sigc::slot<void(const std::vector<Message> &)> cb) {
std::string path = "/channels/" + std::to_string(id) + "/messages?limit=50";
m_http.MakeGET(path, [this, id, cb](const http::response_type &r) {
- if (!CheckCode(r)) return;
+ if (!CheckCode(r)) {
+ // fake a thread delete event if the requested channel is a thread and we get a 404
+
+ if (r.status_code == http::NotFound) {
+ const auto channel = m_store.GetChannel(id);
+ if (channel.has_value() && channel->IsThread()) {
+ ThreadDeleteData data;
+ data.GuildID = *channel->GuildID;
+ data.ID = id;
+ data.ParentID = *channel->ParentID;
+ data.Type = channel->Type;
+ m_signal_thread_delete.emit(data);
+ }
+ }
+
+ return;
+ }
std::vector<Message> msgs;
@@ -249,6 +265,34 @@ std::set<Snowflake> DiscordClient::GetChannelsInGuild(Snowflake id) const {
return {};
}
+std::vector<Snowflake> DiscordClient::GetUsersInThread(Snowflake id) const {
+ if (auto it = m_thread_members.find(id); it != m_thread_members.end())
+ return it->second;
+ return {};
+}
+
+// there is an endpoint for this but it should be synced before this is called anyways
+std::vector<ChannelData> DiscordClient::GetActiveThreads(Snowflake channel_id) const {
+ return m_store.GetActiveThreads(channel_id);
+}
+
+void DiscordClient::GetArchivedPublicThreads(Snowflake channel_id, sigc::slot<void(DiscordError, const ArchivedThreadsResponseData &)> callback) {
+ m_http.MakeGET("/channels/" + std::to_string(channel_id) + "/threads/archived/public", [this, callback](const http::response_type &r) {
+ if (CheckCode(r)) {
+ const auto data = nlohmann::json::parse(r.text).get<ArchivedThreadsResponseData>();
+ for (const auto &thread : data.Threads)
+ m_store.SetChannel(thread.ID, thread);
+ callback(DiscordError::NONE, data);
+ } else {
+ callback(GetCodeFromResponse(r), {});
+ }
+ });
+}
+
+bool DiscordClient::IsThreadJoined(Snowflake thread_id) const {
+ return std::find(m_joined_threads.begin(), m_joined_threads.end(), thread_id) != m_joined_threads.end();
+}
+
bool DiscordClient::HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const {
const auto base = ComputePermissions(user_id, guild_id);
return (base & perm) == perm;
@@ -429,6 +473,22 @@ void DiscordClient::SendLazyLoad(Snowflake id) {
msg.GuildID = *GetChannel(id)->GuildID;
msg.ShouldGetActivities = true;
msg.ShouldGetTyping = true;
+ msg.ShouldGetThreads = true;
+
+ m_websocket.Send(msg);
+
+ m_channels_lazy_loaded.insert(id);
+}
+
+void DiscordClient::SendThreadLazyLoad(Snowflake id) {
+ auto thread = GetChannel(id);
+ if (thread.has_value())
+ if (m_channels_lazy_loaded.find(*thread->ParentID) == m_channels_lazy_loaded.end())
+ SendLazyLoad(*thread->ParentID);
+
+ LazyLoadRequestMessage msg;
+ msg.GuildID = *GetChannel(id)->GuildID;
+ msg.ThreadIDs.emplace().push_back(id);
m_websocket.Send(msg);
}
@@ -760,6 +820,41 @@ void DiscordClient::Unpin(Snowflake channel_id, Snowflake message_id, sigc::slot
});
}
+// i dont know if the location parameter is necessary at all but discord's thread implementation is extremely strange
+// so its here just in case
+void DiscordClient::LeaveThread(Snowflake channel_id, const std::string &location, sigc::slot<void(DiscordError code)> callback) {
+ m_http.MakeDELETE("/channels/" + std::to_string(channel_id) + "/thread-members/@me?location=" + location, [this, callback](const http::response_type &response) {
+ if (CheckCode(response, 204))
+ callback(DiscordError::NONE);
+ else
+ callback(GetCodeFromResponse(response));
+ });
+}
+
+void DiscordClient::ArchiveThread(Snowflake channel_id, sigc::slot<void(DiscordError code)> callback) {
+ ModifyChannelObject obj;
+ obj.Archived = true;
+ obj.Locked = true;
+ m_http.MakePATCH("/channels/" + std::to_string(channel_id), nlohmann::json(obj).dump(), [this, callback](const http::response_type &response) {
+ if (CheckCode(response))
+ callback(DiscordError::NONE);
+ else
+ callback(GetCodeFromResponse(response));
+ });
+}
+
+void DiscordClient::UnArchiveThread(Snowflake channel_id, sigc::slot<void(DiscordError code)> callback) {
+ ModifyChannelObject obj;
+ obj.Archived = false;
+ obj.Locked = false;
+ m_http.MakePATCH("/channels/" + std::to_string(channel_id), nlohmann::json(obj).dump(), [this, callback](const http::response_type &response) {
+ if (CheckCode(response))
+ callback(DiscordError::NONE);
+ else
+ callback(GetCodeFromResponse(response));
+ });
+}
+
void DiscordClient::FetchPinned(Snowflake id, sigc::slot<void(std::vector<Message>, DiscordError code)> callback) {
// return from db if we know the pins have already been requested
if (m_channels_pinned_requested.find(id) != m_channels_pinned_requested.end()) {
@@ -1155,6 +1250,27 @@ void DiscordClient::HandleGatewayMessage(std::string str) {
case GatewayEvent::RELATIONSHIP_ADD: {
HandleGatewayRelationshipAdd(m);
} break;
+ case GatewayEvent::THREAD_CREATE: {
+ HandleGatewayThreadCreate(m);
+ } break;
+ case GatewayEvent::THREAD_DELETE: {
+ HandleGatewayThreadDelete(m);
+ } break;
+ case GatewayEvent::THREAD_LIST_SYNC: {
+ HandleGatewayThreadListSync(m);
+ } break;
+ case GatewayEvent::THREAD_MEMBERS_UPDATE: {
+ HandleGatewayThreadMembersUpdate(m);
+ } break;
+ case GatewayEvent::THREAD_MEMBER_UPDATE: {
+ HandleGatewayThreadMemberUpdate(m);
+ } break;
+ case GatewayEvent::THREAD_UPDATE: {
+ HandleGatewayThreadUpdate(m);
+ } break;
+ case GatewayEvent::THREAD_MEMBER_LIST_UPDATE: {
+ HandleGatewayThreadMemberListUpdate(m);
+ } break;
}
} break;
default:
@@ -1209,7 +1325,7 @@ void DiscordClient::ProcessNewGuild(GuildData &guild) {
m_store.BeginTransaction();
m_store.SetGuild(guild.ID, guild);
- if (guild.Channels.has_value())
+ if (guild.Channels.has_value()) {
for (auto &c : *guild.Channels) {
c.GuildID = guild.ID;
m_store.SetChannel(c.ID, c);
@@ -1218,6 +1334,15 @@ void DiscordClient::ProcessNewGuild(GuildData &guild) {
m_store.SetPermissionOverwrite(c.ID, p.ID, p);
}
}
+ }
+
+ if (guild.Threads.has_value()) {
+ for (auto &c : *guild.Threads) {
+ m_joined_threads.insert(c.ID);
+ c.GuildID = guild.ID;
+ m_store.SetChannel(c.ID, c);
+ }
+ }
for (auto &r : *guild.Roles)
m_store.SetRole(r.ID, r);
@@ -1373,7 +1498,7 @@ void DiscordClient::HandleGatewayChannelCreate(const GatewayMessage &msg) {
for (const auto &p : *data.PermissionOverwrites)
m_store.SetPermissionOverwrite(data.ID, p.ID, p);
m_store.EndTransaction();
- m_signal_channel_create.emit(data.ID);
+ m_signal_channel_create.emit(data);
}
void DiscordClient::HandleGatewayGuildUpdate(const GatewayMessage &msg) {
@@ -1627,6 +1752,73 @@ void DiscordClient::HandleGatewayRelationshipAdd(const GatewayMessage &msg) {
m_signal_relationship_add.emit(std::move(data));
}
+// remarkably this doesnt actually mean a thread was created
+// it can also mean you gained access to a thread. yay ...
+// except sometimes it doesnt??? i dont know whats going on
+void DiscordClient::HandleGatewayThreadCreate(const GatewayMessage &msg) {
+ ThreadCreateData data = msg.Data;
+ m_store.SetChannel(data.Channel.ID, data.Channel);
+ m_signal_thread_create.emit(data.Channel);
+}
+
+void DiscordClient::HandleGatewayThreadDelete(const GatewayMessage &msg) {
+ ThreadDeleteData data = msg.Data;
+ m_store.ClearChannel(data.ID);
+ m_signal_thread_delete.emit(data);
+}
+
+// this message is received when you load a channel as part of the lazy load request
+// so the ui will only update thread when you load a channel in some guild
+// which is rather annoying but oh well
+void DiscordClient::HandleGatewayThreadListSync(const GatewayMessage &msg) {
+ ThreadListSyncData data = msg.Data;
+ for (const auto &thread : data.Threads)
+ m_store.SetChannel(thread.ID, thread);
+ m_signal_thread_list_sync.emit(data);
+}
+
+void DiscordClient::HandleGatewayThreadMembersUpdate(const GatewayMessage &msg) {
+ ThreadMembersUpdateData data = msg.Data;
+ if (data.AddedMembers.has_value() &&
+ std::find_if(data.AddedMembers->begin(), data.AddedMembers->end(), [this](const auto &x) {
+ return *x.UserID == m_user_data.ID; // safe to assume UserID is present here
+ }) != data.AddedMembers->end()) {
+ m_joined_threads.insert(data.ID);
+ m_signal_added_to_thread.emit(data.ID);
+ } else if (data.RemovedMemberIDs.has_value() &&
+ std::find(data.RemovedMemberIDs->begin(), data.RemovedMemberIDs->end(), m_user_data.ID) != data.RemovedMemberIDs->end()) {
+ m_joined_threads.erase(data.ID);
+ m_signal_removed_from_thread.emit(data.ID);
+ }
+ m_signal_thread_members_update.emit(data);
+}
+
+void DiscordClient::HandleGatewayThreadMemberUpdate(const GatewayMessage &msg) {
+ ThreadMemberUpdateData data = msg.Data;
+ m_joined_threads.insert(*data.Member.ThreadID);
+ if (*data.Member.UserID == GetUserData().ID)
+ m_signal_added_to_thread.emit(*data.Member.ThreadID);
+}
+
+void DiscordClient::HandleGatewayThreadUpdate(const GatewayMessage &msg) {
+ ThreadUpdateData data = msg.Data;
+ m_store.SetChannel(data.Thread.ID, data.Thread);
+ m_signal_thread_update.emit(data);
+}
+
+void DiscordClient::HandleGatewayThreadMemberListUpdate(const GatewayMessage &msg) {
+ ThreadMemberListUpdateData data = msg.Data;
+ m_store.BeginTransaction();
+ for (const auto &entry : data.Members) {
+ m_thread_members[data.ThreadID].push_back(entry.UserID);
+ if (entry.Member.User.has_value())
+ m_store.SetUser(entry.Member.User->ID, *entry.Member.User);
+ m_store.SetGuildMember(data.GuildID, entry.Member.User->ID, entry.Member);
+ }
+ m_store.EndTransaction();
+ m_signal_thread_member_list_update.emit(data);
+}
+
void DiscordClient::HandleGatewayReadySupplemental(const GatewayMessage &msg) {
ReadySupplementalData data = msg.Data;
for (const auto &p : data.MergedPresences.Friends) {
@@ -1989,6 +2181,13 @@ void DiscordClient::LoadEventMap() {
m_event_map["GUILD_JOIN_REQUEST_DELETE"] = GatewayEvent::GUILD_JOIN_REQUEST_DELETE;
m_event_map["RELATIONSHIP_REMOVE"] = GatewayEvent::RELATIONSHIP_REMOVE;
m_event_map["RELATIONSHIP_ADD"] = GatewayEvent::RELATIONSHIP_ADD;
+ m_event_map["THREAD_CREATE"] = GatewayEvent::THREAD_CREATE;
+ m_event_map["THREAD_DELETE"] = GatewayEvent::THREAD_DELETE;
+ m_event_map["THREAD_LIST_SYNC"] = GatewayEvent::THREAD_LIST_SYNC;
+ m_event_map["THREAD_MEMBERS_UPDATE"] = GatewayEvent::THREAD_MEMBERS_UPDATE;
+ m_event_map["THREAD_MEMBER_UPDATE"] = GatewayEvent::THREAD_MEMBER_UPDATE;
+ m_event_map["THREAD_UPDATE"] = GatewayEvent::THREAD_UPDATE;
+ m_event_map["THREAD_MEMBER_LIST_UPDATE"] = GatewayEvent::THREAD_MEMBER_LIST_UPDATE;
}
DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() {
@@ -2127,6 +2326,38 @@ DiscordClient::type_signal_message_pinned DiscordClient::signal_message_pinned()
return m_signal_message_pinned;
}
+DiscordClient::type_signal_thread_create DiscordClient::signal_thread_create() {
+ return m_signal_thread_create;
+}
+
+DiscordClient::type_signal_thread_delete DiscordClient::signal_thread_delete() {
+ return m_signal_thread_delete;
+}
+
+DiscordClient::type_signal_thread_list_sync DiscordClient::signal_thread_list_sync() {
+ return m_signal_thread_list_sync;
+}
+
+DiscordClient::type_signal_thread_members_update DiscordClient::signal_thread_members_update() {
+ return m_signal_thread_members_update;
+}
+
+DiscordClient::type_signal_thread_update DiscordClient::signal_thread_update() {
+ return m_signal_thread_update;
+}
+
+DiscordClient::type_signal_thread_member_list_update DiscordClient::signal_thread_member_list_update() {
+ return m_signal_thread_member_list_update;
+}
+
+DiscordClient::type_signal_added_to_thread DiscordClient::signal_added_to_thread() {
+ return m_signal_added_to_thread;
+}
+
+DiscordClient::type_signal_removed_from_thread DiscordClient::signal_removed_from_thread() {
+ return m_signal_removed_from_thread;
+}
+
DiscordClient::type_signal_message_sent DiscordClient::signal_message_sent() {
return m_signal_message_sent;
}