summaryrefslogtreecommitdiff
path: root/discord
diff options
context:
space:
mode:
Diffstat (limited to 'discord')
-rw-r--r--discord/activity.cpp116
-rw-r--r--discord/activity.hpp137
-rw-r--r--discord/auditlog.cpp34
-rw-r--r--discord/auditlog.hpp120
-rw-r--r--discord/ban.cpp6
-rw-r--r--discord/ban.hpp10
-rw-r--r--discord/channel.cpp97
-rw-r--r--discord/channel.hpp92
-rw-r--r--discord/discord.cpp2372
-rw-r--r--discord/discord.hpp457
-rw-r--r--discord/emoji.cpp51
-rw-r--r--discord/emoji.hpp25
-rw-r--r--discord/errors.hpp36
-rw-r--r--discord/guild.cpp218
-rw-r--r--discord/guild.hpp100
-rw-r--r--discord/httpclient.cpp139
-rw-r--r--discord/httpclient.hpp39
-rw-r--r--discord/interactions.cpp11
-rw-r--r--discord/interactions.hpp25
-rw-r--r--discord/invite.cpp39
-rw-r--r--discord/invite.hpp41
-rw-r--r--discord/json.hpp148
-rw-r--r--discord/member.cpp40
-rw-r--r--discord/member.hpp27
-rw-r--r--discord/message.cpp265
-rw-r--r--discord/message.hpp218
-rw-r--r--discord/objects.cpp534
-rw-r--r--discord/objects.hpp747
-rw-r--r--discord/permissions.cpp11
-rw-r--r--discord/permissions.hpp224
-rw-r--r--discord/relationship.cpp6
-rw-r--r--discord/relationship.hpp21
-rw-r--r--discord/role.cpp14
-rw-r--r--discord/role.hpp20
-rw-r--r--discord/snowflake.cpp66
-rw-r--r--discord/snowflake.hpp55
-rw-r--r--discord/sticker.cpp52
-rw-r--r--discord/sticker.hpp40
-rw-r--r--discord/store.cpp1507
-rw-r--r--discord/store.hpp172
-rw-r--r--discord/user.cpp197
-rw-r--r--discord/user.hpp82
-rw-r--r--discord/usersettings.cpp40
-rw-r--r--discord/usersettings.hpp47
-rw-r--r--discord/webhook.cpp13
-rw-r--r--discord/webhook.hpp24
-rw-r--r--discord/websocket.cpp66
-rw-r--r--discord/websocket.hpp41
48 files changed, 0 insertions, 8842 deletions
diff --git a/discord/activity.cpp b/discord/activity.cpp
deleted file mode 100644
index 95dda5d..0000000
--- a/discord/activity.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-#include "activity.hpp"
-
-void from_json(const nlohmann::json &j, ActivityTimestamps &m) {
- JS_O("start", m.Start);
- JS_O("end", m.End);
-}
-
-void to_json(nlohmann::json &j, const ActivityTimestamps &m) {
- JS_IF("start", m.Start);
- JS_IF("end", m.End);
-}
-
-void from_json(const nlohmann::json &j, ActivityEmoji &m) {
- JS_D("name", m.Name);
- JS_O("id", m.ID);
- JS_O("animated", m.IsAnimated);
-}
-
-void to_json(nlohmann::json &j, const ActivityEmoji &m) {
- j["name"] = m.Name;
- if (m.ID.has_value())
- j["id"] = *m.ID;
- if (m.IsAnimated.has_value())
- j["animated"] = *m.IsAnimated;
-}
-
-void from_json(const nlohmann::json &j, ActivityParty &m) {
- JS_O("id", m.ID);
- JS_O("size", m.Size);
-}
-
-void to_json(nlohmann::json &j, const ActivityParty &m) {
- JS_IF("id", m.ID);
- JS_IF("size", m.Size);
-}
-
-void from_json(const nlohmann::json &j, ActivityAssets &m) {
- JS_O("large_image", m.LargeImage);
- JS_O("large_text", m.LargeText);
- JS_O("small_image", m.SmallImage);
- JS_O("small_text", m.SmallText);
-}
-
-void to_json(nlohmann::json &j, const ActivityAssets &m) {
- JS_IF("large_image", m.LargeImage);
- JS_IF("large_text", m.LargeText);
- JS_IF("small_image", m.SmallImage);
- JS_IF("small_text", m.SmallText);
-}
-
-void from_json(const nlohmann::json &j, ActivitySecrets &m) {
- JS_O("join", m.Join);
- JS_O("spectate", m.Spectate);
- JS_O("match", m.Match);
-}
-
-void to_json(nlohmann::json &j, const ActivitySecrets &m) {
- JS_IF("join", m.Join);
- JS_IF("spectate", m.Spectate);
- JS_IF("match", m.Match);
-}
-
-void from_json(const nlohmann::json &j, ActivityData &m) {
- JS_D("name", m.Name);
- JS_D("type", m.Type);
- JS_ON("url", m.URL);
- JS_D("created_at", m.CreatedAt);
- JS_O("timestamps", m.Timestamps);
- JS_O("application_id", m.ApplicationID);
- JS_ON("details", m.Details);
- JS_ON("state", m.State);
- JS_ON("emoji", m.Emoji);
- JS_ON("party", m.Party);
- JS_O("assets", m.Assets);
- JS_O("secrets", m.Secrets);
- JS_O("instance", m.IsInstance);
- JS_O("flags", m.Flags);
-}
-
-void to_json(nlohmann::json &j, const ActivityData &m) {
- if (m.Type == ActivityType::Custom) {
- j["name"] = "Custom Status";
- j["state"] = m.Name;
- } else {
- j["name"] = m.Name;
- JS_IF("state", m.State);
- }
-
- j["type"] = m.Type;
- JS_IF("url", m.URL);
- JS_IF("created_at", m.CreatedAt);
- JS_IF("timestamps", m.Timestamps);
- JS_IF("application_id", m.ApplicationID);
- JS_IF("details", m.Details);
- JS_IF("emoji", m.Emoji);
- JS_IF("party", m.Party);
- JS_IF("assets", m.Assets);
- JS_IF("secrets", m.Secrets);
- JS_IF("instance", m.IsInstance);
- JS_IF("flags", m.Flags);
-}
-
-void from_json(const nlohmann::json &j, PresenceData &m) {
- JS_N("activities", m.Activities);
- JS_D("status", m.Status);
-}
-
-void to_json(nlohmann::json &j, const PresenceData &m) {
- j["activities"] = m.Activities;
- j["status"] = m.Status;
- JS_IF("afk", m.IsAFK);
- if (m.Since.has_value())
- j["since"] = *m.Since;
- else
- j["since"] = 0;
-}
diff --git a/discord/activity.hpp b/discord/activity.hpp
deleted file mode 100644
index 76ba9cd..0000000
--- a/discord/activity.hpp
+++ /dev/null
@@ -1,137 +0,0 @@
-#pragma once
-#include <string>
-#include <optional>
-#include "../util.hpp"
-#include "json.hpp"
-#include "snowflake.hpp"
-
-enum class PresenceStatus : uint8_t {
- Online,
- Offline,
- Idle,
- DND,
-};
-
-constexpr inline const char *GetPresenceString(PresenceStatus s) {
- switch (s) {
- case PresenceStatus::Online:
- return "online";
- case PresenceStatus::Offline:
- return "offline";
- case PresenceStatus::Idle:
- return "idle";
- case PresenceStatus::DND:
- return "dnd";
- }
- return "";
-}
-
-constexpr inline const char* GetPresenceDisplayString(PresenceStatus s) {
- switch (s) {
- case PresenceStatus::Online:
- return "Online";
- case PresenceStatus::Offline:
- return "Offline";
- case PresenceStatus::Idle:
- return "Away";
- case PresenceStatus::DND:
- return "Do Not Disturb";
- }
- return "";
-}
-
-enum class ActivityType : int {
- Game = 0,
- Streaming = 1,
- Listening = 2,
- Watching = 3, // not documented
- Custom = 4,
- Competing = 5,
-};
-
-enum class ActivityFlags {
- INSTANCE = (1 << 0),
- JOIN = (1 << 1),
- SPECTATE = (1 << 2),
- JOIN_REQUEST = (1 << 3),
- SYNC = (1 << 4),
- PLAY = (1 << 5),
-};
-template<>
-struct Bitwise<ActivityFlags> {
- static const bool enable = true;
-};
-
-struct ActivityTimestamps {
- std::optional<int> Start;
- std::optional<int> End;
-
- friend void from_json(const nlohmann::json &j, ActivityTimestamps &m);
- friend void to_json(nlohmann::json &j, const ActivityTimestamps &m);
-};
-
-struct ActivityEmoji {
- std::string Name;
- std::optional<Snowflake> ID;
- std::optional<bool> IsAnimated;
-
- friend void from_json(const nlohmann::json &j, ActivityEmoji &m);
- friend void to_json(nlohmann::json &j, const ActivityEmoji &m);
-};
-
-struct ActivityParty {
- std::optional<std::string> ID;
- std::optional<std::array<int, 2>> Size;
-
- friend void from_json(const nlohmann::json &j, ActivityParty &m);
- friend void to_json(nlohmann::json &j, const ActivityParty &m);
-};
-
-struct ActivityAssets {
- std::optional<std::string> LargeImage;
- std::optional<std::string> LargeText;
- std::optional<std::string> SmallImage;
- std::optional<std::string> SmallText;
-
- friend void from_json(const nlohmann::json &j, ActivityAssets &m);
- friend void to_json(nlohmann::json &j, const ActivityAssets &m);
-};
-
-struct ActivitySecrets {
- std::optional<std::string> Join;
- std::optional<std::string> Spectate;
- std::optional<std::string> Match;
-
- friend void from_json(const nlohmann::json &j, ActivitySecrets &m);
- friend void to_json(nlohmann::json &j, const ActivitySecrets &m);
-};
-
-struct ActivityData {
- std::string Name; //
- ActivityType Type; //
- std::optional<std::string> URL; // null
- std::optional<uint64_t> CreatedAt; //
- std::optional<ActivityTimestamps> Timestamps; //
- std::optional<Snowflake> ApplicationID; //
- std::optional<std::string> Details; // null
- std::optional<std::string> State; // null
- std::optional<ActivityEmoji> Emoji; // null
- std::optional<ActivityParty> Party; //
- std::optional<ActivityAssets> Assets; //
- std::optional<ActivitySecrets> Secrets; //
- std::optional<bool> IsInstance; //
- std::optional<ActivityFlags> Flags; //
-
- friend void from_json(const nlohmann::json &j, ActivityData &m);
- friend void to_json(nlohmann::json &j, const ActivityData &m);
-};
-
-struct PresenceData {
- std::vector<ActivityData> Activities; // null (but never sent as such)
- std::string Status;
- std::optional<bool> IsAFK;
- std::optional<int> Since;
-
- friend void from_json(const nlohmann::json &j, PresenceData &m);
- friend void to_json(nlohmann::json &j, const PresenceData &m);
-};
diff --git a/discord/auditlog.cpp b/discord/auditlog.cpp
deleted file mode 100644
index bfada39..0000000
--- a/discord/auditlog.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#include "auditlog.hpp"
-
-void from_json(const nlohmann::json &j, AuditLogChange &m) {
- JS_D("key", m.Key);
- JS_O("old_value", m.OldValue);
- JS_O("new_value", m.NewValue);
-}
-
-void from_json(const nlohmann::json &j, AuditLogOptions &m) {
- JS_O("delete_member_days", m.DeleteMemberDays);
- JS_O("members_removed", m.MembersRemoved);
- JS_O("channel_id", m.ChannelID);
- JS_O("message_id", m.MessageID);
- JS_O("count", m.Count);
- JS_O("id", m.ID);
- JS_O("type", m.Type);
- JS_O("role_name", m.RoleName);
-}
-
-void from_json(const nlohmann::json &j, AuditLogEntry &m) {
- JS_N("target_id", m.TargetID);
- JS_O("changes", m.Changes);
- JS_N("user_id", m.UserID);
- JS_D("id", m.ID);
- JS_D("action_type", m.Type);
- JS_O("options", m.Options);
- JS_O("reason", m.Reason);
-}
-
-void from_json(const nlohmann::json &j, AuditLogData &m) {
- JS_D("audit_log_entries", m.Entries);
- JS_D("users", m.Users);
- JS_D("webhooks", m.Webhooks);
-}
diff --git a/discord/auditlog.hpp b/discord/auditlog.hpp
deleted file mode 100644
index 3a902d1..0000000
--- a/discord/auditlog.hpp
+++ /dev/null
@@ -1,120 +0,0 @@
-#pragma once
-#include "snowflake.hpp"
-#include "user.hpp"
-#include "json.hpp"
-#include "webhook.hpp"
-
-enum class AuditLogActionType {
- GUILD_UPDATE = 1,
- CHANNEL_CREATE = 10,
- CHANNEL_UPDATE = 11,
- CHANNEL_DELETE = 12,
- CHANNEL_OVERWRITE_CREATE = 13,
- CHANNEL_OVERWRITE_UPDATE = 14,
- CHANNEL_OVERWRITE_DELETE = 15,
- MEMBER_KICK = 20,
- MEMBER_PRUNE = 21,
- MEMBER_BAN_ADD = 22,
- MEMBER_BAN_REMOVE = 23,
- MEMBER_UPDATE = 24,
- MEMBER_ROLE_UPDATE = 25,
- MEMBER_MOVE = 26,
- MEMBER_DISCONNECT = 27,
- BOT_ADD = 28,
- ROLE_CREATE = 30,
- ROLE_UPDATE = 31,
- ROLE_DELETE = 32,
- INVITE_CREATE = 40,
- INVITE_UPDATE = 41,
- INVITE_DELETE = 42,
- WEBHOOK_CREATE = 50,
- WEBHOOK_UPDATE = 51,
- WEBHOOK_DELETE = 52,
- EMOJI_CREATE = 60,
- EMOJI_UPDATE = 61,
- EMOJI_DELETE = 62,
- MESSAGE_DELETE = 72,
- MESSAGE_BULK_DELETE = 73,
- MESSAGE_PIN = 74,
- MESSAGE_UNPIN = 75,
- INTEGRATION_CREATE = 80,
- INTEGRATION_UPDATE = 81,
- INTEGRATION_DELETE = 82,
- STAGE_INSTANCE_CREATE = 83,
- STAGE_INSTANCE_UPDATE = 84,
- STAGE_INSTANCE_DELETE = 85,
- STICKER_CREATE = 90,
- STICKER_UPDATE = 91,
- STICKER_DELETE = 92,
- THREAD_CREATE = 110,
- THREAD_UPDATE = 111,
- THREAD_DELETE = 112,
-};
-
-struct AuditLogChange {
- std::string Key;
- std::optional<nlohmann::json> OldValue;
- std::optional<nlohmann::json> NewValue;
-
- friend void from_json(const nlohmann::json &j, AuditLogChange &m);
-};
-
-struct AuditLogOptions {
- std::optional<std::string> DeleteMemberDays; // MEMBER_PRUNE
- std::optional<std::string> MembersRemoved; // MEMBER_PRUNE
- std::optional<Snowflake> ChannelID; // MEMBER_MOVE, MESSAGE_PIN, MESSAGE_UNPIN, MESSAGE_DELETE
- std::optional<Snowflake> MessageID; // MESSAGE_PIN, MESSAGE_UNPIN,
- std::optional<std::string> Count; // MESSAGE_DELETE, MESSAGE_BULK_DELETE, MEMBER_DISCONNECT, MEMBER_MOVE
- std::optional<Snowflake> ID; // CHANNEL_OVERWRITE_CREATE, CHANNEL_OVERWRITE_UPDATE, CHANNEL_OVERWRITE_DELETE
- std::optional<std::string> Type; // CHANNEL_OVERWRITE_CREATE, CHANNEL_OVERWRITE_UPDATE, CHANNEL_OVERWRITE_DELETE
- std::optional<std::string> RoleName; // CHANNEL_OVERWRITE_CREATE, CHANNEL_OVERWRITE_UPDATE, CHANNEL_OVERWRITE_DELETE
-
- friend void from_json(const nlohmann::json &j, AuditLogOptions &m);
-};
-
-struct AuditLogEntry {
- Snowflake ID;
- std::string TargetID; // null
- std::optional<Snowflake> UserID;
- AuditLogActionType Type;
- std::optional<std::string> Reason;
- std::optional<std::vector<AuditLogChange>> Changes;
- std::optional<AuditLogOptions> Options;
-
- friend void from_json(const nlohmann::json &j, AuditLogEntry &m);
-
- template<typename T>
- std::optional<T> GetOldFromKey(const std::string &key) const;
-
- template<typename T>
- std::optional<T> GetNewFromKey(const std::string &key) const;
-};
-
-struct AuditLogData {
- std::vector<AuditLogEntry> Entries;
- std::vector<UserData> Users;
- std::vector<WebhookData> Webhooks;
- // std::vector<IntegrationData> Integrations;
-
- friend void from_json(const nlohmann::json &j, AuditLogData &m);
-};
-
-template<typename T>
-inline std::optional<T> AuditLogEntry::GetOldFromKey(const std::string &key) const {
- if (!Changes.has_value()) return std::nullopt;
- for (const auto &change : *Changes)
- if (change.Key == key && change.OldValue.has_value())
- return change.OldValue->get<T>();
-
- return std::nullopt;
-}
-
-template<typename T>
-inline std::optional<T> AuditLogEntry::GetNewFromKey(const std::string &key) const {
- if (!Changes.has_value()) return std::nullopt;
- for (const auto &change : *Changes)
- if (change.Key == key && change.NewValue.has_value())
- return change.NewValue->get<T>();
-
- return std::nullopt;
-}
diff --git a/discord/ban.cpp b/discord/ban.cpp
deleted file mode 100644
index a354c15..0000000
--- a/discord/ban.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "ban.hpp"
-
-void from_json(const nlohmann::json &j, BanData &m) {
- JS_N("reason", m.Reason);
- JS_D("user", m.User);
-}
diff --git a/discord/ban.hpp b/discord/ban.hpp
deleted file mode 100644
index d417ce3..0000000
--- a/discord/ban.hpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-#include <string>
-#include "user.hpp"
-
-struct BanData {
- std::string Reason; // null
- UserData User; // access id
-
- friend void from_json(const nlohmann::json &j, BanData &m);
-};
diff --git a/discord/channel.cpp b/discord/channel.cpp
deleted file mode 100644
index 60f481b..0000000
--- a/discord/channel.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-#include "../abaddon.hpp"
-#include "channel.hpp"
-
-void from_json(const nlohmann::json &j, ThreadMetadataData &m) {
- JS_D("archived", m.IsArchived);
- JS_D("auto_archive_duration", m.AutoArchiveDuration);
- JS_D("archive_timestamp", m.ArchiveTimestamp);
- JS_O("locked", m.IsLocked);
-}
-
-void from_json(const nlohmann::json &j, ThreadMemberObject &m) {
- JS_O("id", m.ThreadID);
- JS_O("user_id", m.UserID);
- JS_D("join_timestamp", m.JoinTimestamp);
- JS_D("flags", m.Flags);
-}
-
-void from_json(const nlohmann::json &j, ChannelData &m) {
- JS_D("id", m.ID);
- JS_D("type", m.Type);
- JS_O("guild_id", m.GuildID);
- JS_O("position", m.Position);
- JS_O("permission_overwrites", m.PermissionOverwrites);
- JS_ON("name", m.Name);
- JS_ON("topic", m.Topic);
- JS_O("nsfw", m.IsNSFW);
- JS_ON("last_message_id", m.LastMessageID);
- JS_O("bitrate", m.Bitrate);
- JS_O("user_limit", m.UserLimit);
- JS_O("rate_limit_per_user", m.RateLimitPerUser);
- JS_O("recipients", m.Recipients);
- JS_O("recipient_ids", m.RecipientIDs);
- JS_ON("icon", m.Icon);
- JS_O("owner_id", m.OwnerID);
- JS_O("application_id", m.ApplicationID);
- JS_ON("parent_id", m.ParentID);
- JS_ON("last_pin_timestamp", m.LastPinTimestamp);
- JS_O("thread_metadata", m.ThreadMetadata);
- JS_O("member", m.ThreadMember);
-}
-
-void ChannelData::update_from_json(const nlohmann::json &j) {
- JS_RD("type", Type);
- JS_RD("guild_id", GuildID);
- JS_RV("position", Position, -1);
- JS_RD("permission_overwrites", PermissionOverwrites);
- JS_RD("name", Name);
- JS_RD("topic", Topic);
- JS_RD("nsfw", IsNSFW);
- JS_RD("last_message_id", LastMessageID);
- JS_RD("bitrate", Bitrate);
- JS_RD("user_limit", UserLimit);
- JS_RD("rate_limit_per_user", RateLimitPerUser);
- JS_RD("recipients", Recipients);
- JS_RD("icon", Icon);
- JS_RD("owner_id", OwnerID);
- JS_RD("application_id", ApplicationID);
- JS_RD("parent_id", ParentID);
- JS_RD("last_pin_timestamp", LastPinTimestamp);
-}
-
-bool ChannelData::NSFW() const {
- return IsNSFW.has_value() && *IsNSFW;
-}
-
-bool ChannelData::IsThread() const noexcept {
- return Type == ChannelType::GUILD_PUBLIC_THREAD ||
- Type == ChannelType::GUILD_PRIVATE_THREAD ||
- Type == ChannelType::GUILD_NEWS_THREAD;
-}
-
-bool ChannelData::IsJoinedThread() const {
- return Abaddon::Get().GetDiscordClient().IsThreadJoined(ID);
-}
-
-std::optional<PermissionOverwrite> ChannelData::GetOverwrite(Snowflake id) const {
- return Abaddon::Get().GetDiscordClient().GetPermissionOverwrite(ID, id);
-}
-
-std::vector<UserData> ChannelData::GetDMRecipients() const {
- const auto &discord = Abaddon::Get().GetDiscordClient();
- if (Recipients.has_value())
- return *Recipients;
-
- if (RecipientIDs.has_value()) {
- std::vector<UserData> ret;
- for (const auto &id : *RecipientIDs) {
- auto user = discord.GetUser(id);
- if (user.has_value())
- ret.push_back(std::move(*user));
- }
-
- return ret;
- }
-
- return std::vector<UserData>();
-}
diff --git a/discord/channel.hpp b/discord/channel.hpp
deleted file mode 100644
index 942d555..0000000
--- a/discord/channel.hpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#pragma once
-#include "snowflake.hpp"
-#include "json.hpp"
-#include "user.hpp"
-#include "permissions.hpp"
-#include <string>
-#include <vector>
-
-enum class ChannelType : int {
- GUILD_TEXT = 0,
- DM = 1,
- GUILD_VOICE = 2,
- GROUP_DM = 3,
- GUILD_CATEGORY = 4,
- GUILD_NEWS = 5,
- GUILD_STORE = 6,
- /* 7 and 8 were used for LFG */
- /* 9 was used for threads */
- GUILD_NEWS_THREAD = 10,
- GUILD_PUBLIC_THREAD = 11,
- GUILD_PRIVATE_THREAD = 12,
- GUILD_STAGE_VOICE = 13,
-};
-
-enum class StagePrivacy {
- PUBLIC = 1,
- GUILD_ONLY = 2,
-};
-
-constexpr const char *GetStagePrivacyDisplayString(StagePrivacy e) {
- switch (e) {
- case StagePrivacy::PUBLIC:
- return "Public";
- case StagePrivacy::GUILD_ONLY:
- return "Guild Only";
- default:
- return "Unknown";
- }
-}
-
-// should be moved somewhere?
-
-struct ThreadMetadataData {
- bool IsArchived;
- int AutoArchiveDuration;
- std::string ArchiveTimestamp;
- std::optional<bool> IsLocked;
-
- friend void from_json(const nlohmann::json &j, ThreadMetadataData &m);
-};
-
-struct ThreadMemberObject {
- std::optional<Snowflake> ThreadID;
- std::optional<Snowflake> UserID;
- std::string JoinTimestamp;
- int Flags;
-
- friend void from_json(const nlohmann::json &j, ThreadMemberObject &m);
-};
-
-struct ChannelData {
- 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<UserData>> Recipients; // only access id
- std::optional<std::vector<Snowflake>> RecipientIDs;
- 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
- std::optional<ThreadMetadataData> ThreadMetadata;
- std::optional<ThreadMemberObject> ThreadMember;
-
- friend void from_json(const nlohmann::json &j, ChannelData &m);
- void update_from_json(const nlohmann::json &j);
-
- bool NSFW() const;
- bool IsThread() const noexcept;
- bool IsJoinedThread() const;
- std::optional<PermissionOverwrite> GetOverwrite(Snowflake id) const;
- std::vector<UserData> GetDMRecipients() const;
-};
diff --git a/discord/discord.cpp b/discord/discord.cpp
deleted file mode 100644
index 671c29d..0000000
--- a/discord/discord.cpp
+++ /dev/null
@@ -1,2372 +0,0 @@
-#include "discord.hpp"
-#include <cassert>
-#include <cinttypes>
-#include "../util.hpp"
-#include "../abaddon.hpp"
-
-DiscordClient::DiscordClient(bool mem_store)
- : m_decompress_buf(InflateChunkSize)
- , m_store(mem_store) {
- m_msg_dispatch.connect(sigc::mem_fun(*this, &DiscordClient::MessageDispatch));
- auto dispatch_cb = [this]() {
- m_generic_mutex.lock();
- auto func = m_generic_queue.front();
- m_generic_queue.pop();
- m_generic_mutex.unlock();
- func();
- };
- m_generic_dispatch.connect(dispatch_cb);
-
- m_websocket.signal_message().connect(sigc::mem_fun(*this, &DiscordClient::HandleGatewayMessageRaw));
- m_websocket.signal_open().connect(sigc::mem_fun(*this, &DiscordClient::HandleSocketOpen));
- m_websocket.signal_close().connect(sigc::mem_fun(*this, &DiscordClient::HandleSocketClose));
-
- LoadEventMap();
-}
-
-void DiscordClient::Start() {
- if (m_client_started) return;
-
- m_http.SetBase(GetAPIURL());
-
- std::memset(&m_zstream, 0, sizeof(m_zstream));
- inflateInit2(&m_zstream, MAX_WBITS + 32);
-
- m_last_sequence = -1;
- m_heartbeat_acked = true;
- m_client_connected = true;
- m_client_started = true;
- m_websocket.StartConnection(GetGatewayURL());
-}
-
-void DiscordClient::Stop() {
- if (m_client_started) {
- inflateEnd(&m_zstream);
- m_compressed_buf.clear();
-
- m_heartbeat_waiter.kill();
- if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join();
- m_client_connected = false;
- m_reconnecting = false;
-
- m_store.ClearAll();
- m_guild_to_users.clear();
-
- m_websocket.Stop();
- }
-
- m_client_started = false;
-}
-
-bool DiscordClient::IsStarted() const {
- return m_client_started;
-}
-
-bool DiscordClient::IsStoreValid() const {
- return m_store.IsValid();
-}
-
-const UserSettings &DiscordClient::GetUserSettings() const {
- return m_user_settings;
-}
-
-std::unordered_set<Snowflake> DiscordClient::GetGuilds() const {
- return m_store.GetGuilds();
-}
-
-const UserData &DiscordClient::GetUserData() const {
- return m_user_data;
-}
-
-std::vector<Snowflake> DiscordClient::GetUserSortedGuilds() const {
- // sort order is unfolder'd guilds sorted by id descending, then guilds in folders in array order
- // todo: make sure folder'd guilds are sorted properly
- std::vector<Snowflake> folder_order;
- auto guilds = GetGuilds();
- for (const auto &entry : m_user_settings.GuildFolders) { // can contain guilds not a part of
- for (const auto &id : entry.GuildIDs) {
- if (std::find(guilds.begin(), guilds.end(), id) != guilds.end())
- folder_order.push_back(id);
- }
- }
-
- std::vector<Snowflake> ret;
- for (const auto &gid : guilds) {
- if (std::find(folder_order.begin(), folder_order.end(), gid) == folder_order.end()) {
- ret.push_back(gid);
- }
- }
-
- std::sort(ret.rbegin(), ret.rend());
-
- for (const auto &gid : folder_order)
- ret.push_back(gid);
-
- return ret;
-}
-
-std::vector<Message> DiscordClient::GetMessagesForChannel(Snowflake id, size_t limit) const {
- return m_store.GetLastMessages(id, limit);
-}
-
-std::vector<Snowflake> DiscordClient::GetMessageIDsForChannel(Snowflake id) const {
- return m_store.GetChannelMessageIDs(id);
-}
-
-void DiscordClient::FetchInvite(std::string code, sigc::slot<void(std::optional<InviteData>)> callback) {
- m_http.MakeGET("/invites/" + code + "?with_counts=true", [this, callback](http::response_type r) {
- if (!CheckCode(r)) {
- if (r.status_code == 404)
- callback(std::nullopt);
- return;
- };
-
- callback(nlohmann::json::parse(r.text).get<InviteData>());
- });
-}
-
-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)) {
- // 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;
-
- nlohmann::json::parse(r.text).get_to(msgs);
-
- m_store.BeginTransaction();
- for (auto &msg : msgs) {
- StoreMessageData(msg);
- if (msg.GuildID.has_value())
- AddUserToGuild(msg.Author.ID, *msg.GuildID);
- }
- m_store.EndTransaction();
-
- cb(msgs);
- });
-}
-
-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);
- m_http.MakeGET(path, [this, channel_id, cb](http::response_type r) {
- if (!CheckCode(r)) return;
-
- std::vector<Message> msgs;
-
- nlohmann::json::parse(r.text).get_to(msgs);
-
- m_store.BeginTransaction();
- for (auto &msg : msgs) {
- StoreMessageData(msg);
- if (msg.GuildID.has_value())
- AddUserToGuild(msg.Author.ID, *msg.GuildID);
- }
- m_store.EndTransaction();
-
- std::sort(msgs.begin(), msgs.end(), [](const Message &a, const Message &b) { return a.ID < b.ID; });
- cb(msgs);
- });
-}
-
-std::optional<Message> DiscordClient::GetMessage(Snowflake id) const {
- return m_store.GetMessage(id);
-}
-
-std::optional<ChannelData> DiscordClient::GetChannel(Snowflake id) const {
- return m_store.GetChannel(id);
-}
-
-std::optional<UserData> DiscordClient::GetUser(Snowflake id) const {
- return m_store.GetUser(id);
-}
-
-std::optional<RoleData> DiscordClient::GetRole(Snowflake id) const {
- return m_store.GetRole(id);
-}
-
-std::optional<GuildData> DiscordClient::GetGuild(Snowflake id) const {
- return m_store.GetGuild(id);
-}
-
-std::optional<GuildMember> DiscordClient::GetMember(Snowflake user_id, Snowflake guild_id) const {
- return m_store.GetGuildMember(guild_id, user_id);
-}
-
-std::optional<BanData> DiscordClient::GetBan(Snowflake guild_id, Snowflake user_id) const {
- return m_store.GetBan(guild_id, user_id);
-}
-
-std::optional<PermissionOverwrite> DiscordClient::GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const {
- return m_store.GetPermissionOverwrite(channel_id, id);
-}
-
-std::optional<EmojiData> DiscordClient::GetEmoji(Snowflake id) const {
- return m_store.GetEmoji(id);
-}
-
-Snowflake DiscordClient::GetMemberHoistedRole(Snowflake guild_id, Snowflake user_id, bool with_color) const {
- const auto data = GetMember(user_id, guild_id);
- if (!data.has_value()) return Snowflake::Invalid;
-
- std::optional<RoleData> top_role;
- for (const auto &id : data->Roles) {
- const auto role = GetRole(id);
- if (role.has_value()) {
- if ((with_color && role->Color != 0x000000) || (!with_color && role->IsHoisted))
- if (!top_role.has_value() || top_role->Position < role->Position)
- top_role = role;
- }
- }
-
- return top_role.has_value() ? top_role->ID : Snowflake::Invalid;
-}
-
-std::optional<RoleData> DiscordClient::GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const {
- const auto data = GetMember(user_id, guild_id);
- if (!data.has_value()) return std::nullopt;
-
- if (data->Roles.size() == 0) return std::nullopt;
- if (data->Roles.size() == 1) return GetRole(data->Roles[0]);
-
- std::vector<RoleData> roles;
- for (const auto id : data->Roles)
- roles.push_back(*GetRole(id));
-
- return *std::max_element(roles.begin(), roles.end(), [this](const auto &a, const auto &b) -> bool {
- return a.Position < b.Position;
- });
-}
-
-std::set<Snowflake> DiscordClient::GetUsersInGuild(Snowflake id) const {
- auto it = m_guild_to_users.find(id);
- if (it != m_guild_to_users.end())
- return it->second;
-
- return {};
-}
-
-std::set<Snowflake> DiscordClient::GetChannelsInGuild(Snowflake id) const {
- auto it = m_guild_to_channels.find(id);
- if (it != m_guild_to_channels.end())
- return it->second;
- 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;
-}
-
-bool DiscordClient::HasAnyChannelPermission(Snowflake user_id, Snowflake channel_id, Permission perm) const {
- const auto channel = m_store.GetChannel(channel_id);
- if (!channel.has_value() || !channel->GuildID.has_value()) return false;
- const auto base = ComputePermissions(user_id, *channel->GuildID);
- const auto overwrites = ComputeOverwrites(base, user_id, channel_id);
- return (overwrites & perm) != Permission::NONE;
-}
-
-bool DiscordClient::HasChannelPermission(Snowflake user_id, Snowflake channel_id, Permission perm) const {
- 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;
-}
-
-Permission DiscordClient::ComputePermissions(Snowflake member_id, Snowflake guild_id) const {
- const auto member = GetMember(member_id, guild_id);
- const auto guild = GetGuild(guild_id);
- if (!member.has_value() || !guild.has_value())
- return Permission::NONE;
-
- if (guild->OwnerID == member_id)
- return Permission::ALL;
-
- const auto everyone = GetRole(guild_id);
- if (!everyone.has_value())
- return Permission::NONE;
-
- Permission perms = everyone->Permissions;
- for (const auto role_id : member->Roles) {
- const auto role = GetRole(role_id);
- if (role.has_value())
- perms |= role->Permissions;
- }
-
- if ((perms & Permission::ADMINISTRATOR) == Permission::ADMINISTRATOR)
- return Permission::ALL;
-
- return perms;
-}
-
-Permission DiscordClient::ComputeOverwrites(Permission base, Snowflake member_id, Snowflake channel_id) const {
- 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.has_value())
- return Permission::NONE;
-
- Permission perms = base;
- const auto overwrite_everyone = GetPermissionOverwrite(channel_id, *channel->GuildID);
- if (overwrite_everyone.has_value()) {
- perms &= ~overwrite_everyone->Deny;
- perms |= overwrite_everyone->Allow;
- }
-
- Permission allow = Permission::NONE;
- Permission deny = Permission::NONE;
- for (const auto role_id : member->Roles) {
- const auto overwrite = GetPermissionOverwrite(channel_id, role_id);
- if (overwrite.has_value()) {
- allow |= overwrite->Allow;
- deny |= overwrite->Deny;
- }
- }
-
- perms &= ~deny;
- perms |= allow;
-
- const auto member_overwrite = GetPermissionOverwrite(channel_id, member_id);
- if (member_overwrite.has_value()) {
- perms &= ~member_overwrite->Deny;
- perms |= member_overwrite->Allow;
- }
-
- return perms;
-}
-
-bool DiscordClient::CanManageMember(Snowflake guild_id, Snowflake actor, Snowflake target) const {
- const auto guild = GetGuild(guild_id);
- if (guild.has_value() && guild->OwnerID == target) return false;
- const auto actor_highest = GetMemberHighestRole(guild_id, actor);
- const auto target_highest = GetMemberHighestRole(guild_id, target);
- if (!actor_highest.has_value()) return false;
- if (!target_highest.has_value()) return true;
- return actor_highest->Position > target_highest->Position;
-}
-
-void DiscordClient::ChatMessageCallback(std::string nonce, const http::response_type &response) {
- if (!CheckCode(response)) {
- if (response.status_code == http::TooManyRequests) {
- try { // not sure if this body is guaranteed
- RateLimitedResponse r = nlohmann::json::parse(response.text);
- m_signal_message_send_fail.emit(nonce, r.RetryAfter);
- } catch (...) {
- m_signal_message_send_fail.emit(nonce, 0);
- }
- } else {
- m_signal_message_send_fail.emit(nonce, 0);
- }
- }
-}
-
-void DiscordClient::SendChatMessage(const std::string &content, Snowflake channel) {
- // @([^@#]{1,32})#(\\d{4})
- const auto nonce = std::to_string(Snowflake::FromNow());
- CreateMessageObject obj;
- obj.Content = content;
- obj.Nonce = nonce;
- m_http.MakePOST("/channels/" + std::to_string(channel) + "/messages", nlohmann::json(obj).dump(), sigc::bind<0>(sigc::mem_fun(*this, &DiscordClient::ChatMessageCallback), nonce));
- // dummy data so the content can be shown while waiting for MESSAGE_CREATE
- Message tmp;
- tmp.Content = content;
- tmp.ID = nonce;
- tmp.ChannelID = channel;
- tmp.Author = GetUserData();
- tmp.IsTTS = false;
- tmp.DoesMentionEveryone = false;
- tmp.Type = MessageType::DEFAULT;
- tmp.IsPinned = false;
- tmp.Timestamp = "2000-01-01T00:00:00.000000+00:00";
- tmp.Nonce = obj.Nonce;
- tmp.IsPending = true;
- m_store.SetMessage(tmp.ID, tmp);
- m_signal_message_sent.emit(tmp);
-}
-
-void DiscordClient::SendChatMessage(const std::string &content, Snowflake channel, Snowflake referenced_message) {
- const auto nonce = std::to_string(Snowflake::FromNow());
- CreateMessageObject obj;
- obj.Content = content;
- obj.Nonce = nonce;
- obj.MessageReference.emplace().MessageID = referenced_message;
- m_http.MakePOST("/channels/" + std::to_string(channel) + "/messages", nlohmann::json(obj).dump(), sigc::bind<0>(sigc::mem_fun(*this, &DiscordClient::ChatMessageCallback), nonce));
- Message tmp;
- tmp.Content = content;
- tmp.ID = nonce;
- tmp.ChannelID = channel;
- tmp.Author = GetUserData();
- tmp.IsTTS = false;
- tmp.DoesMentionEveryone = false;
- tmp.Type = MessageType::DEFAULT;
- tmp.IsPinned = false;
- tmp.Timestamp = "2000-01-01T00:00:00.000000+00:00";
- tmp.Nonce = obj.Nonce;
- tmp.IsPending = true;
- m_store.SetMessage(tmp.ID, tmp);
- m_signal_message_sent.emit(tmp);
-}
-
-void DiscordClient::DeleteMessage(Snowflake channel_id, Snowflake id) {
- std::string path = "/channels/" + std::to_string(channel_id) + "/messages/" + std::to_string(id);
- m_http.MakeDELETE(path, [](auto) {});
-}
-
-void DiscordClient::EditMessage(Snowflake channel_id, Snowflake id, std::string content) {
- std::string path = "/channels/" + std::to_string(channel_id) + "/messages/" + std::to_string(id);
- MessageEditObject obj;
- obj.Content = content;
- nlohmann::json j = obj;
- m_http.MakePATCH(path, j.dump(), [](auto) {});
-}
-
-void DiscordClient::SendLazyLoad(Snowflake id) {
- LazyLoadRequestMessage msg;
- msg.Channels.emplace();
- msg.Channels.value()[id] = {
- std::make_pair(0, 99),
- std::make_pair(100, 199)
- };
- 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);
-}
-
-void DiscordClient::JoinGuild(std::string code) {
- m_http.MakePOST("/invites/" + code, "{}", [](auto) {});
-}
-
-void DiscordClient::LeaveGuild(Snowflake id) {
- m_http.MakeDELETE("/users/@me/guilds/" + std::to_string(id), [](auto) {});
-}
-
-void DiscordClient::KickUser(Snowflake user_id, Snowflake guild_id) {
- m_http.MakeDELETE("/guilds/" + std::to_string(guild_id) + "/members/" + std::to_string(user_id), [](auto) {});
-}
-
-void DiscordClient::BanUser(Snowflake user_id, Snowflake guild_id) {
- m_http.MakePUT("/guilds/" + std::to_string(guild_id) + "/bans/" + std::to_string(user_id), "{}", [](auto) {});
-}
-
-void DiscordClient::UpdateStatus(PresenceStatus status, bool is_afk) {
- UpdateStatusMessage msg;
- msg.Status = status;
- msg.IsAFK = is_afk;
-
- m_websocket.Send(nlohmann::json(msg));
- // fake message cuz we dont receive messages for ourself
- m_user_to_status[m_user_data.ID] = status;
- m_signal_presence_update.emit(GetUserData(), status);
-}
-
-void DiscordClient::UpdateStatus(PresenceStatus status, bool is_afk, const ActivityData &obj) {
- UpdateStatusMessage msg;
- msg.Status = status;
- msg.IsAFK = is_afk;
- msg.Activities.push_back(obj);
-
- m_websocket.Send(nlohmann::json(msg));
- m_user_to_status[m_user_data.ID] = status;
- m_signal_presence_update.emit(GetUserData(), status);
-}
-
-void DiscordClient::CreateDM(Snowflake user_id) {
- CreateDM(user_id, [](...) {});
-}
-
-void DiscordClient::CreateDM(Snowflake user_id, sigc::slot<void(DiscordError code, Snowflake channel_id)> callback) {
- CreateDMObject obj;
- obj.Recipients.push_back(user_id);
- m_http.MakePOST("/users/@me/channels", nlohmann::json(obj).dump(), [this, callback](const http::response &response) {
- if (!CheckCode(response)) {
- callback(DiscordError::NONE, Snowflake::Invalid);
- return;
- }
- auto channel = nlohmann::json::parse(response.text).get<ChannelData>();
- callback(GetCodeFromResponse(response), channel.ID);
- });
-}
-
-void DiscordClient::CloseDM(Snowflake channel_id) {
- m_http.MakeDELETE("/channels/" + std::to_string(channel_id), [this](const http::response &response) {
- CheckCode(response);
- });
-}
-
-std::optional<Snowflake> DiscordClient::FindDM(Snowflake user_id) {
- const auto &channels = m_store.GetChannels();
- for (const auto &id : channels) {
- const auto channel = m_store.GetChannel(id);
- const auto recipients = channel->GetDMRecipients();
- if (recipients.size() == 1 && recipients[0].ID == user_id)
- return id;
- }
-
- return std::nullopt;
-}
-
-void DiscordClient::AddReaction(Snowflake id, Glib::ustring param) {
- if (!param.is_ascii()) // means unicode param
- param = Glib::uri_escape_string(param, "", false);
- else {
- const auto &tmp = m_store.GetEmoji(param);
- if (tmp.has_value())
- param = tmp->Name + ":" + std::to_string(tmp->ID);
- else
- return;
- }
- Snowflake channel_id = m_store.GetMessage(id)->ChannelID;
- m_http.MakePUT("/channels/" + std::to_string(channel_id) + "/messages/" + std::to_string(id) + "/reactions/" + param + "/@me", "", [](auto) {});
-}
-
-void DiscordClient::RemoveReaction(Snowflake id, Glib::ustring param) {
- if (!param.is_ascii()) // means unicode param
- param = Glib::uri_escape_string(param, "", false);
- else {
- const auto &tmp = m_store.GetEmoji(param);
- if (tmp.has_value())
- param = tmp->Name + ":" + std::to_string(tmp->ID);
- else
- return;
- }
- Snowflake channel_id = m_store.GetMessage(id)->ChannelID;
- m_http.MakeDELETE("/channels/" + std::to_string(channel_id) + "/messages/" + std::to_string(id) + "/reactions/" + param + "/@me", [](auto) {});
-}
-
-void DiscordClient::SetGuildName(Snowflake id, const Glib::ustring &name) {
- SetGuildName(id, name, [](auto) {});
-}
-
-void DiscordClient::SetGuildName(Snowflake id, const Glib::ustring &name, sigc::slot<void(DiscordError code)> callback) {
- ModifyGuildObject obj;
- obj.Name = name;
- m_http.MakePATCH("/guilds/" + std::to_string(id), nlohmann::json(obj).dump(), [this, callback](const http::response_type &r) {
- if (CheckCode(r))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(r));
- });
-}
-
-void DiscordClient::SetGuildIcon(Snowflake id, const std::string &data) {
- SetGuildIcon(id, data, [](auto) {});
-}
-
-void DiscordClient::SetGuildIcon(Snowflake id, const std::string &data, sigc::slot<void(DiscordError code)> callback) {
- ModifyGuildObject obj;
- obj.IconData = data;
- m_http.MakePATCH("/guilds/" + std::to_string(id), nlohmann::json(obj).dump(), [this, callback](const http::response_type &r) {
- if (CheckCode(r))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(r));
- });
-}
-
-void DiscordClient::UnbanUser(Snowflake guild_id, Snowflake user_id) {
- UnbanUser(guild_id, user_id, [](const auto) {});
-}
-
-void DiscordClient::UnbanUser(Snowflake guild_id, Snowflake user_id, sigc::slot<void(DiscordError code)> callback) {
- m_http.MakeDELETE("/guilds/" + std::to_string(guild_id) + "/bans/" + std::to_string(user_id), [this, callback](const http::response_type &response) {
- if (CheckCode(response, 204))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::DeleteInvite(const std::string &code) {
- DeleteInvite(code, [](const auto) {});
-}
-
-void DiscordClient::DeleteInvite(const std::string &code, sigc::slot<void(DiscordError code)> callback) {
- m_http.MakeDELETE("/invites/" + code, [this, callback](const http::response_type &response) {
- if (CheckCode(response))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::AddGroupDMRecipient(Snowflake channel_id, Snowflake user_id) {
- m_http.MakePUT("/channels/" + std::to_string(channel_id) + "/recipients/" + std::to_string(user_id), "", [this](const http::response_type &response) {
- CheckCode(response);
- });
-}
-
-void DiscordClient::RemoveGroupDMRecipient(Snowflake channel_id, Snowflake user_id) {
- m_http.MakeDELETE("/channels/" + std::to_string(channel_id) + "/recipients/" + std::to_string(user_id), [this](const http::response_type &response) {
- CheckCode(response);
- });
-}
-
-void DiscordClient::ModifyRolePermissions(Snowflake guild_id, Snowflake role_id, Permission permissions, sigc::slot<void(DiscordError code)> callback) {
- ModifyGuildRoleObject obj;
- obj.Permissions = permissions;
- m_http.MakePATCH("/guilds/" + std::to_string(guild_id) + "/roles/" + std::to_string(role_id), nlohmann::json(obj).dump(), [this, callback](const http::response_type &response) {
- if (CheckCode(response))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::ModifyRoleName(Snowflake guild_id, Snowflake role_id, const Glib::ustring &name, sigc::slot<void(DiscordError code)> callback) {
- ModifyGuildRoleObject obj;
- obj.Name = name;
- m_http.MakePATCH("/guilds/" + std::to_string(guild_id) + "/roles/" + std::to_string(role_id), nlohmann::json(obj).dump(), [this, callback](const http::response_type &response) {
- if (CheckCode(response))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::ModifyRoleColor(Snowflake guild_id, Snowflake role_id, uint32_t color, sigc::slot<void(DiscordError code)> callback) {
- ModifyGuildRoleObject obj;
- obj.Color = color;
- m_http.MakePATCH("/guilds/" + std::to_string(guild_id) + "/roles/" + std::to_string(role_id), nlohmann::json(obj).dump(), [this, callback](const http::response_type &response) {
- if (CheckCode(response))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::ModifyRoleColor(Snowflake guild_id, Snowflake role_id, Gdk::RGBA color, sigc::slot<void(DiscordError code)> callback) {
- uint32_t int_color = 0;
- int_color |= static_cast<uint32_t>(color.get_blue() * 255.0) << 0;
- int_color |= static_cast<uint32_t>(color.get_green() * 255.0) << 8;
- int_color |= static_cast<uint32_t>(color.get_red() * 255.0) << 16;
- ModifyRoleColor(guild_id, role_id, int_color, callback);
-}
-
-void DiscordClient::ModifyRolePosition(Snowflake guild_id, Snowflake role_id, int position, sigc::slot<void(DiscordError code)> callback) {
- const auto roles = GetGuild(guild_id)->FetchRoles();
- if (static_cast<size_t>(position) > roles.size()) return;
- // gay and makes you send every role in between new and old position
- constexpr auto IDX_MAX = ~size_t { 0 };
- size_t index_from = IDX_MAX, index_to = IDX_MAX;
- for (size_t i = 0; i < roles.size(); i++) {
- const auto &role = roles[i];
- if (role.ID == role_id)
- index_from = i;
- else if (role.Position == position)
- index_to = i;
- if (index_from != IDX_MAX && index_to != IDX_MAX) break;
- }
-
- if (index_from == IDX_MAX || index_to == IDX_MAX) return;
-
- int dir;
- size_t range_from, range_to;
- if (index_to > index_from) {
- dir = 1;
- range_from = index_from + 1;
- range_to = index_to + 1;
- } else {
- dir = -1;
- range_from = index_to;
- range_to = index_from;
- }
-
- ModifyGuildRolePositionsObject obj;
-
- obj.Positions.push_back({ roles[index_from].ID, position });
- for (size_t i = range_from; i < range_to; i++)
- obj.Positions.push_back({ roles[i].ID, roles[i].Position + dir });
-
- m_http.MakePATCH("/guilds/" + std::to_string(guild_id) + "/roles", nlohmann::json(obj).dump(), [this, callback](const http::response_type &response) {
- if (CheckCode(response))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::ModifyEmojiName(Snowflake guild_id, Snowflake emoji_id, const Glib::ustring &name, sigc::slot<void(DiscordError code)> callback) {
- ModifyGuildEmojiObject obj;
- obj.Name = name;
-
- m_http.MakePATCH("/guilds/" + std::to_string(guild_id) + "/emojis/" + std::to_string(emoji_id), nlohmann::json(obj).dump(), [this, callback](const http::response_type &response) {
- if (CheckCode(response))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::DeleteEmoji(Snowflake guild_id, Snowflake emoji_id, sigc::slot<void(DiscordError code)> callback) {
- m_http.MakeDELETE("/guilds/" + std::to_string(guild_id) + "/emojis/" + std::to_string(emoji_id), [this, callback](const http::response_type &response) {
- if (CheckCode(response, 204))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-std::optional<GuildApplicationData> DiscordClient::GetGuildApplication(Snowflake guild_id) const {
- const auto it = m_guild_join_requests.find(guild_id);
- if (it == m_guild_join_requests.end()) return std::nullopt;
- return it->second;
-}
-
-void DiscordClient::RemoveRelationship(Snowflake id, sigc::slot<void(DiscordError Code)> callback) {
- m_http.MakeDELETE("/users/@me/relationships/" + std::to_string(id), [this, callback](const http::response_type &response) {
- if (CheckCode(response))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::SendFriendRequest(const Glib::ustring &username, int discriminator, sigc::slot<void(DiscordError code)> callback) {
- FriendRequestObject obj;
- obj.Username = username;
- obj.Discriminator = discriminator;
- m_http.MakePOST("/users/@me/relationships", nlohmann::json(obj).dump(), [this, callback](const http::response_type &response) {
- if (CheckCode(response, 204))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::PutRelationship(Snowflake id, sigc::slot<void(DiscordError code)> callback) {
- m_http.MakePUT("/users/@me/relationships/" + std::to_string(id), "{}", [this, callback](const http::response_type &response) {
- if (CheckCode(response, 204))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::Pin(Snowflake channel_id, Snowflake message_id, sigc::slot<void(DiscordError code)> callback) {
- m_http.MakePUT("/channels/" + std::to_string(channel_id) + "/pins/" + std::to_string(message_id), "", [this, callback](const http::response_type &response) {
- if (CheckCode(response, 204))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::Unpin(Snowflake channel_id, Snowflake message_id, sigc::slot<void(DiscordError code)> callback) {
- m_http.MakeDELETE("/channels/" + std::to_string(channel_id) + "/pins/" + std::to_string(message_id), [this, callback](const http::response_type &response) {
- if (CheckCode(response, 204))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-// 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()) {
- callback(m_store.GetPinnedMessages(id), DiscordError::NONE);
- return;
- }
- m_channels_pinned_requested.insert(id);
-
- m_http.MakeGET("/channels/" + std::to_string(id) + "/pins", [this, callback](const http::response_type &response) {
- if (!CheckCode(response)) {
- callback({}, GetCodeFromResponse(response));
- return;
- }
-
- auto data = nlohmann::json::parse(response.text).get<std::vector<Message>>();
- std::sort(data.begin(), data.end(), [](const Message &a, const Message &b) { return a.ID < b.ID; });
- for (auto &msg : data)
- StoreMessageData(msg);
- callback(std::move(data), DiscordError::NONE);
- });
-}
-
-bool DiscordClient::CanModifyRole(Snowflake guild_id, Snowflake role_id, Snowflake user_id) const {
- const auto guild = *GetGuild(guild_id);
- if (guild.OwnerID == user_id) return true;
- const auto role = *GetRole(role_id);
- const auto has_modify = HasGuildPermission(user_id, guild_id, Permission::MANAGE_CHANNELS);
- const auto highest = GetMemberHighestRole(guild_id, user_id);
- return has_modify && highest.has_value() && highest->Position > role.Position;
-}
-
-bool DiscordClient::CanModifyRole(Snowflake guild_id, Snowflake role_id) const {
- return CanModifyRole(guild_id, role_id, GetUserData().ID);
-}
-
-std::vector<BanData> DiscordClient::GetBansInGuild(Snowflake guild_id) {
- return m_store.GetBans(guild_id);
-}
-
-void DiscordClient::FetchGuildBan(Snowflake guild_id, Snowflake user_id, sigc::slot<void(BanData)> callback) {
- m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/bans/" + std::to_string(user_id), [this, callback, guild_id](const http::response_type &response) {
- if (!CheckCode(response)) return;
- auto ban = nlohmann::json::parse(response.text).get<BanData>();
- m_store.SetBan(guild_id, ban.User.ID, ban);
- m_store.SetUser(ban.User.ID, ban.User);
- callback(ban);
- });
-}
-
-void DiscordClient::FetchGuildBans(Snowflake guild_id, sigc::slot<void(std::vector<BanData>)> callback) {
- m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/bans", [this, callback, guild_id](const http::response_type &response) {
- if (!CheckCode(response)) return;
- auto bans = nlohmann::json::parse(response.text).get<std::vector<BanData>>();
- m_store.BeginTransaction();
- for (const auto &ban : bans) {
- m_store.SetBan(guild_id, ban.User.ID, ban);
- m_store.SetUser(ban.User.ID, ban.User);
- }
- m_store.EndTransaction();
- callback(bans);
- });
-}
-
-void DiscordClient::FetchGuildInvites(Snowflake guild_id, sigc::slot<void(std::vector<InviteData>)> callback) {
- m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/invites", [this, callback, guild_id](const http::response_type &response) {
- // store?
- if (!CheckCode(response)) return;
- auto invites = nlohmann::json::parse(response.text).get<std::vector<InviteData>>();
-
- m_store.BeginTransaction();
- for (const auto &invite : invites)
- if (invite.Inviter.has_value())
- m_store.SetUser(invite.Inviter->ID, *invite.Inviter);
- m_store.EndTransaction();
-
- callback(invites);
- });
-}
-
-void DiscordClient::FetchAuditLog(Snowflake guild_id, sigc::slot<void(AuditLogData)> callback) {
- m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/audit-logs", [this, callback](const http::response &response) {
- if (!CheckCode(response)) return;
- auto data = nlohmann::json::parse(response.text).get<AuditLogData>();
-
- m_store.BeginTransaction();
- for (const auto &user : data.Users)
- m_store.SetUser(user.ID, user);
- m_store.EndTransaction();
-
- callback(data);
- });
-}
-
-void DiscordClient::FetchGuildEmojis(Snowflake guild_id, sigc::slot<void(std::vector<EmojiData>)> callback) {
- m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/emojis", [this, callback](const http::response_type &response) {
- if (!CheckCode(response)) return;
- auto emojis = nlohmann::json::parse(response.text).get<std::vector<EmojiData>>();
- m_store.BeginTransaction();
- for (const auto &emoji : emojis)
- m_store.SetEmoji(emoji.ID, emoji);
- m_store.EndTransaction();
- callback(std::move(emojis));
- });
-}
-
-void DiscordClient::FetchUserProfile(Snowflake user_id, sigc::slot<void(UserProfileData)> callback) {
- m_http.MakeGET("/users/" + std::to_string(user_id) + "/profile", [this, callback](const http::response_type &response) {
- if (!CheckCode(response)) return;
- callback(nlohmann::json::parse(response.text).get<UserProfileData>());
- });
-}
-
-void DiscordClient::FetchUserNote(Snowflake user_id, sigc::slot<void(std::string note)> callback) {
- m_http.MakeGET("/users/@me/notes/" + std::to_string(user_id), [this, callback](const http::response_type &response) {
- if (response.status_code == 404) return;
- if (!CheckCode(response)) return;
- const auto note = nlohmann::json::parse(response.text).get<UserNoteObject>().Note;
- if (note.has_value())
- callback(*note);
- });
-}
-
-void DiscordClient::SetUserNote(Snowflake user_id, std::string note) {
- SetUserNote(user_id, note, [](auto) {});
-}
-
-void DiscordClient::SetUserNote(Snowflake user_id, std::string note, sigc::slot<void(DiscordError code)> callback) {
- UserSetNoteObject obj;
- obj.Note = note;
- m_http.MakePUT("/users/@me/notes/" + std::to_string(user_id), nlohmann::json(obj).dump(), [this, callback](const http::response_type &response) {
- if (CheckCode(response, 204))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::FetchUserRelationships(Snowflake user_id, sigc::slot<void(std::vector<UserData>)> callback) {
- m_http.MakeGET("/users/" + std::to_string(user_id) + "/relationships", [this, callback](const http::response_type &response) {
- if (!CheckCode(response)) return;
- RelationshipsData data = nlohmann::json::parse(response.text);
- for (const auto &user : data.Users)
- m_store.SetUser(user.ID, user);
- callback(data.Users);
- });
-}
-
-bool DiscordClient::IsVerificationRequired(Snowflake guild_id) {
- const auto member = GetMember(GetUserData().ID, guild_id);
- if (member.has_value() && member->IsPending.has_value())
- return *member->IsPending;
- return false;
-}
-
-void DiscordClient::GetVerificationGateInfo(Snowflake guild_id, sigc::slot<void(std::optional<VerificationGateInfoObject>)> callback) {
- m_http.MakeGET("/guilds/" + std::to_string(guild_id) + "/member-verification", [this, callback](const http::response_type &response) {
- if (!CheckCode(response)) return;
- if (response.status_code == 204) callback(std::nullopt);
- callback(nlohmann::json::parse(response.text).get<VerificationGateInfoObject>());
- });
-}
-
-void DiscordClient::AcceptVerificationGate(Snowflake guild_id, VerificationGateInfoObject info, sigc::slot<void(DiscordError code)> callback) {
- if (info.VerificationFields.has_value())
- for (auto &field : *info.VerificationFields)
- field.Response = true;
- m_http.MakePUT("/guilds/" + std::to_string(guild_id) + "/requests/@me", nlohmann::json(info).dump(), [this, callback](const http::response_type &response) {
- if (CheckCode(response))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
-}
-
-void DiscordClient::UpdateToken(std::string token) {
- if (!IsStarted()) {
- m_token = token;
- m_http.SetAuth(token);
- }
-}
-
-void DiscordClient::SetUserAgent(std::string agent) {
- m_http.SetUserAgent(agent);
- m_websocket.SetUserAgent(agent);
-}
-
-PresenceStatus DiscordClient::GetUserStatus(Snowflake id) const {
- auto it = m_user_to_status.find(id);
- if (it != m_user_to_status.end())
- return it->second;
-
- return PresenceStatus::Offline;
-}
-
-std::map<Snowflake, RelationshipType> DiscordClient::GetRelationships() const {
- return m_user_relationships;
-}
-
-std::set<Snowflake> DiscordClient::GetRelationships(RelationshipType type) const {
- std::set<Snowflake> ret;
- for (const auto &[id, rtype] : m_user_relationships)
- if (rtype == type)
- ret.insert(id);
- return ret;
-}
-
-std::optional<RelationshipType> DiscordClient::GetRelationship(Snowflake id) const {
- if (auto it = m_user_relationships.find(id); it != m_user_relationships.end())
- return it->second;
- return std::nullopt;
-}
-
-void DiscordClient::HandleGatewayMessageRaw(std::string str) {
- // handles multiple zlib compressed messages, calling HandleGatewayMessage when a full message is received
- std::vector<uint8_t> buf(str.begin(), str.end());
- int len = static_cast<int>(buf.size());
- bool has_suffix = buf[len - 4] == 0x00 && buf[len - 3] == 0x00 && buf[len - 2] == 0xFF && buf[len - 1] == 0xFF;
-
- m_compressed_buf.insert(m_compressed_buf.end(), buf.begin(), buf.end());
-
- if (!has_suffix) return;
-
- m_zstream.next_in = m_compressed_buf.data();
- m_zstream.avail_in = static_cast<uInt>(m_compressed_buf.size());
- m_zstream.total_in = m_zstream.total_out = 0;
-
- // loop in case of really big messages (e.g. READY)
- while (true) {
- m_zstream.next_out = m_decompress_buf.data() + m_zstream.total_out;
- m_zstream.avail_out = static_cast<uInt>(m_decompress_buf.size() - m_zstream.total_out);
-
- int err = inflate(&m_zstream, Z_SYNC_FLUSH);
- if ((err == Z_OK || err == Z_BUF_ERROR) && m_zstream.avail_in > 0) {
- m_decompress_buf.resize(m_decompress_buf.size() + InflateChunkSize);
- } else {
- if (err != Z_OK) {
- fprintf(stderr, "Error decompressing input buffer %d (%d/%d)\n", err, m_zstream.avail_in, m_zstream.avail_out);
- } else {
- m_msg_mutex.lock();
- m_msg_queue.push(std::string(m_decompress_buf.begin(), m_decompress_buf.begin() + m_zstream.total_out));
- m_msg_dispatch.emit();
- m_msg_mutex.unlock();
- if (m_decompress_buf.size() > InflateChunkSize)
- m_decompress_buf.resize(InflateChunkSize);
- }
- break;
- }
- }
-
- m_compressed_buf.clear();
-}
-
-void DiscordClient::MessageDispatch() {
- m_msg_mutex.lock();
- auto msg = m_msg_queue.front();
- m_msg_queue.pop();
- m_msg_mutex.unlock();
- HandleGatewayMessage(msg);
-}
-
-void DiscordClient::HandleGatewayMessage(std::string str) {
- GatewayMessage m;
- try {
- m = nlohmann::json::parse(str);
- } catch (std::exception &e) {
- printf("Error decoding JSON. Discarding message: %s\n", e.what());
- return;
- }
-
- if (m.Sequence != -1)
- m_last_sequence = m.Sequence;
-
- try {
- switch (m.Opcode) {
- case GatewayOp::Hello: {
- HandleGatewayHello(m);
- } break;
- case GatewayOp::HeartbeatAck: {
- m_heartbeat_acked = true;
- } break;
- case GatewayOp::Reconnect: {
- HandleGatewayReconnect(m);
- } break;
- case GatewayOp::InvalidSession: {
- HandleGatewayInvalidSession(m);
- } break;
- case GatewayOp::Event: {
- auto iter = m_event_map.find(m.Type);
- if (iter == m_event_map.end()) {
- printf("Unknown event %s\n", m.Type.c_str());
- break;
- }
- switch (iter->second) {
- case GatewayEvent::READY: {
- HandleGatewayReady(m);
- } break;
- case GatewayEvent::MESSAGE_CREATE: {
- HandleGatewayMessageCreate(m);
- } break;
- case GatewayEvent::MESSAGE_DELETE: {
- HandleGatewayMessageDelete(m);
- } break;
- case GatewayEvent::MESSAGE_UPDATE: {
- HandleGatewayMessageUpdate(m);
- } break;
- case GatewayEvent::GUILD_MEMBER_LIST_UPDATE: {
- HandleGatewayGuildMemberListUpdate(m);
- } break;
- case GatewayEvent::GUILD_CREATE: {
- HandleGatewayGuildCreate(m);
- } break;
- case GatewayEvent::GUILD_DELETE: {
- HandleGatewayGuildDelete(m);
- } break;
- case GatewayEvent::MESSAGE_DELETE_BULK: {
- HandleGatewayMessageDeleteBulk(m);
- } break;
- case GatewayEvent::GUILD_MEMBER_UPDATE: {
- HandleGatewayGuildMemberUpdate(m);
- } break;
- case GatewayEvent::PRESENCE_UPDATE: {
- HandleGatewayPresenceUpdate(m);
- } break;
- case GatewayEvent::CHANNEL_DELETE: {
- HandleGatewayChannelDelete(m);
- } break;
- case GatewayEvent::CHANNEL_UPDATE: {
- HandleGatewayChannelUpdate(m);
- } break;
- case GatewayEvent::CHANNEL_CREATE: {
- HandleGatewayChannelCreate(m);
- } break;
- case GatewayEvent::GUILD_UPDATE: {
- HandleGatewayGuildUpdate(m);
- } break;
- case GatewayEvent::GUILD_ROLE_UPDATE: {
- HandleGatewayGuildRoleUpdate(m);
- } break;
- case GatewayEvent::GUILD_ROLE_CREATE: {
- HandleGatewayGuildRoleCreate(m);
- } break;
- case GatewayEvent::GUILD_ROLE_DELETE: {
- HandleGatewayGuildRoleDelete(m);
- } break;
- case GatewayEvent::MESSAGE_REACTION_ADD: {
- HandleGatewayMessageReactionAdd(m);
- } break;
- case GatewayEvent::MESSAGE_REACTION_REMOVE: {
- HandleGatewayMessageReactionRemove(m);
- } break;
- case GatewayEvent::CHANNEL_RECIPIENT_ADD: {
- HandleGatewayChannelRecipientAdd(m);
- } break;
- case GatewayEvent::CHANNEL_RECIPIENT_REMOVE: {
- HandleGatewayChannelRecipientRemove(m);
- } break;
- case GatewayEvent::TYPING_START: {
- HandleGatewayTypingStart(m);
- } break;
- case GatewayEvent::GUILD_BAN_REMOVE: {
- HandleGatewayGuildBanRemove(m);
- } break;
- case GatewayEvent::GUILD_BAN_ADD: {
- HandleGatewayGuildBanAdd(m);
- } break;
- case GatewayEvent::INVITE_CREATE: {
- HandleGatewayInviteCreate(m);
- } break;
- case GatewayEvent::INVITE_DELETE: {
- HandleGatewayInviteDelete(m);
- } break;
- case GatewayEvent::USER_NOTE_UPDATE: {
- HandleGatewayUserNoteUpdate(m);
- } break;
- case GatewayEvent::READY_SUPPLEMENTAL: {
- HandleGatewayReadySupplemental(m);
- } break;
- case GatewayEvent::GUILD_EMOJIS_UPDATE: {
- HandleGatewayGuildEmojisUpdate(m);
- } break;
- case GatewayEvent::GUILD_JOIN_REQUEST_CREATE: {
- HandleGatewayGuildJoinRequestCreate(m);
- } break;
- case GatewayEvent::GUILD_JOIN_REQUEST_UPDATE: {
- HandleGatewayGuildJoinRequestUpdate(m);
- } break;
- case GatewayEvent::GUILD_JOIN_REQUEST_DELETE: {
- HandleGatewayGuildJoinRequestDelete(m);
- } break;
- case GatewayEvent::RELATIONSHIP_REMOVE: {
- HandleGatewayRelationshipRemove(m);
- } break;
- 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:
- printf("Unknown opcode %d\n", static_cast<int>(m.Opcode));
- break;
- }
- } catch (std::exception &e) {
- fprintf(stderr, "error handling message (opcode %d): %s\n", static_cast<int>(m.Opcode), e.what());
- }
-}
-
-void DiscordClient::HandleGatewayHello(const GatewayMessage &msg) {
- m_client_connected = true;
- HelloMessageData d = msg.Data;
- m_heartbeat_msec = d.HeartbeatInterval;
- m_heartbeat_waiter.revive();
- m_heartbeat_thread = std::thread(std::bind(&DiscordClient::HeartbeatThread, this));
- m_signal_connected.emit(); // socket is connected before this but emitting here should b fine
- m_reconnecting = false; // maybe should go elsewhere?
- if (m_wants_resume) {
- m_wants_resume = false;
- SendResume();
- } else
- SendIdentify();
-}
-
-// perhaps this should be set by the main class
-std::string DiscordClient::GetAPIURL() {
- static const auto url = Abaddon::Get().GetSettings().GetAPIBaseURL();
- return url;
-}
-
-std::string DiscordClient::GetGatewayURL() {
- static const auto url = Abaddon::Get().GetSettings().GetGatewayURL();
- return url;
-}
-
-DiscordError DiscordClient::GetCodeFromResponse(const http::response_type &response) {
- try {
- const auto data = nlohmann::json::parse(response.text);
- return data.at("code").get<DiscordError>();
- } catch (...) {}
- return DiscordError::GENERIC;
-}
-
-void DiscordClient::ProcessNewGuild(GuildData &guild) {
- if (guild.IsUnavailable) {
- printf("guild (%" PRIu64 ") unavailable\n", static_cast<uint64_t>(guild.ID));
- return;
- }
-
- m_store.BeginTransaction();
-
- m_store.SetGuild(guild.ID, guild);
- if (guild.Channels.has_value()) {
- for (auto &c : *guild.Channels) {
- c.GuildID = guild.ID;
- m_store.SetChannel(c.ID, c);
- m_guild_to_channels[guild.ID].insert(c.ID);
- for (auto &p : *c.PermissionOverwrites) {
- m_store.SetPermissionOverwrite(c.ID, p.ID, p);
- }
- }
- }
-
- 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);
-
- for (auto &e : *guild.Emojis)
- m_store.SetEmoji(e.ID, e);
-
- m_store.EndTransaction();
-}
-
-void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) {
- m_ready_received = true;
- ReadyEventData data = msg.Data;
- for (auto &g : data.Guilds)
- ProcessNewGuild(g);
-
- m_store.BeginTransaction();
-
- for (const auto &dm : data.PrivateChannels) {
- m_store.SetChannel(dm.ID, dm);
- if (dm.Recipients.has_value())
- for (const auto &recipient : *dm.Recipients)
- m_store.SetUser(recipient.ID, recipient);
- }
-
- if (data.Users.has_value())
- for (const auto &user : *data.Users)
- m_store.SetUser(user.ID, user);
-
- if (data.MergedMembers.has_value()) {
- for (size_t i = 0; i < data.MergedMembers->size(); i++) {
- const auto guild_id = data.Guilds[i].ID;
- for (const auto &member : data.MergedMembers.value()[i]) {
- m_store.SetGuildMember(guild_id, *member.UserID, member);
- }
- }
- }
-
- if (data.Relationships.has_value())
- for (const auto &relationship : *data.Relationships)
- m_user_relationships[relationship.ID] = relationship.Type;
-
- if (data.GuildJoinRequests.has_value())
- for (const auto &request : *data.GuildJoinRequests)
- m_guild_join_requests[request.GuildID] = request;
-
- m_store.EndTransaction();
-
- m_session_id = data.SessionID;
- m_user_data = data.SelfUser;
- m_user_settings = data.Settings;
- m_signal_gateway_ready.emit();
-}
-
-void DiscordClient::HandleGatewayMessageCreate(const GatewayMessage &msg) {
- Message data = msg.Data;
- StoreMessageData(data);
- if (data.GuildID.has_value())
- AddUserToGuild(data.Author.ID, *data.GuildID);
- m_signal_message_create.emit(data);
-}
-
-void DiscordClient::HandleGatewayMessageDelete(const GatewayMessage &msg) {
- MessageDeleteData data = msg.Data;
- auto cur = m_store.GetMessage(data.ID);
- if (!cur.has_value())
- return;
-
- cur->SetDeleted();
- m_store.SetMessage(data.ID, *cur);
- m_signal_message_delete.emit(data.ID, data.ChannelID);
-}
-
-void DiscordClient::HandleGatewayMessageDeleteBulk(const GatewayMessage &msg) {
- MessageDeleteBulkData data = msg.Data;
- m_store.BeginTransaction();
- for (const auto &id : data.IDs) {
- auto cur = m_store.GetMessage(id);
- if (!cur.has_value())
- continue;
-
- cur->SetDeleted();
- m_store.SetMessage(id, *cur);
- m_signal_message_delete.emit(id, data.ChannelID);
- }
- m_store.EndTransaction();
-}
-
-void DiscordClient::HandleGatewayGuildMemberUpdate(const GatewayMessage &msg) {
- GuildMemberUpdateMessage data = msg.Data;
- auto cur = m_store.GetGuildMember(data.GuildID, data.User.ID);
- if (cur.has_value()) {
- cur->update_from_json(msg.Data);
- m_store.SetGuildMember(data.GuildID, data.User.ID, *cur);
- }
- m_signal_guild_member_update.emit(data.GuildID, data.User.ID);
-}
-
-void DiscordClient::HandleGatewayPresenceUpdate(const GatewayMessage &msg) {
- PresenceUpdateMessage data = msg.Data;
- const auto user_id = data.User.at("id").get<Snowflake>();
-
- auto cur = m_store.GetUser(user_id);
- if (cur.has_value()) {
- cur->update_from_json(data.User);
- m_store.SetUser(cur->ID, *cur);
- } else
- return;
-
- PresenceStatus e;
- if (data.StatusMessage == "online")
- e = PresenceStatus::Online;
- else if (data.StatusMessage == "offline")
- e = PresenceStatus::Offline;
- else if (data.StatusMessage == "idle")
- e = PresenceStatus::Idle;
- else if (data.StatusMessage == "dnd")
- e = PresenceStatus::DND;
-
- m_user_to_status[user_id] = e;
-
- m_signal_presence_update.emit(*cur, e);
-}
-
-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);
- if (it != m_guild_to_channels.end())
- it->second.erase(id);
- m_store.ClearChannel(id);
- m_signal_channel_delete.emit(id);
-}
-
-void DiscordClient::HandleGatewayChannelUpdate(const GatewayMessage &msg) {
- const auto id = msg.Data.at("id").get<Snowflake>();
- auto cur = m_store.GetChannel(id);
- if (cur.has_value()) {
- cur->update_from_json(msg.Data);
- m_store.SetChannel(id, *cur);
- if (cur->PermissionOverwrites.has_value())
- for (const auto &p : *cur->PermissionOverwrites)
- m_store.SetPermissionOverwrite(id, p.ID, p);
- m_signal_channel_update.emit(id);
- }
-}
-
-void DiscordClient::HandleGatewayChannelCreate(const GatewayMessage &msg) {
- ChannelData data = msg.Data;
- m_store.BeginTransaction();
- m_store.SetChannel(data.ID, data);
- m_guild_to_channels[*data.GuildID].insert(data.ID);
- if (data.PermissionOverwrites.has_value())
- for (const auto &p : *data.PermissionOverwrites)
- m_store.SetPermissionOverwrite(data.ID, p.ID, p);
- m_store.EndTransaction();
- m_signal_channel_create.emit(data);
-}
-
-void DiscordClient::HandleGatewayGuildUpdate(const GatewayMessage &msg) {
- Snowflake id = msg.Data.at("id");
- auto current = m_store.GetGuild(id);
- if (!current.has_value()) return;
- current->update_from_json(msg.Data);
- m_store.SetGuild(id, *current);
- m_signal_guild_update.emit(id);
-}
-
-void DiscordClient::HandleGatewayGuildRoleUpdate(const GatewayMessage &msg) {
- GuildRoleUpdateObject data = msg.Data;
- m_store.SetRole(data.Role.ID, data.Role);
- m_signal_role_update.emit(data.GuildID, data.Role.ID);
-}
-
-void DiscordClient::HandleGatewayGuildRoleCreate(const GatewayMessage &msg) {
- GuildRoleCreateObject data = msg.Data;
- auto guild = *m_store.GetGuild(data.GuildID);
- guild.Roles->push_back(data.Role);
- m_store.BeginTransaction();
- m_store.SetRole(data.Role.ID, data.Role);
- m_store.SetGuild(guild.ID, guild);
- m_store.EndTransaction();
- m_signal_role_create.emit(data.GuildID, data.Role.ID);
-}
-
-void DiscordClient::HandleGatewayGuildRoleDelete(const GatewayMessage &msg) {
- GuildRoleDeleteObject data = msg.Data;
- auto guild = *m_store.GetGuild(data.GuildID);
- const auto pred = [this, id = data.RoleID](const RoleData &role) -> bool {
- return role.ID == id;
- };
- guild.Roles->erase(std::remove_if(guild.Roles->begin(), guild.Roles->end(), pred), guild.Roles->end());
- m_store.SetGuild(guild.ID, guild);
- m_signal_role_delete.emit(data.GuildID, data.RoleID);
-}
-
-void DiscordClient::HandleGatewayMessageReactionAdd(const GatewayMessage &msg) {
- MessageReactionAddObject data = msg.Data;
- auto to = m_store.GetMessage(data.MessageID);
- if (data.Emoji.ID.IsValid()) {
- const auto cur_emoji = m_store.GetEmoji(data.Emoji.ID);
- if (!cur_emoji.has_value())
- m_store.SetEmoji(data.Emoji.ID, data.Emoji);
- }
- if (!to.has_value()) return;
- if (!to->Reactions.has_value()) to->Reactions.emplace();
- // add if present
- bool stock;
- auto it = std::find_if(to->Reactions->begin(), to->Reactions->end(), [&](const ReactionData &x) {
- if (data.Emoji.ID.IsValid() && x.Emoji.ID.IsValid()) {
- stock = false;
- return data.Emoji.ID == x.Emoji.ID;
- } else {
- stock = true;
- return data.Emoji.Name == x.Emoji.Name;
- }
- });
-
- if (it != to->Reactions->end()) {
- it->Count++;
- if (data.UserID == GetUserData().ID)
- it->HasReactedWith = true;
- m_store.SetMessage(data.MessageID, *to);
- if (stock)
- m_signal_reaction_add.emit(data.MessageID, data.Emoji.Name);
- else
- m_signal_reaction_add.emit(data.MessageID, std::to_string(data.Emoji.ID));
- return;
- }
-
- // create new
- auto &rdata = to->Reactions->emplace_back();
- rdata.Count = 1;
- rdata.Emoji = data.Emoji;
- rdata.HasReactedWith = data.UserID == GetUserData().ID;
- m_store.SetMessage(data.MessageID, *to);
- if (stock)
- m_signal_reaction_add.emit(data.MessageID, data.Emoji.Name);
- else
- m_signal_reaction_add.emit(data.MessageID, std::to_string(data.Emoji.ID));
-}
-
-void DiscordClient::HandleGatewayMessageReactionRemove(const GatewayMessage &msg) {
- MessageReactionRemoveObject data = msg.Data;
- auto to = m_store.GetMessage(data.MessageID);
- if (!to.has_value()) return;
- if (!to->Reactions.has_value()) return;
- bool stock;
- auto it = std::find_if(to->Reactions->begin(), to->Reactions->end(), [&](const ReactionData &x) {
- if (data.Emoji.ID.IsValid() && x.Emoji.ID.IsValid()) {
- stock = false;
- return data.Emoji.ID == x.Emoji.ID;
- } else {
- stock = true;
- return data.Emoji.Name == x.Emoji.Name;
- }
- });
- if (it == to->Reactions->end()) return;
-
- if (it->Count == 1)
- to->Reactions->erase(it);
- else {
- if (data.UserID == GetUserData().ID)
- it->HasReactedWith = false;
- it->Count--;
- }
-
- m_store.SetMessage(data.MessageID, *to);
-
- if (stock)
- m_signal_reaction_remove.emit(data.MessageID, data.Emoji.Name);
- else
- m_signal_reaction_remove.emit(data.MessageID, std::to_string(data.Emoji.ID));
-}
-
-// todo: update channel list item and member list
-void DiscordClient::HandleGatewayChannelRecipientAdd(const GatewayMessage &msg) {
- ChannelRecipientAdd data = msg.Data;
- auto cur = m_store.GetChannel(data.ChannelID);
- if (!cur.has_value() || !cur->RecipientIDs.has_value()) return;
- if (std::find(cur->RecipientIDs->begin(), cur->RecipientIDs->end(), data.User.ID) == cur->RecipientIDs->end())
- cur->RecipientIDs->push_back(data.User.ID);
- m_store.SetUser(data.User.ID, data.User);
- m_store.SetChannel(cur->ID, *cur);
-}
-
-void DiscordClient::HandleGatewayChannelRecipientRemove(const GatewayMessage &msg) {
- ChannelRecipientRemove data = msg.Data;
- auto cur = m_store.GetChannel(data.ChannelID);
- if (!cur.has_value() || !cur->RecipientIDs.has_value()) return;
- cur->RecipientIDs->erase(std::remove(cur->RecipientIDs->begin(), cur->RecipientIDs->end(), data.User.ID));
- m_store.SetChannel(cur->ID, *cur);
-}
-
-void DiscordClient::HandleGatewayTypingStart(const GatewayMessage &msg) {
- TypingStartObject data = msg.Data;
- Snowflake guild_id;
- if (data.GuildID.has_value()) {
- guild_id = *data.GuildID;
- } else {
- auto chan = m_store.GetChannel(data.ChannelID);
- if (chan.has_value() && chan->GuildID.has_value())
- guild_id = *chan->GuildID;
- }
- if (guild_id.IsValid() && data.Member.has_value()) {
- auto cur = m_store.GetGuildMember(guild_id, data.UserID);
- if (!cur.has_value()) {
- AddUserToGuild(data.UserID, guild_id);
- m_store.SetGuildMember(guild_id, data.UserID, *data.Member);
- }
- if (data.Member->User.has_value())
- m_store.SetUser(data.UserID, *data.Member->User);
- }
- m_signal_typing_start.emit(data.UserID, data.ChannelID);
-}
-
-void DiscordClient::HandleGatewayGuildBanRemove(const GatewayMessage &msg) {
- GuildBanRemoveObject data = msg.Data;
- m_store.SetUser(data.User.ID, data.User);
- m_store.ClearBan(data.GuildID, data.User.ID);
- m_signal_guild_ban_remove.emit(data.GuildID, data.User.ID);
-}
-
-void DiscordClient::HandleGatewayGuildBanAdd(const GatewayMessage &msg) {
- GuildBanAddObject data = msg.Data;
- BanData ban;
- ban.Reason = "";
- ban.User = data.User;
- m_store.SetUser(data.User.ID, data.User);
- m_store.SetBan(data.GuildID, data.User.ID, ban);
- m_signal_guild_ban_add.emit(data.GuildID, data.User.ID);
-}
-
-void DiscordClient::HandleGatewayInviteCreate(const GatewayMessage &msg) {
- InviteCreateObject data = msg.Data;
- InviteData invite;
- invite.Code = std::move(data.Code);
- invite.CreatedAt = std::move(data.CreatedAt);
- invite.Channel = *m_store.GetChannel(data.ChannelID);
- invite.Inviter = std::move(data.Inviter);
- invite.IsTemporary = std::move(data.IsTemporary);
- invite.MaxAge = std::move(data.MaxAge);
- invite.MaxUses = std::move(data.MaxUses);
- invite.TargetUser = std::move(data.TargetUser);
- invite.TargetUserType = std::move(data.TargetUserType);
- invite.Uses = std::move(data.Uses);
- if (data.GuildID.has_value())
- invite.Guild = m_store.GetGuild(*data.GuildID);
- m_signal_invite_create.emit(invite);
-}
-
-void DiscordClient::HandleGatewayInviteDelete(const GatewayMessage &msg) {
- InviteDeleteObject data = msg.Data;
- if (!data.GuildID.has_value()) {
- const auto chan = GetChannel(data.ChannelID);
- data.GuildID = chan->ID;
- }
- m_signal_invite_delete.emit(data);
-}
-
-void DiscordClient::HandleGatewayUserNoteUpdate(const GatewayMessage &msg) {
- UserNoteUpdateMessage data = msg.Data;
- m_signal_note_update.emit(data.ID, data.Note);
-}
-
-void DiscordClient::HandleGatewayGuildEmojisUpdate(const GatewayMessage &msg) {
- // like the real client, the emoji data sent in this message is ignored
- // we just use it as a signal to re-request all emojis
- GuildEmojisUpdateObject data = msg.Data;
- const auto cb = [this, id = data.GuildID](const std::vector<EmojiData> &emojis) {
- m_store.BeginTransaction();
- for (const auto &emoji : emojis)
- m_store.SetEmoji(emoji.ID, emoji);
- m_store.EndTransaction();
- m_signal_guild_emojis_update.emit(id, emojis);
- };
- FetchGuildEmojis(data.GuildID, cb);
-}
-
-void DiscordClient::HandleGatewayGuildJoinRequestCreate(const GatewayMessage &msg) {
- GuildJoinRequestCreateData data = msg.Data;
- m_guild_join_requests[data.GuildID] = data.Request;
- m_signal_guild_join_request_create.emit(data);
-}
-
-void DiscordClient::HandleGatewayGuildJoinRequestUpdate(const GatewayMessage &msg) {
- GuildJoinRequestUpdateData data = msg.Data;
- m_guild_join_requests[data.GuildID] = data.Request;
- m_signal_guild_join_request_update.emit(data);
-}
-
-void DiscordClient::HandleGatewayGuildJoinRequestDelete(const GatewayMessage &msg) {
- GuildJoinRequestDeleteData data = msg.Data;
- m_guild_join_requests.erase(data.GuildID);
- m_signal_guild_join_request_delete.emit(data);
-}
-
-void DiscordClient::HandleGatewayRelationshipRemove(const GatewayMessage &msg) {
- RelationshipRemoveData data = msg.Data;
- m_user_relationships.erase(data.ID);
- m_signal_relationship_remove.emit(data.ID, data.Type);
-}
-
-void DiscordClient::HandleGatewayRelationshipAdd(const GatewayMessage &msg) {
- RelationshipAddData data = msg.Data;
- m_store.SetUser(data.ID, data.User);
- m_user_relationships[data.ID] = data.Type;
- 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);
- if (data.Channel.ThreadMember.has_value()) {
- m_signal_added_to_thread.emit(data.Channel.ID);
- }
-}
-
-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) {
- const auto user = GetUser(p.UserID);
- if (!user.has_value()) return; // should be sent in READY's `users`
- const auto s = p.Presence.Status;
- if (s == "online")
- m_user_to_status[p.UserID] = PresenceStatus::Online;
- else if (s == "offline")
- m_user_to_status[p.UserID] = PresenceStatus::Offline;
- else if (s == "idle")
- m_user_to_status[p.UserID] = PresenceStatus::Idle;
- else if (s == "dnd")
- m_user_to_status[p.UserID] = PresenceStatus::DND;
- m_signal_presence_update.emit(*user, m_user_to_status.at(p.UserID));
- }
-}
-
-void DiscordClient::HandleGatewayReconnect(const GatewayMessage &msg) {
- printf("received reconnect\n");
- inflateEnd(&m_zstream);
- m_compressed_buf.clear();
-
- m_heartbeat_waiter.kill();
- if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join();
-
- m_reconnecting = true;
- m_wants_resume = true;
- m_heartbeat_acked = true;
-
- m_websocket.Stop(1012); // 1000 (kNormalClosureCode) and 1001 will invalidate the session id
-
- std::memset(&m_zstream, 0, sizeof(m_zstream));
- inflateInit2(&m_zstream, MAX_WBITS + 32);
-
- m_websocket.StartConnection(GetGatewayURL());
-}
-
-void DiscordClient::HandleGatewayInvalidSession(const GatewayMessage &msg) {
- printf("invalid session! re-identifying\n");
-
- inflateEnd(&m_zstream);
- m_compressed_buf.clear();
-
- std::memset(&m_zstream, 0, sizeof(m_zstream));
- inflateInit2(&m_zstream, MAX_WBITS + 32);
-
- m_heartbeat_acked = true;
- m_wants_resume = false;
- m_reconnecting = true;
-
- m_heartbeat_waiter.kill();
- if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join();
-
- m_websocket.Stop(1000);
-
- if (m_client_started)
- Glib::signal_timeout().connect_once([this] { if (m_client_started) m_websocket.StartConnection(GetGatewayURL()); }, 1000);
-}
-
-bool IsCompleteMessageObject(const nlohmann::json &j) {
- const auto required = { "id", "channel_id", "author", "content", "timestamp", "edited_timestamp", "tts", "mention_everyone", "mention_roles", "attachments", "embeds", "pinned", "type" };
- for (const auto &str : required) {
- if (!j.contains(str)) return false;
- }
- return true;
-}
-
-void DiscordClient::HandleGatewayMessageUpdate(const GatewayMessage &msg) {
- Snowflake id = msg.Data.at("id");
-
- auto current = m_store.GetMessage(id);
- if (!current.has_value()) {
- // im not sure how the client determines if a MESSAGE_UPDATE is suitable to be stored as a full message but i guess its something like this
- if (IsCompleteMessageObject(msg.Data)) {
- current = msg.Data;
- m_store.SetMessage(id, *current);
- // this doesnt mean a message is newly pinned when called here
- // it just means theres an (old) message that the client is now aware of that is also pinned
- m_signal_message_pinned.emit(*current);
- } else
- return;
- } else {
- const bool old_pinned = current->IsPinned;
-
- current->from_json_edited(msg.Data);
- m_store.SetMessage(id, *current);
-
- if (old_pinned && !current->IsPinned)
- m_signal_message_unpinned.emit(*current);
- else if (!old_pinned && current->IsPinned)
- m_signal_message_pinned.emit(*current);
- }
-
- m_signal_message_update.emit(id, current->ChannelID);
-}
-
-void DiscordClient::HandleGatewayGuildMemberListUpdate(const GatewayMessage &msg) {
- GuildMemberListUpdateMessage data = msg.Data;
-
- m_store.BeginTransaction();
-
- bool has_sync = false;
- for (const auto &op : data.Ops) {
- if (op.Op == "SYNC") {
- has_sync = true;
- for (const auto &item : *op.Items) {
- if (item->Type == "member") {
- auto member = static_cast<const GuildMemberListUpdateMessage::MemberItem *>(item.get());
- m_store.SetUser(member->User.ID, member->User);
- AddUserToGuild(member->User.ID, data.GuildID);
- m_store.SetGuildMember(data.GuildID, member->User.ID, member->GetAsMemberData());
- if (member->Presence.has_value()) {
- const auto &s = member->Presence->Status;
- if (s == "online")
- m_user_to_status[member->User.ID] = PresenceStatus::Online;
- else if (s == "offline")
- m_user_to_status[member->User.ID] = PresenceStatus::Offline;
- else if (s == "idle")
- m_user_to_status[member->User.ID] = PresenceStatus::Idle;
- else if (s == "dnd")
- m_user_to_status[member->User.ID] = PresenceStatus::DND;
- }
- }
- }
- } else if (op.Op == "UPDATE") {
- if (op.OpItem.has_value() && op.OpItem.value()->Type == "member") {
- const auto &m = static_cast<const GuildMemberListUpdateMessage::MemberItem *>(op.OpItem.value().get())->GetAsMemberData();
- m_store.SetGuildMember(data.GuildID, m.User->ID, m);
- m_signal_guild_member_update.emit(data.GuildID, m.User->ID); // cheeky
- }
- }
- }
-
- m_store.EndTransaction();
-
- // todo: manage this event a little better
- if (has_sync)
- m_signal_guild_member_list_update.emit(data.GuildID);
-}
-
-void DiscordClient::HandleGatewayGuildCreate(const GatewayMessage &msg) {
- GuildData data = msg.Data;
- ProcessNewGuild(data);
-
- m_signal_guild_create.emit(data);
-}
-
-void DiscordClient::HandleGatewayGuildDelete(const GatewayMessage &msg) {
- Snowflake id = msg.Data.at("id");
- bool unavailable = msg.Data.contains("unavilable") && msg.Data.at("unavailable").get<bool>();
-
- if (unavailable)
- printf("guild %" PRIu64 " became unavailable\n", static_cast<uint64_t>(id));
-
- const auto guild = m_store.GetGuild(id);
- if (!guild.has_value()) {
- m_store.ClearGuild(id);
- m_signal_guild_delete.emit(id);
- return;
- }
-
- m_store.ClearGuild(id);
- if (guild->Channels.has_value())
- for (const auto &c : *guild->Channels)
- m_store.ClearChannel(c.ID);
-
- m_signal_guild_delete.emit(id);
-}
-
-void DiscordClient::AddUserToGuild(Snowflake user_id, Snowflake guild_id) {
- m_guild_to_users[guild_id].insert(user_id);
-}
-
-std::set<Snowflake> DiscordClient::GetPrivateChannels() const {
- auto ret = std::set<Snowflake>();
-
- 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);
- }
-
- return ret;
-}
-
-EPremiumType DiscordClient::GetSelfPremiumType() const {
- const auto &data = GetUserData();
- if (data.PremiumType.has_value())
- return *data.PremiumType;
- return EPremiumType::None;
-}
-
-void DiscordClient::HeartbeatThread() {
- while (m_client_connected) {
- if (!m_heartbeat_acked) {
- printf("wow! a heartbeat wasn't acked! how could this happen?");
- }
-
- m_heartbeat_acked = false;
-
- HeartbeatMessage msg;
- msg.Sequence = m_last_sequence;
- nlohmann::json j = msg;
- m_websocket.Send(j);
-
- if (!m_heartbeat_waiter.wait_for(std::chrono::milliseconds(m_heartbeat_msec)))
- break;
- }
-}
-
-void DiscordClient::SendIdentify() {
- IdentifyMessage msg;
- msg.Token = m_token;
- msg.Capabilities = 125; // no idea what this is
- msg.Properties.OS = "Windows";
- msg.Properties.Browser = "Chrome";
- msg.Properties.Device = "";
- msg.Properties.SystemLocale = "en-US";
- msg.Properties.BrowserUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36";
- msg.Properties.BrowserVersion = "67.0.3396.87";
- msg.Properties.OSVersion = "10";
- msg.Properties.Referrer = "";
- msg.Properties.ReferringDomain = "";
- msg.Properties.ReferrerCurrent = "";
- msg.Properties.ReferringDomainCurrent = "";
- msg.Properties.ReleaseChannel = "stable";
- msg.Properties.ClientBuildNumber = 91734;
- msg.Properties.ClientEventSource = "";
- msg.Presence.Status = "online";
- msg.Presence.Since = 0;
- msg.Presence.IsAFK = false;
- msg.DoesSupportCompression = false;
- msg.ClientState.HighestLastMessageID = "0";
- msg.ClientState.ReadStateVersion = 0;
- msg.ClientState.UserGuildSettingsVersion = -1;
- m_websocket.Send(msg);
-}
-
-void DiscordClient::SendResume() {
- ResumeMessage msg;
- msg.Sequence = m_last_sequence;
- msg.SessionID = m_session_id;
- msg.Token = m_token;
- m_websocket.Send(msg);
-}
-
-void DiscordClient::HandleSocketOpen() {
-}
-
-void DiscordClient::HandleSocketClose(uint16_t code) {
- printf("got socket close code: %d\n", code);
- auto close_code = static_cast<GatewayCloseCode>(code);
- auto cb = [this, close_code]() {
- m_heartbeat_waiter.kill();
- if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join();
- m_client_connected = false;
-
- if (m_client_started && !m_reconnecting && close_code == GatewayCloseCode::Abnormal) {
- Glib::signal_timeout().connect_once([this] { if (m_client_started) HandleGatewayReconnect(GatewayMessage()); }, 1000);
- m_reconnecting = true;
- }
-
- m_signal_disconnected.emit(m_reconnecting, close_code);
- };
- m_generic_mutex.lock();
- m_generic_queue.push(cb);
- m_generic_dispatch.emit();
- m_generic_mutex.unlock();
-}
-
-bool DiscordClient::CheckCode(const http::response_type &r) {
- if (r.status_code >= 300 || r.error) {
- fprintf(stderr, "api request to %s failed with status code %d: %s\n", r.url.c_str(), r.status_code, r.error_string.c_str());
- return false;
- }
-
- return true;
-}
-
-bool DiscordClient::CheckCode(const http::response_type &r, int expected) {
- if (!CheckCode(r)) return false;
- if (r.status_code != expected) {
- fprintf(stderr, "api request to %s returned %d, expected %d\n", r.url.c_str(), r.status_code, expected);
- return false;
- }
- return true;
-}
-
-void DiscordClient::StoreMessageData(Message &msg) {
- const auto chan = m_store.GetChannel(msg.ChannelID);
- if (chan.has_value() && chan->GuildID.has_value())
- msg.GuildID = *chan->GuildID;
-
- m_store.BeginTransaction();
-
- m_store.SetMessage(msg.ID, msg);
- m_store.SetUser(msg.Author.ID, msg.Author);
- if (msg.Reactions.has_value())
- for (const auto &r : *msg.Reactions) {
- if (!r.Emoji.ID.IsValid()) continue;
- const auto cur = m_store.GetEmoji(r.Emoji.ID);
- if (!cur.has_value())
- m_store.SetEmoji(r.Emoji.ID, r.Emoji);
- }
-
- for (const auto &user : msg.Mentions)
- m_store.SetUser(user.ID, user);
-
- if (msg.Member.has_value())
- m_store.SetGuildMember(*msg.GuildID, msg.Author.ID, *msg.Member);
-
- if (msg.Interaction.has_value() && msg.Interaction->Member.has_value()) {
- m_store.SetUser(msg.Interaction->User.ID, msg.Interaction->User);
- m_store.SetGuildMember(*msg.GuildID, msg.Interaction->User.ID, *msg.Interaction->Member);
- }
-
- m_store.EndTransaction();
-
- if (msg.ReferencedMessage.has_value() && msg.MessageReference.has_value() && msg.MessageReference->ChannelID.has_value())
- if (msg.ReferencedMessage.value() != nullptr)
- StoreMessageData(**msg.ReferencedMessage);
-}
-
-void DiscordClient::LoadEventMap() {
- m_event_map["READY"] = GatewayEvent::READY;
- m_event_map["MESSAGE_CREATE"] = GatewayEvent::MESSAGE_CREATE;
- m_event_map["MESSAGE_DELETE"] = GatewayEvent::MESSAGE_DELETE;
- m_event_map["MESSAGE_UPDATE"] = GatewayEvent::MESSAGE_UPDATE;
- m_event_map["GUILD_MEMBER_LIST_UPDATE"] = GatewayEvent::GUILD_MEMBER_LIST_UPDATE;
- m_event_map["GUILD_CREATE"] = GatewayEvent::GUILD_CREATE;
- m_event_map["GUILD_DELETE"] = GatewayEvent::GUILD_DELETE;
- m_event_map["MESSAGE_DELETE_BULK"] = GatewayEvent::MESSAGE_DELETE_BULK;
- m_event_map["GUILD_MEMBER_UPDATE"] = GatewayEvent::GUILD_MEMBER_UPDATE;
- m_event_map["PRESENCE_UPDATE"] = GatewayEvent::PRESENCE_UPDATE;
- m_event_map["CHANNEL_DELETE"] = GatewayEvent::CHANNEL_DELETE;
- m_event_map["CHANNEL_UPDATE"] = GatewayEvent::CHANNEL_UPDATE;
- m_event_map["CHANNEL_CREATE"] = GatewayEvent::CHANNEL_CREATE;
- m_event_map["GUILD_UPDATE"] = GatewayEvent::GUILD_UPDATE;
- m_event_map["GUILD_ROLE_UPDATE"] = GatewayEvent::GUILD_ROLE_UPDATE;
- m_event_map["GUILD_ROLE_CREATE"] = GatewayEvent::GUILD_ROLE_CREATE;
- m_event_map["GUILD_ROLE_DELETE"] = GatewayEvent::GUILD_ROLE_DELETE;
- m_event_map["MESSAGE_REACTION_ADD"] = GatewayEvent::MESSAGE_REACTION_ADD;
- m_event_map["MESSAGE_REACTION_REMOVE"] = GatewayEvent::MESSAGE_REACTION_REMOVE;
- m_event_map["CHANNEL_RECIPIENT_ADD"] = GatewayEvent::CHANNEL_RECIPIENT_ADD;
- m_event_map["CHANNEL_RECIPIENT_REMOVE"] = GatewayEvent::CHANNEL_RECIPIENT_REMOVE;
- m_event_map["TYPING_START"] = GatewayEvent::TYPING_START;
- m_event_map["GUILD_BAN_REMOVE"] = GatewayEvent::GUILD_BAN_REMOVE;
- m_event_map["GUILD_BAN_ADD"] = GatewayEvent::GUILD_BAN_ADD;
- m_event_map["INVITE_CREATE"] = GatewayEvent::INVITE_CREATE;
- m_event_map["INVITE_DELETE"] = GatewayEvent::INVITE_DELETE;
- m_event_map["USER_NOTE_UPDATE"] = GatewayEvent::USER_NOTE_UPDATE;
- m_event_map["READY_SUPPLEMENTAL"] = GatewayEvent::READY_SUPPLEMENTAL;
- m_event_map["GUILD_EMOJIS_UPDATE"] = GatewayEvent::GUILD_EMOJIS_UPDATE;
- m_event_map["GUILD_JOIN_REQUEST_CREATE"] = GatewayEvent::GUILD_JOIN_REQUEST_CREATE;
- m_event_map["GUILD_JOIN_REQUEST_UPDATE"] = GatewayEvent::GUILD_JOIN_REQUEST_UPDATE;
- 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() {
- return m_signal_gateway_ready;
-}
-
-DiscordClient::type_signal_message_create DiscordClient::signal_message_create() {
- return m_signal_message_create;
-}
-
-DiscordClient::type_signal_message_delete DiscordClient::signal_message_delete() {
- return m_signal_message_delete;
-}
-
-DiscordClient::type_signal_message_update DiscordClient::signal_message_update() {
- return m_signal_message_update;
-}
-
-DiscordClient::type_signal_guild_member_list_update DiscordClient::signal_guild_member_list_update() {
- return m_signal_guild_member_list_update;
-}
-
-DiscordClient::type_signal_guild_create DiscordClient::signal_guild_create() {
- return m_signal_guild_create;
-}
-
-DiscordClient::type_signal_guild_delete DiscordClient::signal_guild_delete() {
- return m_signal_guild_delete;
-}
-
-DiscordClient::type_signal_channel_delete DiscordClient::signal_channel_delete() {
- return m_signal_channel_delete;
-}
-
-DiscordClient::type_signal_channel_update DiscordClient::signal_channel_update() {
- return m_signal_channel_update;
-}
-
-DiscordClient::type_signal_channel_create DiscordClient::signal_channel_create() {
- return m_signal_channel_create;
-}
-
-DiscordClient::type_signal_guild_update DiscordClient::signal_guild_update() {
- return m_signal_guild_update;
-}
-
-DiscordClient::type_signal_disconnected DiscordClient::signal_disconnected() {
- return m_signal_disconnected;
-}
-
-DiscordClient::type_signal_connected DiscordClient::signal_connected() {
- return m_signal_connected;
-}
-
-DiscordClient::type_signal_role_update DiscordClient::signal_role_update() {
- return m_signal_role_update;
-}
-
-DiscordClient::type_signal_role_create DiscordClient::signal_role_create() {
- return m_signal_role_create;
-}
-
-DiscordClient::type_signal_role_delete DiscordClient::signal_role_delete() {
- return m_signal_role_delete;
-}
-
-DiscordClient::type_signal_reaction_add DiscordClient::signal_reaction_add() {
- return m_signal_reaction_add;
-}
-
-DiscordClient::type_signal_reaction_remove DiscordClient::signal_reaction_remove() {
- return m_signal_reaction_remove;
-}
-
-DiscordClient::type_signal_typing_start DiscordClient::signal_typing_start() {
- return m_signal_typing_start;
-}
-
-DiscordClient::type_signal_guild_member_update DiscordClient::signal_guild_member_update() {
- return m_signal_guild_member_update;
-}
-
-DiscordClient::type_signal_guild_ban_remove DiscordClient::signal_guild_ban_remove() {
- return m_signal_guild_ban_remove;
-}
-
-DiscordClient::type_signal_guild_ban_add DiscordClient::signal_guild_ban_add() {
- return m_signal_guild_ban_add;
-}
-
-DiscordClient::type_signal_invite_create DiscordClient::signal_invite_create() {
- return m_signal_invite_create;
-}
-
-DiscordClient::type_signal_invite_delete DiscordClient::signal_invite_delete() {
- return m_signal_invite_delete;
-}
-
-DiscordClient::type_signal_presence_update DiscordClient::signal_presence_update() {
- return m_signal_presence_update;
-}
-
-DiscordClient::type_signal_note_update DiscordClient::signal_note_update() {
- return m_signal_note_update;
-}
-
-DiscordClient::type_signal_guild_emojis_update DiscordClient::signal_guild_emojis_update() {
- return m_signal_guild_emojis_update;
-}
-
-DiscordClient::type_signal_guild_join_request_create DiscordClient::signal_guild_join_request_create() {
- return m_signal_guild_join_request_create;
-}
-
-DiscordClient::type_signal_guild_join_request_update DiscordClient::signal_guild_join_request_update() {
- return m_signal_guild_join_request_update;
-}
-
-DiscordClient::type_signal_guild_join_request_delete DiscordClient::signal_guild_join_request_delete() {
- return m_signal_guild_join_request_delete;
-}
-
-DiscordClient::type_signal_relationship_remove DiscordClient::signal_relationship_remove() {
- return m_signal_relationship_remove;
-}
-
-DiscordClient::type_signal_relationship_add DiscordClient::signal_relationship_add() {
- return m_signal_relationship_add;
-}
-
-DiscordClient::type_signal_message_unpinned DiscordClient::signal_message_unpinned() {
- return m_signal_message_unpinned;
-}
-
-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;
-}
-
-DiscordClient::type_signal_message_send_fail DiscordClient::signal_message_send_fail() {
- return m_signal_message_send_fail;
-}
diff --git a/discord/discord.hpp b/discord/discord.hpp
deleted file mode 100644
index aefe1f6..0000000
--- a/discord/discord.hpp
+++ /dev/null
@@ -1,457 +0,0 @@
-#pragma once
-#include "websocket.hpp"
-#include "httpclient.hpp"
-#include "objects.hpp"
-#include "store.hpp"
-#include <sigc++/sigc++.h>
-#include <nlohmann/json.hpp>
-#include <thread>
-#include <map>
-#include <set>
-#include <mutex>
-#include <zlib.h>
-#include <glibmm.h>
-#include <queue>
-
-#ifdef GetMessage
- #undef GetMessage
-#endif
-
-class HeartbeatWaiter {
-public:
- template<class R, class P>
- bool wait_for(std::chrono::duration<R, P> const &time) const {
- std::unique_lock<std::mutex> lock(m);
- return !cv.wait_for(lock, time, [&] { return terminate; });
- }
-
- void kill() {
- std::unique_lock<std::mutex> lock(m);
- terminate = true;
- cv.notify_all();
- }
-
- void revive() {
- std::unique_lock<std::mutex> lock(m);
- terminate = false;
- }
-
-private:
- mutable std::condition_variable cv;
- mutable std::mutex m;
- bool terminate = false;
-};
-
-class Abaddon;
-class DiscordClient {
- friend class Abaddon;
-
-public:
- DiscordClient(bool mem_store = false);
- void Start();
- void Stop();
- bool IsStarted() const;
- bool IsStoreValid() const;
-
- using guilds_type = Store::guilds_type;
- using channels_type = Store::channels_type;
- using messages_type = Store::messages_type;
- using users_type = Store::users_type;
- using roles_type = Store::roles_type;
- using members_type = Store::members_type;
- using permission_overwrites_type = Store::permission_overwrites_type;
-
- std::unordered_set<Snowflake> GetGuilds() const;
- const UserData &GetUserData() const;
- const UserSettings &GetUserSettings() const;
- std::vector<Snowflake> GetUserSortedGuilds() const;
- std::vector<Message> GetMessagesForChannel(Snowflake id, size_t limit = 50) const;
- std::vector<Snowflake> GetMessageIDsForChannel(Snowflake id) const;
- std::set<Snowflake> GetPrivateChannels() const;
-
- EPremiumType GetSelfPremiumType() const;
-
- void FetchMessagesInChannel(Snowflake id, sigc::slot<void(const std::vector<Message> &)> 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<ChannelData> GetChannel(Snowflake id) const;
- std::optional<EmojiData> GetEmoji(Snowflake id) const;
- std::optional<PermissionOverwrite> GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const;
- std::optional<UserData> GetUser(Snowflake id) const;
- std::optional<RoleData> GetRole(Snowflake id) const;
- std::optional<GuildData> GetGuild(Snowflake id) const;
- std::optional<GuildMember> GetMember(Snowflake user_id, Snowflake guild_id) const;
- std::optional<BanData> GetBan(Snowflake guild_id, Snowflake user_id) const;
- Snowflake GetMemberHoistedRole(Snowflake guild_id, Snowflake user_id, bool with_color = false) const;
- std::optional<RoleData> GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const;
- std::set<Snowflake> GetUsersInGuild(Snowflake id) const;
- std::set<Snowflake> GetChannelsInGuild(Snowflake id) const;
- std::vector<Snowflake> GetUsersInThread(Snowflake id) const;
- std::vector<ChannelData> GetActiveThreads(Snowflake channel_id) const;
- void GetArchivedPublicThreads(Snowflake channel_id, sigc::slot<void(DiscordError, const ArchivedThreadsResponseData &)> callback);
-
- bool IsThreadJoined(Snowflake thread_id) const;
- bool HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const;
-
- bool HasAnyChannelPermission(Snowflake user_id, Snowflake channel_id, Permission perm) const;
- bool HasChannelPermission(Snowflake user_id, Snowflake channel_id, Permission perm) const;
- Permission ComputePermissions(Snowflake member_id, Snowflake guild_id) const;
- Permission ComputeOverwrites(Permission base, Snowflake member_id, Snowflake channel_id) const;
- bool CanManageMember(Snowflake guild_id, Snowflake actor, Snowflake target) const; // kick, ban, edit nickname (cant think of a better name)
-
- void ChatMessageCallback(std::string nonce, const http::response_type &response);
-
- void SendChatMessage(const std::string &content, Snowflake channel);
- void SendChatMessage(const std::string &content, Snowflake channel, Snowflake referenced_message);
- void DeleteMessage(Snowflake channel_id, Snowflake id);
- void EditMessage(Snowflake channel_id, Snowflake id, std::string content);
- void SendLazyLoad(Snowflake id);
- void SendThreadLazyLoad(Snowflake id);
- void JoinGuild(std::string code);
- void LeaveGuild(Snowflake id);
- void KickUser(Snowflake user_id, Snowflake guild_id);
- void BanUser(Snowflake user_id, Snowflake guild_id); // todo: reason, delete messages
- void UpdateStatus(PresenceStatus status, bool is_afk);
- void UpdateStatus(PresenceStatus status, bool is_afk, const ActivityData &obj);
- void CreateDM(Snowflake user_id);
- void CreateDM(Snowflake user_id, sigc::slot<void(DiscordError code, Snowflake channel_id)> callback);
- void CloseDM(Snowflake channel_id);
- std::optional<Snowflake> FindDM(Snowflake user_id); // wont find group dms
- void AddReaction(Snowflake id, Glib::ustring param);
- void RemoveReaction(Snowflake id, Glib::ustring param);
- void SetGuildName(Snowflake id, const Glib::ustring &name);
- void SetGuildName(Snowflake id, const Glib::ustring &name, sigc::slot<void(DiscordError code)> callback);
- void SetGuildIcon(Snowflake id, const std::string &data);
- void SetGuildIcon(Snowflake id, const std::string &data, sigc::slot<void(DiscordError code)> callback);
- void UnbanUser(Snowflake guild_id, Snowflake user_id);
- void UnbanUser(Snowflake guild_id, Snowflake user_id, sigc::slot<void(DiscordError code)> callback);
- void DeleteInvite(const std::string &code);
- void DeleteInvite(const std::string &code, sigc::slot<void(DiscordError code)> callback);
- void AddGroupDMRecipient(Snowflake channel_id, Snowflake user_id);
- void RemoveGroupDMRecipient(Snowflake channel_id, Snowflake user_id);
- void ModifyRolePermissions(Snowflake guild_id, Snowflake role_id, Permission permissions, sigc::slot<void(DiscordError code)> callback);
- void ModifyRoleName(Snowflake guild_id, Snowflake role_id, const Glib::ustring &name, sigc::slot<void(DiscordError code)> callback);
- void ModifyRoleColor(Snowflake guild_id, Snowflake role_id, uint32_t color, sigc::slot<void(DiscordError code)> callback);
- void ModifyRoleColor(Snowflake guild_id, Snowflake role_id, Gdk::RGBA color, sigc::slot<void(DiscordError code)> callback);
- void ModifyRolePosition(Snowflake guild_id, Snowflake role_id, int position, sigc::slot<void(DiscordError code)> callback);
- void ModifyEmojiName(Snowflake guild_id, Snowflake emoji_id, const Glib::ustring &name, sigc::slot<void(DiscordError code)> callback);
- void DeleteEmoji(Snowflake guild_id, Snowflake emoji_id, sigc::slot<void(DiscordError code)> callback);
- std::optional<GuildApplicationData> GetGuildApplication(Snowflake guild_id) const;
- void RemoveRelationship(Snowflake id, sigc::slot<void(DiscordError code)> callback);
- void SendFriendRequest(const Glib::ustring &username, int discriminator, sigc::slot<void(DiscordError code)> callback);
- void PutRelationship(Snowflake id, sigc::slot<void(DiscordError code)> callback); // send fr by id, accept incoming
- void Pin(Snowflake channel_id, Snowflake message_id, sigc::slot<void(DiscordError code)> callback);
- void Unpin(Snowflake channel_id, Snowflake message_id, sigc::slot<void(DiscordError code)> callback);
- 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);
-
- bool CanModifyRole(Snowflake guild_id, Snowflake role_id) const;
- bool CanModifyRole(Snowflake guild_id, Snowflake role_id, Snowflake user_id) const;
-
- // real client doesn't seem to use the single role endpoints so neither do we
- template<typename Iter>
- auto SetMemberRoles(Snowflake guild_id, Snowflake user_id, Iter begin, Iter end, sigc::slot<void(DiscordError code)> callback) {
- ModifyGuildMemberObject obj;
- obj.Roles = { begin, end };
- m_http.MakePATCH("/guilds/" + std::to_string(guild_id) + "/members/" + std::to_string(user_id), nlohmann::json(obj).dump(), [this, callback](const http::response_type &response) {
- if (CheckCode(response))
- callback(DiscordError::NONE);
- else
- callback(GetCodeFromResponse(response));
- });
- }
-
- // FetchGuildBans fetches all bans+reasons via api, this func fetches stored bans (so usually just GUILD_BAN_ADD data)
- std::vector<BanData> GetBansInGuild(Snowflake guild_id);
- void FetchGuildBan(Snowflake guild_id, Snowflake user_id, sigc::slot<void(BanData)> callback);
- void FetchGuildBans(Snowflake guild_id, sigc::slot<void(std::vector<BanData>)> callback);
-
- void FetchInvite(std::string code, sigc::slot<void(std::optional<InviteData>)> callback);
- void FetchGuildInvites(Snowflake guild_id, sigc::slot<void(std::vector<InviteData>)> callback);
-
- void FetchAuditLog(Snowflake guild_id, sigc::slot<void(AuditLogData)> callback);
-
- void FetchGuildEmojis(Snowflake guild_id, sigc::slot<void(std::vector<EmojiData>)> callback);
-
- void FetchUserProfile(Snowflake user_id, sigc::slot<void(UserProfileData)> callback);
- void FetchUserNote(Snowflake user_id, sigc::slot<void(std::string note)> callback);
- void SetUserNote(Snowflake user_id, std::string note);
- void SetUserNote(Snowflake user_id, std::string note, sigc::slot<void(DiscordError code)> callback);
- void FetchUserRelationships(Snowflake user_id, sigc::slot<void(std::vector<UserData>)> callback);
-
- void FetchPinned(Snowflake id, sigc::slot<void(std::vector<Message>, DiscordError code)> callback);
-
- bool IsVerificationRequired(Snowflake guild_id);
- void GetVerificationGateInfo(Snowflake guild_id, sigc::slot<void(std::optional<VerificationGateInfoObject>)> callback);
- void AcceptVerificationGate(Snowflake guild_id, VerificationGateInfoObject info, sigc::slot<void(DiscordError code)> callback);
-
- void UpdateToken(std::string token);
- void SetUserAgent(std::string agent);
-
- PresenceStatus GetUserStatus(Snowflake id) const;
-
- std::map<Snowflake, RelationshipType> GetRelationships() const;
- std::set<Snowflake> GetRelationships(RelationshipType type) const;
- std::optional<RelationshipType> GetRelationship(Snowflake id) const;
-
-private:
- static const constexpr int InflateChunkSize = 0x10000;
- std::vector<uint8_t> m_compressed_buf;
- std::vector<uint8_t> m_decompress_buf;
- z_stream m_zstream;
-
- std::string GetAPIURL();
- std::string GetGatewayURL();
-
- static DiscordError GetCodeFromResponse(const http::response_type &response);
-
- void ProcessNewGuild(GuildData &guild);
-
- void HandleGatewayMessageRaw(std::string str);
- void HandleGatewayMessage(std::string str);
- void HandleGatewayHello(const GatewayMessage &msg);
- void HandleGatewayReady(const GatewayMessage &msg);
- void HandleGatewayMessageCreate(const GatewayMessage &msg);
- void HandleGatewayMessageDelete(const GatewayMessage &msg);
- void HandleGatewayMessageUpdate(const GatewayMessage &msg);
- void HandleGatewayGuildMemberListUpdate(const GatewayMessage &msg);
- void HandleGatewayGuildCreate(const GatewayMessage &msg);
- void HandleGatewayGuildDelete(const GatewayMessage &msg);
- void HandleGatewayMessageDeleteBulk(const GatewayMessage &msg);
- void HandleGatewayGuildMemberUpdate(const GatewayMessage &msg);
- void HandleGatewayPresenceUpdate(const GatewayMessage &msg);
- void HandleGatewayChannelDelete(const GatewayMessage &msg);
- void HandleGatewayChannelUpdate(const GatewayMessage &msg);
- void HandleGatewayChannelCreate(const GatewayMessage &msg);
- void HandleGatewayGuildUpdate(const GatewayMessage &msg);
- void HandleGatewayGuildRoleUpdate(const GatewayMessage &msg);
- void HandleGatewayGuildRoleCreate(const GatewayMessage &msg);
- void HandleGatewayGuildRoleDelete(const GatewayMessage &msg);
- void HandleGatewayMessageReactionAdd(const GatewayMessage &msg);
- void HandleGatewayMessageReactionRemove(const GatewayMessage &msg);
- void HandleGatewayChannelRecipientAdd(const GatewayMessage &msg);
- void HandleGatewayChannelRecipientRemove(const GatewayMessage &msg);
- void HandleGatewayTypingStart(const GatewayMessage &msg);
- void HandleGatewayGuildBanRemove(const GatewayMessage &msg);
- void HandleGatewayGuildBanAdd(const GatewayMessage &msg);
- void HandleGatewayInviteCreate(const GatewayMessage &msg);
- void HandleGatewayInviteDelete(const GatewayMessage &msg);
- void HandleGatewayUserNoteUpdate(const GatewayMessage &msg);
- void HandleGatewayGuildEmojisUpdate(const GatewayMessage &msg);
- void HandleGatewayGuildJoinRequestCreate(const GatewayMessage &msg);
- void HandleGatewayGuildJoinRequestUpdate(const GatewayMessage &msg);
- void HandleGatewayGuildJoinRequestDelete(const GatewayMessage &msg);
- void HandleGatewayRelationshipRemove(const GatewayMessage &msg);
- void HandleGatewayRelationshipAdd(const GatewayMessage &msg);
- void HandleGatewayThreadCreate(const GatewayMessage &msg);
- void HandleGatewayThreadDelete(const GatewayMessage &msg);
- void HandleGatewayThreadListSync(const GatewayMessage &msg);
- void HandleGatewayThreadMembersUpdate(const GatewayMessage &msg);
- void HandleGatewayThreadMemberUpdate(const GatewayMessage &msg);
- void HandleGatewayThreadUpdate(const GatewayMessage &msg);
- void HandleGatewayThreadMemberListUpdate(const GatewayMessage &msg);
- void HandleGatewayReadySupplemental(const GatewayMessage &msg);
- void HandleGatewayReconnect(const GatewayMessage &msg);
- void HandleGatewayInvalidSession(const GatewayMessage &msg);
- void HeartbeatThread();
- void SendIdentify();
- void SendResume();
-
- void HandleSocketOpen();
- void HandleSocketClose(uint16_t code);
-
- bool CheckCode(const http::response_type &r);
- bool CheckCode(const http::response_type &r, int expected);
-
- void StoreMessageData(Message &msg);
-
- std::string m_token;
-
- void AddUserToGuild(Snowflake user_id, Snowflake guild_id);
- std::map<Snowflake, std::set<Snowflake>> m_guild_to_users;
- std::map<Snowflake, std::set<Snowflake>> m_guild_to_channels;
- std::map<Snowflake, GuildApplicationData> m_guild_join_requests;
- std::map<Snowflake, PresenceStatus> m_user_to_status;
- std::map<Snowflake, RelationshipType> m_user_relationships;
- std::set<Snowflake> m_joined_threads;
- std::map<Snowflake, std::vector<Snowflake>> m_thread_members;
-
- UserData m_user_data;
- UserSettings m_user_settings;
-
- Store m_store;
- HTTPClient m_http;
- Websocket m_websocket;
- std::atomic<bool> m_client_connected = false;
- std::atomic<bool> m_ready_received = false;
- bool m_client_started = false;
-
- std::map<std::string, GatewayEvent> m_event_map;
- void LoadEventMap();
-
- std::thread m_heartbeat_thread;
- std::atomic<int> m_last_sequence = -1;
- std::atomic<int> m_heartbeat_msec = 0;
- HeartbeatWaiter m_heartbeat_waiter;
- std::atomic<bool> m_heartbeat_acked = true;
-
- bool m_reconnecting = false; // reconnecting either to resume or reidentify
- bool m_wants_resume = false; // reconnecting specifically to resume
- std::string m_session_id;
-
- mutable std::mutex m_msg_mutex;
- Glib::Dispatcher m_msg_dispatch;
- std::queue<std::string> m_msg_queue;
- void MessageDispatch();
-
- mutable std::mutex m_generic_mutex;
- Glib::Dispatcher m_generic_dispatch;
- std::queue<std::function<void()>> m_generic_queue;
-
- std::set<Snowflake> m_channels_pinned_requested;
- std::set<Snowflake> m_channels_lazy_loaded;
-
- // signals
-public:
- typedef sigc::signal<void> type_signal_gateway_ready;
- typedef sigc::signal<void, Message> type_signal_message_create;
- typedef sigc::signal<void, Snowflake, Snowflake> type_signal_message_delete;
- typedef sigc::signal<void, Snowflake, Snowflake> type_signal_message_update;
- typedef sigc::signal<void, Snowflake> type_signal_guild_member_list_update;
- typedef sigc::signal<void, GuildData> type_signal_guild_create;
- typedef sigc::signal<void, Snowflake> type_signal_guild_delete;
- typedef sigc::signal<void, Snowflake> type_signal_channel_delete;
- typedef sigc::signal<void, Snowflake> type_signal_channel_update;
- typedef sigc::signal<void, ChannelData> type_signal_channel_create;
- typedef sigc::signal<void, Snowflake> type_signal_guild_update;
- typedef sigc::signal<void, Snowflake, Snowflake> type_signal_role_update; // guild id, role id
- typedef sigc::signal<void, Snowflake, Snowflake> type_signal_role_create; // guild id, role id
- typedef sigc::signal<void, Snowflake, Snowflake> type_signal_role_delete; // guild id, role id
- typedef sigc::signal<void, Snowflake, Glib::ustring> type_signal_reaction_add;
- typedef sigc::signal<void, Snowflake, Glib::ustring> type_signal_reaction_remove;
- typedef sigc::signal<void, Snowflake, Snowflake> type_signal_typing_start; // user id, channel id
- typedef sigc::signal<void, Snowflake, Snowflake> type_signal_guild_member_update; // guild id, user id
- typedef sigc::signal<void, Snowflake, Snowflake> type_signal_guild_ban_remove; // guild id, user id
- typedef sigc::signal<void, Snowflake, Snowflake> type_signal_guild_ban_add; // guild id, user id
- typedef sigc::signal<void, InviteData> type_signal_invite_create;
- typedef sigc::signal<void, InviteDeleteObject> type_signal_invite_delete;
- typedef sigc::signal<void, UserData, PresenceStatus> type_signal_presence_update;
- typedef sigc::signal<void, Snowflake, std::string> type_signal_note_update;
- typedef sigc::signal<void, Snowflake, std::vector<EmojiData>> type_signal_guild_emojis_update; // guild id
- typedef sigc::signal<void, GuildJoinRequestCreateData> type_signal_guild_join_request_create;
- typedef sigc::signal<void, GuildJoinRequestUpdateData> type_signal_guild_join_request_update;
- typedef sigc::signal<void, GuildJoinRequestDeleteData> type_signal_guild_join_request_delete;
- typedef sigc::signal<void, Snowflake, RelationshipType> type_signal_relationship_remove;
- typedef sigc::signal<void, RelationshipAddData> type_signal_relationship_add;
- typedef sigc::signal<void, ChannelData> type_signal_thread_create;
- typedef sigc::signal<void, ThreadDeleteData> type_signal_thread_delete;
- typedef sigc::signal<void, ThreadListSyncData> type_signal_thread_list_sync;
- 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;
-
- // not discord dispatch events
- typedef sigc::signal<void, Snowflake> type_signal_added_to_thread;
- typedef sigc::signal<void, Snowflake> type_signal_removed_from_thread;
- typedef sigc::signal<void, Message> type_signal_message_unpinned;
- typedef sigc::signal<void, Message> type_signal_message_pinned;
- typedef sigc::signal<void, Message> type_signal_message_sent;
-
- typedef sigc::signal<void, std::string /* nonce */, float /* retry_after */> type_signal_message_send_fail; // retry after param will be 0 if it failed for a reason that isnt slowmode
- typedef sigc::signal<void, bool, GatewayCloseCode> type_signal_disconnected; // bool true if reconnecting
- typedef sigc::signal<void> type_signal_connected;
-
- type_signal_gateway_ready signal_gateway_ready();
- type_signal_message_create signal_message_create();
- type_signal_message_delete signal_message_delete();
- type_signal_message_update signal_message_update();
- type_signal_guild_member_list_update signal_guild_member_list_update();
- type_signal_guild_create signal_guild_create(); // structs are complete in this signal
- type_signal_guild_delete signal_guild_delete();
- type_signal_channel_delete signal_channel_delete();
- type_signal_channel_update signal_channel_update();
- type_signal_channel_create signal_channel_create();
- type_signal_guild_update signal_guild_update();
- type_signal_role_update signal_role_update();
- type_signal_role_create signal_role_create();
- type_signal_role_delete signal_role_delete();
- type_signal_reaction_add signal_reaction_add();
- type_signal_reaction_remove signal_reaction_remove();
- type_signal_typing_start signal_typing_start();
- type_signal_guild_member_update signal_guild_member_update();
- type_signal_guild_ban_remove signal_guild_ban_remove();
- type_signal_guild_ban_add signal_guild_ban_add();
- type_signal_invite_create signal_invite_create();
- type_signal_invite_delete signal_invite_delete(); // safe to assume guild id is set
- type_signal_presence_update signal_presence_update();
- type_signal_note_update signal_note_update();
- type_signal_guild_emojis_update signal_guild_emojis_update();
- type_signal_guild_join_request_create signal_guild_join_request_create();
- type_signal_guild_join_request_update signal_guild_join_request_update();
- type_signal_guild_join_request_delete signal_guild_join_request_delete();
- type_signal_relationship_remove signal_relationship_remove();
- type_signal_relationship_add signal_relationship_add();
- type_signal_message_unpinned signal_message_unpinned();
- type_signal_message_pinned signal_message_pinned();
- type_signal_thread_create signal_thread_create();
- type_signal_thread_delete signal_thread_delete();
- type_signal_thread_list_sync signal_thread_list_sync();
- 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_added_to_thread signal_added_to_thread();
- type_signal_removed_from_thread signal_removed_from_thread();
- type_signal_message_sent signal_message_sent();
- type_signal_message_send_fail signal_message_send_fail();
- type_signal_disconnected signal_disconnected();
- type_signal_connected signal_connected();
-
-protected:
- type_signal_gateway_ready m_signal_gateway_ready;
- type_signal_message_create m_signal_message_create;
- type_signal_message_delete m_signal_message_delete;
- type_signal_message_update m_signal_message_update;
- type_signal_guild_member_list_update m_signal_guild_member_list_update;
- type_signal_guild_create m_signal_guild_create;
- type_signal_guild_delete m_signal_guild_delete;
- type_signal_channel_delete m_signal_channel_delete;
- type_signal_channel_update m_signal_channel_update;
- type_signal_channel_create m_signal_channel_create;
- type_signal_guild_update m_signal_guild_update;
- type_signal_role_update m_signal_role_update;
- type_signal_role_create m_signal_role_create;
- type_signal_role_delete m_signal_role_delete;
- type_signal_reaction_add m_signal_reaction_add;
- type_signal_reaction_remove m_signal_reaction_remove;
- type_signal_typing_start m_signal_typing_start;
- type_signal_guild_member_update m_signal_guild_member_update;
- type_signal_guild_ban_remove m_signal_guild_ban_remove;
- type_signal_guild_ban_add m_signal_guild_ban_add;
- type_signal_invite_create m_signal_invite_create;
- type_signal_invite_delete m_signal_invite_delete;
- type_signal_presence_update m_signal_presence_update;
- type_signal_note_update m_signal_note_update;
- type_signal_guild_emojis_update m_signal_guild_emojis_update;
- type_signal_guild_join_request_create m_signal_guild_join_request_create;
- type_signal_guild_join_request_update m_signal_guild_join_request_update;
- type_signal_guild_join_request_delete m_signal_guild_join_request_delete;
- type_signal_relationship_remove m_signal_relationship_remove;
- type_signal_relationship_add m_signal_relationship_add;
- type_signal_message_unpinned m_signal_message_unpinned;
- type_signal_message_pinned m_signal_message_pinned;
- type_signal_thread_create m_signal_thread_create;
- type_signal_thread_delete m_signal_thread_delete;
- type_signal_thread_list_sync m_signal_thread_list_sync;
- 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_removed_from_thread m_signal_removed_from_thread;
- type_signal_added_to_thread m_signal_added_to_thread;
- type_signal_message_sent m_signal_message_sent;
- type_signal_message_send_fail m_signal_message_send_fail;
- type_signal_disconnected m_signal_disconnected;
- type_signal_connected m_signal_connected;
-};
diff --git a/discord/emoji.cpp b/discord/emoji.cpp
deleted file mode 100644
index 1a97eb8..0000000
--- a/discord/emoji.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "emoji.hpp"
-
-void from_json(const nlohmann::json &j, EmojiData &m) {
- JS_N("id", m.ID);
- JS_N("name", m.Name);
- JS_O("roles", m.Roles);
- JS_O("user", m.Creator);
- JS_O("require_colons", m.NeedsColons);
- JS_O("managed", m.IsManaged);
- JS_O("animated", m.IsAnimated);
- JS_O("available", m.IsAvailable);
-}
-
-void to_json(nlohmann::json &j, const EmojiData &m) {
- if (m.ID.IsValid())
- j["id"] = m.ID;
- else
- j["id"] = nullptr;
- if (m.Name != "")
- j["name"] = m.Name;
- else
- j["name"] = nullptr;
- JS_IF("roles", m.Roles);
- JS_IF("user", m.Creator);
- JS_IF("require_colons", m.NeedsColons);
- JS_IF("managed", m.IsManaged);
- JS_IF("animated", m.IsAnimated);
- JS_IF("available", m.IsAvailable);
-}
-
-std::string EmojiData::GetURL(const char *ext, const char *size) const {
- if (size != nullptr)
- return "https://cdn.discordapp.com/emojis/" + std::to_string(ID) + "." + ext + "?size=" + size;
- else
- return "https://cdn.discordapp.com/emojis/" + std::to_string(ID) + "." + ext;
-}
-
-std::string EmojiData::URLFromID(const std::string &emoji_id, const char *ext, const char *size) {
- if (size != nullptr)
- return "https://cdn.discordapp.com/emojis/" + emoji_id + "." + ext + "?size=" + size;
- else
- return "https://cdn.discordapp.com/emojis/" + emoji_id + "." + ext;
-}
-
-std::string EmojiData::URLFromID(Snowflake emoji_id, const char *ext, const char *size) {
- return URLFromID(std::to_string(emoji_id), ext, size);
-}
-
-std::string EmojiData::URLFromID(const Glib::ustring &emoji_id, const char *ext, const char *size) {
- return URLFromID(emoji_id.raw(), ext, size);
-}
diff --git a/discord/emoji.hpp b/discord/emoji.hpp
deleted file mode 100644
index 156e127..0000000
--- a/discord/emoji.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-#include <string>
-#include <vector>
-#include "json.hpp"
-#include "snowflake.hpp"
-#include "user.hpp"
-
-struct EmojiData {
- Snowflake ID; // null
- std::string Name; // null (in reactions)
- std::optional<std::vector<Snowflake>> Roles;
- std::optional<UserData> Creator; // only reliable to access ID
- std::optional<bool> NeedsColons;
- std::optional<bool> IsManaged;
- std::optional<bool> IsAnimated;
- std::optional<bool> IsAvailable;
-
- friend void from_json(const nlohmann::json &j, EmojiData &m);
- friend void to_json(nlohmann::json &j, const EmojiData &m);
-
- std::string GetURL(const char *ext = "png", const char *size = nullptr) const;
- static std::string URLFromID(const std::string &emoji_id, const char *ext = "png", const char *size = nullptr);
- static std::string URLFromID(Snowflake emoji_id, const char *ext = "png", const char *size = nullptr);
- static std::string URLFromID(const Glib::ustring &emoji_id, const char *ext = "png", const char *size = nullptr);
-};
diff --git a/discord/errors.hpp b/discord/errors.hpp
deleted file mode 100644
index 4579563..0000000
--- a/discord/errors.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#pragma once
-
-enum class DiscordError {
- GENERIC = 0,
- INVALID_FORM_BODY = 50035,
- RELATIONSHIP_INCOMING_DISABLED = 80000,
- RELATIONSHIP_INCOMING_BLOCKED = 80001,
- RELATIONSHIP_INVALID_USER_BOT = 80002, // this is misspelled in discord's source lul
- RELATIONSHIP_INVALID_SELF = 80003,
- RELATIONSHIP_INVALID_DISCORD_TAG = 80004,
- RELATIONSHIP_ALREADY_FRIENDS = 80007,
-
- NONE = -1,
-};
-
-constexpr const char *GetDiscordErrorDisplayString(DiscordError error) {
- switch (error) {
- case DiscordError::INVALID_FORM_BODY:
- return "Something's wrong with your input";
- case DiscordError::RELATIONSHIP_INCOMING_DISABLED:
- return "This user isn't accepting friend requests";
- case DiscordError::RELATIONSHIP_INCOMING_BLOCKED:
- return "You are blocked by this user";
- case DiscordError::RELATIONSHIP_INVALID_USER_BOT:
- return "You can't send a request to a bot";
- case DiscordError::RELATIONSHIP_INVALID_SELF:
- return "You can't send a request to yourself";
- case DiscordError::RELATIONSHIP_INVALID_DISCORD_TAG:
- return "No users with that tag exist";
- case DiscordError::RELATIONSHIP_ALREADY_FRIENDS:
- return "You are already friends with that user";
- case DiscordError::GENERIC:
- default:
- return "An error occurred";
- }
-}
diff --git a/discord/guild.cpp b/discord/guild.cpp
deleted file mode 100644
index 23a45ee..0000000
--- a/discord/guild.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-#include "guild.hpp"
-#include "../abaddon.hpp"
-
-void from_json(const nlohmann::json &j, GuildData &m) {
- JS_D("id", m.ID);
- if (j.contains("unavailable")) {
- m.IsUnavailable = true;
- return;
- }
-
- JS_D("name", m.Name);
- JS_N("icon", m.Icon);
- JS_N("splash", m.Splash);
- JS_ON("discovery_splash", m.DiscoverySplash);
- JS_O("owner", m.IsOwner);
- JS_O("owner_id", m.OwnerID);
- std::optional<std::string> tmp;
- JS_O("permissions", tmp);
- if (tmp.has_value())
- m.Permissions = std::stoull(*tmp);
- JS_O("region", m.VoiceRegion);
- JS_ON("afk_channel_id", m.AFKChannelID);
- JS_O("afk_timeout", m.AFKTimeout);
- JS_O("embed_enabled", m.IsEmbedEnabled);
- JS_ON("embed_channel_id", m.EmbedChannelID);
- JS_O("verification_level", m.VerificationLevel);
- JS_O("default_message_notifications", m.DefaultMessageNotifications);
- JS_O("explicit_content_filter", m.ExplicitContentFilter);
- JS_O("roles", m.Roles);
- JS_O("emojis", m.Emojis);
- JS_O("features", m.Features);
- JS_O("mfa_level", m.MFALevel);
- JS_ON("application_id", m.ApplicationID);
- JS_O("widget_enabled", m.IsWidgetEnabled);
- JS_ON("widget_channel_id", m.WidgetChannelID);
- JS_ON("system_channel_id", m.SystemChannelID);
- JS_O("system_channel_flags", m.SystemChannelFlags);
- JS_ON("rules_channel_id", m.RulesChannelID);
- JS_O("joined_at", m.JoinedAt);
- JS_O("large", m.IsLarge);
- JS_O("unavailable", m.IsUnavailable);
- JS_O("member_count", m.MemberCount);
- // JS_O("voice_states", m.VoiceStates);
- // JS_O("members", m.Members);
- JS_O("channels", m.Channels);
- JS_O("threads", m.Threads);
- // JS_O("presences", m.Presences);
- JS_ON("max_presences", m.MaxPresences);
- JS_O("max_members", m.MaxMembers);
- JS_ON("vanity_url_code", m.VanityURL);
- JS_ON("description", m.Description);
- JS_ON("banner", m.BannerHash);
- JS_O("premium_tier", m.PremiumTier);
- JS_O("premium_subscription_count", m.PremiumSubscriptionCount);
- JS_O("preferred_locale", m.PreferredLocale);
- JS_ON("public_updates_channel_id", m.PublicUpdatesChannelID);
- JS_O("max_video_channel_users", m.MaxVideoChannelUsers);
- JS_O("approximate_member_count", tmp);
- if (tmp.has_value())
- m.ApproximateMemberCount = std::stol(*tmp);
- JS_O("approximate_presence_count", tmp);
- if (tmp.has_value())
- m.ApproximatePresenceCount = std::stol(*tmp);
-}
-
-void GuildData::update_from_json(const nlohmann::json &j) {
- if (j.contains("unavailable")) {
- IsUnavailable = true;
- return;
- }
-
- JS_RD("name", Name);
- JS_RD("icon", Icon);
- JS_RD("splash", Splash);
- JS_RD("discovery_splash", DiscoverySplash);
- JS_RD("owner", IsOwner);
- JS_RD("owner_id", OwnerID);
- std::string tmp;
- JS_RD("permissions", tmp);
- if (tmp != "")
- Permissions = std::stoull(tmp);
- JS_RD("region", VoiceRegion);
- JS_RD("afk_channel_id", AFKChannelID);
- JS_RD("afk_timeout", AFKTimeout);
- JS_RD("embed_enabled", IsEmbedEnabled);
- JS_RD("embed_channel_id", EmbedChannelID);
- JS_RD("verification_level", VerificationLevel);
- JS_RD("default_message_notifications", DefaultMessageNotifications);
- JS_RD("explicit_content_filter", ExplicitContentFilter);
- JS_RD("roles", Roles);
- JS_RD("emojis", Emojis);
- JS_RD("features", Features);
- JS_RD("mfa_level", MFALevel);
- JS_RD("application_id", ApplicationID);
- JS_RD("widget_enabled", IsWidgetEnabled);
- JS_RD("widget_channel_id", WidgetChannelID);
- JS_RD("system_channel_id", SystemChannelID);
- JS_RD("system_channel_flags", SystemChannelFlags);
- JS_RD("rules_channel_id", RulesChannelID);
- JS_RD("joined_at", JoinedAt);
- JS_RD("large", IsLarge);
- JS_RD("unavailable", IsUnavailable);
- JS_RD("member_count", MemberCount);
- // JS_O("voice_states", m.VoiceStates);
- // JS_O("members", m.Members);
- JS_RD("channels", Channels);
- // JS_O("presences", m.Presences);
- JS_RD("max_presences", MaxPresences);
- JS_RD("max_members", MaxMembers);
- JS_RD("vanity_url_code", VanityURL);
- JS_RD("description", Description);
- JS_RD("banner", BannerHash);
- JS_RD("premium_tier", PremiumTier);
- JS_RD("premium_subscription_count", PremiumSubscriptionCount);
- JS_RD("preferred_locale", PreferredLocale);
- JS_RD("public_updates_channel_id", PublicUpdatesChannelID);
- JS_RD("max_video_channel_users", MaxVideoChannelUsers);
- JS_RD("approximate_member_count", ApproximateMemberCount);
- JS_RD("approximate_presence_count", ApproximatePresenceCount);
-}
-
-bool GuildData::HasFeature(const std::string &search_feature) {
- if (!Features.has_value()) return false;
- for (const auto &feature : *Features)
- if (search_feature == feature)
- return true;
- return false;
-}
-
-bool GuildData::HasIcon() const {
- return Icon != "";
-}
-
-bool GuildData::HasAnimatedIcon() const {
- return HasIcon() && Icon[0] == 'a' && Icon[1] == '_';
-}
-
-std::string GuildData::GetIconURL(std::string ext, std::string size) const {
- return "https://cdn.discordapp.com/icons/" + std::to_string(ID) + "/" + Icon + "." + ext + "?size=" + size;
-}
-
-std::vector<Snowflake> GuildData::GetSortedChannels(Snowflake ignore) const {
- std::vector<Snowflake> ret;
-
- const auto &discord = Abaddon::Get().GetDiscordClient();
- auto channels = discord.GetChannelsInGuild(ID);
-
- std::unordered_map<Snowflake, std::vector<ChannelData>> category_to_channels;
- std::map<int, std::vector<ChannelData>> position_to_categories;
- std::map<int, std::vector<ChannelData>> orphan_channels;
- for (const auto &channel_id : channels) {
- const auto data = discord.GetChannel(channel_id);
- if (!data->ParentID.has_value() && (data->Type == ChannelType::GUILD_TEXT || data->Type == ChannelType::GUILD_NEWS))
- orphan_channels[*data->Position].push_back(*data);
- else if (data->ParentID.has_value() && (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);
- }
-
- for (auto &[pos, channels] : orphan_channels) {
- std::sort(channels.begin(), channels.end(), [&](const ChannelData &a, const ChannelData &b) -> bool {
- return a.ID < b.ID;
- });
- for (const auto &chan : channels)
- ret.push_back(chan.ID);
- }
-
- for (auto &[pos, categories] : position_to_categories) {
- std::sort(categories.begin(), categories.end(), [&](const ChannelData &a, const ChannelData &b) -> bool {
- return a.ID < b.ID;
- });
- for (const auto &category : categories) {
- ret.push_back(category.ID);
- if (ignore == category.ID) continue; // stupid hack to save me some time
- auto it = category_to_channels.find(category.ID);
- if (it == category_to_channels.end()) continue;
- auto &channels = it->second;
- std::sort(channels.begin(), channels.end(), [&](const ChannelData &a, const ChannelData &b) -> bool {
- return a.Position < b.Position;
- });
- for (auto &channel : channels) {
- ret.push_back(channel.ID);
- }
- }
- }
-
- return ret;
-}
-
-std::vector<RoleData> GuildData::FetchRoles() const {
- if (!Roles.has_value()) return {};
- std::vector<RoleData> ret;
- ret.reserve(Roles->size());
- for (const auto &thing : *Roles)
- ret.push_back(*Abaddon::Get().GetDiscordClient().GetRole(thing.ID));
- std::sort(ret.begin(), ret.end(), [](const RoleData &a, const RoleData &b) -> bool {
- return a.Position > b.Position;
- });
- return ret;
-}
-
-void from_json(const nlohmann::json &j, GuildApplicationData &m) {
- JS_D("user_id", m.UserID);
- JS_D("guild_id", m.GuildID);
- auto tmp = j.at("application_status").get<std::string_view>();
- if (tmp == "STARTED")
- m.ApplicationStatus = GuildApplicationStatus::STARTED;
- else if (tmp == "PENDING")
- m.ApplicationStatus = GuildApplicationStatus::PENDING;
- else if (tmp == "REJECTED")
- m.ApplicationStatus = GuildApplicationStatus::REJECTED;
- else if (tmp == "APPROVED")
- m.ApplicationStatus = GuildApplicationStatus::APPROVED;
- JS_N("rejection_reason", m.RejectionReason);
- JS_N("last_seen", m.LastSeen);
- JS_N("created_at", m.CreatedAt);
-}
diff --git a/discord/guild.hpp b/discord/guild.hpp
deleted file mode 100644
index 3c3828d..0000000
--- a/discord/guild.hpp
+++ /dev/null
@@ -1,100 +0,0 @@
-#pragma once
-#include "json.hpp"
-#include "snowflake.hpp"
-#include "role.hpp"
-#include "channel.hpp"
-#include "emoji.hpp"
-#include <vector>
-#include <string>
-#include <unordered_set>
-
-enum class GuildApplicationStatus {
- STARTED,
- PENDING,
- REJECTED,
- APPROVED,
- UNKNOWN,
-};
-
-struct GuildApplicationData {
- Snowflake UserID;
- Snowflake GuildID;
- GuildApplicationStatus ApplicationStatus;
- std::optional<std::string> RejectionReason;
- std::optional<std::string> LastSeen;
- std::optional<std::string> CreatedAt;
-
- friend void from_json(const nlohmann::json &j, GuildApplicationData &m);
-};
-
-// a bot is apparently only supposed to receive the `id` and `unavailable` as false
-// but user tokens seem to get the full objects (minus users)
-
-// everythings optional cuz of muh partial guild object
-// anything not marked optional in https://discord.com/developers/docs/resources/guild#guild-object is guaranteed to be set when returned from Store::GetGuild
-struct GuildData {
- Snowflake ID;
- std::string Name;
- std::string Icon; // null
- std::string Splash; // null
- std::optional<std::string> DiscoverySplash; // null
- std::optional<bool> IsOwner;
- std::optional<Snowflake> OwnerID;
- std::optional<uint64_t> Permissions;
- std::optional<std::string> PermissionsNew;
- std::optional<std::string> VoiceRegion;
- std::optional<Snowflake> AFKChannelID; // null
- std::optional<int> AFKTimeout;
- std::optional<bool> IsEmbedEnabled; // deprecated
- std::optional<Snowflake> EmbedChannelID; // null, deprecated
- std::optional<int> VerificationLevel;
- std::optional<int> DefaultMessageNotifications;
- std::optional<int> ExplicitContentFilter;
- std::optional<std::vector<RoleData>> Roles; // only access id
- std::optional<std::vector<EmojiData>> Emojis; // only access id
- std::optional<std::unordered_set<std::string>> Features;
- std::optional<int> MFALevel;
- std::optional<Snowflake> ApplicationID; // null
- std::optional<bool> IsWidgetEnabled;
- std::optional<Snowflake> WidgetChannelID; // null
- std::optional<Snowflake> SystemChannelID; // null
- std::optional<int> SystemChannelFlags;
- std::optional<Snowflake> RulesChannelID; // null
- std::optional<std::string> JoinedAt; // *
- std::optional<bool> IsLarge; // *
- std::optional<bool> IsUnavailable; // *
- std::optional<int> MemberCount; // *
- // std::vector<VoiceStateData> VoiceStates; // opt*
- // std::vector<MemberData> Members; // opt* - incomplete anyways
- std::optional<std::vector<ChannelData>> Channels; // *
- // std::vector<PresenceUpdateData> Presences; // opt*
- std::optional<int> MaxPresences; // null
- std::optional<int> MaxMembers;
- std::optional<std::string> VanityURL; // null
- std::optional<std::string> Description; // null
- std::optional<std::string> BannerHash; // null
- std::optional<int> PremiumTier;
- std::optional<int> PremiumSubscriptionCount;
- std::optional<std::string> PreferredLocale;
- std::optional<Snowflake> PublicUpdatesChannelID; // null
- std::optional<int> MaxVideoChannelUsers;
- std::optional<int> ApproximateMemberCount;
- std::optional<int> ApproximatePresenceCount;
- std::optional<std::vector<ChannelData>> Threads; // only with permissions to view, id only
-
- // undocumented
- // std::map<std::string, Unknown> GuildHashes;
- bool IsLazy = false;
-
- // * - documentation says only sent in GUILD_CREATE, but these can be sent anyways in the READY event
-
- friend void from_json(const nlohmann::json &j, GuildData &m);
- void update_from_json(const nlohmann::json &j);
-
- bool HasFeature(const std::string &feature);
- bool HasIcon() const;
- bool HasAnimatedIcon() const;
- std::string GetIconURL(std::string ext = "png", std::string size = "32") const;
- std::vector<Snowflake> GetSortedChannels(Snowflake ignore = Snowflake::Invalid) const;
- std::vector<RoleData> FetchRoles() const; // sorted
-};
diff --git a/discord/httpclient.cpp b/discord/httpclient.cpp
deleted file mode 100644
index 05474df..0000000
--- a/discord/httpclient.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-#include "httpclient.hpp"
-
-//#define USE_LOCAL_PROXY
-HTTPClient::HTTPClient() {
- m_dispatcher.connect(sigc::mem_fun(*this, &HTTPClient::RunCallbacks));
-}
-
-void HTTPClient::SetBase(const std::string &url) {
- m_api_base = url;
-}
-
-void HTTPClient::SetUserAgent(std::string agent) {
- m_agent = agent;
-}
-
-void HTTPClient::SetAuth(std::string auth) {
- m_authorization = auth;
-}
-
-void HTTPClient::MakeDELETE(const std::string &path, std::function<void(http::response_type r)> cb) {
- printf("DELETE %s\n", path.c_str());
- m_futures.push_back(std::async(std::launch::async, [this, path, cb] {
- http::request req(http::REQUEST_DELETE, m_api_base + path);
- req.set_header("Authorization", m_authorization);
- req.set_user_agent(m_agent != "" ? m_agent : "Abaddon");
-#ifdef USE_LOCAL_PROXY
- req.set_proxy("http://127.0.0.1:8888");
- req.set_verify_ssl(false);
-#endif
-
- auto res = req.execute();
-
- OnResponse(res, cb);
- }));
-}
-
-void HTTPClient::MakePATCH(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb) {
- printf("PATCH %s\n", path.c_str());
- m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] {
- http::request req(http::REQUEST_PATCH, m_api_base + path);
- req.set_header("Authorization", m_authorization);
- req.set_header("Content-Type", "application/json");
- req.set_user_agent(m_agent != "" ? m_agent : "Abaddon");
- req.set_body(payload);
-#ifdef USE_LOCAL_PROXY
- req.set_proxy("http://127.0.0.1:8888");
- req.set_verify_ssl(false);
-#endif
-
- auto res = req.execute();
-
- OnResponse(res, cb);
- }));
-}
-
-void HTTPClient::MakePOST(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb) {
- printf("POST %s\n", path.c_str());
- m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] {
- http::request req(http::REQUEST_POST, m_api_base + path);
- req.set_header("Authorization", m_authorization);
- req.set_header("Content-Type", "application/json");
- req.set_user_agent(m_agent != "" ? m_agent : "Abaddon");
- req.set_body(payload);
-#ifdef USE_LOCAL_PROXY
- req.set_proxy("http://127.0.0.1:8888");
- req.set_verify_ssl(false);
-#endif
-
- auto res = req.execute();
-
- OnResponse(res, cb);
- }));
-}
-
-void HTTPClient::MakePUT(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb) {
- printf("PUT %s\n", path.c_str());
- m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] {
- http::request req(http::REQUEST_PUT, m_api_base + path);
- req.set_header("Authorization", m_authorization);
- if (payload != "")
- req.set_header("Content-Type", "application/json");
- req.set_user_agent(m_agent != "" ? m_agent : "Abaddon");
- req.set_body(payload);
-#ifdef USE_LOCAL_PROXY
- req.set_proxy("http://127.0.0.1:8888");
- req.set_verify_ssl(false);
-#endif
-
- auto res = req.execute();
-
- OnResponse(res, cb);
- }));
-}
-
-void HTTPClient::MakeGET(const std::string &path, std::function<void(http::response_type r)> cb) {
- printf("GET %s\n", path.c_str());
- m_futures.push_back(std::async(std::launch::async, [this, path, cb] {
- http::request req(http::REQUEST_GET, m_api_base + path);
- req.set_header("Authorization", m_authorization);
- req.set_header("Content-Type", "application/json");
- req.set_user_agent(m_agent != "" ? m_agent : "Abaddon");
-#ifdef USE_LOCAL_PROXY
- req.set_proxy("http://127.0.0.1:8888");
- req.set_verify_ssl(false);
-#endif
-
- auto res = req.execute();
-
- OnResponse(res, cb);
- }));
-}
-
-void HTTPClient::CleanupFutures() {
- for (auto it = m_futures.begin(); it != m_futures.end();) {
- if (it->wait_for(std::chrono::seconds(0)) == std::future_status::ready)
- it = m_futures.erase(it);
- else
- it++;
- }
-}
-
-void HTTPClient::RunCallbacks() {
- m_mutex.lock();
- m_queue.front()();
- m_queue.pop();
- m_mutex.unlock();
-}
-
-void HTTPClient::OnResponse(const http::response_type &r, std::function<void(http::response_type r)> cb) {
- CleanupFutures();
- try {
- m_mutex.lock();
- m_queue.push([this, r, cb] { cb(r); });
- m_dispatcher.emit();
- m_mutex.unlock();
- } catch (const std::exception &e) {
- fprintf(stderr, "error handling response (%s, code %d): %s\n", r.url.c_str(), r.status_code, e.what());
- }
-}
diff --git a/discord/httpclient.hpp b/discord/httpclient.hpp
deleted file mode 100644
index 81723b8..0000000
--- a/discord/httpclient.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma once
-#include <functional>
-#include <future>
-#include <string>
-#include <unordered_map>
-#include <memory>
-#include <mutex>
-#include <queue>
-#include <glibmm.h>
-#include "../http.hpp"
-
-class HTTPClient {
-public:
- HTTPClient();
-
- void SetBase(const std::string &url);
-
- void SetUserAgent(std::string agent);
- void SetAuth(std::string auth);
- void MakeDELETE(const std::string &path, std::function<void(http::response_type r)> cb);
- void MakeGET(const std::string &path, std::function<void(http::response_type r)> cb);
- void MakePATCH(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb);
- void MakePOST(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb);
- void MakePUT(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb);
-
-private:
- void OnResponse(const http::response_type &r, std::function<void(http::response_type r)> cb);
- void CleanupFutures();
-
- mutable std::mutex m_mutex;
- Glib::Dispatcher m_dispatcher;
- std::queue<std::function<void()>> m_queue;
- void RunCallbacks();
-
- std::vector<std::future<void>> m_futures;
- std::string m_api_base;
- std::string m_authorization;
- std::string m_agent;
-};
diff --git a/discord/interactions.cpp b/discord/interactions.cpp
deleted file mode 100644
index 0bb09b1..0000000
--- a/discord/interactions.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "interactions.hpp"
-#include "json.hpp"
-#include "../abaddon.hpp"
-
-void from_json(const nlohmann::json &j, MessageInteractionData &m) {
- JS_D("id", m.ID);
- JS_D("type", m.Type);
- JS_D("name", m.Name);
- JS_D("user", m.User);
- JS_O("member", m.Member);
-}
diff --git a/discord/interactions.hpp b/discord/interactions.hpp
deleted file mode 100644
index c076145..0000000
--- a/discord/interactions.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-#include <string>
-#include <optional>
-#include "member.hpp"
-#include "user.hpp"
-#include "snowflake.hpp"
-
-enum class InteractionType {
- Pong = 1, // ACK a Ping
- Acknowledge = 2, // DEPRECATED ACK a command without sending a message, eating the user's input
- ChannelMessage = 3, // DEPRECATED respond with a message, eating the user's input
- ChannelMessageWithSource = 4, // respond to an interaction with a message
- DeferredChannelMessageWithSource = 5, // ACK an interaction and edit to a response later, the user sees a loading state
-};
-
-struct MessageInteractionData {
- Snowflake ID; // id of the interaction
- InteractionType Type; // the type of interaction
- std::string Name; // the name of the ApplicationCommand
- UserData User; // the user who invoked the interaction
- // undocumented???
- std::optional<GuildMember> Member; // the member who invoked the interaction (in a guild)
-
- friend void from_json(const nlohmann::json &j, MessageInteractionData &m);
-};
diff --git a/discord/invite.cpp b/discord/invite.cpp
deleted file mode 100644
index 63043a1..0000000
--- a/discord/invite.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "invite.hpp"
-
-void from_json(const nlohmann::json &j, InviteChannelData &m) {
- JS_D("id", m.ID);
- JS_D("type", m.Type);
- JS_ON("name", m.Name);
- if (j.contains("recipients") && j.at("recipients").is_null()) {
- m.RecipientUsernames.emplace();
- for (const auto &x : j.at("recipients"))
- m.RecipientUsernames->push_back(x.at("username").get<std::string>());
- }
-}
-
-void from_json(const nlohmann::json &j, InviteData &m) {
- JS_D("code", m.Code);
- JS_O("guild", m.Guild);
- JS_O("channel", m.Channel);
- JS_O("inviter", m.Inviter);
- JS_O("target_user", m.TargetUser);
- JS_O("target_user_type", m.TargetUserType);
- JS_O("approximate_presence_count", m.PresenceCount);
- JS_O("approximate_member_count", m.MemberCount);
- JS_O("uses", m.Uses);
- JS_O("max_uses", m.MaxUses);
- JS_O("max_age", m.MaxAge);
- JS_O("temporary", m.IsTemporary);
- JS_O("created_at", m.CreatedAt);
-}
-
-InviteChannelData::InviteChannelData(const ChannelData &c) {
- ID = c.ID;
- Type = c.Type;
- Name = c.Name;
- if (Type == ChannelType::GROUP_DM) {
- RecipientUsernames.emplace();
- for (const auto &r : c.GetDMRecipients())
- RecipientUsernames->push_back(r.Username);
- }
-}
diff --git a/discord/invite.hpp b/discord/invite.hpp
deleted file mode 100644
index c4c2cf3..0000000
--- a/discord/invite.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#pragma once
-#include "json.hpp"
-#include "guild.hpp"
-#include <string>
-
-enum class ETargetUserType {
- STREAM = 1
-};
-
-class InviteChannelData {
-public:
- InviteChannelData() = default;
- InviteChannelData(const ChannelData &c);
-
- Snowflake ID;
- ChannelType Type;
- std::optional<std::string> Name;
- std::optional<std::vector<std::string>> RecipientUsernames;
- // std::optional<??> Icon;
-
- friend void from_json(const nlohmann::json &j, InviteChannelData &m);
-};
-
-class InviteData {
-public:
- std::string Code;
- std::optional<GuildData> Guild;
- std::optional<InviteChannelData> Channel;
- std::optional<UserData> Inviter;
- std::optional<UserData> TargetUser;
- std::optional<ETargetUserType> TargetUserType;
- std::optional<int> PresenceCount;
- std::optional<int> MemberCount;
- std::optional<int> Uses;
- std::optional<int> MaxUses;
- std::optional<int> MaxAge;
- std::optional<bool> IsTemporary;
- std::optional<std::string> CreatedAt;
-
- friend void from_json(const nlohmann::json &j, InviteData &m);
-};
diff --git a/discord/json.hpp b/discord/json.hpp
deleted file mode 100644
index de779b9..0000000
--- a/discord/json.hpp
+++ /dev/null
@@ -1,148 +0,0 @@
-#pragma once
-#include <nlohmann/json.hpp>
-#include <optional>
-#include "../util.hpp"
-
-namespace detail { // more or less because idk what to name this stuff
-template<typename T>
-inline void json_direct(const ::nlohmann::json &j, const char *key, T &val) {
- if constexpr (::util::is_optional<T>::value)
- val = j.at(key).get<typename T::value_type>();
- else
- j.at(key).get_to(val);
-}
-
-template<typename T>
-inline void json_optional(const ::nlohmann::json &j, const char *key, T &val) {
- if constexpr (::util::is_optional<T>::value) {
- if (j.contains(key))
- val = j.at(key).get<typename T::value_type>();
- else
- val = ::std::nullopt;
- } else {
- if (j.contains(key))
- j.at(key).get_to(val);
- }
-}
-
-template<typename T>
-inline void json_nullable(const ::nlohmann::json &j, const char *key, T &val) {
- if constexpr (::util::is_optional<T>::value) {
- const auto &at = j.at(key);
- if (!at.is_null())
- val = at.get<typename T::value_type>();
- else
- val = ::std::nullopt;
- } else {
- const auto &at = j.at(key);
- if (!at.is_null())
- at.get_to(val);
- }
-}
-
-template<typename T>
-inline void json_optional_nullable(const ::nlohmann::json &j, const char *key, T &val) {
- if constexpr (::util::is_optional<T>::value) {
- if (j.contains(key)) {
- const auto &at = j.at(key);
- if (!at.is_null())
- val = at.get<typename T::value_type>();
- else
- val = ::std::nullopt;
- } else {
- val = ::std::nullopt;
- }
- } else {
- if (j.contains(key)) {
- const auto &at = j.at(key);
- if (!at.is_null())
- at.get_to(val);
- }
- }
-}
-
-template<typename T>
-inline void json_update_optional_nullable(const ::nlohmann::json &j, const char *key, T &val) {
- if constexpr (::util::is_optional<T>::value) {
- if (j.contains(key)) {
- const auto &at = j.at(key);
- if (!at.is_null())
- val = at.get<typename T::value_type>();
- else
- val = ::std::nullopt;
- }
- } else {
- if (j.contains(key)) {
- const auto &at = j.at(key);
- if (!at.is_null())
- at.get_to(val);
- else
- val = T();
- }
- }
-}
-
-template<typename T, typename U>
-inline void json_update_optional_nullable_default(const ::nlohmann::json &j, const char *key, T &val, const U &fallback) {
- if constexpr (::util::is_optional<T>::value) {
- if (j.contains(key)) {
- const auto &at = j.at(key);
- if (at.is_null())
- val = fallback;
- else
- val = at.get<typename T::value_type>();
- }
- } else {
- if (j.contains(key)) {
- const auto &at = j.at(key);
- if (at.is_null())
- val = fallback;
- else
- at.get_to(val);
- }
- }
-}
-} // namespace detail
-
-// get a json value that is guaranteed to be present and non-null
-#define JS_D(k, t) \
- do { \
- detail::json_direct(j, k, t); \
- } while (0)
-
-// get a json value that may not be present
-#define JS_O(k, t) \
- do { \
- detail::json_optional(j, k, t); \
- } while (0)
-
-// get a json value that may be null
-#define JS_N(k, t) \
- do { \
- detail::json_nullable(j, k, t); \
- } while (0)
-
-// get a json value that may not be present or may be null
-#define JS_ON(k, t) \
- do { \
- detail::json_optional_nullable(j, k, t); \
- } while (0)
-
-// set from a json value only if it is present. null will assign default-constructed value
-#define JS_RD(k, t) \
- do { \
- detail::json_update_optional_nullable(j, k, t); \
- } while (0)
-
-// set from a json value only if it is present. null will assign the given default
-#define JS_RV(k, t, d) \
- do { \
- detail::json_update_optional_nullable_default(j, k, t, d); \
- } while (0)
-
-// set a json value from a std::optional only if it has a value
-#define JS_IF(k, v) \
- do { \
- if (v.has_value()) \
- j[k] = *v; \
- } while (0)
diff --git a/discord/member.cpp b/discord/member.cpp
deleted file mode 100644
index 70a5727..0000000
--- a/discord/member.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "member.hpp"
-#include "../abaddon.hpp"
-
-void from_json(const nlohmann::json &j, GuildMember &m) {
- JS_O("user", m.User);
- JS_ON("nick", m.Nickname);
- JS_D("roles", m.Roles);
- JS_D("joined_at", m.JoinedAt);
- JS_ON("premium_since", m.PremiumSince);
- JS_D("deaf", m.IsDeafened);
- JS_D("mute", m.IsMuted);
- JS_O("user_id", m.UserID);
- JS_ON("avatar", m.Avatar);
- JS_O("pending", m.IsPending);
-}
-
-std::vector<RoleData> GuildMember::GetSortedRoles() const {
- std::vector<RoleData> roles;
- for (const auto role_id : Roles) {
- const auto role = Abaddon::Get().GetDiscordClient().GetRole(role_id);
- if (!role.has_value()) continue;
- roles.push_back(std::move(*role));
- }
-
- std::sort(roles.begin(), roles.end(), [](const RoleData &a, const RoleData &b) {
- return a.Position > b.Position;
- });
-
- return roles;
-}
-
-void GuildMember::update_from_json(const nlohmann::json &j) {
- JS_RD("roles", Roles);
- JS_RD("user", User);
- JS_RD("nick", Nickname);
- JS_RD("joined_at", JoinedAt);
- JS_RD("premium_since", PremiumSince);
- JS_RD("avatar", Avatar);
- JS_RD("pending", IsPending);
-}
diff --git a/discord/member.hpp b/discord/member.hpp
deleted file mode 100644
index e17da05..0000000
--- a/discord/member.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-#include "snowflake.hpp"
-#include "json.hpp"
-#include "user.hpp"
-#include "role.hpp"
-#include <string>
-#include <vector>
-
-struct GuildMember {
- std::optional<UserData> User; // only reliable to access id. only opt in MESSAGE_*
- std::string Nickname;
- std::vector<Snowflake> Roles;
- std::string JoinedAt;
- std::optional<std::string> PremiumSince; // null
- bool IsDeafened;
- bool IsMuted;
- std::optional<Snowflake> UserID; // present in merged_members
- std::optional<bool> IsPending; // this uses `pending` not `is_pending`
-
- // undocuemtned moment !!!1
- std::optional<std::string> Avatar;
-
- std::vector<RoleData> GetSortedRoles() const;
-
- void update_from_json(const nlohmann::json &j);
- friend void from_json(const nlohmann::json &j, GuildMember &m);
-};
diff --git a/discord/message.cpp b/discord/message.cpp
deleted file mode 100644
index 70c557d..0000000
--- a/discord/message.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-#include "message.hpp"
-
-void to_json(nlohmann::json &j, const EmbedFooterData &m) {
- j["text"] = m.Text;
- JS_IF("icon_url", m.IconURL);
- JS_IF("proxy_icon_url", m.ProxyIconURL);
-}
-
-void from_json(const nlohmann::json &j, EmbedFooterData &m) {
- JS_D("text", m.Text);
- JS_O("icon_url", m.IconURL);
- JS_O("proxy_icon_url", m.ProxyIconURL);
-}
-
-void to_json(nlohmann::json &j, const EmbedImageData &m) {
- JS_IF("url", m.URL);
- JS_IF("proxy_url", m.ProxyURL);
- JS_IF("height", m.Height);
- JS_IF("width", m.Width);
-}
-
-void from_json(const nlohmann::json &j, EmbedImageData &m) {
- JS_O("url", m.URL);
- JS_O("proxy_url", m.ProxyURL);
- JS_O("height", m.Height);
- JS_O("width", m.Width);
-}
-
-void to_json(nlohmann::json &j, const EmbedThumbnailData &m) {
- JS_IF("url", m.URL);
- JS_IF("proxy_url", m.ProxyURL);
- JS_IF("height", m.Height);
- JS_IF("width", m.Width);
-}
-
-void from_json(const nlohmann::json &j, EmbedThumbnailData &m) {
- JS_O("url", m.URL);
- JS_O("proxy_url", m.ProxyURL);
- JS_O("height", m.Height);
- JS_O("width", m.Width);
-}
-
-void to_json(nlohmann::json &j, const EmbedVideoData &m) {
- JS_IF("url", m.URL);
- JS_IF("height", m.Height);
- JS_IF("width", m.Width);
-}
-
-void from_json(const nlohmann::json &j, EmbedVideoData &m) {
- JS_O("url", m.URL);
- JS_O("height", m.Height);
- JS_O("width", m.Width);
-}
-
-void to_json(nlohmann::json &j, const EmbedProviderData &m) {
- JS_IF("name", m.Name);
- JS_IF("url", m.URL);
-}
-
-void from_json(const nlohmann::json &j, EmbedProviderData &m) {
- JS_O("name", m.Name);
- JS_ON("url", m.URL);
-}
-
-void to_json(nlohmann::json &j, const EmbedAuthorData &m) {
- JS_IF("name", m.Name);
- JS_IF("url", m.URL);
- JS_IF("icon_url", m.IconURL);
- JS_IF("proxy_icon_url", m.ProxyIconURL);
-}
-
-void from_json(const nlohmann::json &j, EmbedAuthorData &m) {
- JS_O("name", m.Name);
- JS_O("url", m.URL);
- JS_O("icon_url", m.IconURL);
- JS_O("proxy_icon_url", m.ProxyIconURL);
-}
-
-void to_json(nlohmann::json &j, const EmbedFieldData &m) {
- j["name"] = m.Name;
- j["value"] = m.Value;
- JS_IF("inline", m.Inline);
-}
-
-void from_json(const nlohmann::json &j, EmbedFieldData &m) {
- JS_D("name", m.Name);
- JS_D("value", m.Value);
- JS_O("inline", m.Inline);
-}
-
-void to_json(nlohmann::json &j, const EmbedData &m) {
- JS_IF("title", m.Title);
- JS_IF("type", m.Type);
- JS_IF("description", m.Description);
- JS_IF("url", m.URL);
- JS_IF("timestamp", m.Timestamp);
- JS_IF("color", m.Color);
- JS_IF("footer", m.Footer);
- JS_IF("image", m.Image);
- JS_IF("thumbnail", m.Thumbnail);
- JS_IF("video", m.Video);
- JS_IF("provider", m.Provider);
- JS_IF("author", m.Author);
- JS_IF("fields", m.Fields);
-}
-
-void from_json(const nlohmann::json &j, EmbedData &m) {
- JS_O("title", m.Title);
- JS_O("type", m.Type);
- JS_O("description", m.Description);
- JS_O("url", m.URL);
- JS_O("timestamp", m.Timestamp);
- JS_O("color", m.Color);
- JS_O("footer", m.Footer);
- JS_O("image", m.Image);
- JS_O("thumbnail", m.Thumbnail);
- JS_O("video", m.Video);
- JS_O("provider", m.Provider);
- JS_O("author", m.Author);
- JS_O("fields", m.Fields);
-}
-
-void to_json(nlohmann::json &j, const AttachmentData &m) {
- j["id"] = m.ID;
- j["filename"] = m.Filename;
- j["size"] = m.Bytes;
- j["url"] = m.URL;
- j["proxy_url"] = m.ProxyURL;
- JS_IF("height", m.Height);
- JS_IF("width", m.Width);
-}
-
-void from_json(const nlohmann::json &j, AttachmentData &m) {
- JS_D("id", m.ID);
- JS_D("filename", m.Filename);
- JS_D("size", m.Bytes);
- JS_D("url", m.URL);
- JS_D("proxy_url", m.ProxyURL);
- JS_ON("height", m.Height);
- JS_ON("width", m.Width);
-}
-
-void from_json(const nlohmann::json &j, MessageReferenceData &m) {
- JS_O("message_id", m.MessageID);
- JS_O("channel_id", m.ChannelID);
- JS_O("guild_id", m.GuildID);
-}
-
-void to_json(nlohmann::json &j, const MessageReferenceData &m) {
- JS_IF("message_id", m.MessageID);
- JS_IF("channel_id", m.ChannelID);
- JS_IF("guild_id", m.GuildID);
-}
-
-void from_json(const nlohmann::json &j, ReactionData &m) {
- JS_D("count", m.Count);
- JS_D("me", m.HasReactedWith);
- JS_D("emoji", m.Emoji);
-}
-
-void to_json(nlohmann::json &j, const ReactionData &m) {
- j["count"] = m.Count;
- j["me"] = m.HasReactedWith;
- j["emoji"] = m.Emoji;
-}
-
-void from_json(const nlohmann::json &j, MessageApplicationData &m) {
- JS_D("id", m.ID);
- JS_O("cover_image", m.CoverImage);
- JS_D("description", m.Description);
- JS_N("icon", m.Icon);
- JS_D("name", m.Name);
-}
-
-void to_json(nlohmann::json &j, const MessageApplicationData &m) {
- j["id"] = m.ID;
- JS_IF("cover_image", m.CoverImage);
- j["description"] = m.Description;
- if (m.Icon == "")
- j["icon"] = nullptr;
- else
- j["icon"] = m.Icon;
- j["name"] = m.Name;
-}
-
-void from_json(const nlohmann::json &j, Message &m) {
- JS_D("id", m.ID);
- JS_D("channel_id", m.ChannelID);
- JS_O("guild_id", m.GuildID);
- JS_D("author", m.Author);
- JS_O("member", m.Member);
- JS_D("content", m.Content);
- JS_D("timestamp", m.Timestamp);
- JS_N("edited_timestamp", m.EditedTimestamp);
- if (!j.at("edited_timestamp").is_null())
- m.SetEdited();
- JS_D("tts", m.IsTTS);
- JS_D("mention_everyone", m.DoesMentionEveryone);
- JS_D("mentions", m.Mentions);
- // JS_D("mention_roles", m.MentionRoles);
- // JS_O("mention_channels", m.MentionChannels);
- JS_D("attachments", m.Attachments);
- JS_D("embeds", m.Embeds);
- JS_O("reactions", m.Reactions);
- JS_O("nonce", m.Nonce);
- JS_D("pinned", m.IsPinned);
- JS_O("webhook_id", m.WebhookID);
- JS_D("type", m.Type);
- // JS_O("activity", m.Activity);
- JS_O("application", m.Application);
- JS_O("message_reference", m.MessageReference);
- JS_O("flags", m.Flags);
- JS_O("stickers", m.Stickers);
- if (j.contains("referenced_message")) {
- if (!j.at("referenced_message").is_null()) {
- m.ReferencedMessage = std::make_shared<Message>(j.at("referenced_message").get<Message>());
- } else
- m.ReferencedMessage = nullptr;
- }
- JS_O("interaction", m.Interaction);
- JS_O("sticker_items", m.StickerItems);
-}
-
-void Message::from_json_edited(const nlohmann::json &j) {
- JS_D("id", ID);
- JS_D("channel_id", ChannelID);
- JS_O("guild_id", GuildID);
- JS_O("author", Author);
- JS_O("member", Member);
- JS_O("content", Content);
- JS_O("timestamp", Timestamp);
- JS_ON("edited_timestamp", EditedTimestamp);
- if (EditedTimestamp.size() > 0)
- SetEdited();
- JS_O("tts", IsTTS);
- JS_O("mention_everyone", DoesMentionEveryone);
- JS_O("mentions", Mentions);
- JS_O("embeds", Embeds);
- JS_O("nonce", Nonce);
- JS_O("pinned", IsPinned);
- JS_O("webhook_id", WebhookID);
- JS_O("type", Type);
- JS_O("application", Application);
- JS_O("message_reference", MessageReference);
- JS_O("flags", Flags);
- JS_O("stickers", Stickers);
- JS_O("interaction", Interaction);
- JS_O("sticker_items", StickerItems);
-}
-
-void Message::SetDeleted() {
- m_deleted = true;
-}
-
-void Message::SetEdited() {
- m_edited = true;
-}
-
-bool Message::IsDeleted() const {
- return m_deleted;
-}
-
-bool Message::IsEdited() const {
- return m_edited;
-}
diff --git a/discord/message.hpp b/discord/message.hpp
deleted file mode 100644
index 56f4c0f..0000000
--- a/discord/message.hpp
+++ /dev/null
@@ -1,218 +0,0 @@
-#pragma once
-#include <string>
-#include <vector>
-#include "snowflake.hpp"
-#include "json.hpp"
-#include "user.hpp"
-#include "sticker.hpp"
-#include "emoji.hpp"
-#include "member.hpp"
-#include "interactions.hpp"
-
-enum class MessageType {
- DEFAULT = 0, // yep
- RECIPIENT_ADD = 1, // yep
- RECIPIENT_REMOVE = 2, // yep
- CALL = 3, // yep (sorta)
- CHANNEL_NAME_CHANGE = 4, // yep
- CHANNEL_ICON_CHANGE = 5, // yep
- CHANNEL_PINNED_MESSAGE = 6, // yep
- GUILD_MEMBER_JOIN = 7, // yep
- USER_PREMIUM_GUILD_SUBSCRIPTION = 8, // yep
- USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1 = 9, // yep
- USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2 = 10, // yep
- USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3 = 11, // yep
- CHANNEL_FOLLOW_ADD = 12, // yep
- GUILD_DISCOVERY_DISQUALIFIED = 14, // yep
- GUILD_DISCOVERY_REQUALIFIED = 15, // yep
- GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING = 16, // yep
- GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING = 17, // yep
- THREAD_CREATED = 18, // yep
- INLINE_REPLY = 19, // yep
- APPLICATION_COMMAND = 20, // yep
- THREAD_STARTER_MESSAGE = 21, // nope
-};
-
-enum class MessageFlags {
- NONE = 0,
- CROSSPOSTED = 1 << 0, // this message has been published to subscribed channels (via Channel Following)
- IS_CROSSPOST = 1 << 1, // this message originated from a message in another channel (via Channel Following)
- SUPPRESS_EMBEDS = 1 << 2, // do not include any embeds when serializing this message
- SOURCE_MESSAGE_DELETE = 1 << 3, // the source message for this crosspost has been deleted (via Channel Following)
- URGENT = 1 << 4, // this message came from the urgent message system
- HAS_THREAD = 1 << 5, // this message has an associated thread, with the same id as the message
- EPHEMERAL = 1 << 6, // this message is only visible to the user who invoked the Interaction
- LOADING = 1 << 7, // this message is an Interaction Response and the bot is "thinking"
-};
-
-struct EmbedFooterData {
- std::string Text;
- std::optional<std::string> IconURL;
- std::optional<std::string> ProxyIconURL;
-
- friend void to_json(nlohmann::json &j, const EmbedFooterData &m);
- friend void from_json(const nlohmann::json &j, EmbedFooterData &m);
-};
-
-struct EmbedImageData {
- std::optional<std::string> URL;
- std::optional<std::string> ProxyURL;
- std::optional<int> Height;
- std::optional<int> Width;
-
- friend void to_json(nlohmann::json &j, const EmbedImageData &m);
- friend void from_json(const nlohmann::json &j, EmbedImageData &m);
-};
-
-struct EmbedThumbnailData {
- std::optional<std::string> URL;
- std::optional<std::string> ProxyURL;
- std::optional<int> Height;
- std::optional<int> Width;
-
- friend void to_json(nlohmann::json &j, const EmbedThumbnailData &m);
- friend void from_json(const nlohmann::json &j, EmbedThumbnailData &m);
-};
-
-struct EmbedVideoData {
- std::optional<std::string> URL;
- std::optional<int> Height;
- std::optional<int> Width;
-
- friend void to_json(nlohmann::json &j, const EmbedVideoData &m);
- friend void from_json(const nlohmann::json &j, EmbedVideoData &m);
-};
-
-struct EmbedProviderData {
- std::optional<std::string> Name;
- std::optional<std::string> URL; // null
-
- friend void to_json(nlohmann::json &j, const EmbedProviderData &m);
- friend void from_json(const nlohmann::json &j, EmbedProviderData &m);
-};
-
-struct EmbedAuthorData {
- std::optional<std::string> Name;
- std::optional<std::string> URL;
- std::optional<std::string> IconURL;
- std::optional<std::string> ProxyIconURL;
-
- friend void to_json(nlohmann::json &j, const EmbedAuthorData &m);
- friend void from_json(const nlohmann::json &j, EmbedAuthorData &m);
-};
-
-struct EmbedFieldData {
- std::string Name;
- std::string Value;
- std::optional<bool> Inline;
-
- friend void to_json(nlohmann::json &j, const EmbedFieldData &m);
- friend void from_json(const nlohmann::json &j, EmbedFieldData &m);
-};
-
-struct EmbedData {
- std::optional<std::string> Title;
- std::optional<std::string> Type;
- std::optional<std::string> Description;
- std::optional<std::string> URL;
- std::optional<std::string> Timestamp;
- std::optional<int> Color;
- std::optional<EmbedFooterData> Footer;
- std::optional<EmbedImageData> Image;
- std::optional<EmbedThumbnailData> Thumbnail;
- std::optional<EmbedVideoData> Video;
- std::optional<EmbedProviderData> Provider;
- std::optional<EmbedAuthorData> Author;
- std::optional<std::vector<EmbedFieldData>> Fields;
-
- friend void to_json(nlohmann::json &j, const EmbedData &m);
- friend void from_json(const nlohmann::json &j, EmbedData &m);
-};
-
-struct AttachmentData {
- Snowflake ID;
- std::string Filename;
- int Bytes;
- std::string URL;
- std::string ProxyURL;
- std::optional<int> Height; // null
- std::optional<int> Width; // null
-
- friend void to_json(nlohmann::json &j, const AttachmentData &m);
- friend void from_json(const nlohmann::json &j, AttachmentData &m);
-};
-
-struct MessageReferenceData {
- std::optional<Snowflake> MessageID;
- std::optional<Snowflake> ChannelID;
- std::optional<Snowflake> GuildID;
-
- friend void from_json(const nlohmann::json &j, MessageReferenceData &m);
- friend void to_json(nlohmann::json &j, const MessageReferenceData &m);
-};
-
-struct ReactionData {
- int Count;
- bool HasReactedWith;
- EmojiData Emoji;
-
- friend void from_json(const nlohmann::json &j, ReactionData &m);
- friend void to_json(nlohmann::json &j, const ReactionData &m);
-};
-
-struct MessageApplicationData {
- Snowflake ID;
- std::optional<std::string> CoverImage;
- std::string Description;
- std::string Icon; // null
- std::string Name;
-
- friend void from_json(const nlohmann::json &j, MessageApplicationData &m);
- friend void to_json(nlohmann::json &j, const MessageApplicationData &m);
-};
-
-struct Message {
- Snowflake ID;
- Snowflake ChannelID;
- std::optional<Snowflake> GuildID;
- UserData Author;
- std::optional<GuildMember> Member;
- std::string Content;
- std::string Timestamp;
- std::string EditedTimestamp; // null
- bool IsTTS;
- bool DoesMentionEveryone;
- std::vector<UserData> Mentions; // full user accessible
- // std::vector<RoleData> MentionRoles;
- // std::optional<std::vector<ChannelMentionData>> MentionChannels;
- std::vector<AttachmentData> Attachments;
- std::vector<EmbedData> Embeds;
- std::optional<std::vector<ReactionData>> Reactions;
- std::optional<std::string> Nonce;
- bool IsPinned;
- std::optional<Snowflake> WebhookID;
- MessageType Type;
- // std::optional<MessageActivityData> ActivityData;
- std::optional<MessageApplicationData> Application;
- std::optional<MessageReferenceData> MessageReference;
- std::optional<MessageFlags> Flags = MessageFlags::NONE;
- std::optional<std::vector<StickerData>> Stickers;
- std::optional<std::shared_ptr<Message>> ReferencedMessage; // has_value && null means deleted
- std::optional<MessageInteractionData> Interaction;
- std::optional<std::vector<StickerItem>> StickerItems;
-
- friend void from_json(const nlohmann::json &j, Message &m);
- void from_json_edited(const nlohmann::json &j); // for MESSAGE_UPDATE
-
- // custom fields to track changes
- bool IsPending = false; // for user-sent messages yet to be received in a MESSAGE_CREATE
-
- void SetDeleted();
- void SetEdited();
- bool IsDeleted() const;
- bool IsEdited() const;
-
-private:
- bool m_deleted = false;
- bool m_edited = false;
-};
diff --git a/discord/objects.cpp b/discord/objects.cpp
deleted file mode 100644
index c6de2ce..0000000
--- a/discord/objects.cpp
+++ /dev/null
@@ -1,534 +0,0 @@
-#include "objects.hpp"
-
-void from_json(const nlohmann::json &j, GatewayMessage &m) {
- JS_D("op", m.Opcode);
- m.Data = j.at("d");
-
- JS_ON("t", m.Type);
- JS_ON("s", m.Sequence);
-}
-
-void from_json(const nlohmann::json &j, HelloMessageData &m) {
- JS_D("heartbeat_interval", m.HeartbeatInterval);
-}
-
-void from_json(const nlohmann::json &j, MessageDeleteData &m) {
- JS_D("id", m.ID);
- JS_D("channel_id", m.ChannelID);
- JS_O("guild_id", m.GuildID);
-}
-
-void from_json(const nlohmann::json &j, MessageDeleteBulkData &m) {
- JS_D("ids", m.IDs);
- JS_D("channel_id", m.ChannelID);
- JS_O("guild_id", m.GuildID);
-}
-
-void from_json(const nlohmann::json &j, GuildMemberListUpdateMessage::GroupItem &m) {
- m.Type = "group";
- JS_D("id", m.ID);
- JS_D("count", m.Count);
-}
-
-GuildMember GuildMemberListUpdateMessage::MemberItem::GetAsMemberData() const {
- return m_member_data;
-}
-
-void from_json(const nlohmann::json &j, GuildMemberListUpdateMessage::MemberItem &m) {
- m.Type = "member";
- JS_D("user", m.User);
- JS_D("roles", m.Roles);
- JS_D("mute", m.IsMuted);
- JS_D("joined_at", m.JoinedAt);
- JS_D("deaf", m.IsDefeaned);
- JS_N("hoisted_role", m.HoistedRole);
- JS_ON("premium_since", m.PremiumSince);
- JS_ON("nick", m.Nickname);
- JS_ON("presence", m.Presence);
- m.m_member_data = j;
-}
-
-void from_json(const nlohmann::json &j, GuildMemberListUpdateMessage::OpObject &m) {
- JS_D("op", m.Op);
- if (m.Op == "SYNC") {
- m.Items.emplace();
- JS_D("range", m.Range);
- for (const auto &ij : j.at("items")) {
- if (ij.contains("group"))
- m.Items->push_back(std::make_unique<GuildMemberListUpdateMessage::GroupItem>(ij.at("group")));
- else if (ij.contains("member"))
- m.Items->push_back(std::make_unique<GuildMemberListUpdateMessage::MemberItem>(ij.at("member")));
- }
- } else if (m.Op == "UPDATE") {
- JS_D("index", m.Index);
- const auto &ij = j.at("item");
- if (ij.contains("member"))
- m.OpItem = std::make_unique<GuildMemberListUpdateMessage::MemberItem>(ij.at("member"));
- }
-}
-
-void from_json(const nlohmann::json &j, GuildMemberListUpdateMessage &m) {
- JS_D("online_count", m.OnlineCount);
- JS_D("member_count", m.MemberCount);
- JS_D("id", m.ListIDHash);
- JS_D("guild_id", m.GuildID);
- JS_D("groups", m.Groups);
- JS_D("ops", m.Ops);
-}
-
-void to_json(nlohmann::json &j, const LazyLoadRequestMessage &m) {
- j["op"] = GatewayOp::LazyLoadRequest;
- j["d"] = nlohmann::json::object();
- j["d"]["guild_id"] = m.GuildID;
- if (m.Channels.has_value()) {
- j["d"]["channels"] = nlohmann::json::object();
- for (const auto &[key, chans] : *m.Channels)
- j["d"]["channels"][std::to_string(key)] = chans;
- }
- if (m.ShouldGetTyping)
- j["d"]["typing"] = *m.ShouldGetTyping;
- if (m.ShouldGetActivities)
- j["d"]["activities"] = *m.ShouldGetActivities;
- if (m.ShouldGetThreads)
- j["d"]["threads"] = *m.ShouldGetThreads;
- if (m.Members.has_value())
- j["d"]["members"] = *m.Members;
- if (m.ThreadIDs.has_value())
- j["d"]["thread_member_lists"] = *m.ThreadIDs;
-}
-
-void to_json(nlohmann::json &j, const UpdateStatusMessage &m) {
- j["op"] = GatewayOp::UpdateStatus;
- j["d"] = nlohmann::json::object();
- j["d"]["since"] = m.Since;
- j["d"]["activities"] = m.Activities;
- j["d"]["afk"] = m.IsAFK;
- switch (m.Status) {
- case PresenceStatus::Online:
- j["d"]["status"] = "online";
- break;
- case PresenceStatus::Offline:
- j["d"]["status"] = "invisible";
- break;
- case PresenceStatus::Idle:
- j["d"]["status"] = "idle";
- break;
- case PresenceStatus::DND:
- j["d"]["status"] = "dnd";
- break;
- }
-}
-
-void from_json(const nlohmann::json &j, ReadyEventData &m) {
- JS_D("v", m.GatewayVersion);
- JS_D("user", m.SelfUser);
- JS_D("guilds", m.Guilds);
- JS_D("session_id", m.SessionID);
- JS_O("analytics_token", m.AnalyticsToken);
- JS_O("friend_suggestion_count", m.FriendSuggestionCount);
- JS_D("user_settings", m.Settings);
- JS_D("private_channels", m.PrivateChannels);
- JS_O("users", m.Users);
- JS_ON("merged_members", m.MergedMembers);
- JS_O("relationships", m.Relationships);
- JS_O("guild_join_requests", m.GuildJoinRequests);
-}
-
-void from_json(const nlohmann::json &j, MergedPresence &m) {
- JS_D("user_id", m.UserID);
- JS_O("last_modified", m.LastModified);
- m.Presence = j;
-}
-
-void from_json(const nlohmann::json &j, SupplementalMergedPresencesData &m) {
- JS_D("guilds", m.Guilds);
- JS_D("friends", m.Friends);
-}
-
-void from_json(const nlohmann::json &j, ReadySupplementalData &m) {
- JS_D("merged_presences", m.MergedPresences);
-}
-
-void to_json(nlohmann::json &j, const IdentifyProperties &m) {
- j["os"] = m.OS;
- j["browser"] = m.Browser;
- j["device"] = m.Device;
- j["system_locale"] = m.SystemLocale;
- j["browser_user_agent"] = m.BrowserUserAgent;
- j["browser_version"] = m.BrowserVersion;
- j["os_version"] = m.OSVersion;
- j["referrer"] = m.Referrer;
- j["referring_domain"] = m.ReferringDomain;
- j["referrer_current"] = m.ReferrerCurrent;
- j["referring_domain_current"] = m.ReferringDomainCurrent;
- j["release_channel"] = m.ReleaseChannel;
- j["client_build_number"] = m.ClientBuildNumber;
- if (m.ClientEventSource == "")
- j["client_event_source"] = nullptr;
- else
- j["client_event_source"] = m.ClientEventSource;
-}
-
-void to_json(nlohmann::json &j, const ClientStateProperties &m) {
- j["guild_hashes"] = m.GuildHashes;
- j["highest_last_message_id"] = m.HighestLastMessageID;
- j["read_state_version"] = m.ReadStateVersion;
- j["user_guild_settings_version"] = m.UserGuildSettingsVersion;
-}
-
-void to_json(nlohmann::json &j, const IdentifyMessage &m) {
- j["op"] = GatewayOp::Identify;
- j["d"] = nlohmann::json::object();
- j["d"]["token"] = m.Token;
- j["d"]["capabilities"] = m.Capabilities;
- j["d"]["properties"] = m.Properties;
- j["d"]["presence"] = m.Presence;
- j["d"]["compress"] = m.DoesSupportCompression;
- j["d"]["client_state"] = m.ClientState;
-}
-
-void to_json(nlohmann::json &j, const HeartbeatMessage &m) {
- j["op"] = GatewayOp::Heartbeat;
- if (m.Sequence == -1)
- j["d"] = nullptr;
- else
- j["d"] = m.Sequence;
-}
-
-void to_json(nlohmann::json &j, const CreateMessageObject &m) {
- j["content"] = m.Content;
- JS_IF("message_reference", m.MessageReference);
- JS_IF("nonce", m.Nonce);
-}
-
-void to_json(nlohmann::json &j, const MessageEditObject &m) {
- if (m.Content.size() > 0)
- j["content"] = m.Content;
-
- // todo EmbedData to_json
- // if (m.Embeds.size() > 0)
- // j["embeds"] = m.Embeds;
-
- if (m.Flags != -1)
- j["flags"] = m.Flags;
-}
-
-void from_json(const nlohmann::json &j, GuildMemberUpdateMessage &m) {
- JS_D("guild_id", m.GuildID);
- JS_D("roles", m.Roles);
- JS_D("user", m.User);
- JS_ON("nick", m.Nick);
- JS_D("joined_at", m.JoinedAt);
-}
-
-void from_json(const nlohmann::json &j, ClientStatusData &m) {
- JS_O("desktop", m.Desktop);
- JS_O("mobile", m.Mobile);
- JS_O("web", m.Web);
-}
-
-void from_json(const nlohmann::json &j, PresenceUpdateMessage &m) {
- m.User = j.at("user");
- JS_O("guild_id", m.GuildID);
- JS_D("status", m.StatusMessage);
- JS_D("activities", m.Activities);
- JS_D("client_status", m.ClientStatus);
-}
-
-void to_json(nlohmann::json &j, const CreateDMObject &m) {
- std::vector<std::string> conv;
- for (const auto &id : m.Recipients)
- conv.push_back(std::to_string(id));
- j["recipients"] = conv;
-}
-
-void to_json(nlohmann::json &j, const ResumeMessage &m) {
- j["op"] = GatewayOp::Resume;
- j["d"] = nlohmann::json::object();
- j["d"]["token"] = m.Token;
- j["d"]["session_id"] = m.SessionID;
- j["d"]["seq"] = m.Sequence;
-}
-
-void from_json(const nlohmann::json &j, GuildRoleUpdateObject &m) {
- JS_D("guild_id", m.GuildID);
- JS_D("role", m.Role);
-}
-
-void from_json(const nlohmann::json &j, GuildRoleCreateObject &m) {
- JS_D("guild_id", m.GuildID);
- JS_D("role", m.Role);
-}
-
-void from_json(const nlohmann::json &j, GuildRoleDeleteObject &m) {
- JS_D("guild_id", m.GuildID);
- JS_D("role_id", m.RoleID);
-}
-
-void from_json(const nlohmann::json &j, MessageReactionAddObject &m) {
- JS_D("user_id", m.UserID);
- JS_D("channel_id", m.ChannelID);
- JS_D("message_id", m.MessageID);
- JS_O("guild_id", m.GuildID);
- JS_O("member", m.Member);
- JS_D("emoji", m.Emoji);
-}
-
-void from_json(const nlohmann::json &j, MessageReactionRemoveObject &m) {
- JS_D("user_id", m.UserID);
- JS_D("channel_id", m.ChannelID);
- JS_D("message_id", m.MessageID);
- JS_O("guild_id", m.GuildID);
- JS_D("emoji", m.Emoji);
-}
-
-void from_json(const nlohmann::json &j, ChannelRecipientAdd &m) {
- JS_D("user", m.User);
- JS_D("channel_id", m.ChannelID);
-}
-
-void from_json(const nlohmann::json &j, ChannelRecipientRemove &m) {
- JS_D("user", m.User);
- JS_D("channel_id", m.ChannelID);
-}
-
-void from_json(const nlohmann::json &j, TypingStartObject &m) {
- JS_D("channel_id", m.ChannelID);
- JS_O("guild_id", m.GuildID);
- JS_D("user_id", m.UserID);
- JS_D("timestamp", m.Timestamp);
- JS_O("member", m.Member);
-}
-
-void to_json(nlohmann::json &j, const ModifyGuildObject &m) {
- JS_IF("name", m.Name);
- JS_IF("icon", m.IconData);
-}
-
-void from_json(const nlohmann::json &j, GuildBanRemoveObject &m) {
- JS_D("guild_id", m.GuildID);
- JS_D("user", m.User);
-}
-
-void from_json(const nlohmann::json &j, GuildBanAddObject &m) {
- JS_D("guild_id", m.GuildID);
- JS_D("user", m.User);
-}
-
-void from_json(const nlohmann::json &j, InviteCreateObject &m) {
- JS_D("channel_id", m.ChannelID);
- JS_D("code", m.Code);
- JS_D("created_at", m.CreatedAt);
- JS_O("guild_id", m.GuildID);
- JS_O("inviter", m.Inviter);
- JS_D("max_age", m.MaxAge);
- JS_D("max_uses", m.MaxUses);
- JS_O("target_user", m.TargetUser);
- JS_O("target_user_type", m.TargetUserType);
- JS_D("temporary", m.IsTemporary);
- JS_D("uses", m.Uses);
-}
-
-void from_json(const nlohmann::json &j, InviteDeleteObject &m) {
- JS_D("channel_id", m.ChannelID);
- JS_O("guild_id", m.GuildID);
- JS_D("code", m.Code);
-}
-
-void from_json(const nlohmann::json &j, ConnectionData &m) {
- JS_D("id", m.ID);
- JS_D("type", m.Type);
- JS_D("name", m.Name);
- JS_D("verified", m.IsVerified);
-}
-
-void from_json(const nlohmann::json &j, MutualGuildData &m) {
- JS_D("id", m.ID);
- JS_ON("nick", m.Nick);
-}
-
-void from_json(const nlohmann::json &j, UserProfileData &m) {
- JS_D("connected_accounts", m.ConnectedAccounts);
- JS_D("mutual_guilds", m.MutualGuilds);
- JS_ON("premium_guild_since", m.PremiumGuildSince);
- JS_ON("premium_since", m.PremiumSince);
- JS_D("user", m.User);
-}
-
-void from_json(const nlohmann::json &j, UserNoteObject &m) {
- JS_ON("note", m.Note);
- JS_ON("note_user_id", m.NoteUserID);
- JS_ON("user_id", m.UserID);
-}
-
-void to_json(nlohmann::json &j, const UserSetNoteObject &m) {
- j["note"] = m.Note;
-}
-
-void from_json(const nlohmann::json &j, UserNoteUpdateMessage &m) {
- JS_D("note", m.Note);
- JS_D("id", m.ID);
-}
-
-void from_json(const nlohmann::json &j, RelationshipsData &m) {
- j.get_to(m.Users);
-}
-
-void to_json(nlohmann::json &j, const ModifyGuildMemberObject &m) {
- JS_IF("roles", m.Roles);
-}
-
-void to_json(nlohmann::json &j, const ModifyGuildRoleObject &m) {
- JS_IF("name", m.Name);
- JS_IF("color", m.Color);
- JS_IF("hoist", m.IsHoisted);
- JS_IF("mentionable", m.Mentionable);
- if (m.Permissions.has_value())
- j["permissions"] = std::to_string(static_cast<uint64_t>(*m.Permissions));
-}
-
-void to_json(nlohmann::json &j, const ModifyGuildRolePositionsObject::PositionParam &m) {
- j["id"] = m.ID;
- JS_IF("position", m.Position);
-}
-
-void to_json(nlohmann::json &j, const ModifyGuildRolePositionsObject &m) {
- j = m.Positions;
-}
-
-void from_json(const nlohmann::json &j, GuildEmojisUpdateObject &m) {
- JS_D("guild_id", m.GuildID);
-}
-
-void to_json(nlohmann::json &j, const ModifyGuildEmojiObject &m) {
- JS_IF("name", m.Name);
-}
-
-void from_json(const nlohmann::json &j, GuildJoinRequestCreateData &m) {
- auto tmp = j.at("status").get<std::string_view>();
- if (tmp == "STARTED")
- m.Status = GuildApplicationStatus::STARTED;
- else if (tmp == "PENDING")
- m.Status = GuildApplicationStatus::PENDING;
- else if (tmp == "REJECTED")
- m.Status = GuildApplicationStatus::REJECTED;
- else if (tmp == "APPROVED")
- m.Status = GuildApplicationStatus::APPROVED;
- JS_D("request", m.Request);
- JS_D("guild_id", m.GuildID);
-}
-
-void from_json(const nlohmann::json &j, GuildJoinRequestDeleteData &m) {
- JS_D("user_id", m.UserID);
- JS_D("guild_id", m.GuildID);
-}
-
-void from_json(const nlohmann::json &j, VerificationFieldObject &m) {
- JS_D("field_type", m.Type);
- JS_D("label", m.Label);
- JS_D("required", m.Required);
- JS_D("values", m.Values);
-}
-
-void from_json(const nlohmann::json &j, VerificationGateInfoObject &m) {
- JS_O("description", m.Description);
- JS_O("form_fields", m.VerificationFields);
- JS_O("version", m.Version);
- JS_O("enabled", m.Enabled);
-}
-
-void to_json(nlohmann::json &j, const VerificationFieldObject &m) {
- j["field_type"] = m.Type;
- j["label"] = m.Label;
- j["required"] = m.Required;
- j["values"] = m.Values;
- JS_IF("response", m.Response);
-}
-
-void to_json(nlohmann::json &j, const VerificationGateInfoObject &m) {
- JS_IF("description", m.Description);
- JS_IF("form_fields", m.VerificationFields);
- JS_IF("version", m.Version);
- JS_IF("enabled", m.Enabled);
-}
-
-void from_json(const nlohmann::json &j, RateLimitedResponse &m) {
- JS_D("code", m.Code);
- JS_D("global", m.Global);
- JS_O("message", m.Message);
- JS_D("retry_after", m.RetryAfter);
-}
-
-void from_json(const nlohmann::json &j, RelationshipRemoveData &m) {
- JS_D("id", m.ID);
- JS_D("type", m.Type);
-}
-
-void from_json(const nlohmann::json &j, RelationshipAddData &m) {
- JS_D("id", m.ID);
- JS_D("type", m.Type);
- JS_D("user", m.User);
-}
-
-void to_json(nlohmann::json &j, const FriendRequestObject &m) {
- j["username"] = m.Username;
- j["discriminator"] = m.Discriminator;
-}
-
-void to_json(nlohmann::json &j, const PutRelationshipObject &m) {
- JS_IF("type", m.Type);
-}
-
-void from_json(const nlohmann::json &j, ThreadCreateData &m) {
- j.get_to(m.Channel);
-}
-
-void from_json(const nlohmann::json &j, ThreadDeleteData &m) {
- JS_D("id", m.ID);
- JS_D("guild_id", m.GuildID);
- JS_D("parent_id", m.ParentID);
- JS_D("type", m.Type);
-}
-
-void from_json(const nlohmann::json &j, ThreadListSyncData &m) {
- JS_D("threads", m.Threads);
- JS_D("guild_id", m.GuildID);
-}
-
-void from_json(const nlohmann::json &j, ThreadMembersUpdateData &m) {
- JS_D("id", m.ID);
- JS_D("guild_id", m.GuildID);
- JS_D("member_count", m.MemberCount);
- JS_O("added_members", m.AddedMembers);
- JS_O("removed_member_ids", m.RemovedMemberIDs);
-}
-
-void from_json(const nlohmann::json &j, ArchivedThreadsResponseData &m) {
- JS_D("threads", m.Threads);
- JS_D("members", m.Members);
- JS_D("has_more", m.HasMore);
-}
-
-void from_json(const nlohmann::json &j, ThreadMemberUpdateData &m) {
- m.Member = j;
-}
-
-void from_json(const nlohmann::json &j, ThreadUpdateData &m) {
- m.Thread = j;
-}
-
-void from_json(const nlohmann::json &j, ThreadMemberListUpdateData::UserEntry &m) {
- JS_D("user_id", m.UserID);
- JS_D("member", m.Member);
-}
-
-void from_json(const nlohmann::json &j, ThreadMemberListUpdateData &m) {
- JS_D("thread_id", m.ThreadID);
- JS_D("guild_id", m.GuildID);
- JS_D("members", m.Members);
-}
-
-void to_json(nlohmann::json &j, const ModifyChannelObject &m) {
- JS_IF("archived", m.Archived);
- JS_IF("locked", m.Locked);
-}
diff --git a/discord/objects.hpp b/discord/objects.hpp
deleted file mode 100644
index 7084efb..0000000
--- a/discord/objects.hpp
+++ /dev/null
@@ -1,747 +0,0 @@
-#pragma once
-#include <algorithm>
-#include <nlohmann/json.hpp>
-#include <vector>
-#include <string>
-#include "snowflake.hpp"
-#include "user.hpp"
-#include "role.hpp"
-#include "member.hpp"
-#include "channel.hpp"
-#include "guild.hpp"
-#include "usersettings.hpp"
-#include "message.hpp"
-#include "invite.hpp"
-#include "permissions.hpp"
-#include "emoji.hpp"
-#include "activity.hpp"
-#include "sticker.hpp"
-#include "ban.hpp"
-#include "auditlog.hpp"
-#include "relationship.hpp"
-#include "errors.hpp"
-
-// most stuff below should just be objects that get processed and thrown away immediately
-
-enum class GatewayOp : int {
- Event = 0,
- Heartbeat = 1,
- Identify = 2,
- UpdateStatus = 3,
- Resume = 6,
- Reconnect = 7,
- InvalidSession = 9,
- Hello = 10,
- HeartbeatAck = 11,
- LazyLoadRequest = 14,
-};
-
-enum class GatewayEvent : int {
- READY,
- MESSAGE_CREATE,
- MESSAGE_DELETE,
- MESSAGE_UPDATE,
- GUILD_MEMBER_LIST_UPDATE,
- GUILD_CREATE,
- GUILD_DELETE,
- MESSAGE_DELETE_BULK,
- GUILD_MEMBER_UPDATE,
- PRESENCE_UPDATE,
- CHANNEL_DELETE,
- CHANNEL_UPDATE,
- CHANNEL_CREATE,
- GUILD_UPDATE,
- GUILD_ROLE_UPDATE,
- GUILD_ROLE_CREATE,
- GUILD_ROLE_DELETE,
- MESSAGE_REACTION_ADD,
- MESSAGE_REACTION_REMOVE,
- CHANNEL_RECIPIENT_ADD,
- CHANNEL_RECIPIENT_REMOVE,
- TYPING_START,
- GUILD_BAN_REMOVE,
- GUILD_BAN_ADD,
- INVITE_CREATE,
- INVITE_DELETE,
- USER_NOTE_UPDATE,
- READY_SUPPLEMENTAL,
- GUILD_EMOJIS_UPDATE,
- GUILD_JOIN_REQUEST_CREATE,
- GUILD_JOIN_REQUEST_UPDATE,
- GUILD_JOIN_REQUEST_DELETE,
- RELATIONSHIP_REMOVE,
- RELATIONSHIP_ADD,
- THREAD_CREATE,
- THREAD_UPDATE,
- THREAD_DELETE,
- THREAD_LIST_SYNC,
- THREAD_MEMBER_UPDATE,
- THREAD_MEMBERS_UPDATE,
- THREAD_MEMBER_LIST_UPDATE,
-};
-
-enum class GatewayCloseCode : uint16_t {
- // standard
- Normal = 1000,
- GoingAway = 1001,
- ProtocolError = 1002,
- Unsupported = 1003,
- NoStatus = 1005,
- Abnormal = 1006,
- UnsupportedPayload = 1007,
- PolicyViolation = 1008,
- TooLarge = 1009,
- MandatoryExtension = 1010,
- ServerError = 1011,
- ServiceRestart = 1012,
- TryAgainLater = 1013,
- BadGateway = 1014,
- TLSHandshakeFailed = 1015,
-
- // discord
- UnknownError = 4000,
- UnknownOpcode = 4001,
- DecodeError = 4002,
- NotAuthenticated = 4003,
- AuthenticationFailed = 4004,
- AlreadyAuthenticated = 4005,
- InvalidSequence = 4007,
- RateLimited = 4008,
- SessionTimedOut = 4009,
- InvalidShard = 4010,
- ShardingRequired = 4011,
- InvalidAPIVersion = 4012,
- InvalidIntents = 4013,
- DisallowedIntents = 4014,
-
- // internal
- UserDisconnect = 4091,
- Reconnecting = 4092,
-};
-
-struct GatewayMessage {
- GatewayOp Opcode;
- nlohmann::json Data;
- std::string Type;
- int Sequence = -1;
-
- friend void from_json(const nlohmann::json &j, GatewayMessage &m);
-};
-
-struct HelloMessageData {
- int HeartbeatInterval;
-
- friend void from_json(const nlohmann::json &j, HelloMessageData &m);
-};
-
-struct MessageDeleteData {
- Snowflake ID; //
- Snowflake ChannelID; //
- Snowflake GuildID; // opt
-
- friend void from_json(const nlohmann::json &j, MessageDeleteData &m);
-};
-
-struct MessageDeleteBulkData {
- std::vector<Snowflake> IDs; //
- Snowflake ChannelID; //
- Snowflake GuildID; // opt
-
- friend void from_json(const nlohmann::json &j, MessageDeleteBulkData &m);
-};
-
-struct GuildMemberListUpdateMessage {
- struct Item {
- virtual ~Item() = default;
-
- std::string Type;
- };
-
- struct GroupItem : Item {
- std::string ID;
- int Count;
-
- friend void from_json(const nlohmann::json &j, GroupItem &m);
- };
-
- struct MemberItem : Item {
- UserData User;
- std::vector<Snowflake> Roles;
- std::optional<PresenceData> Presence;
- std::string PremiumSince; // opt
- std::string Nickname; // opt
- bool IsMuted;
- std::string JoinedAt;
- std::string HoistedRole; // null
- bool IsDefeaned;
-
- GuildMember GetAsMemberData() const;
-
- friend void from_json(const nlohmann::json &j, MemberItem &m);
-
- private:
- GuildMember m_member_data;
- };
-
- struct OpObject {
- std::string Op;
- std::optional<int> Index;
- std::optional<std::vector<std::unique_ptr<Item>>> Items; // SYNC
- std::optional<std::pair<int, int>> Range; // SYNC
- std::optional<std::unique_ptr<Item>> OpItem; // UPDATE
-
- friend void from_json(const nlohmann::json &j, OpObject &m);
- };
-
- int OnlineCount;
- int MemberCount;
- std::string ListIDHash;
- std::string GuildID;
- std::vector<GroupItem> Groups;
- std::vector<OpObject> Ops;
-
- friend void from_json(const nlohmann::json &j, GuildMemberListUpdateMessage &m);
-};
-
-struct LazyLoadRequestMessage {
- Snowflake GuildID;
- std::optional<bool> ShouldGetTyping;
- std::optional<bool> ShouldGetActivities;
- std::optional<bool> ShouldGetThreads;
- std::optional<std::vector<std::string>> Members; // snowflake?
- std::optional<std::map<Snowflake, std::vector<std::pair<int, int>>>> Channels; // channel ID -> range of sidebar
- std::optional<std::vector<Snowflake>> ThreadIDs;
-
- friend void to_json(nlohmann::json &j, const LazyLoadRequestMessage &m);
-};
-
-struct UpdateStatusMessage {
- int Since = 0;
- std::vector<ActivityData> Activities;
- PresenceStatus Status;
- bool IsAFK = false;
-
- friend void to_json(nlohmann::json &j, const UpdateStatusMessage &m);
-};
-
-struct ReadyEventData {
- int GatewayVersion;
- UserData SelfUser;
- std::vector<GuildData> Guilds;
- std::string SessionID;
- std::vector<ChannelData> PrivateChannels;
-
- // undocumented
- std::optional<std::vector<UserData>> Users;
- std::optional<std::string> AnalyticsToken;
- std::optional<int> FriendSuggestionCount;
- UserSettings Settings;
- std::optional<std::vector<std::vector<GuildMember>>> MergedMembers;
- std::optional<std::vector<RelationshipData>> Relationships;
- std::optional<std::vector<GuildApplicationData>> GuildJoinRequests;
- // std::vector<Unknown> ConnectedAccounts; // opt
- // std::map<std::string, Unknown> Consents; // opt
- // std::vector<Unknown> Experiments; // opt
- // std::vector<Unknown> GuildExperiments; // opt
- // std::map<Unknown, Unknown> Notes; // opt
- // std::vector<PresenceData> Presences; // opt
- // std::vector<ReadStateData> ReadStates; // opt
- // Unknown Tutorial; // opt, null
- // std::vector<GuildSettingData> UserGuildSettings; // opt
-
- friend void from_json(const nlohmann::json &j, ReadyEventData &m);
-};
-
-struct MergedPresence {
- Snowflake UserID;
- std::optional<uint64_t> LastModified;
- PresenceData Presence;
-
- friend void from_json(const nlohmann::json &j, MergedPresence &m);
-};
-
-struct SupplementalMergedPresencesData {
- std::vector<std::vector<MergedPresence>> Guilds;
- std::vector<MergedPresence> Friends;
-
- friend void from_json(const nlohmann::json &j, SupplementalMergedPresencesData &m);
-};
-
-struct ReadySupplementalData {
- SupplementalMergedPresencesData MergedPresences;
-
- friend void from_json(const nlohmann::json &j, ReadySupplementalData &m);
-};
-
-struct IdentifyProperties {
- std::string OS;
- std::string Browser;
- std::string Device;
- std::string SystemLocale;
- std::string BrowserUserAgent;
- std::string BrowserVersion;
- std::string OSVersion;
- std::string Referrer;
- std::string ReferringDomain;
- std::string ReferrerCurrent;
- std::string ReferringDomainCurrent;
- std::string ReleaseChannel;
- int ClientBuildNumber;
- std::string ClientEventSource; // empty -> null
-
- friend void to_json(nlohmann::json &j, const IdentifyProperties &m);
-};
-
-struct ClientStateProperties {
- std::map<std::string, std::string> GuildHashes;
- std::string HighestLastMessageID = "0";
- int ReadStateVersion = 0;
- int UserGuildSettingsVersion = -1;
-
- friend void to_json(nlohmann::json &j, const ClientStateProperties &m);
-};
-
-struct IdentifyMessage : GatewayMessage {
- std::string Token;
- IdentifyProperties Properties;
- PresenceData Presence;
- ClientStateProperties ClientState;
- bool DoesSupportCompression = false;
- int Capabilities;
-
- friend void to_json(nlohmann::json &j, const IdentifyMessage &m);
-};
-
-struct HeartbeatMessage : GatewayMessage {
- int Sequence;
-
- friend void to_json(nlohmann::json &j, const HeartbeatMessage &m);
-};
-
-struct CreateMessageObject {
- std::string Content;
- std::optional<MessageReferenceData> MessageReference;
- std::optional<std::string> Nonce;
-
- friend void to_json(nlohmann::json &j, const CreateMessageObject &m);
-};
-
-struct MessageEditObject {
- std::string Content; // opt, null
- std::vector<EmbedData> Embeds; // opt, null
- int Flags = -1; // opt, null
-
- friend void to_json(nlohmann::json &j, const MessageEditObject &m);
-};
-
-struct GuildMemberUpdateMessage {
- Snowflake GuildID; //
- std::vector<Snowflake> Roles; //
- UserData User; //
- std::string Nick; // opt, null
- std::string JoinedAt;
- std::string PremiumSince; // opt, null
-
- friend void from_json(const nlohmann::json &j, GuildMemberUpdateMessage &m);
-};
-
-struct ClientStatusData {
- std::optional<std::string> Desktop;
- std::optional<std::string> Mobile;
- std::optional<std::string> Web;
-
- friend void from_json(const nlohmann::json &j, ClientStatusData &m);
-};
-
-struct PresenceUpdateMessage {
- nlohmann::json User; // the client updates an existing object from this data
- std::optional<Snowflake> GuildID;
- std::string StatusMessage;
- std::vector<ActivityData> Activities;
- ClientStatusData ClientStatus;
-
- friend void from_json(const nlohmann::json &j, PresenceUpdateMessage &m);
-};
-
-struct CreateDMObject {
- std::vector<Snowflake> Recipients;
-
- friend void to_json(nlohmann::json &j, const CreateDMObject &m);
-};
-
-struct ResumeMessage : GatewayMessage {
- std::string Token;
- std::string SessionID;
- int Sequence;
-
- friend void to_json(nlohmann::json &j, const ResumeMessage &m);
-};
-
-struct GuildRoleUpdateObject {
- Snowflake GuildID;
- RoleData Role;
-
- friend void from_json(const nlohmann::json &j, GuildRoleUpdateObject &m);
-};
-
-struct GuildRoleCreateObject {
- Snowflake GuildID;
- RoleData Role;
-
- friend void from_json(const nlohmann::json &j, GuildRoleCreateObject &m);
-};
-
-struct GuildRoleDeleteObject {
- Snowflake GuildID;
- Snowflake RoleID;
-
- friend void from_json(const nlohmann::json &j, GuildRoleDeleteObject &m);
-};
-
-struct MessageReactionAddObject {
- Snowflake UserID;
- Snowflake ChannelID;
- Snowflake MessageID;
- std::optional<Snowflake> GuildID;
- std::optional<GuildMember> Member;
- EmojiData Emoji;
-
- friend void from_json(const nlohmann::json &j, MessageReactionAddObject &m);
-};
-
-struct MessageReactionRemoveObject {
- Snowflake UserID;
- Snowflake ChannelID;
- Snowflake MessageID;
- std::optional<Snowflake> GuildID;
- EmojiData Emoji;
-
- friend void from_json(const nlohmann::json &j, MessageReactionRemoveObject &m);
-};
-
-struct ChannelRecipientAdd {
- UserData User;
- Snowflake ChannelID;
-
- friend void from_json(const nlohmann::json &j, ChannelRecipientAdd &m);
-};
-
-struct ChannelRecipientRemove {
- UserData User;
- Snowflake ChannelID;
-
- friend void from_json(const nlohmann::json &j, ChannelRecipientRemove &m);
-};
-
-struct TypingStartObject {
- Snowflake ChannelID;
- std::optional<Snowflake> GuildID;
- Snowflake UserID;
- uint64_t Timestamp;
- std::optional<GuildMember> Member;
-
- friend void from_json(const nlohmann::json &j, TypingStartObject &m);
-};
-
-// implement rest as needed
-struct ModifyGuildObject {
- std::optional<std::string> Name;
- std::optional<std::string> IconData;
-
- friend void to_json(nlohmann::json &j, const ModifyGuildObject &m);
-};
-
-struct GuildBanRemoveObject {
- Snowflake GuildID;
- UserData User;
-
- friend void from_json(const nlohmann::json &j, GuildBanRemoveObject &m);
-};
-
-struct GuildBanAddObject {
- Snowflake GuildID;
- UserData User;
-
- friend void from_json(const nlohmann::json &j, GuildBanAddObject &m);
-};
-
-struct InviteCreateObject {
- Snowflake ChannelID;
- std::string Code;
- std::string CreatedAt;
- std::optional<Snowflake> GuildID;
- std::optional<UserData> Inviter;
- int MaxAge;
- int MaxUses;
- UserData TargetUser;
- std::optional<ETargetUserType> TargetUserType;
- bool IsTemporary;
- int Uses;
-
- friend void from_json(const nlohmann::json &j, InviteCreateObject &m);
-};
-
-struct InviteDeleteObject {
- Snowflake ChannelID;
- std::optional<Snowflake> GuildID;
- std::string Code;
-
- friend void from_json(const nlohmann::json &j, InviteDeleteObject &m);
-};
-
-struct ConnectionData {
- std::string ID;
- std::string Type;
- std::string Name;
- bool IsVerified;
-
- friend void from_json(const nlohmann::json &j, ConnectionData &m);
-};
-
-struct MutualGuildData {
- Snowflake ID;
- std::optional<std::string> Nick; // null
-
- friend void from_json(const nlohmann::json &j, MutualGuildData &m);
-};
-
-struct UserProfileData {
- std::vector<ConnectionData> ConnectedAccounts;
- std::vector<MutualGuildData> MutualGuilds;
- std::optional<std::string> PremiumGuildSince; // null
- std::optional<std::string> PremiumSince; // null
- UserData User;
-
- friend void from_json(const nlohmann::json &j, UserProfileData &m);
-};
-
-struct UserNoteObject {
- // idk if these can be null or missing but i play it safe
- std::optional<std::string> Note;
- std::optional<Snowflake> NoteUserID;
- std::optional<Snowflake> UserID;
-
- friend void from_json(const nlohmann::json &j, UserNoteObject &m);
-};
-
-struct UserSetNoteObject {
- std::string Note;
-
- friend void to_json(nlohmann::json &j, const UserSetNoteObject &m);
-};
-
-struct UserNoteUpdateMessage {
- std::string Note;
- Snowflake ID;
-
- friend void from_json(const nlohmann::json &j, UserNoteUpdateMessage &m);
-};
-
-struct RelationshipsData {
- std::vector<UserData> Users;
-
- friend void from_json(const nlohmann::json &j, RelationshipsData &m);
-};
-
-struct ModifyGuildMemberObject {
- // std::optional<std::string> Nick;
- // std::optional<bool> IsMuted;
- // std::optional<bool> IsDeaf;
- // std::optional<Snowflake> ChannelID;
-
- std::optional<std::vector<Snowflake>> Roles;
-
- friend void to_json(nlohmann::json &j, const ModifyGuildMemberObject &m);
-};
-
-struct ModifyGuildRoleObject {
- std::optional<std::string> Name;
- std::optional<Permission> Permissions;
- std::optional<uint32_t> Color;
- std::optional<bool> IsHoisted;
- std::optional<bool> Mentionable;
-
- friend void to_json(nlohmann::json &j, const ModifyGuildRoleObject &m);
-};
-
-struct ModifyGuildRolePositionsObject {
- struct PositionParam {
- Snowflake ID;
- std::optional<int> Position; // no idea why this can be optional
-
- friend void to_json(nlohmann::json &j, const PositionParam &m);
- };
- std::vector<PositionParam> Positions;
-
- friend void to_json(nlohmann::json &j, const ModifyGuildRolePositionsObject &m);
-};
-
-struct GuildEmojisUpdateObject {
- Snowflake GuildID;
- // std::vector<EmojiData> Emojis;
- // GuildHashes, undocumented
-
- friend void from_json(const nlohmann::json &j, GuildEmojisUpdateObject &m);
-};
-
-struct ModifyGuildEmojiObject {
- std::optional<std::string> Name;
- // std::optional<std::vector<Snowflake>> Roles;
-
- friend void to_json(nlohmann::json &j, const ModifyGuildEmojiObject &m);
-};
-
-struct GuildJoinRequestCreateData {
- GuildApplicationStatus Status;
- GuildApplicationData Request;
- Snowflake GuildID;
-
- friend void from_json(const nlohmann::json &j, GuildJoinRequestCreateData &m);
-};
-
-using GuildJoinRequestUpdateData = GuildJoinRequestCreateData;
-
-struct GuildJoinRequestDeleteData {
- Snowflake UserID;
- Snowflake GuildID;
-
- friend void from_json(const nlohmann::json &j, GuildJoinRequestDeleteData &m);
-};
-
-struct VerificationFieldObject {
- std::string Type;
- std::string Label;
- bool Required;
- std::vector<std::string> Values;
- std::optional<bool> Response; // present in client to server
-
- friend void from_json(const nlohmann::json &j, VerificationFieldObject &m);
- friend void to_json(nlohmann::json &j, const VerificationFieldObject &m);
-};
-
-struct VerificationGateInfoObject {
- std::optional<std::string> Description;
- std::optional<std::vector<VerificationFieldObject>> VerificationFields;
- std::optional<std::string> Version;
- std::optional<bool> Enabled; // present only in client to server in modify gate
-
- friend void from_json(const nlohmann::json &j, VerificationGateInfoObject &m);
- friend void to_json(nlohmann::json &j, const VerificationGateInfoObject &m);
-};
-
-// not sure what the structure for this really is
-struct RateLimitedResponse {
- int Code;
- bool Global;
- std::optional<std::string> Message;
- float RetryAfter;
-
- friend void from_json(const nlohmann::json &j, RateLimitedResponse &m);
-};
-
-struct RelationshipRemoveData {
- Snowflake ID;
- RelationshipType Type;
-
- friend void from_json(const nlohmann::json &j, RelationshipRemoveData &m);
-};
-
-struct RelationshipAddData {
- Snowflake ID;
- // Nickname; same deal as the other comment somewhere else
- RelationshipType Type;
- UserData User;
- // std::optional<bool> ShouldNotify; // i guess if the client should send a notification. not worth caring about
-
- friend void from_json(const nlohmann::json &j, RelationshipAddData &m);
-};
-
-struct FriendRequestObject {
- std::string Username;
- int Discriminator;
-
- friend void to_json(nlohmann::json &j, const FriendRequestObject &m);
-};
-
-struct PutRelationshipObject {
- std::optional<RelationshipType> Type;
-
- friend void to_json(nlohmann::json &j, const PutRelationshipObject &m);
-};
-
-struct ThreadCreateData {
- ChannelData Channel;
-
- friend void from_json(const nlohmann::json &j, ThreadCreateData &m);
-};
-
-struct ThreadDeleteData {
- Snowflake ID;
- Snowflake GuildID;
- Snowflake ParentID;
- ChannelType Type;
-
- friend void from_json(const nlohmann::json &j, ThreadDeleteData &m);
-};
-
-// pretty different from docs
-struct ThreadListSyncData {
- std::vector<ChannelData> Threads;
- Snowflake GuildID;
- // std::optional<std::vector<???>> MostRecentMessages;
-
- friend void from_json(const nlohmann::json &j, ThreadListSyncData &m);
-};
-
-struct ThreadMembersUpdateData {
- Snowflake ID;
- Snowflake GuildID;
- int MemberCount;
- std::optional<std::vector<ThreadMemberObject>> AddedMembers;
- std::optional<std::vector<Snowflake>> RemovedMemberIDs;
-
- friend void from_json(const nlohmann::json &j, ThreadMembersUpdateData &m);
-};
-
-struct ArchivedThreadsResponseData {
- std::vector<ChannelData> Threads;
- std::vector<ThreadMemberObject> Members;
- bool HasMore;
-
- friend void from_json(const nlohmann::json &j, ArchivedThreadsResponseData &m);
-};
-
-struct ThreadMemberUpdateData {
- ThreadMemberObject Member;
-
- friend void from_json(const nlohmann::json &j, ThreadMemberUpdateData &m);
-};
-
-struct ThreadUpdateData {
- ChannelData Thread;
-
- friend void from_json(const nlohmann::json &j, ThreadUpdateData &m);
-};
-
-struct ThreadMemberListUpdateData {
- struct UserEntry {
- Snowflake UserID;
- // PresenceData Presence;
- GuildMember Member;
-
- friend void from_json(const nlohmann::json &j, UserEntry &m);
- };
-
- Snowflake ThreadID;
- Snowflake GuildID;
- std::vector<UserEntry> Members;
-
- friend void from_json(const nlohmann::json &j, ThreadMemberListUpdateData &m);
-};
-
-struct ModifyChannelObject {
- std::optional<bool> Archived;
- std::optional<bool> Locked;
-
- friend void to_json(nlohmann::json &j, const ModifyChannelObject &m);
-};
diff --git a/discord/permissions.cpp b/discord/permissions.cpp
deleted file mode 100644
index 63eeb9f..0000000
--- a/discord/permissions.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "permissions.hpp"
-
-void from_json(const nlohmann::json &j, PermissionOverwrite &m) {
- JS_D("id", m.ID);
- std::string tmp;
- m.Type = j.at("type").get<int>() == 0 ? PermissionOverwrite::ROLE : PermissionOverwrite::MEMBER;
- JS_D("allow", tmp);
- m.Allow = static_cast<Permission>(std::stoull(tmp));
- JS_D("deny", tmp);
- m.Deny = static_cast<Permission>(std::stoull(tmp));
-}
diff --git a/discord/permissions.hpp b/discord/permissions.hpp
deleted file mode 100644
index 5609135..0000000
--- a/discord/permissions.hpp
+++ /dev/null
@@ -1,224 +0,0 @@
-#pragma once
-#include <cstdint>
-#include "snowflake.hpp"
-#include "json.hpp"
-#include "../util.hpp"
-
-constexpr static uint64_t PERMISSION_MAX_BIT = 31;
-enum class Permission : uint64_t {
- NONE = 0,
- CREATE_INSTANT_INVITE = (1ULL << 0), // Allows creation of instant invites
- KICK_MEMBERS = (1ULL << 1), // Allows kicking members
- BAN_MEMBERS = (1ULL << 2), // Allows banning members
- ADMINISTRATOR = (1ULL << 3), // Allows all permissions and bypasses channel permission overwrites
- MANAGE_CHANNELS = (1ULL << 4), // Allows management and editing of channels
- MANAGE_GUILD = (1ULL << 5), // Allows management and editing of the guild
- ADD_REACTIONS = (1ULL << 6), // Allows for the addition of reactions to messages
- VIEW_AUDIT_LOG = (1ULL << 7), // Allows for viewing of audit logs
- PRIORITY_SPEAKER = (1ULL << 8), // Allows for using priority speaker in a voice channel
- STREAM = (1ULL << 9), // Allows the user to go live
- VIEW_CHANNEL = (1ULL << 10), // Allows guild members to view a channel, which includes reading messages in text channels
- SEND_MESSAGES = (1ULL << 11), // Allows for sending messages in a channel
- SEND_TTS_MESSAGES = (1ULL << 12), // Allows for sending of /tts messages
- MANAGE_MESSAGES = (1ULL << 13), // Allows for deletion of other users messages
- EMBED_LINKS = (1ULL << 14), // Links sent by users with this permission will be auto-embedded
- ATTACH_FILES = (1ULL << 15), // Allows for uploading images and files
- READ_MESSAGE_HISTORY = (1ULL << 16), // Allows for reading of message history
- MENTION_EVERYONE = (1ULL << 17), // Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all online users in a channel
- USE_EXTERNAL_EMOJIS = (1ULL << 18), // Allows the usage of custom emojis from other servers
- VIEW_GUILD_INSIGHTS = (1ULL << 19), // Allows for viewing guild insights
- CONNECT = (1ULL << 20), // Allows for joining of a voice channel
- SPEAK = (1ULL << 21), // Allows for speaking in a voice channel
- MUTE_MEMBERS = (1ULL << 22), // Allows for muting members in a voice channel
- DEAFEN_MEMBERS = (1ULL << 23), // Allows for deafening of members in a voice channel
- MOVE_MEMBERS = (1ULL << 24), // Allows for moving of members between voice channels
- USE_VAD = (1ULL << 25), // Allows for using voice-activity-detection in a voice channel
- CHANGE_NICKNAME = (1ULL << 26), // Allows for modification of own nickname
- MANAGE_NICKNAMES = (1ULL << 27), // Allows for modification of other users nicknames
- MANAGE_ROLES = (1ULL << 28), // Allows management and editing of roles
- MANAGE_WEBHOOKS = (1ULL << 29), // Allows management and editing of webhooks
- MANAGE_EMOJIS = (1ULL << 30), // Allows management and editing of emojis
- USE_SLASH_COMMANDS = (1ULL << 31), // Allows members to use slash commands in text channels
- REQUEST_TO_SPEAK = (1ULL << 32), // Allows for requesting to speak in stage channels
- MANAGE_THREADS = (1ULL << 34), // Allows for deleting and archiving threads, and viewing all private threads
- USE_PUBLIC_THREADS = (1ULL << 35), // Allows for creating and participating in threads
- USE_PRIVATE_THREADS = (1ULL << 36), // Allows for creating and participating in private threads
-
- ALL = 0x1FFFFFFFFFULL,
-};
-template<>
-struct Bitwise<Permission> {
- static const bool enable = true;
-};
-
-struct PermissionOverwrite {
- enum OverwriteType : uint8_t {
- ROLE = 0,
- MEMBER = 1,
- };
-
- Snowflake ID;
- OverwriteType Type;
- Permission Allow;
- Permission Deny;
-
- friend void from_json(const nlohmann::json &j, PermissionOverwrite &m);
-};
-
-constexpr const char *GetPermissionString(Permission perm) {
- switch (perm) {
- case Permission::NONE:
- return "None";
- case Permission::CREATE_INSTANT_INVITE:
- return "Create Invite";
- case Permission::KICK_MEMBERS:
- return "Kick Members";
- case Permission::BAN_MEMBERS:
- return "Ban Members";
- case Permission::ADMINISTRATOR:
- return "Administrator";
- case Permission::MANAGE_CHANNELS:
- return "Manage Channels";
- case Permission::MANAGE_GUILD:
- return "Manage Server";
- case Permission::ADD_REACTIONS:
- return "Add Reactions";
- case Permission::VIEW_AUDIT_LOG:
- return "View Audit Log";
- case Permission::PRIORITY_SPEAKER:
- return "Use Priority Speaker";
- case Permission::STREAM:
- return "Video";
- case Permission::VIEW_CHANNEL:
- return "View Channel";
- case Permission::SEND_MESSAGES:
- return "Send Messages";
- case Permission::SEND_TTS_MESSAGES:
- return "Use TTS";
- case Permission::MANAGE_MESSAGES:
- return "Manage Messages";
- case Permission::EMBED_LINKS:
- return "Embed Links";
- case Permission::ATTACH_FILES:
- return "Attach Files";
- case Permission::READ_MESSAGE_HISTORY:
- return "Read Message History";
- case Permission::MENTION_EVERYONE:
- return "Mention @everyone";
- case Permission::USE_EXTERNAL_EMOJIS:
- return "Use External Emojis";
- case Permission::VIEW_GUILD_INSIGHTS:
- return "View Server Insights";
- case Permission::CONNECT:
- return "Connect to Voice";
- case Permission::SPEAK:
- return "Speak in Voice";
- case Permission::MUTE_MEMBERS:
- return "Mute Members";
- case Permission::DEAFEN_MEMBERS:
- return "Deafen Members";
- case Permission::MOVE_MEMBERS:
- return "Move Members";
- case Permission::USE_VAD:
- return "Use Voice Activation";
- case Permission::CHANGE_NICKNAME:
- return "Change Nickname";
- case Permission::MANAGE_NICKNAMES:
- return "Manage Nicknames";
- case Permission::MANAGE_ROLES:
- return "Manage Roles";
- case Permission::MANAGE_WEBHOOKS:
- return "Manage Webhooks";
- case Permission::MANAGE_EMOJIS:
- return "Manage Emojis";
- case Permission::USE_SLASH_COMMANDS:
- return "Use Slash Commands";
- case Permission::MANAGE_THREADS:
- return "Manage Threads";
- case Permission::USE_PUBLIC_THREADS:
- return "Use Public Threads";
- case Permission::USE_PRIVATE_THREADS:
- return "Use Private Threads";
- default:
- return "Unknown Permission";
- }
-}
-
-constexpr const char *GetPermissionDescription(Permission perm) {
- switch (perm) {
- case Permission::NONE:
- return "";
- case Permission::CREATE_INSTANT_INVITE:
- return "Allows members to invite new people to this server.";
- case Permission::KICK_MEMBERS:
- return "Allows members to remove other members from this server. Kicked members will be able to rejoin if they have another invite.";
- case Permission::BAN_MEMBERS:
- return "Allows members to permanently ban other members from this server.";
- case Permission::ADMINISTRATOR:
- return "Members with this permission will have every permission and will also bypass all channel specific permissions or restrictions (for example, these members would get access to all private channels). This is a dangerous permission to grant.";
- case Permission::MANAGE_CHANNELS:
- return "Allows members to create, edit, or delete channels.";
- case Permission::MANAGE_GUILD:
- return "Allows members to change this server's name, switch regions, and add bots to this server.";
- case Permission::ADD_REACTIONS:
- return "Allows members to add new emoji reactions to a message. If this permission is disabled, members can still react using any existing reactions on a message.";
- case Permission::VIEW_AUDIT_LOG:
- return "Allows members to view a record of who made which changes in this server.";
- case Permission::PRIORITY_SPEAKER:
- return "Allows members to be more easily heard in voice channels. When activated, the volume of others without this permission will be automatically lowered. Priority Speaker is activated by using the Push to Talk (Priority) keybind.";
- case Permission::STREAM:
- return "Allows members to share their video, screen share, or stream a game in this server.";
- case Permission::VIEW_CHANNEL:
- return "Allows members to view channels by default (excluding private channels).";
- case Permission::SEND_MESSAGES:
- return "Allows members to send messages in text channels.";
- case Permission::SEND_TTS_MESSAGES:
- return "Allows members to send text-to-speech messages by starting a message with /tts. These messages can be heard by anyone focused on thsi channel.";
- case Permission::MANAGE_MESSAGES:
- return "Allows members to delete messages by other members or pin any message";
- case Permission::EMBED_LINKS:
- return "Allows links that members share to show embedded content in text channels.";
- case Permission::ATTACH_FILES:
- return "Allows members to upload files or media in text channels.";
- case Permission::READ_MESSAGE_HISTORY:
- return "Allows members to read previous messages sent in channels. If this permission is disabled, members only see messages sent when they are online and focused on that channel.";
- case Permission::MENTION_EVERYONE:
- return "Allows members to use @everyone (everyone in the server) or @here (only online members in that channel). They can also @mention all roles, even if the role's \"Allow anyone to mention this role\" permission is disabled.";
- case Permission::USE_EXTERNAL_EMOJIS:
- return "Allows members to use emoji from other servers, if they're a Discord Nitro member";
- case Permission::VIEW_GUILD_INSIGHTS:
- return "Allows members to view Server Insights, which shows data on community growth, engagement, and more.";
- case Permission::CONNECT:
- return "Allows members to join voice channels and hear others.";
- case Permission::SPEAK:
- return "Allows members to talk in voice channels. If this permission is disabled, members are default muted until somebody with the \"Mute Members\" permission un-mutes them.";
- case Permission::MUTE_MEMBERS:
- return "Allows members to mute other members in voice channels for everyone.";
- case Permission::DEAFEN_MEMBERS:
- return "Allows members to deafen other members in voice channels, which means they won't be able to speak or hear others.";
- case Permission::MOVE_MEMBERS:
- return "Allows members to move other members between voice channels that the member with the permission has access to.";
- case Permission::USE_VAD:
- return "Allows members to speak in voice channels by simply talking. If this permission is disabled, members are required to use Push-to-talk. Good for controlling background noise or noisy members.";
- case Permission::CHANGE_NICKNAME:
- return "Allows members to change their own nickname, a custom name for just this server.";
- case Permission::MANAGE_NICKNAMES:
- return "Allows members to change the nicknames of other members.";
- case Permission::MANAGE_ROLES:
- return "Allows members to create new roles and edit or delete roles lower than their highest role. Also allows members to change permissions of individual channels that they have access to.";
- case Permission::MANAGE_WEBHOOKS:
- return "Allows members to create, edit, or delete webhooks, which can post messages from other apps or sites into this server.";
- case Permission::MANAGE_EMOJIS:
- return "Allows members to add or remove custom emojis in this server.";
- case Permission::USE_SLASH_COMMANDS:
- return "Allows members to use slash commands in text channels.";
- case Permission::MANAGE_THREADS:
- return "Allows members to rename, delete, archive/unarchive, and turn on slow mode for threads.";
- case Permission::USE_PUBLIC_THREADS:
- return "Allows members to talk in threads. The \"Send Messages\" permission must be enabled for members to start new threads; if it's disabled, they can only respond to existing threads.";
- case Permission::USE_PRIVATE_THREADS:
- return "Allows members to create and chat in private threads. The \"Send Messages\" permission must be enabled for members to start new private threads; if it's disabled, they can only respond to private threads they're added to.";
- default:
- return "";
- }
-}
diff --git a/discord/relationship.cpp b/discord/relationship.cpp
deleted file mode 100644
index d65d2c1..0000000
--- a/discord/relationship.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "relationship.hpp"
-
-void from_json(const nlohmann::json &j, RelationshipData &m) {
- JS_D("type", m.Type);
- JS_D("id", m.ID);
-}
diff --git a/discord/relationship.hpp b/discord/relationship.hpp
deleted file mode 100644
index d492bd3..0000000
--- a/discord/relationship.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma once
-#include "json.hpp"
-#include "user.hpp"
-
-enum class RelationshipType {
- None = 0,
- Friend = 1,
- Blocked = 2,
- PendingIncoming = 3,
- PendingOutgoing = 4,
- Implicit = 5,
-};
-
-struct RelationshipData {
- // Snowflake UserID; this is the same as ID apparently but it looks new so i wont touch it
- RelationshipType Type;
- Snowflake ID;
- // Unknown Nickname; // null
-
- friend void from_json(const nlohmann::json &j, RelationshipData &m);
-};
diff --git a/discord/role.cpp b/discord/role.cpp
deleted file mode 100644
index 07a912e..0000000
--- a/discord/role.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "role.hpp"
-
-void from_json(const nlohmann::json &j, RoleData &m) {
- JS_D("id", m.ID);
- JS_D("name", m.Name);
- JS_D("color", m.Color);
- JS_D("hoist", m.IsHoisted);
- JS_D("position", m.Position);
- std::string tmp;
- JS_D("permissions", tmp);
- m.Permissions = static_cast<Permission>(std::stoull(tmp));
- JS_D("managed", m.IsManaged);
- JS_D("mentionable", m.IsMentionable);
-}
diff --git a/discord/role.hpp b/discord/role.hpp
deleted file mode 100644
index f638b65..0000000
--- a/discord/role.hpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#pragma once
-#include "snowflake.hpp"
-#include "json.hpp"
-#include "permissions.hpp"
-#include <string>
-#include <cstdint>
-
-struct RoleData {
- Snowflake ID;
- std::string Name;
- int Color;
- bool IsHoisted;
- int Position;
- int PermissionsLegacy;
- Permission Permissions;
- bool IsManaged;
- bool IsMentionable;
-
- friend void from_json(const nlohmann::json &j, RoleData &m);
-};
diff --git a/discord/snowflake.cpp b/discord/snowflake.cpp
deleted file mode 100644
index 6909a15..0000000
--- a/discord/snowflake.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "snowflake.hpp"
-#include <ctime>
-#include <iomanip>
-#include <chrono>
-#include <glibmm.h>
-
-constexpr static uint64_t DiscordEpochSeconds = 1420070400;
-
-const Snowflake Snowflake::Invalid = -1ULL;
-
-Snowflake::Snowflake()
- : m_num(Invalid) {}
-
-Snowflake::Snowflake(uint64_t n)
- : m_num(n) {}
-
-Snowflake::Snowflake(const std::string &str) {
- if (str.size())
- m_num = std::stoull(str);
- else
- m_num = Invalid;
-}
-Snowflake::Snowflake(const Glib::ustring &str) {
- if (str.size())
- m_num = std::strtoull(str.c_str(), nullptr, 10);
- else
- m_num = Invalid;
-};
-
-Snowflake Snowflake::FromNow() {
- using namespace std::chrono;
- // not guaranteed to work but it probably will anyway
- static uint64_t counter = 0;
- const auto millis_since_epoch = static_cast<uint64_t>(duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count());
- const auto epoch = millis_since_epoch - DiscordEpochSeconds * 1000;
- uint64_t snowflake = epoch << 22;
- // worker id and process id would be OR'd in here but there's no point
- snowflake |= counter++ % 4096;
- return snowflake;
-}
-
-bool Snowflake::IsValid() const {
- return m_num != Invalid;
-}
-
-Glib::ustring Snowflake::GetLocalTimestamp() const {
- const time_t secs_since_epoch = (m_num / SecondsInterval) + DiscordEpochSeconds;
- const std::tm tm = *localtime(&secs_since_epoch);
- std::array<char, 256> tmp;
- std::strftime(tmp.data(), sizeof(tmp), "%X %x", &tm);
- return tmp.data();
-}
-
-void from_json(const nlohmann::json &j, Snowflake &s) {
- if (j.is_string()) {
- std::string tmp;
- j.get_to(tmp);
- s.m_num = std::stoull(tmp);
- } else {
- j.get_to(s.m_num);
- }
-}
-
-void to_json(nlohmann::json &j, const Snowflake &s) {
- j = std::to_string(s);
-}
diff --git a/discord/snowflake.hpp b/discord/snowflake.hpp
deleted file mode 100644
index 1cabf3d..0000000
--- a/discord/snowflake.hpp
+++ /dev/null
@@ -1,55 +0,0 @@
-#pragma once
-#include <cstdint>
-#include <nlohmann/json.hpp>
-#include <glibmm/ustring.h>
-
-struct Snowflake {
- Snowflake();
- Snowflake(uint64_t n);
- Snowflake(const std::string &str);
- Snowflake(const Glib::ustring &str);
-
- static Snowflake FromNow(); // not thread safe
-
- bool IsValid() const;
- Glib::ustring GetLocalTimestamp() const;
-
- bool operator==(const Snowflake &s) const noexcept {
- return m_num == s.m_num;
- }
-
- bool operator<(const Snowflake &s) const noexcept {
- return m_num < s.m_num;
- }
-
- operator uint64_t() const noexcept {
- return m_num;
- }
-
- const static Snowflake Invalid; // makes sense to me
- const static uint64_t SecondsInterval = 4194304000ULL; // the "difference" between two snowflakes one second apart
-
- friend void from_json(const nlohmann::json &j, Snowflake &s);
- friend void to_json(nlohmann::json &j, const Snowflake &s);
-
-private:
- friend struct std::hash<Snowflake>;
- friend struct std::less<Snowflake>;
- unsigned long long m_num;
-};
-
-namespace std {
-template<>
-struct hash<Snowflake> {
- std::size_t operator()(const Snowflake &k) const {
- return k.m_num;
- }
-};
-
-template<>
-struct less<Snowflake> {
- bool operator()(const Snowflake &l, const Snowflake &r) const {
- return l.m_num < r.m_num;
- }
-};
-} // namespace std
diff --git a/discord/sticker.cpp b/discord/sticker.cpp
deleted file mode 100644
index b92d031..0000000
--- a/discord/sticker.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "sticker.hpp"
-
-void to_json(nlohmann::json &j, const StickerData &m) {
- j["id"] = m.ID;
- j["pack_id"] = m.PackID;
- j["name"] = m.Name;
- j["description"] = m.Description;
- JS_IF("tags", m.Tags);
- JS_IF("asset", m.AssetHash);
- JS_IF("preview_asset", m.PreviewAssetHash);
- j["format_type"] = m.FormatType;
-}
-
-void from_json(const nlohmann::json &j, StickerData &m) {
- JS_D("id", m.ID);
- JS_D("pack_id", m.PackID);
- JS_D("name", m.Name);
- JS_D("description", m.Description);
- JS_O("tags", m.Tags);
- JS_O("asset", m.AssetHash);
- JS_ON("preview_asset", m.PreviewAssetHash);
- JS_D("format_type", m.FormatType);
-}
-
-std::string StickerData::GetURL() const {
- if (!AssetHash.has_value()) return "";
- if (FormatType == StickerFormatType::PNG || FormatType == StickerFormatType::APNG)
- return "https://media.discordapp.net/stickers/" + std::to_string(ID) + "/" + *AssetHash + ".png?size=256";
- else if (FormatType == StickerFormatType::LOTTIE)
- return "https://media.discordapp.net/stickers/" + std::to_string(ID) + "/" + *AssetHash + ".json";
- return "";
-}
-
-void to_json(nlohmann::json &j, const StickerItem &m) {
- j["id"] = m.ID;
- j["name"] = m.Name;
- j["format_type"] = m.FormatType;
-}
-
-void from_json(const nlohmann::json &j, StickerItem &m) {
- JS_D("id", m.ID);
- JS_D("name", m.Name);
- JS_D("format_type", m.FormatType);
-}
-
-std::string StickerItem::GetURL() const {
- if (FormatType == StickerFormatType::PNG || FormatType == StickerFormatType::APNG)
- return "https://media.discordapp.net/stickers/" + std::to_string(ID) + ".png?size=256";
- else if (FormatType == StickerFormatType::LOTTIE)
- return "https://media.discordapp.net/stickers/" + std::to_string(ID) + ".json";
- return "";
-}
diff --git a/discord/sticker.hpp b/discord/sticker.hpp
deleted file mode 100644
index d23fe7b..0000000
--- a/discord/sticker.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#pragma once
-#include <optional>
-#include <string>
-#include "snowflake.hpp"
-#include "json.hpp"
-
-// unstable
-
-enum class StickerFormatType {
- PNG = 1,
- APNG = 2,
- LOTTIE = 3,
-};
-
-struct StickerData {
- Snowflake ID;
- Snowflake PackID;
- std::string Name;
- std::string Description;
- std::optional<std::string> Tags;
- std::optional<std::string> AssetHash;
- std::optional<std::string> PreviewAssetHash;
- StickerFormatType FormatType;
-
- friend void to_json(nlohmann::json &j, const StickerData &m);
- friend void from_json(const nlohmann::json &j, StickerData &m);
-
- std::string GetURL() const;
-};
-
-struct StickerItem {
- StickerFormatType FormatType;
- Snowflake ID;
- std::string Name;
-
- friend void to_json(nlohmann::json &j, const StickerItem &m);
- friend void from_json(const nlohmann::json &j, StickerItem &m);
-
- std::string GetURL() const;
-};
diff --git a/discord/store.cpp b/discord/store.cpp
deleted file mode 100644
index bc73f67..0000000
--- a/discord/store.cpp
+++ /dev/null
@@ -1,1507 +0,0 @@
-#include "store.hpp"
-
-using namespace std::literals::string_literals;
-
-// hopefully the casting between signed and unsigned int64 doesnt cause issues
-
-Store::Store(bool mem_store) {
- if (mem_store) {
- m_db_path = ":memory:";
- m_db_err = sqlite3_open(":memory:", &m_db);
- } else {
- m_db_path = std::filesystem::temp_directory_path() / "abaddon-store.db";
- m_db_err = sqlite3_open(m_db_path.string().c_str(), &m_db);
- }
-
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "error opening database: %s\n", sqlite3_errstr(m_db_err));
- return;
- }
-
- // clang-format off
- m_db_err = sqlite3_exec(m_db, R"(
- PRAGMA writable_schema = 1;
- DELETE FROM sqlite_master;
- PRAGMA writable_schema = 0;
- VACUUM;
- PRAGMA integrity_check;
- )", nullptr, nullptr, nullptr);
- // clang-format on
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to clear database: %s\n", sqlite3_errstr(m_db_err));
- return;
- }
-
- m_db_err = sqlite3_exec(m_db, "PRAGMA journal_mode = WAL", nullptr, nullptr, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "enabling write-ahead-log failed: %s\n", sqlite3_errstr(m_db_err));
- return;
- }
-
- m_db_err = sqlite3_exec(m_db, "PRAGMA synchronous = NORMAL", nullptr, nullptr, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "setting synchronous failed: %s\n", sqlite3_errstr(m_db_err));
- return;
- }
-
- CreateTables();
- CreateStatements();
-}
-
-Store::~Store() {
- Cleanup();
-
- m_db_err = sqlite3_close(m_db);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "error closing database: %s\n", sqlite3_errstr(m_db_err));
- return;
- }
-
- if (m_db_path != ":memory:") {
- std::error_code ec;
- std::filesystem::remove(m_db_path, ec);
- }
-}
-
-bool Store::IsValid() const {
- return m_db_err == SQLITE_OK;
-}
-
-void Store::SetBan(Snowflake guild_id, Snowflake user_id, const BanData &ban) {
- Bind(m_set_ban_stmt, 1, guild_id);
- Bind(m_set_ban_stmt, 2, user_id);
- Bind(m_set_ban_stmt, 3, ban.Reason);
-
- if (!RunInsert(m_set_ban_stmt))
- fprintf(stderr, "ban insert failed: %s\n", sqlite3_errstr(m_db_err));
-}
-
-void Store::SetChannel(Snowflake id, const ChannelData &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 if (chan.RecipientIDs.has_value()) {
- Bind(m_set_chan_stmt, 13, nlohmann::json(*chan.RecipientIDs).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 (chan.ThreadMetadata.has_value()) {
- Bind(m_set_chan_stmt, 19, chan.ThreadMetadata->IsArchived);
- Bind(m_set_chan_stmt, 20, chan.ThreadMetadata->AutoArchiveDuration);
- Bind(m_set_chan_stmt, 21, chan.ThreadMetadata->ArchiveTimestamp);
- } else {
- Bind(m_set_chan_stmt, 19, nullptr);
- Bind(m_set_chan_stmt, 20, nullptr);
- Bind(m_set_chan_stmt, 21, nullptr);
- }
-
- if (!RunInsert(m_set_chan_stmt))
- fprintf(stderr, "channel insert failed: %s\n", sqlite3_errstr(m_db_err));
-
- m_channels.insert(id);
-}
-
-void Store::SetEmoji(Snowflake id, const EmojiData &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 GuildData &guild) {
- Bind(m_set_guild_stmt, 1, id);
- Bind(m_set_guild_stmt, 2, guild.Name);
- Bind(m_set_guild_stmt, 3, guild.Icon);
- Bind(m_set_guild_stmt, 4, guild.Splash);
- Bind(m_set_guild_stmt, 5, guild.IsOwner);
- Bind(m_set_guild_stmt, 6, guild.OwnerID);
- Bind(m_set_guild_stmt, 7, guild.PermissionsNew);
- Bind(m_set_guild_stmt, 8, guild.VoiceRegion);
- Bind(m_set_guild_stmt, 9, guild.AFKChannelID);
- Bind(m_set_guild_stmt, 10, guild.AFKTimeout);
- Bind(m_set_guild_stmt, 11, guild.VerificationLevel);
- Bind(m_set_guild_stmt, 12, guild.DefaultMessageNotifications);
- std::vector<Snowflake> snowflakes;
- if (guild.Roles.has_value()) {
- for (const auto &x : *guild.Roles) snowflakes.push_back(x.ID);
- Bind(m_set_guild_stmt, 13, nlohmann::json(snowflakes).dump());
- } else {
- Bind(m_set_guild_stmt, 13, "[]"s);
- }
- snowflakes.clear();
- if (guild.Emojis.has_value()) {
- for (const auto &x : *guild.Emojis) snowflakes.push_back(x.ID);
- Bind(m_set_guild_stmt, 14, nlohmann::json(snowflakes).dump());
- } else {
- Bind(m_set_guild_stmt, 14, "[]"s);
- }
- if (guild.Features.has_value())
- Bind(m_set_guild_stmt, 15, nlohmann::json(*guild.Features).dump());
- else
- Bind(m_set_guild_stmt, 15, "[]"s);
- Bind(m_set_guild_stmt, 16, guild.MFALevel);
- Bind(m_set_guild_stmt, 17, guild.ApplicationID);
- Bind(m_set_guild_stmt, 18, guild.IsWidgetEnabled);
- Bind(m_set_guild_stmt, 19, guild.WidgetChannelID);
- Bind(m_set_guild_stmt, 20, guild.SystemChannelFlags);
- Bind(m_set_guild_stmt, 21, guild.RulesChannelID);
- Bind(m_set_guild_stmt, 22, guild.JoinedAt);
- Bind(m_set_guild_stmt, 23, guild.IsLarge);
- Bind(m_set_guild_stmt, 24, guild.IsUnavailable);
- Bind(m_set_guild_stmt, 25, guild.MemberCount);
- if (guild.Channels.has_value()) {
- snowflakes.clear();
- for (const auto &x : *guild.Channels) snowflakes.push_back(x.ID);
- Bind(m_set_guild_stmt, 26, nlohmann::json(snowflakes).dump());
- } else
- Bind(m_set_guild_stmt, 26, "[]"s);
- Bind(m_set_guild_stmt, 27, guild.MaxPresences);
- Bind(m_set_guild_stmt, 28, guild.MaxMembers);
- Bind(m_set_guild_stmt, 29, guild.VanityURL);
- Bind(m_set_guild_stmt, 30, guild.Description);
- Bind(m_set_guild_stmt, 31, guild.BannerHash);
- Bind(m_set_guild_stmt, 32, guild.PremiumTier);
- Bind(m_set_guild_stmt, 33, guild.PremiumSubscriptionCount);
- Bind(m_set_guild_stmt, 34, guild.PreferredLocale);
- Bind(m_set_guild_stmt, 35, guild.PublicUpdatesChannelID);
- Bind(m_set_guild_stmt, 36, guild.MaxVideoChannelUsers);
- Bind(m_set_guild_stmt, 37, guild.ApproximateMemberCount);
- Bind(m_set_guild_stmt, 38, guild.ApproximatePresenceCount);
- Bind(m_set_guild_stmt, 39, guild.IsLazy);
- if (guild.Threads.has_value()) {
- snowflakes.clear();
- for (const auto &x : *guild.Threads) snowflakes.push_back(x.ID);
- Bind(m_set_guild_stmt, 40, nlohmann::json(snowflakes).dump());
- } else
- Bind(m_set_guild_stmt, 40, "[]"s);
-
- if (!RunInsert(m_set_guild_stmt))
- fprintf(stderr, "guild insert failed: %s\n", sqlite3_errstr(m_db_err));
-
- m_guilds.insert(id);
-}
-
-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);
- Bind(m_set_member_stmt, 9, data.Avatar);
- Bind(m_set_member_stmt, 10, data.IsPending);
-
- 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) {
- Bind(m_set_msg_stmt, 1, id);
- Bind(m_set_msg_stmt, 2, message.ChannelID);
- Bind(m_set_msg_stmt, 3, message.GuildID);
- Bind(m_set_msg_stmt, 4, message.Author.ID);
- Bind(m_set_msg_stmt, 5, message.Content);
- Bind(m_set_msg_stmt, 6, message.Timestamp);
- Bind(m_set_msg_stmt, 7, message.EditedTimestamp);
- Bind(m_set_msg_stmt, 8, message.IsTTS);
- Bind(m_set_msg_stmt, 9, message.DoesMentionEveryone);
- Bind(m_set_msg_stmt, 10, nlohmann::json(message.Mentions).dump());
- Bind(m_set_msg_stmt, 11, nlohmann::json(message.Attachments).dump());
- Bind(m_set_msg_stmt, 12, nlohmann::json(message.Embeds).dump());
- Bind(m_set_msg_stmt, 13, message.IsPinned);
- Bind(m_set_msg_stmt, 14, message.WebhookID);
- Bind(m_set_msg_stmt, 15, static_cast<uint64_t>(message.Type));
-
- if (message.Application.has_value())
- Bind(m_set_msg_stmt, 16, nlohmann::json(*message.Application).dump());
- else
- Bind(m_set_msg_stmt, 16, nullptr);
-
- if (message.MessageReference.has_value())
- Bind(m_set_msg_stmt, 17, nlohmann::json(*message.MessageReference).dump());
- else
- Bind(m_set_msg_stmt, 17, nullptr);
-
- if (message.Flags.has_value())
- Bind(m_set_msg_stmt, 18, static_cast<uint64_t>(*message.Flags));
- else
- Bind(m_set_msg_stmt, 18, nullptr);
-
- if (message.Stickers.has_value())
- Bind(m_set_msg_stmt, 19, nlohmann::json(*message.Stickers).dump());
- else
- Bind(m_set_msg_stmt, 19, nullptr);
-
- if (message.Reactions.has_value()) {
- std::string tmp = nlohmann::json(*message.Reactions).dump();
- Bind(m_set_msg_stmt, 20, tmp);
- } else
- Bind(m_set_msg_stmt, 20, nullptr);
- Bind(m_set_msg_stmt, 21, message.IsDeleted());
- Bind(m_set_msg_stmt, 22, message.IsEdited());
- Bind(m_set_msg_stmt, 23, message.IsPending);
- Bind(m_set_msg_stmt, 24, message.Nonce); // sorry
-
- if (message.StickerItems.has_value()) {
- std::string tmp = nlohmann::json(*message.StickerItems).dump();
- Bind(m_set_msg_stmt, 25, tmp);
- } else
- Bind(m_set_msg_stmt, 25, nullptr);
-
- if (!RunInsert(m_set_msg_stmt))
- fprintf(stderr, "message insert failed: %s\n", sqlite3_errstr(m_db_err));
-
- if (message.Interaction.has_value())
- SetMessageInteractionPair(id, *message.Interaction);
-}
-
-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);
- Bind(m_set_perm_stmt, 3, static_cast<int>(perm.Type));
- Bind(m_set_perm_stmt, 4, static_cast<uint64_t>(perm.Allow));
- Bind(m_set_perm_stmt, 5, static_cast<uint64_t>(perm.Deny));
-
- if (!RunInsert(m_set_perm_stmt))
- fprintf(stderr, "permission insert failed: %s\n", sqlite3_errstr(m_db_err));
-}
-
-void Store::SetRole(Snowflake id, const RoleData &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 (!RunInsert(m_set_role_stmt))
- fprintf(stderr, "role insert failed: %s\n", sqlite3_errstr(m_db_err));
-}
-
-void Store::SetUser(Snowflake id, const UserData &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));
- }
-}
-
-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);
-
- Get(stmt, 24, tmps);
- if (tmps != "")
- ret.StickerItems = nlohmann::json::parse(tmps).get<std::vector<StickerItem>>();
-
- // interaction data from join
-
- if (!IsNull(stmt, 25)) {
- auto &interaction = ret.Interaction.emplace();
- Get(stmt, 25, interaction.ID);
- Get(stmt, 26, interaction.Name);
- Get(stmt, 27, interaction.Type);
- Get(stmt, 28, 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) {
- Bind(m_set_msg_interaction_stmt, 1, message_id);
- Bind(m_set_msg_interaction_stmt, 2, interaction.ID);
- Bind(m_set_msg_interaction_stmt, 3, interaction.Type);
- Bind(m_set_msg_interaction_stmt, 4, interaction.Name);
- Bind(m_set_msg_interaction_stmt, 5, interaction.User.ID);
-
- if (!RunInsert(m_set_msg_interaction_stmt)) {
- fprintf(stderr, "message interaction insert failed: %s\n", sqlite3_errstr(m_db_err));
- }
-}
-
-std::optional<BanData> Store::GetBan(Snowflake guild_id, Snowflake user_id) const {
- Bind(m_get_ban_stmt, 1, guild_id);
- Bind(m_get_ban_stmt, 2, user_id);
- if (!FetchOne(m_get_ban_stmt)) {
- if (m_db_err != SQLITE_DONE)
- fprintf(stderr, "error while fetching ban: %s\n", sqlite3_errstr(m_db_err));
- Reset(m_get_ban_stmt);
- return std::nullopt;
- }
-
- BanData ret;
- ret.User.ID = user_id;
- Get(m_get_ban_stmt, 2, ret.Reason);
-
- Reset(m_get_ban_stmt);
- return ret;
-}
-
-std::vector<BanData> Store::GetBans(Snowflake guild_id) const {
- Bind(m_get_bans_stmt, 1, guild_id);
-
- std::vector<BanData> ret;
- while (FetchOne(m_get_bans_stmt)) {
- auto &ban = ret.emplace_back();
- Get(m_get_bans_stmt, 1, ban.User.ID);
- Get(m_get_bans_stmt, 2, ban.Reason);
- }
-
- Reset(m_get_bans_stmt);
-
- if (m_db_err != SQLITE_DONE)
- fprintf(stderr, "error while fetching bans: %s\n", sqlite3_errstr(m_db_err));
- 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::vector<Message> Store::GetPinnedMessages(Snowflake channel_id) const {
- std::vector<Message> ret;
-
- Bind(m_get_pins_stmt, 1, channel_id);
- while (FetchOne(m_get_pins_stmt)) {
- Snowflake x;
- Get(m_get_pins_stmt, 0, x);
- auto msg = GetMessage(x);
- if (msg.has_value())
- ret.push_back(*msg);
- }
-
- Reset(m_get_pins_stmt);
-
- if (m_db_err != SQLITE_DONE)
- fprintf(stderr, "error while fetching pins: %s\n", sqlite3_errstr(m_db_err));
- return ret;
-}
-
-std::vector<ChannelData> Store::GetActiveThreads(Snowflake channel_id) const {
- std::vector<ChannelData> ret;
-
- Bind(m_get_threads_stmt, 1, channel_id);
- while (FetchOne(m_get_threads_stmt)) {
- Snowflake x;
- Get(m_get_threads_stmt, 0, x);
- auto chan = GetChannel(x);
- if (chan.has_value())
- ret.push_back(*chan);
- }
-
- Reset(m_get_threads_stmt);
-
- if (m_db_err != SQLITE_DONE)
- fprintf(stderr, "error while fetching threads: %s\n", sqlite3_errstr(m_db_err));
- return ret;
-}
-
-std::optional<ChannelData> 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;
- }
-
- ChannelData 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);
- ret.RecipientIDs = nlohmann::json::parse(tmps).get<std::vector<Snowflake>>();
- }
- 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);
- if (!IsNull(m_get_chan_stmt, 18)) {
- ret.ThreadMetadata.emplace();
- Get(m_get_chan_stmt, 18, ret.ThreadMetadata->IsArchived);
- Get(m_get_chan_stmt, 19, ret.ThreadMetadata->AutoArchiveDuration);
- Get(m_get_chan_stmt, 20, ret.ThreadMetadata->ArchiveTimestamp);
- }
-
- Reset(m_get_chan_stmt);
-
- return ret;
-}
-
-std::optional<EmojiData> Store::GetEmoji(Snowflake id) const {
- Bind(m_get_emote_stmt, 1, id);
- if (!FetchOne(m_get_emote_stmt)) {
- if (m_db_err != SQLITE_DONE)
- fprintf(stderr, "error while fetching emoji: %s\n", sqlite3_errstr(m_db_err));
- Reset(m_get_emote_stmt);
- return std::nullopt;
- }
-
- EmojiData ret;
- ret.ID = id;
- Get(m_get_emote_stmt, 1, ret.Name);
-
- if (!IsNull(m_get_emote_stmt, 2)) {
- std::string tmp;
- Get(m_get_emote_stmt, 2, tmp);
- ret.Roles = nlohmann::json::parse(tmp).get<std::vector<Snowflake>>();
- }
-
- if (!IsNull(m_get_emote_stmt, 3)) {
- ret.Creator = std::optional<UserData>(UserData());
- Get(m_get_emote_stmt, 3, ret.Creator->ID);
- }
- Get(m_get_emote_stmt, 4, ret.NeedsColons);
- Get(m_get_emote_stmt, 5, ret.IsManaged);
- Get(m_get_emote_stmt, 6, ret.IsAnimated);
- Get(m_get_emote_stmt, 7, ret.IsAvailable);
-
- Reset(m_get_emote_stmt);
-
- return ret;
-}
-
-std::optional<GuildData> Store::GetGuild(Snowflake id) const {
- Bind(m_get_guild_stmt, 1, id);
- if (!FetchOne(m_get_guild_stmt)) {
- if (m_db_err != SQLITE_DONE)
- fprintf(stderr, "error while fetching guild: %s\n", sqlite3_errstr(m_db_err));
- Reset(m_get_guild_stmt);
- return std::nullopt;
- }
-
- GuildData ret;
- ret.ID = id;
- Get(m_get_guild_stmt, 1, ret.Name);
- Get(m_get_guild_stmt, 2, ret.Icon);
- Get(m_get_guild_stmt, 3, ret.Splash);
- Get(m_get_guild_stmt, 4, ret.IsOwner);
- Get(m_get_guild_stmt, 5, ret.OwnerID);
- Get(m_get_guild_stmt, 6, ret.PermissionsNew);
- Get(m_get_guild_stmt, 7, ret.VoiceRegion);
- Get(m_get_guild_stmt, 8, ret.AFKChannelID);
- Get(m_get_guild_stmt, 9, ret.AFKTimeout);
- Get(m_get_guild_stmt, 10, ret.VerificationLevel);
- Get(m_get_guild_stmt, 11, ret.DefaultMessageNotifications);
- std::string tmp;
- Get(m_get_guild_stmt, 12, tmp);
- ret.Roles.emplace();
- for (const auto &id : nlohmann::json::parse(tmp).get<std::vector<Snowflake>>())
- ret.Roles->emplace_back().ID = id;
- Get(m_get_guild_stmt, 13, tmp);
- ret.Emojis.emplace();
- for (const auto &id : nlohmann::json::parse(tmp).get<std::vector<Snowflake>>())
- ret.Emojis->emplace_back().ID = id;
- Get(m_get_guild_stmt, 14, tmp);
- ret.Features = nlohmann::json::parse(tmp).get<std::unordered_set<std::string>>();
- Get(m_get_guild_stmt, 15, ret.MFALevel);
- Get(m_get_guild_stmt, 16, ret.ApplicationID);
- Get(m_get_guild_stmt, 17, ret.IsWidgetEnabled);
- Get(m_get_guild_stmt, 18, ret.WidgetChannelID);
- Get(m_get_guild_stmt, 19, ret.SystemChannelFlags);
- Get(m_get_guild_stmt, 20, ret.RulesChannelID);
- Get(m_get_guild_stmt, 21, ret.JoinedAt);
- Get(m_get_guild_stmt, 22, ret.IsLarge);
- Get(m_get_guild_stmt, 23, ret.IsUnavailable);
- Get(m_get_guild_stmt, 24, ret.MemberCount);
- Get(m_get_guild_stmt, 25, tmp);
- ret.Channels.emplace();
- for (const auto &id : nlohmann::json::parse(tmp).get<std::vector<Snowflake>>())
- ret.Channels->emplace_back().ID = id;
- Get(m_get_guild_stmt, 26, ret.MaxPresences);
- Get(m_get_guild_stmt, 27, ret.MaxMembers);
- Get(m_get_guild_stmt, 28, ret.VanityURL);
- Get(m_get_guild_stmt, 29, ret.Description);
- Get(m_get_guild_stmt, 30, ret.BannerHash);
- Get(m_get_guild_stmt, 31, ret.PremiumTier);
- Get(m_get_guild_stmt, 32, ret.PremiumSubscriptionCount);
- Get(m_get_guild_stmt, 33, ret.PreferredLocale);
- Get(m_get_guild_stmt, 34, ret.PublicUpdatesChannelID);
- Get(m_get_guild_stmt, 35, ret.MaxVideoChannelUsers);
- Get(m_get_guild_stmt, 36, ret.ApproximateMemberCount);
- Get(m_get_guild_stmt, 37, ret.ApproximatePresenceCount);
- Get(m_get_guild_stmt, 38, ret.IsLazy);
- Get(m_get_guild_stmt, 39, tmp);
- ret.Threads.emplace();
- for (const auto &id : nlohmann::json::parse(tmp).get<std::vector<Snowflake>>())
- ret.Threads->emplace_back().ID = id;
-
- Reset(m_get_guild_stmt);
-
- return ret;
-}
-
-std::optional<GuildMember> Store::GetGuildMember(Snowflake guild_id, Snowflake user_id) const {
- Bind(m_get_member_stmt, 1, user_id);
- Bind(m_get_member_stmt, 2, guild_id);
- if (!FetchOne(m_get_member_stmt)) {
- if (m_db_err != SQLITE_DONE)
- fprintf(stderr, "error while fetching member: %s\n", sqlite3_errstr(m_db_err));
- Reset(m_get_member_stmt);
- return std::nullopt;
- }
-
- GuildMember ret;
- ret.User.emplace().ID = user_id;
- Get(m_get_member_stmt, 2, ret.Nickname);
- std::string tmp;
- Get(m_get_member_stmt, 3, tmp);
- ret.Roles = nlohmann::json::parse(tmp).get<std::vector<Snowflake>>();
- Get(m_get_member_stmt, 4, ret.JoinedAt);
- Get(m_get_member_stmt, 5, ret.PremiumSince);
- Get(m_get_member_stmt, 6, ret.IsDeafened);
- Get(m_get_member_stmt, 7, ret.IsMuted);
- Get(m_get_member_stmt, 8, ret.Avatar);
- Get(m_get_member_stmt, 9, ret.IsPending);
-
- Reset(m_get_member_stmt);
-
- return ret;
-}
-
-std::optional<Message> Store::GetMessage(Snowflake id) const {
- Bind(m_get_msg_stmt, 1, id);
- if (!FetchOne(m_get_msg_stmt)) {
- if (m_db_err != SQLITE_DONE)
- fprintf(stderr, "error while fetching message: %s\n", sqlite3_errstr(m_db_err));
- Reset(m_get_msg_stmt);
- return std::nullopt;
- }
-
- auto ret = GetMessageBound(m_get_msg_stmt);
-
- return std::optional<Message>(std::move(ret));
-}
-
-std::optional<PermissionOverwrite> Store::GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const {
- Bind(m_get_perm_stmt, 1, id);
- Bind(m_get_perm_stmt, 2, channel_id);
- if (!FetchOne(m_get_perm_stmt)) {
- if (m_db_err != SQLITE_DONE)
- fprintf(stderr, "error while fetching permission: %s\n", sqlite3_errstr(m_db_err));
- Reset(m_get_perm_stmt);
- return std::nullopt;
- }
-
- PermissionOverwrite ret;
- ret.ID = id;
- uint64_t tmp;
- Get(m_get_perm_stmt, 2, tmp);
- ret.Type = static_cast<PermissionOverwrite::OverwriteType>(tmp);
- Get(m_get_perm_stmt, 3, tmp);
- ret.Allow = static_cast<Permission>(tmp);
- Get(m_get_perm_stmt, 4, tmp);
- ret.Deny = static_cast<Permission>(tmp);
-
- Reset(m_get_perm_stmt);
-
- return ret;
-}
-
-std::optional<RoleData> Store::GetRole(Snowflake id) const {
- Bind(m_get_role_stmt, 1, id);
- if (!FetchOne(m_get_role_stmt)) {
- if (m_db_err != SQLITE_DONE)
- fprintf(stderr, "error while fetching role: %s\n", sqlite3_errstr(m_db_err));
- Reset(m_get_role_stmt);
- return std::nullopt;
- }
-
- RoleData ret;
- ret.ID = id;
- Get(m_get_role_stmt, 1, ret.Name);
- Get(m_get_role_stmt, 2, ret.Color);
- Get(m_get_role_stmt, 3, ret.IsHoisted);
- Get(m_get_role_stmt, 4, ret.Position);
- uint64_t tmp;
- Get(m_get_role_stmt, 5, tmp);
- ret.Permissions = static_cast<Permission>(tmp);
- Get(m_get_role_stmt, 6, ret.IsManaged);
- Get(m_get_role_stmt, 7, ret.IsMentionable);
-
- Reset(m_get_role_stmt);
-
- return ret;
-}
-
-std::optional<UserData> Store::GetUser(Snowflake id) const {
- Bind(m_get_user_stmt, 1, id);
- if (!FetchOne(m_get_user_stmt)) {
- if (m_db_err != SQLITE_DONE)
- fprintf(stderr, "error while fetching user info: %s\n", sqlite3_errstr(m_db_err));
- Reset(m_get_user_stmt);
- return std::nullopt;
- }
-
- UserData ret;
- Get(m_get_user_stmt, 0, ret.ID);
- Get(m_get_user_stmt, 1, ret.Username);
- Get(m_get_user_stmt, 2, ret.Discriminator);
- Get(m_get_user_stmt, 3, ret.Avatar);
- Get(m_get_user_stmt, 4, ret.IsBot);
- Get(m_get_user_stmt, 5, ret.IsSystem);
- Get(m_get_user_stmt, 6, ret.IsMFAEnabled);
- Get(m_get_user_stmt, 7, ret.Locale);
- Get(m_get_user_stmt, 8, ret.IsVerified);
- Get(m_get_user_stmt, 9, ret.Email);
- Get(m_get_user_stmt, 10, ret.Flags);
- Get(m_get_user_stmt, 11, ret.PremiumType);
- Get(m_get_user_stmt, 12, ret.PublicFlags);
-
- Reset(m_get_user_stmt);
-
- return ret;
-}
-
-void Store::ClearGuild(Snowflake id) {
- m_guilds.erase(id);
-}
-
-void Store::ClearChannel(Snowflake id) {
- m_channels.erase(id);
- Bind(m_clear_chan_stmt, 1, id);
-
- if ((m_db_err = sqlite3_step(m_clear_chan_stmt)) != SQLITE_DONE)
- printf("clearing channel failed: %s\n", sqlite3_errstr(m_db_err));
-
- Reset(m_clear_chan_stmt);
-}
-
-void Store::ClearBan(Snowflake guild_id, Snowflake user_id) {
- Bind(m_clear_ban_stmt, 1, guild_id);
- Bind(m_clear_ban_stmt, 2, user_id);
-
- if ((m_db_err = sqlite3_step(m_clear_ban_stmt)) != SQLITE_DONE)
- printf("clearing ban failed: %s\n", sqlite3_errstr(m_db_err));
-
- Reset(m_clear_ban_stmt);
-}
-
-const std::unordered_set<Snowflake> &Store::GetChannels() const {
- return m_channels;
-}
-
-const std::unordered_set<Snowflake> &Store::GetGuilds() const {
- return m_guilds;
-}
-void Store::ClearAll() {
- m_channels.clear();
- m_guilds.clear();
-}
-
-void Store::BeginTransaction() {
- m_db_err = sqlite3_exec(m_db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr);
-}
-
-void Store::EndTransaction() {
- m_db_err = sqlite3_exec(m_db, "COMMIT", nullptr, nullptr, nullptr);
-}
-
-bool Store::CreateTables() {
- const char *create_users = R"(
- CREATE TABLE IF NOT EXISTS users (
- id INTEGER PRIMARY KEY,
- username TEXT NOT NULL,
- discriminator TEXT NOT NULL,
- avatar TEXT,
- bot BOOL,
- system BOOL,
- mfa BOOL,
- locale TEXT,
- verified BOOl,
- email TEXT,
- flags INTEGER,
- premium INTEGER,
- pubflags INTEGER
- )
- )";
-
- const char *create_permissions = R"(
- CREATE TABLE IF NOT EXISTS permissions (
- id INTEGER NOT NULL,
- channel_id INTEGER NOT NULL,
- type INTEGER NOT NULL,
- allow INTEGER NOT NULL,
- deny INTEGER NOT NULL,
- PRIMARY KEY(id, channel_id)
- )
- )";
-
- const char *create_messages = R"(
- CREATE TABLE IF NOT EXISTS messages (
- id INTEGER PRIMARY KEY,
- channel_id INTEGER NOT NULL,
- guild_id INTEGER,
- author_id INTEGER NOT NULL,
- content TEXT NOT NULL,
- timestamp TEXT NOT NULL,
- edited_timestamp TEXT,
- tts BOOL NOT NULL,
- everyone BOOL NOT NULL,
- mentions TEXT NOT NULL, /* json */
- attachments TEXT NOT NULL, /* json */
- embeds TEXT NOT NULL, /* json */
- pinned BOOL,
- webhook_id INTEGER,
- type INTEGER,
- application TEXT, /* json */
- reference TEXT, /* json */
- flags INTEGER,
- stickers TEXT, /* json */
- reactions TEXT, /* json */
- deleted BOOL, /* extra */
- edited BOOL, /* extra */
- pending BOOL, /* extra */
- nonce TEXT,
- sticker_items TEXT /* json */
- )
- )";
-
- const char *create_roles = R"(
- CREATE TABLE IF NOT EXISTS roles (
- id INTEGER PRIMARY KEY,
- name TEXT NOT NULL,
- color INTEGER NOT NULL,
- hoisted BOOL NOT NULL,
- position INTEGER NOT NULL,
- permissions INTEGER NOT NULL,
- managed BOOL NOT NULL,
- mentionable BOOL NOT NULL
- )
- )";
-
- const char *create_emojis = R"(
- CREATE TABLE IF NOT EXISTS emojis (
- id INTEGER PRIMARY KEY, /*though nullable, only custom emojis (with non-null ids) are stored*/
- name TEXT NOT NULL, /*same as id*/
- roles TEXT, /* json */
- creator_id INTEGER,
- colons BOOL,
- managed BOOL,
- animated BOOL,
- available BOOL
- )
- )";
-
- const char *create_members = R"(
- CREATE TABLE IF NOT EXISTS members (
- user_id INTEGER NOT NULL,
- guild_id INTEGER NOT NULL,
- nickname TEXT,
- roles TEXT NOT NULL, /* json */
- joined_at TEXT NOT NULL,
- premium_since TEXT,
- deaf BOOL NOT NULL,
- mute BOOL NOT NULL,
- avatar TEXT,
- pending BOOL,
- PRIMARY KEY(user_id, guild_id)
- )
- )";
-
- const char *create_guilds = R"(
- CREATE TABLE IF NOT EXISTS guilds (
- id INTEGER PRIMARY KEY,
- name TEXT NOT NULL,
- icon TEXT NOT NULL,
- splash TEXT,
- owner BOOL,
- owner_id INTEGER NOT NULL,
- permissions INTEGER, /* new */
- voice_region TEXT,
- afk_id INTEGER,
- afk_timeout INTEGER NOT NULL,
- verification INTEGER NOT NULL,
- notifications INTEGER NOT NULL,
- roles TEXT NOT NULL, /* json */
- emojis TEXT NOT NULL, /* json */
- features TEXT NOT NULL, /* json */
- mfa INTEGER NOT NULL,
- application INTEGER,
- widget BOOL,
- widget_channel INTEGER,
- system_flags INTEGER NOT NULL,
- rules_channel INTEGER,
- joined_at TEXT,
- large BOOL,
- unavailable BOOL,
- member_count INTEGER,
- channels TEXT NOT NULL, /* json */
- max_presences INTEGER,
- max_members INTEGER,
- vanity TEXT,
- description TEXT,
- banner_hash TEXT,
- premium_tier INTEGER NOT NULL,
- premium_count INTEGER,
- locale TEXT NOT NULL,
- public_updates_id INTEGER,
- max_video_users INTEGER,
- approx_members INTEGER,
- approx_presences INTEGER,
- lazy BOOL,
- threads TEXT NOT NULL /* json */
- )
- )";
-
- const 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,
- archived BOOL, /* threads */
- auto_archive INTEGER, /* threads */
- archived_ts TEXT /* threads */
- )
- )";
-
- const char *create_bans = R"(
- CREATE TABLE IF NOT EXISTS bans (
- guild_id INTEGER NOT NULL,
- user_id INTEGER NOT NULL,
- reason TEXT,
- PRIMARY KEY(user_id, guild_id)
- )
- )";
-
- const char *create_interactions = R"(
- CREATE TABLE IF NOT EXISTS message_interactions (
- message_id INTEGER NOT NULL,
- interaction_id INTEGER NOT NULL,
- type INTEGER NOT NULL,
- name STRING NOT NULL,
- user_id INTEGER NOT NULL,
- PRIMARY KEY(message_id)
- )
- )";
-
- 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));
- return false;
- }
-
- m_db_err = sqlite3_exec(m_db, create_permissions, nullptr, nullptr, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to create permissions table: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_exec(m_db, create_messages, nullptr, nullptr, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to create messages table: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_exec(m_db, create_roles, nullptr, nullptr, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to create roles table: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_exec(m_db, create_emojis, nullptr, nullptr, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "faile to create emojis table: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_exec(m_db, create_members, nullptr, nullptr, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to create members table: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_exec(m_db, create_guilds, nullptr, nullptr, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to create guilds table: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- 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;
- }
-
- m_db_err = sqlite3_exec(m_db, create_bans, nullptr, nullptr, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to create bans table: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_exec(m_db, create_interactions, nullptr, nullptr, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to create message interactions table: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- return true;
-}
-
-bool Store::CreateStatements() {
- const char *set_user = R"(
- REPLACE INTO users VALUES (
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
- )
- )";
-
- const char *get_user = R"(
- SELECT * FROM users WHERE id = ?
- )";
-
- const char *set_perm = R"(
- REPLACE INTO permissions VALUES (
- ?, ?, ?, ?, ?
- )
- )";
-
- const char *get_perm = R"(
- SELECT * FROM permissions WHERE id = ? AND channel_id = ?
- )";
-
- const char *set_msg = R"(
- REPLACE INTO messages VALUES (
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
- )
- )";
-
- const char *get_msg = R"(
- SELECT messages.*,
- message_interactions.interaction_id as interaction_id,
- message_interactions.name as interaction_name,
- message_interactions.type as interaction_type,
- message_interactions.user_id as interaction_user_id
- FROM messages
- LEFT OUTER JOIN
- message_interactions
- ON messages.id = message_interactions.message_id
- WHERE id = ?
- )";
-
- const char *set_role = R"(
- REPLACE INTO roles VALUES (
- ?, ?, ?, ?, ?, ?, ?, ?
- )
- )";
-
- const char *get_role = R"(
- SELECT * FROM roles WHERE id = ?
- )";
-
- const char *set_emoji = R"(
- REPLACE INTO emojis VALUES (
- ?, ?, ?, ?, ?, ?, ?, ?
- )
- )";
-
- const char *get_emoji = R"(
- SELECT * FROM emojis WHERE id = ?
- )";
-
- const char *set_member = R"(
- REPLACE INTO members VALUES (
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
- )
- )";
-
- const char *get_member = R"(
- SELECT * FROM members WHERE user_id = ? AND guild_id = ?
- )";
-
- const char *set_guild = R"(
- REPLACE INTO guilds VALUES (
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
- )
- )";
-
- const char *get_guild = R"(
- SELECT * FROM guilds WHERE id = ?
- )";
-
- const char *set_chan = R"(
- REPLACE INTO channels VALUES (
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
- )
- )";
-
- const char *get_chan = R"(
- SELECT * FROM channels WHERE id = ?
- )";
-
- const char *set_ban = R"(
- REPLACE INTO bans VALUES (
- ?, ?, ?
- )
- )";
-
- const char *get_ban = R"(
- SELECT * FROM bans WHERE guild_id = ? AND user_id = ?
- )";
-
- const char *clear_ban = R"(
- DELETE FROM bans WHERE guild_id = ? AND user_id = ?
- )";
-
- const char *get_bans = R"(
- SELECT * FROM bans WHERE guild_id = ?
- )";
-
- const char *set_interaction = R"(
- 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 = ? AND pending = 0 ORDER BY id ASC
- )";
-
- const char *get_pins = R"(
- SELECT id FROM messages WHERE channel_id = ? AND pinned = 1 ORDER BY id ASC
- )";
-
- const char *get_threads = R"(
- SELECT id FROM channels WHERE parent_id = ? AND (type = 10 OR type = 11 OR type = 12) AND archived = FALSE
- )";
-
- const char *clear_chan = R"(
- DELETE 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));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, get_user, -1, &m_get_user_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare get user statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, set_perm, -1, &m_set_perm_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare set permission statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, get_perm, -1, &m_get_perm_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare get permission statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, set_msg, -1, &m_set_msg_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare set message statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, get_msg, -1, &m_get_msg_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare get message statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, set_role, -1, &m_set_role_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare set role statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, get_role, -1, &m_get_role_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare get role statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, set_emoji, -1, &m_set_emote_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare set emoji statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, get_emoji, -1, &m_get_emote_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare get emoji statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, set_member, -1, &m_set_member_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare set member statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, get_member, -1, &m_get_member_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare get member statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, set_guild, -1, &m_set_guild_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare set guild statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, get_guild, -1, &m_get_guild_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare get guild statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- 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;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, set_ban, -1, &m_set_ban_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare set ban statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, get_ban, -1, &m_get_ban_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare get ban statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, clear_ban, -1, &m_clear_ban_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare clear ban statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, get_bans, -1, &m_get_bans_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare get bans statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, set_interaction, -1, &m_set_msg_interaction_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare set message interaction statement: %s\n", sqlite3_errstr(m_db_err));
- 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;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, get_pins, -1, &m_get_pins_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare get pins statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, get_threads, -1, &m_get_threads_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare get threads statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- m_db_err = sqlite3_prepare_v2(m_db, clear_chan, -1, &m_clear_chan_stmt, nullptr);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "failed to prepare clear channel statement: %s\n", sqlite3_errstr(m_db_err));
- return false;
- }
-
- return true;
-}
-
-void Store::Cleanup() {
- sqlite3_finalize(m_set_user_stmt);
- sqlite3_finalize(m_get_user_stmt);
- sqlite3_finalize(m_set_perm_stmt);
- sqlite3_finalize(m_get_perm_stmt);
- sqlite3_finalize(m_set_msg_stmt);
- sqlite3_finalize(m_get_msg_stmt);
- sqlite3_finalize(m_set_role_stmt);
- sqlite3_finalize(m_get_role_stmt);
- sqlite3_finalize(m_set_emote_stmt);
- sqlite3_finalize(m_get_emote_stmt);
- sqlite3_finalize(m_set_member_stmt);
- sqlite3_finalize(m_get_member_stmt);
- sqlite3_finalize(m_set_guild_stmt);
- sqlite3_finalize(m_get_guild_stmt);
- sqlite3_finalize(m_set_chan_stmt);
- sqlite3_finalize(m_get_chan_stmt);
- sqlite3_finalize(m_set_ban_stmt);
- sqlite3_finalize(m_get_ban_stmt);
- sqlite3_finalize(m_clear_ban_stmt);
- sqlite3_finalize(m_get_bans_stmt);
- sqlite3_finalize(m_set_msg_interaction_stmt);
- sqlite3_finalize(m_get_last_msgs_stmt);
- sqlite3_finalize(m_get_msg_ids_stmt);
- sqlite3_finalize(m_get_pins_stmt);
- sqlite3_finalize(m_get_threads_stmt);
- sqlite3_finalize(m_clear_chan_stmt);
-}
-
-void Store::Bind(sqlite3_stmt *stmt, int index, int num) const {
- m_db_err = sqlite3_bind_int(stmt, index, num);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "error binding index %d: %s\n", index, sqlite3_errstr(m_db_err));
- }
-}
-
-void Store::Bind(sqlite3_stmt *stmt, int index, uint64_t num) const {
- m_db_err = sqlite3_bind_int64(stmt, index, num);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "error binding index %d: %s\n", index, sqlite3_errstr(m_db_err));
- }
-}
-
-void Store::Bind(sqlite3_stmt *stmt, int index, const std::string &str) const {
- m_db_err = sqlite3_bind_blob(stmt, index, str.c_str(), str.length(), SQLITE_TRANSIENT);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "error binding index %d: %s\n", index, sqlite3_errstr(m_db_err));
- }
-}
-
-void Store::Bind(sqlite3_stmt *stmt, int index, bool val) const {
- m_db_err = sqlite3_bind_int(stmt, index, val ? 1 : 0);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "error binding index %d: %s\n", index, sqlite3_errstr(m_db_err));
- }
-}
-
-void Store::Bind(sqlite3_stmt *stmt, int index, std::nullptr_t) const {
- m_db_err = sqlite3_bind_null(stmt, index);
- if (m_db_err != SQLITE_OK) {
- fprintf(stderr, "error binding index %d: %s\n", index, sqlite3_errstr(m_db_err));
- }
-}
-
-bool Store::RunInsert(sqlite3_stmt *stmt) {
- m_db_err = sqlite3_step(stmt);
- Reset(stmt);
- return m_db_err == SQLITE_DONE;
-}
-
-bool Store::FetchOne(sqlite3_stmt *stmt) const {
- m_db_err = sqlite3_step(stmt);
- return m_db_err == SQLITE_ROW;
-}
-
-void Store::Get(sqlite3_stmt *stmt, int index, int &out) const {
- out = sqlite3_column_int(stmt, index);
-}
-
-void Store::Get(sqlite3_stmt *stmt, int index, uint64_t &out) const {
- out = sqlite3_column_int64(stmt, index);
-}
-
-void Store::Get(sqlite3_stmt *stmt, int index, std::string &out) const {
- const unsigned char *ptr = sqlite3_column_text(stmt, index);
- if (ptr == nullptr)
- out = "";
- else
- out = reinterpret_cast<const char *>(ptr);
-}
-
-void Store::Get(sqlite3_stmt *stmt, int index, bool &out) const {
- out = sqlite3_column_int(stmt, index) != 0;
-}
-
-void Store::Get(sqlite3_stmt *stmt, int index, Snowflake &out) const {
- const int64_t num = sqlite3_column_int64(stmt, index);
- 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
deleted file mode 100644
index f84d13e..0000000
--- a/discord/store.hpp
+++ /dev/null
@@ -1,172 +0,0 @@
-#pragma once
-#include "../util.hpp"
-#include "objects.hpp"
-#include <unordered_map>
-#include <unordered_set>
-#include <mutex>
-#include <filesystem>
-#include <sqlite3.h>
-
-#ifdef GetMessage // fuck you windows.h
- #undef GetMessage
-#endif
-
-class Store {
-public:
- Store(bool mem_store = false);
- ~Store();
-
- bool IsValid() const;
-
- void SetUser(Snowflake id, const UserData &user);
- void SetChannel(Snowflake id, const ChannelData &chan);
- void SetGuild(Snowflake id, const GuildData &guild);
- void SetRole(Snowflake id, const RoleData &role);
- void SetMessage(Snowflake id, const Message &message);
- void SetGuildMember(Snowflake guild_id, Snowflake user_id, const GuildMember &data);
- void SetPermissionOverwrite(Snowflake channel_id, Snowflake id, const PermissionOverwrite &perm);
- void SetEmoji(Snowflake id, const EmojiData &emoji);
- void SetBan(Snowflake guild_id, Snowflake user_id, const BanData &ban);
-
- // slap const on everything even tho its not *really* const
-
- std::optional<ChannelData> GetChannel(Snowflake id) const;
- std::optional<EmojiData> GetEmoji(Snowflake id) const;
- std::optional<GuildData> GetGuild(Snowflake id) const;
- std::optional<GuildMember> GetGuildMember(Snowflake guild_id, Snowflake user_id) const;
- std::optional<Message> GetMessage(Snowflake id) const;
- std::optional<PermissionOverwrite> GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const;
- std::optional<RoleData> GetRole(Snowflake id) const;
- std::optional<UserData> GetUser(Snowflake id) const;
- std::optional<BanData> GetBan(Snowflake guild_id, Snowflake user_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;
- std::vector<Message> GetPinnedMessages(Snowflake channel_id) const;
- std::vector<ChannelData> GetActiveThreads(Snowflake channel_id) const; // public
-
- void ClearGuild(Snowflake id);
- void ClearChannel(Snowflake id);
- void ClearBan(Snowflake guild_id, Snowflake user_id);
-
- using users_type = std::unordered_map<Snowflake, UserData>;
- using channels_type = std::unordered_map<Snowflake, ChannelData>;
- using guilds_type = std::unordered_map<Snowflake, GuildData>;
- using roles_type = std::unordered_map<Snowflake, RoleData>;
- using messages_type = std::unordered_map<Snowflake, Message>;
- using members_type = std::unordered_map<Snowflake, std::unordered_map<Snowflake, GuildMember>>; // [guild][user]
- using permission_overwrites_type = std::unordered_map<Snowflake, std::unordered_map<Snowflake, PermissionOverwrite>>; // [channel][user/role]
- using emojis_type = std::unordered_map<Snowflake, EmojiData>;
-
- const std::unordered_set<Snowflake> &GetChannels() const;
- const std::unordered_set<Snowflake> &GetGuilds() const;
-
- void ClearAll();
-
- void BeginTransaction();
- void EndTransaction();
-
-private:
- Message GetMessageBound(sqlite3_stmt *stmt) const;
-
- void SetMessageInteractionPair(Snowflake message_id, const MessageInteractionData &interaction);
-
- std::unordered_set<Snowflake> m_channels;
- std::unordered_set<Snowflake> m_guilds;
-
- bool CreateTables();
- bool CreateStatements();
- void Cleanup();
-
- template<typename T>
- void Bind(sqlite3_stmt *stmt, int index, const std::optional<T> &opt) const;
-
- template<typename T>
- typename std::enable_if<std::is_enum<T>::value, void>::type
- Bind(sqlite3_stmt *stmt, int index, T val) const;
-
- void Bind(sqlite3_stmt *stmt, int index, int num) const;
- void Bind(sqlite3_stmt *stmt, int index, uint64_t num) const;
- void Bind(sqlite3_stmt *stmt, int index, const std::string &str) const;
- void Bind(sqlite3_stmt *stmt, int index, bool val) const;
- void Bind(sqlite3_stmt *stmt, int index, std::nullptr_t) const;
- bool RunInsert(sqlite3_stmt *stmt);
- bool FetchOne(sqlite3_stmt *stmt) const;
-
- template<typename T>
- void Get(sqlite3_stmt *stmt, int index, std::optional<T> &out) const;
-
- template<typename T>
- typename std::enable_if<std::is_enum<T>::value, void>::type
- Get(sqlite3_stmt *stmt, int index, T &out) const;
-
- void Get(sqlite3_stmt *stmt, int index, int &out) const;
- void Get(sqlite3_stmt *stmt, int index, uint64_t &out) const;
- 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;
- mutable sqlite3 *m_db;
- mutable int m_db_err;
- mutable sqlite3_stmt *m_set_user_stmt;
- mutable sqlite3_stmt *m_get_user_stmt;
- mutable sqlite3_stmt *m_set_perm_stmt;
- mutable sqlite3_stmt *m_get_perm_stmt;
- mutable sqlite3_stmt *m_set_msg_stmt;
- mutable sqlite3_stmt *m_get_msg_stmt;
- mutable sqlite3_stmt *m_set_role_stmt;
- mutable sqlite3_stmt *m_get_role_stmt;
- mutable sqlite3_stmt *m_set_emote_stmt;
- mutable sqlite3_stmt *m_get_emote_stmt;
- mutable sqlite3_stmt *m_set_member_stmt;
- mutable sqlite3_stmt *m_get_member_stmt;
- mutable sqlite3_stmt *m_set_guild_stmt;
- mutable sqlite3_stmt *m_get_guild_stmt;
- mutable sqlite3_stmt *m_set_chan_stmt;
- mutable sqlite3_stmt *m_get_chan_stmt;
- mutable sqlite3_stmt *m_set_ban_stmt;
- mutable sqlite3_stmt *m_get_ban_stmt;
- mutable sqlite3_stmt *m_clear_ban_stmt;
- mutable sqlite3_stmt *m_get_bans_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;
- mutable sqlite3_stmt *m_get_pins_stmt;
- mutable sqlite3_stmt *m_get_threads_stmt;
- mutable sqlite3_stmt *m_clear_chan_stmt;
-};
-
-template<typename T>
-inline void Store::Bind(sqlite3_stmt *stmt, int index, const std::optional<T> &opt) const {
- if (opt.has_value())
- Bind(stmt, index, *opt);
- else
- sqlite3_bind_null(stmt, index);
-}
-
-template<typename T>
-inline typename std::enable_if<std::is_enum<T>::value, void>::type
-Store::Bind(sqlite3_stmt *stmt, int index, T val) const {
- Bind(stmt, index, static_cast<typename std::underlying_type<T>::type>(val));
-}
-
-template<typename T>
-inline void Store::Get(sqlite3_stmt *stmt, int index, std::optional<T> &out) const {
- if (sqlite3_column_type(stmt, index) == SQLITE_NULL)
- out = std::nullopt;
- else {
- T v;
- Get(stmt, index, v);
- out = std::optional<T>(v);
- }
-}
-
-template<typename T>
-inline typename std::enable_if<std::is_enum<T>::value, void>::type
-Store::Get(sqlite3_stmt *stmt, int index, T &out) const {
- out = static_cast<T>(sqlite3_column_int(stmt, index));
-}
diff --git a/discord/user.cpp b/discord/user.cpp
deleted file mode 100644
index a68346e..0000000
--- a/discord/user.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-#include "user.hpp"
-#include "../abaddon.hpp"
-
-bool UserData::IsDeleted() const {
- return Discriminator == "0000";
-}
-
-bool UserData::HasAvatar() const {
- return Avatar.size() > 0;
-}
-
-bool UserData::HasAnimatedAvatar() const {
- return Avatar.size() > 0 && Avatar[0] == 'a' && Avatar[1] == '_';
-}
-
-std::string UserData::GetAvatarURL(Snowflake guild_id, std::string ext, std::string size) const {
- const auto member = Abaddon::Get().GetDiscordClient().GetMember(ID, guild_id);
- if (member.has_value() && member->Avatar.has_value())
- return "https://cdn.discordapp.com/guilds/" +
- std::to_string(guild_id) + "/users/" + std::to_string(ID) +
- "/avatars/" + *member->Avatar + "." +
- ext + "?" + "size=" + size;
- else
- return GetAvatarURL(ext, size);
-}
-
-std::string UserData::GetAvatarURL(const std::optional<Snowflake> &guild_id, std::string ext, std::string size) const {
- if (guild_id.has_value())
- return GetAvatarURL(*guild_id, ext, size);
- else
- return GetAvatarURL(ext, size);
-}
-
-std::string UserData::GetAvatarURL(std::string ext, std::string size) const {
- if (HasAvatar())
- return "https://cdn.discordapp.com/avatars/" + std::to_string(ID) + "/" + Avatar + "." + ext + "?size=" + size;
- else
- return GetDefaultAvatarURL();
-}
-
-std::string UserData::GetDefaultAvatarURL() const {
- return "https://cdn.discordapp.com/embed/avatars/" + std::to_string(std::stoul(Discriminator) % 5) + ".png"; // size isn't respected by the cdn
-}
-
-Snowflake UserData::GetHoistedRole(Snowflake guild_id, bool with_color) const {
- return Abaddon::Get().GetDiscordClient().GetMemberHoistedRole(guild_id, ID, with_color);
-}
-
-std::string UserData::GetMention() const {
- return "<@" + std::to_string(ID) + ">";
-}
-
-std::string UserData::GetEscapedName() const {
- return Glib::Markup::escape_text(Username);
-}
-
-std::string UserData::GetEscapedBoldName() const {
- return "<b>" + Glib::Markup::escape_text(Username) + "</b>";
-}
-
-std::string UserData::GetEscapedString() const {
- return Glib::Markup::escape_text(Username) + "#" + Discriminator;
-}
-
-void from_json(const nlohmann::json &j, UserData &m) {
- JS_D("id", m.ID);
- JS_D("username", m.Username);
- JS_D("discriminator", m.Discriminator);
- JS_N("avatar", m.Avatar);
- JS_O("bot", m.IsBot);
- JS_O("system", m.IsSystem);
- JS_O("mfa_enabled", m.IsMFAEnabled);
- JS_O("locale", m.Locale);
- JS_O("verified", m.IsVerified);
- JS_O("email", m.Email);
- JS_O("flags", m.Flags);
- JS_ON("premium_type", m.PremiumType);
- JS_O("public_flags", m.PublicFlags);
- JS_O("desktop", m.IsDesktop);
- JS_O("mobile", m.IsMobile);
- JS_ON("nsfw_allowed", m.IsNSFWAllowed);
- JS_ON("phone", m.Phone);
- JS_ON("bio", m.Bio);
- JS_ON("banner", m.BannerHash);
-}
-
-void to_json(nlohmann::json &j, const UserData &m) {
- j["id"] = m.ID;
- j["username"] = m.Username;
- j["discriminator"] = m.Discriminator;
- if (m.Avatar == "")
- j["avatar"] = nullptr;
- else
- j["avatar"] = m.Avatar;
- JS_IF("bot", m.IsBot);
- JS_IF("system", m.IsSystem);
- JS_IF("mfa_enabled", m.IsMFAEnabled);
- JS_IF("locale", m.Locale);
- JS_IF("verified", m.IsVerified);
- JS_IF("email", m.Email);
- JS_IF("flags", m.Flags);
- JS_IF("premium_type", m.PremiumType);
- JS_IF("public_flags", m.PublicFlags);
- JS_IF("desktop", m.IsDesktop);
- JS_IF("mobile", m.IsMobile);
- JS_IF("nsfw_allowed", m.IsNSFWAllowed);
- JS_IF("phone", m.Phone);
-}
-
-void UserData::update_from_json(const nlohmann::json &j) {
- JS_RD("username", Username);
- JS_RD("discriminator", Discriminator);
- JS_RD("avatar", Avatar);
- JS_RD("bot", IsBot);
- JS_RD("system", IsSystem);
- JS_RD("mfa_enabled", IsMFAEnabled);
- JS_RD("locale", Locale);
- JS_RD("verified", IsVerified);
- JS_RD("email", Email);
- JS_RD("flags", Flags);
- JS_RD("premium_type", PremiumType);
- JS_RD("public_flags", PublicFlags);
- JS_RD("desktop", IsDesktop);
- JS_RD("mobile", IsMobile);
- JS_RD("nsfw_allowed", IsNSFWAllowed);
- JS_RD("phone", Phone);
-}
-
-const char *UserData::GetFlagName(uint64_t flag) {
- switch (flag) {
- case DiscordEmployee:
- return "discordstaff";
- case PartneredServerOwner:
- return "partneredowner";
- case HypeSquadEvents:
- return "hypesquadevents";
- case BugHunterLevel1:
- return "discordbughunter";
- case HouseBravery:
- return "hypesquadbravery";
- case HouseBrilliance:
- return "hypesquadbrilliance";
- case HouseBalance:
- return "hypesquadbalance";
- case EarlySupporter:
- return "earlysupporter";
- case TeamUser:
- return "teamuser";
- case System:
- return "system";
- case BugHunterLevel2:
- return "discordbughunter2";
- case VerifiedBot:
- return "verifiedbot";
- case EarlyVerifiedBotDeveloper:
- return "earlyverifiedbotdeveloper";
- case CertifiedModerator:
- return "certifiedmoderator";
- default:
- return "unknown";
- }
-}
-
-const char *UserData::GetFlagReadableName(uint64_t flag) {
- switch (flag) {
- case DiscordEmployee:
- return "Discord Staff";
- case PartneredServerOwner:
- return "Partnered Server Owner";
- case HypeSquadEvents:
- return "HypeSquad Events";
- case BugHunterLevel1:
- return "Discord Bug Hunter";
- case HouseBravery:
- return "HypeSquad Bravery";
- case HouseBrilliance:
- return "HypeSquad Brilliance";
- case HouseBalance:
- return "HypeSquad Balance";
- case EarlySupporter:
- return "Early Supporter";
- case TeamUser:
- return "Team User"; // ???
- case System:
- return "System";
- case BugHunterLevel2:
- return "Discord Bug Hunter Level 2";
- case VerifiedBot:
- return "Verified Bot";
- case EarlyVerifiedBotDeveloper:
- return "Early Verified Bot Developer";
- case CertifiedModerator:
- return "Discord Certified Moderator";
- default:
- return "";
- }
-}
diff --git a/discord/user.hpp b/discord/user.hpp
deleted file mode 100644
index d4711fa..0000000
--- a/discord/user.hpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#pragma once
-#include "snowflake.hpp"
-#include "json.hpp"
-#include <string>
-
-enum class EPremiumType {
- None = 0,
- NitroClassic = 1,
- Nitro = 2,
-};
-
-struct UserData {
- enum {
- DiscordEmployee = 1 << 0,
- PartneredServerOwner = 1 << 1,
- HypeSquadEvents = 1 << 2,
- BugHunterLevel1 = 1 << 3,
- HouseBravery = 1 << 6,
- HouseBrilliance = 1 << 7,
- HouseBalance = 1 << 8,
- EarlySupporter = 1 << 9,
- TeamUser = 1 << 10, // no idea what this is
- System = 1 << 12,
- BugHunterLevel2 = 1 << 14,
- VerifiedBot = 1 << 16,
- EarlyVerifiedBotDeveloper = 1 << 17,
- CertifiedModerator = 1 << 18,
-
- MaxFlag_PlusOne,
- MaxFlag = MaxFlag_PlusOne - 1,
- };
-
- static const char *GetFlagName(uint64_t flag);
- static const char *GetFlagReadableName(uint64_t flag);
-
- Snowflake ID;
- std::string Username;
- std::string Discriminator;
- std::string Avatar; // null
- std::optional<bool> IsBot;
- std::optional<bool> IsSystem;
- std::optional<bool> IsMFAEnabled;
- std::optional<std::string> Locale;
- std::optional<bool> IsVerified;
- std::optional<std::string> Email; // null
- std::optional<uint64_t> Flags;
- std::optional<EPremiumType> PremiumType; // null
- std::optional<uint64_t> PublicFlags;
-
- // undocumented (opt)
- std::optional<bool> IsDesktop;
- std::optional<bool> IsMobile;
- std::optional<bool> IsNSFWAllowed; // null
- std::optional<std::string> Phone; // null?
- // for now (unserialized)
- std::optional<std::string> BannerHash; // null
- std::optional<std::string> Bio; // null
-
- friend void from_json(const nlohmann::json &j, UserData &m);
- friend void to_json(nlohmann::json &j, const UserData &m);
- void update_from_json(const nlohmann::json &j);
-
- bool IsDeleted() const;
- bool HasAvatar() const;
- bool HasAnimatedAvatar() const;
- std::string GetAvatarURL(Snowflake guild_id, std::string ext = "png", std::string size = "32") const;
- std::string GetAvatarURL(const std::optional<Snowflake> &guild_id, std::string ext = "png", std::string size = "32") const;
- std::string GetAvatarURL(std::string ext = "png", std::string size = "32") const;
- std::string GetDefaultAvatarURL() const;
- Snowflake GetHoistedRole(Snowflake guild_id, bool with_color = false) const;
- std::string GetMention() const;
- std::string GetEscapedName() const;
- std::string GetEscapedBoldName() const;
- std::string GetEscapedString() const;
- template<bool with_at>
- inline std::string GetEscapedBoldString() const {
- if constexpr (with_at)
- return "<b>@" + Glib::Markup::escape_text(Username) + "</b>#" + Discriminator;
- else
- return "<b>" + Glib::Markup::escape_text(Username) + "</b>#" + Discriminator;
- }
-};
diff --git a/discord/usersettings.cpp b/discord/usersettings.cpp
deleted file mode 100644
index e4ab41a..0000000
--- a/discord/usersettings.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "usersettings.hpp"
-
-void from_json(const nlohmann::json &j, UserSettingsGuildFoldersEntry &m) {
- JS_N("color", m.Color);
- JS_D("guild_ids", m.GuildIDs);
- JS_N("id", m.ID);
- JS_N("name", m.Name);
-}
-
-void from_json(const nlohmann::json &j, UserSettings &m) {
- JS_D("timezone_offset", m.TimezoneOffset);
- JS_D("theme", m.Theme);
- JS_D("stream_notifications_enabled", m.AreStreamNotificationsEnabled);
- JS_D("status", m.Status);
- JS_D("show_current_game", m.ShouldShowCurrentGame);
- // JS_D("restricted_guilds", m.RestrictedGuilds);
- JS_D("render_reactions", m.ShouldRenderReactions);
- JS_D("render_embeds", m.ShouldRenderEmbeds);
- JS_D("native_phone_integration_enabled", m.IsNativePhoneIntegrationEnabled);
- JS_D("message_display_compact", m.ShouldMessageDisplayCompact);
- JS_D("locale", m.Locale);
- JS_D("inline_embed_media", m.ShouldInlineEmbedMedia);
- JS_D("inline_attachment_media", m.ShouldInlineAttachmentMedia);
- JS_D("guild_positions", m.GuildPositions);
- JS_D("guild_folders", m.GuildFolders);
- JS_D("gif_auto_play", m.ShouldGIFAutoplay);
- // JS_D("friend_source_flags", m.FriendSourceFlags);
- JS_D("explicit_content_filter", m.ExplicitContentFilter);
- JS_D("enable_tts_command", m.IsTTSCommandEnabled);
- JS_D("disable_games_tab", m.ShouldDisableGamesTab);
- JS_D("developer_mode", m.DeveloperMode);
- JS_D("detect_platform_accounts", m.ShouldDetectPlatformAccounts);
- JS_D("default_guilds_restricted", m.AreDefaultGuildsRestricted);
- // JS_N("custom_status", m.CustomStatus);
- JS_D("convert_emoticons", m.ShouldConvertEmoticons);
- JS_D("contact_sync_enabled", m.IsContactSyncEnabled);
- JS_D("animate_emoji", m.ShouldAnimateEmojis);
- JS_D("allow_accessibility_detection", m.IsAccessibilityDetectionAllowed);
- JS_D("afk_timeout", m.AFKTimeout);
-}
diff --git a/discord/usersettings.hpp b/discord/usersettings.hpp
deleted file mode 100644
index 6d37b3c..0000000
--- a/discord/usersettings.hpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#pragma once
-#include "json.hpp"
-#include "snowflake.hpp"
-#include <string>
-
-struct UserSettingsGuildFoldersEntry {
- int Color = -1; // null
- std::vector<Snowflake> GuildIDs;
- Snowflake ID; // null (this can be a snowflake as a string or an int that isnt a snowflake lol)
- std::string Name; // null
-
- friend void from_json(const nlohmann::json &j, UserSettingsGuildFoldersEntry &m);
-};
-
-struct UserSettings {
- int TimezoneOffset; //
- std::string Theme; //
- bool AreStreamNotificationsEnabled; //
- std::string Status; //
- bool ShouldShowCurrentGame; //
- // std::vector<Unknown> RestrictedGuilds; //
- bool ShouldRenderReactions; //
- bool ShouldRenderEmbeds; //
- bool IsNativePhoneIntegrationEnabled; //
- bool ShouldMessageDisplayCompact; //
- std::string Locale; //
- bool ShouldInlineEmbedMedia; //
- bool ShouldInlineAttachmentMedia; //
- std::vector<Snowflake> GuildPositions; // deprecated?
- std::vector<UserSettingsGuildFoldersEntry> GuildFolders; //
- bool ShouldGIFAutoplay; //
- // Unknown FriendSourceFlags; //
- int ExplicitContentFilter; //
- bool IsTTSCommandEnabled; //
- bool ShouldDisableGamesTab; //
- bool DeveloperMode; //
- bool ShouldDetectPlatformAccounts; //
- bool AreDefaultGuildsRestricted; //
- // Unknown CustomStatus; // null
- bool ShouldConvertEmoticons; //
- bool IsContactSyncEnabled; //
- bool ShouldAnimateEmojis; //
- bool IsAccessibilityDetectionAllowed; //
- int AFKTimeout;
-
- friend void from_json(const nlohmann::json &j, UserSettings &m);
-};
diff --git a/discord/webhook.cpp b/discord/webhook.cpp
deleted file mode 100644
index 4e8b422..0000000
--- a/discord/webhook.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "webhook.hpp"
-
-void from_json(const nlohmann::json &j, WebhookData &m) {
- JS_D("id", m.ID);
- JS_D("type", m.Type);
- JS_O("guild_id", m.GuildID);
- JS_D("channel_id", m.ChannelID);
- JS_O("user", m.User);
- JS_N("name", m.Name);
- JS_N("avatar", m.Avatar);
- JS_O("token", m.Token);
- JS_N("application_id", m.ApplicationID);
-}
diff --git a/discord/webhook.hpp b/discord/webhook.hpp
deleted file mode 100644
index f0214df..0000000
--- a/discord/webhook.hpp
+++ /dev/null
@@ -1,24 +0,0 @@
-#pragma once
-#include <optional>
-#include "json.hpp"
-#include "snowflake.hpp"
-#include "user.hpp"
-
-enum class WebhookType {
- Incoming = 1,
- ChannelFollower = 2,
-};
-
-struct WebhookData {
- Snowflake ID;
- WebhookType Type;
- std::optional<Snowflake> GuildID;
- Snowflake ChannelID;
- std::optional<UserData> User;
- std::string Name; // null
- std::string Avatar; // null
- std::optional<std::string> Token;
- Snowflake ApplicationID; // null
-
- friend void from_json(const nlohmann::json &j, WebhookData &m);
-};
diff --git a/discord/websocket.cpp b/discord/websocket.cpp
deleted file mode 100644
index ff50cd3..0000000
--- a/discord/websocket.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "websocket.hpp"
-#include <functional>
-
-Websocket::Websocket() {}
-
-void Websocket::StartConnection(std::string url) {
- m_websocket.disableAutomaticReconnection();
- m_websocket.setUrl(url);
- m_websocket.setOnMessageCallback(std::bind(&Websocket::OnMessage, this, std::placeholders::_1));
- m_websocket.setExtraHeaders(ix::WebSocketHttpHeaders { { "User-Agent", m_agent } }); // idk if this actually works
- m_websocket.start();
-}
-
-void Websocket::SetUserAgent(std::string agent) {
- m_agent = agent;
-}
-
-void Websocket::Stop() {
- Stop(ix::WebSocketCloseConstants::kNormalClosureCode);
-}
-
-void Websocket::Stop(uint16_t code) {
- m_websocket.stop(code);
-}
-
-bool Websocket::IsOpen() const {
- auto state = m_websocket.getReadyState();
- return state == ix::ReadyState::Open;
-}
-
-void Websocket::Send(const std::string &str) {
- printf("sending %s\n", str.c_str());
- m_websocket.sendText(str);
-}
-
-void Websocket::Send(const nlohmann::json &j) {
- Send(j.dump());
-}
-
-void Websocket::OnMessage(const ix::WebSocketMessagePtr &msg) {
- switch (msg->type) {
- case ix::WebSocketMessageType::Open: {
- m_signal_open.emit();
- } break;
- case ix::WebSocketMessageType::Close: {
- m_signal_close.emit(msg->closeInfo.code);
- } break;
- case ix::WebSocketMessageType::Message: {
- m_signal_message.emit(msg->str);
- } break;
- default:
- break;
- }
-}
-
-Websocket::type_signal_open Websocket::signal_open() {
- return m_signal_open;
-}
-
-Websocket::type_signal_close Websocket::signal_close() {
- return m_signal_close;
-}
-
-Websocket::type_signal_message Websocket::signal_message() {
- return m_signal_message;
-}
diff --git a/discord/websocket.hpp b/discord/websocket.hpp
deleted file mode 100644
index e6a6489..0000000
--- a/discord/websocket.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#pragma once
-#include <ixwebsocket/IXNetSystem.h>
-#include <ixwebsocket/IXWebSocket.h>
-#include <string>
-#include <functional>
-#include <nlohmann/json.hpp>
-#include <sigc++/sigc++.h>
-
-class Websocket {
-public:
- Websocket();
- void StartConnection(std::string url);
-
- void SetUserAgent(std::string agent);
-
- void Send(const std::string &str);
- void Send(const nlohmann::json &j);
- void Stop();
- void Stop(uint16_t code);
- bool IsOpen() const;
-
-private:
- void OnMessage(const ix::WebSocketMessagePtr &msg);
-
- ix::WebSocket m_websocket;
- std::string m_agent;
-
-public:
- typedef sigc::signal<void> type_signal_open;
- typedef sigc::signal<void, uint16_t> type_signal_close;
- typedef sigc::signal<void, std::string> type_signal_message;
-
- type_signal_open signal_open();
- type_signal_close signal_close();
- type_signal_message signal_message();
-
-private:
- type_signal_open m_signal_open;
- type_signal_close m_signal_close;
- type_signal_message m_signal_message;
-};