diff options
Diffstat (limited to 'discord/discord.hpp')
-rw-r--r-- | discord/discord.hpp | 221 |
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(); |