summaryrefslogtreecommitdiff
path: root/discord/discord.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'discord/discord.hpp')
-rw-r--r--discord/discord.hpp221
1 files changed, 219 insertions, 2 deletions
diff --git a/discord/discord.hpp b/discord/discord.hpp
index 5a2d256..3c27efe 100644
--- a/discord/discord.hpp
+++ b/discord/discord.hpp
@@ -3,6 +3,41 @@
#include <nlohmann/json.hpp>
#include <thread>
#include <unordered_map>
+#include <mutex>
+
+struct Snowflake {
+ Snowflake();
+ Snowflake(const Snowflake &s);
+ Snowflake(uint64_t n);
+ Snowflake(const std::string &str);
+
+ bool IsValid() 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;
+ }
+
+ const static int Invalid = -1;
+
+ friend void from_json(const nlohmann::json &j, Snowflake &s);
+
+private:
+ friend struct std::hash<Snowflake>;
+ unsigned long long m_num;
+};
+
+namespace std {
+template<>
+struct hash<Snowflake> {
+ std::size_t operator()(const Snowflake &k) const {
+ return k.m_num;
+ }
+};
+} // namespace std
enum class GatewayOp : int {
Event = 0,
@@ -30,9 +65,180 @@ struct HelloMessageData {
friend void from_json(const nlohmann::json &j, HelloMessageData &m);
};
+enum class ChannelType : int {
+ GUILD_TEXT = 0,
+ DM = 1,
+ GUILD_VOICE = 2,
+ GROUP_DM = 3,
+ GUILD_CATEGORY = 4,
+ GUILD_NEWS = 5,
+ GUILD_STORE = 6,
+};
+
+struct UserData {
+ Snowflake ID; //
+ std::string Username; //
+ std::string Discriminator; //
+ std::string Avatar; // null
+ bool IsBot = false; // opt
+ bool IsSystem = false; // opt
+ bool IsMFAEnabled = false; // opt
+ std::string Locale; // opt
+ bool IsVerified = false; // opt
+ std::string Email; // opt, null
+ int Flags = 0; // opt
+ int PremiumType = 0; // opt
+ int PublicFlags = 0; // opt
+
+ // undocumented (opt)
+ bool IsDesktop = false; //
+ bool IsMobile = false; //
+ bool IsNSFWAllowed = false; // null
+ std::string Phone; // null?
+
+ friend void from_json(const nlohmann::json &j, UserData &m);
+};
+
+struct ChannelData {
+ Snowflake ID; //
+ ChannelType Type; //
+ Snowflake GuildID; // opt
+ int Position = -1; // opt
+ // std::vector<PermissionOverwriteData> PermissionOverwrites; // opt
+ std::string Name; // opt
+ std::string Topic; // opt, null
+ bool IsNSFW = false; // opt
+ Snowflake LastMessageID; // opt, null
+ int Bitrate = 0; // opt
+ int UserLimit = 0; // opt
+ int RateLimitPerUser = 0; // opt
+ std::vector<UserData> Recipients; // opt
+ std::string Icon; // opt, null
+ Snowflake OwnerID; // opt
+ Snowflake ApplicationID; // opt
+ Snowflake ParentID; // opt, null
+ std::string LastPinTimestamp; // opt, can be null even tho docs say otherwise
+
+ friend void from_json(const nlohmann::json &j, ChannelData &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)
+struct GuildData {
+ Snowflake ID; //
+ std::string Name; //
+ std::string Icon; // null
+ std::string Splash; // null
+ std::string DiscoverySplash; // null
+ bool IsOwner = false; // opt
+ Snowflake OwnerID; //
+ int Permissions = 0; // opt
+ std::string PermissionsNew; // opt
+ std::string VoiceRegion; // opt
+ Snowflake AFKChannelID; // null
+ int AFKTimeout; //
+ bool IsEmbedEnabled = false; // opt, deprecated
+ Snowflake EmbedChannelID; // opt, null, deprecated
+ int VerificationLevel; //
+ int DefaultMessageNotifications; //
+ int ExplicitContentFilter; //
+ // std::vector<RoleData> Roles; //
+ // std::vector<EmojiData> Emojis; //
+ std::vector<std::string> Features; //
+ int MFALevel; //
+ Snowflake ApplicationID; // null
+ bool IsWidgetEnabled = false; // opt
+ Snowflake WidgetChannelID; // opt, null
+ Snowflake SystemChannelID; // null
+ int SystemChannelFlags; //
+ Snowflake RulesChannelID; // null
+ std::string JoinedAt; // opt*
+ bool IsLarge = false; // opt*
+ bool IsUnavailable = false; // opt*
+ int MemberCount = 0; // opt*
+ // std::vector<VoiceStateData> VoiceStates; // opt*
+ // std::vector<MemberData> Members; // opt* - incomplete anyways
+ std::vector<ChannelData> Channels; // opt*
+ // std::vector<PresenceUpdateData> Presences; // opt*
+ int MaxPresences = 0; // opt, null
+ int MaxMembers = 0; // opt
+ std::string VanityURL; // null
+ std::string Description; // null
+ std::string BannerHash; // null
+ int PremiumTier; //
+ int PremiumSubscriptionCount = 0; // opt
+ std::string PreferredLocale; //
+ Snowflake PublicUpdatesChannelID; // null
+ int MaxVideoChannelUsers = 0; // opt
+ int ApproximateMemberCount = 0; // opt
+ int ApproximatePresenceCount = 0; // opt
+
+ // 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);
+};
+
+struct UserSettingsData {
+ 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; //
+ // std::vector<GuildFolderEntryData> 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, UserSettingsData &m);
+};
+
struct ReadyEventData {
- std::string AnalyticsToken; // opt
+ int GatewayVersion; //
+ UserData User; //
+ std::vector<GuildData> Guilds; //
+ std::string SessionID; //
+ // std::vector<ChannelData?/PrivateChannelData?> PrivateChannels;
+ // undocumented
+ std::string AnalyticsToken; // opt
+ int FriendSuggestionCount; // opt
+ UserSettingsData UserSettings; // opt
+ // 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
+ // std::vector<RelationshipData> Relationships; // opt
+ // Unknown Tutorial; // opt, null
+ // std::vector<GuildSettingData> UserGuildSettings; // opt
+
+ friend void from_json(const nlohmann::json &j, ReadyEventData &m);
};
struct IdentifyProperties {
@@ -92,6 +298,10 @@ public:
void Stop();
bool IsStarted() const;
+ using Guilds_t = std::unordered_map<Snowflake, GuildData>;
+ const Guilds_t &GetGuilds() const;
+ const UserSettingsData &GetUserSettings() const;
+
private:
void HandleGatewayMessage(nlohmann::json msg);
void HandleGatewayReady(const GatewayMessage &msg);
@@ -99,9 +309,16 @@ private:
void SendIdentify();
Abaddon *m_abaddon = nullptr;
+ mutable std::mutex m_mutex;
+
+ void StoreGuild(Snowflake id, const GuildData &g);
+ Guilds_t m_guilds;
+
+ UserSettingsData m_user_settings;
Websocket m_websocket;
- bool m_client_connected = false;
+ std::atomic<bool> m_client_connected = false;
+ std::atomic<bool> m_ready_received = false;
std::unordered_map<std::string, GatewayEvent> m_event_map;
void LoadEventMap();