summaryrefslogtreecommitdiff
path: root/src/discord
diff options
context:
space:
mode:
authorouwou <26526779+ouwou@users.noreply.github.com>2021-12-05 03:57:26 -0500
committerouwou <26526779+ouwou@users.noreply.github.com>2021-12-05 03:57:26 -0500
commitaf567847970121765674dc8d0542b9c4a1f89ed1 (patch)
treea67af688c82fb3e49fee9fe60d5ab69ac2173b20 /src/discord
parent246140688714936820b5c977665ad2a904fa7222 (diff)
downloadabaddon-portaudio-af567847970121765674dc8d0542b9c4a1f89ed1.tar.gz
abaddon-portaudio-af567847970121765674dc8d0542b9c4a1f89ed1.zip
basic unread indicators for channels
Diffstat (limited to 'src/discord')
-rw-r--r--src/discord/discord.cpp57
-rw-r--r--src/discord/discord.hpp11
-rw-r--r--src/discord/objects.cpp19
-rw-r--r--src/discord/objects.hpp27
4 files changed, 112 insertions, 2 deletions
diff --git a/src/discord/discord.cpp b/src/discord/discord.cpp
index b678de0..5d888f4 100644
--- a/src/discord/discord.cpp
+++ b/src/discord/discord.cpp
@@ -1,8 +1,8 @@
#include "discord.hpp"
-#include <cassert>
-#include <cinttypes>
#include "util.hpp"
#include "abaddon.hpp"
+#include <cassert>
+#include <cinttypes>
DiscordClient::DiscordClient(bool mem_store)
: m_decompress_buf(InflateChunkSize)
@@ -874,6 +874,17 @@ void DiscordClient::UnArchiveThread(Snowflake channel_id, sigc::slot<void(Discor
});
}
+void DiscordClient::MarkAsRead(Snowflake channel_id, sigc::slot<void(DiscordError code)> callback) {
+ const auto iter = m_last_message_id.find(channel_id);
+ if (iter == m_last_message_id.end()) return;
+ m_http.MakePOST("/channels/" + std::to_string(channel_id) + "/messages/" + std::to_string(iter->second) + "/ack", "{\"token\":null}", [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()) {
@@ -1060,6 +1071,12 @@ void DiscordClient::SetUserAgent(std::string agent) {
m_websocket.SetUserAgent(agent);
}
+int DiscordClient::GetUnreadStateForChannel(Snowflake id) const noexcept {
+ const auto iter = m_unread.find(id);
+ if (iter == m_unread.end()) return -1; // todo: no magic number
+ return iter->second;
+}
+
PresenceStatus DiscordClient::GetUserStatus(Snowflake id) const {
auto it = m_user_to_status.find(id);
if (it != m_user_to_status.end())
@@ -1290,6 +1307,9 @@ void DiscordClient::HandleGatewayMessage(std::string str) {
case GatewayEvent::THREAD_MEMBER_LIST_UPDATE: {
HandleGatewayThreadMemberListUpdate(m);
} break;
+ case GatewayEvent::MESSAGE_ACK: {
+ HandleGatewayMessageAck(m);
+ } break;
}
} break;
default:
@@ -1411,6 +1431,9 @@ void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) {
m_session_id = data.SessionID;
m_user_data = data.SelfUser;
m_user_settings = data.Settings;
+
+ HandleReadyReadState(data);
+
m_signal_gateway_ready.emit();
}
@@ -1419,6 +1442,7 @@ void DiscordClient::HandleGatewayMessageCreate(const GatewayMessage &msg) {
StoreMessageData(data);
if (data.GuildID.has_value())
AddUserToGuild(data.Author.ID, *data.GuildID);
+ m_last_message_id[data.ChannelID] = data.ID;
m_signal_message_create.emit(data);
}
@@ -1778,6 +1802,12 @@ void DiscordClient::HandleGatewayThreadMemberListUpdate(const GatewayMessage &ms
m_signal_thread_member_list_update.emit(data);
}
+void DiscordClient::HandleGatewayMessageAck(const GatewayMessage &msg) {
+ MessageAckData data = msg.Data;
+ m_unread.erase(data.ChannelID);
+ m_signal_message_ack.emit(data);
+}
+
void DiscordClient::HandleGatewayReadySupplemental(const GatewayMessage &msg) {
ReadySupplementalData data = msg.Data;
for (const auto &p : data.MergedPresences.Friends) {
@@ -2105,6 +2135,24 @@ void DiscordClient::StoreMessageData(Message &msg) {
StoreMessageData(**msg.ReferencedMessage);
}
+// some notes for myself
+// a read channel is determined by checking if the channel object's last message id is equal to the read state's last message id
+// here the absence of an entry in m_unread indicates a read channel and the value is only the mention count since the message doesnt matter
+// no entry.id cannot be a guild even though sometimes it looks like it
+void DiscordClient::HandleReadyReadState(const ReadyEventData &data) {
+ for (const auto &guild : data.Guilds)
+ for (const auto &channel : *guild.Channels)
+ if (channel.Type == ChannelType::GUILD_TEXT || channel.Type == ChannelType::GUILD_NEWS && channel.LastMessageID.has_value())
+ m_last_message_id[channel.ID] = *channel.LastMessageID;
+
+ for (const auto &entry : data.ReadState.Entries) {
+ const auto it = m_last_message_id.find(entry.ID);
+ if (it == m_last_message_id.end()) continue;
+ if (it->second > entry.LastMessageID)
+ m_unread[entry.ID] = entry.MentionCount;
+ }
+}
+
void DiscordClient::LoadEventMap() {
m_event_map["READY"] = GatewayEvent::READY;
m_event_map["MESSAGE_CREATE"] = GatewayEvent::MESSAGE_CREATE;
@@ -2147,6 +2195,7 @@ void DiscordClient::LoadEventMap() {
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;
+ m_event_map["MESSAGE_ACK"] = GatewayEvent::MESSAGE_ACK;
}
DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() {
@@ -2309,6 +2358,10 @@ DiscordClient::type_signal_thread_member_list_update DiscordClient::signal_threa
return m_signal_thread_member_list_update;
}
+DiscordClient::type_signal_message_ack DiscordClient::signal_message_ack() {
+ return m_signal_message_ack;
+}
+
DiscordClient::type_signal_added_to_thread DiscordClient::signal_added_to_thread() {
return m_signal_added_to_thread;
}
diff --git a/src/discord/discord.hpp b/src/discord/discord.hpp
index 4010977..06aa698 100644
--- a/src/discord/discord.hpp
+++ b/src/discord/discord.hpp
@@ -138,6 +138,7 @@ public:
void LeaveThread(Snowflake channel_id, const std::string &location, sigc::slot<void(DiscordError code)> callback);
void ArchiveThread(Snowflake channel_id, sigc::slot<void(DiscordError code)> callback);
void UnArchiveThread(Snowflake channel_id, sigc::slot<void(DiscordError code)> callback);
+ void MarkAsRead(Snowflake channel_id, sigc::slot<void(DiscordError code)> callback);
bool CanModifyRole(Snowflake guild_id, Snowflake role_id) const;
bool CanModifyRole(Snowflake guild_id, Snowflake role_id, Snowflake user_id) const;
@@ -182,6 +183,8 @@ public:
void UpdateToken(std::string token);
void SetUserAgent(std::string agent);
+ int GetUnreadStateForChannel(Snowflake id) const noexcept;
+
PresenceStatus GetUserStatus(Snowflake id) const;
std::map<Snowflake, RelationshipType> GetRelationships() const;
@@ -244,6 +247,7 @@ private:
void HandleGatewayThreadMemberUpdate(const GatewayMessage &msg);
void HandleGatewayThreadUpdate(const GatewayMessage &msg);
void HandleGatewayThreadMemberListUpdate(const GatewayMessage &msg);
+ void HandleGatewayMessageAck(const GatewayMessage &msg);
void HandleGatewayReadySupplemental(const GatewayMessage &msg);
void HandleGatewayReconnect(const GatewayMessage &msg);
void HandleGatewayInvalidSession(const GatewayMessage &msg);
@@ -259,6 +263,8 @@ private:
void StoreMessageData(Message &msg);
+ void HandleReadyReadState(const ReadyEventData &data);
+
std::string m_token;
void AddUserToGuild(Snowflake user_id, Snowflake guild_id);
@@ -269,6 +275,8 @@ private:
std::map<Snowflake, RelationshipType> m_user_relationships;
std::set<Snowflake> m_joined_threads;
std::map<Snowflake, std::vector<Snowflake>> m_thread_members;
+ std::map<Snowflake, Snowflake> m_last_message_id;
+ std::unordered_map<Snowflake, int> m_unread;
UserData m_user_data;
UserSettings m_user_settings;
@@ -343,6 +351,7 @@ public:
typedef sigc::signal<void, ThreadMembersUpdateData> type_signal_thread_members_update;
typedef sigc::signal<void, ThreadUpdateData> type_signal_thread_update;
typedef sigc::signal<void, ThreadMemberListUpdateData> type_signal_thread_member_list_update;
+ typedef sigc::signal<void, MessageAckData> type_signal_message_ack;
// not discord dispatch events
typedef sigc::signal<void, Snowflake> type_signal_added_to_thread;
@@ -393,6 +402,7 @@ public:
type_signal_thread_members_update signal_thread_members_update();
type_signal_thread_update signal_thread_update();
type_signal_thread_member_list_update signal_thread_member_list_update();
+ type_signal_message_ack signal_message_ack();
type_signal_added_to_thread signal_added_to_thread();
type_signal_removed_from_thread signal_removed_from_thread();
@@ -440,6 +450,7 @@ protected:
type_signal_thread_members_update m_signal_thread_members_update;
type_signal_thread_update m_signal_thread_update;
type_signal_thread_member_list_update m_signal_thread_member_list_update;
+ type_signal_message_ack m_signal_message_ack;
type_signal_removed_from_thread m_signal_removed_from_thread;
type_signal_added_to_thread m_signal_added_to_thread;
diff --git a/src/discord/objects.cpp b/src/discord/objects.cpp
index c6de2ce..88d3f30 100644
--- a/src/discord/objects.cpp
+++ b/src/discord/objects.cpp
@@ -119,6 +119,18 @@ void to_json(nlohmann::json &j, const UpdateStatusMessage &m) {
}
}
+void from_json(const nlohmann::json &j, ReadStateEntry &m) {
+ JS_ON("mention_count", m.MentionCount);
+ JS_ON("last_message_id", m.LastMessageID);
+ JS_D("id", m.ID);
+}
+
+void from_json(const nlohmann::json &j, ReadStateData &m) {
+ JS_ON("version", m.Version);
+ JS_ON("partial", m.IsPartial);
+ JS_ON("entries", m.Entries);
+}
+
void from_json(const nlohmann::json &j, ReadyEventData &m) {
JS_D("v", m.GatewayVersion);
JS_D("user", m.SelfUser);
@@ -132,6 +144,7 @@ void from_json(const nlohmann::json &j, ReadyEventData &m) {
JS_ON("merged_members", m.MergedMembers);
JS_O("relationships", m.Relationships);
JS_O("guild_join_requests", m.GuildJoinRequests);
+ JS_O("read_state", m.ReadState);
}
void from_json(const nlohmann::json &j, MergedPresence &m) {
@@ -532,3 +545,9 @@ void to_json(nlohmann::json &j, const ModifyChannelObject &m) {
JS_IF("archived", m.Archived);
JS_IF("locked", m.Locked);
}
+
+void from_json(const nlohmann::json &j, MessageAckData &m) {
+ // JS_D("version", m.Version);
+ JS_D("message_id", m.MessageID);
+ JS_D("channel_id", m.ChannelID);
+}
diff --git a/src/discord/objects.hpp b/src/discord/objects.hpp
index 7084efb..008fe98 100644
--- a/src/discord/objects.hpp
+++ b/src/discord/objects.hpp
@@ -78,6 +78,7 @@ enum class GatewayEvent : int {
THREAD_MEMBER_UPDATE,
THREAD_MEMBERS_UPDATE,
THREAD_MEMBER_LIST_UPDATE,
+ MESSAGE_ACK,
};
enum class GatewayCloseCode : uint16_t {
@@ -224,6 +225,23 @@ struct UpdateStatusMessage {
friend void to_json(nlohmann::json &j, const UpdateStatusMessage &m);
};
+struct ReadStateEntry {
+ int MentionCount;
+ Snowflake LastMessageID;
+ Snowflake ID;
+ // std::string LastPinTimestamp; iso
+
+ friend void from_json(const nlohmann::json &j, ReadStateEntry &m);
+};
+
+struct ReadStateData {
+ int Version;
+ bool IsPartial;
+ std::vector<ReadStateEntry> Entries;
+
+ friend void from_json(const nlohmann::json &j, ReadStateData &m);
+};
+
struct ReadyEventData {
int GatewayVersion;
UserData SelfUser;
@@ -239,6 +257,7 @@ struct ReadyEventData {
std::optional<std::vector<std::vector<GuildMember>>> MergedMembers;
std::optional<std::vector<RelationshipData>> Relationships;
std::optional<std::vector<GuildApplicationData>> GuildJoinRequests;
+ ReadStateData ReadState;
// std::vector<Unknown> ConnectedAccounts; // opt
// std::map<std::string, Unknown> Consents; // opt
// std::vector<Unknown> Experiments; // opt
@@ -745,3 +764,11 @@ struct ModifyChannelObject {
friend void to_json(nlohmann::json &j, const ModifyChannelObject &m);
};
+
+struct MessageAckData {
+ // int Version; // what is this ?!?!?!!?
+ Snowflake MessageID;
+ Snowflake ChannelID;
+
+ friend void from_json(const nlohmann::json &j, MessageAckData &m);
+};