├── .github └── FUNDING.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── discordpp ├── alias.hh ├── bot.hh ├── botStruct.hh ├── enum.hh ├── intents.hh ├── log.hh ├── macros.hh ├── macros │ ├── defineCallClose.hh │ └── defineCallOpen.hh ├── snowflake.hh └── util.hh └── lib └── .gitkeep /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [UndarkAido] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build-debug/ 2 | 3 | # Created by https://www.gitignore.io/api/jetbrains,c++,linux,windows 4 | 5 | ### JetBrains ### 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 7 | 8 | *.iml 9 | 10 | ## Directory-based project format: 11 | .idea/ 12 | # if you remove the above rule, at least ignore the following: 13 | 14 | # User-specific stuff: 15 | # .idea/workspace.xml 16 | # .idea/tasks.xml 17 | # .idea/dictionaries 18 | 19 | # Sensitive or high-churn files: 20 | # .idea/dataSources.ids 21 | # .idea/dataSources.xml 22 | # .idea/sqlDataSources.xml 23 | # .idea/dynamic.xml 24 | # .idea/uiDesigner.xml 25 | 26 | # Gradle: 27 | # .idea/gradle.xml 28 | # .idea/libraries 29 | 30 | # Mongo Explorer plugin: 31 | # .idea/mongoSettings.xml 32 | 33 | ## File-based project format: 34 | *.ipr 35 | *.iws 36 | 37 | ## Plugin-specific files: 38 | 39 | # IntelliJ 40 | /out/ 41 | 42 | # mpeltonen/sbt-idea plugin 43 | .idea_modules/ 44 | 45 | # JIRA plugin 46 | atlassian-ide-plugin.xml 47 | 48 | # Crashlytics plugin (for Android Studio and IntelliJ) 49 | com_crashlytics_export_strings.xml 50 | crashlytics.properties 51 | crashlytics-build.properties 52 | 53 | 54 | ### C++ ### 55 | # Compiled Object files 56 | *.slo 57 | *.lo 58 | *.o 59 | *.obj 60 | 61 | # Precompiled Headers 62 | *.gch 63 | *.pch 64 | 65 | # Compiled Dynamic libraries 66 | *.so 67 | *.dylib 68 | *.dll 69 | 70 | # Fortran module files 71 | *.mod 72 | 73 | # Compiled Static libraries 74 | *.lai 75 | *.la 76 | *.a 77 | *.lib 78 | 79 | # Executables 80 | *.exe 81 | *.out 82 | *.app 83 | 84 | 85 | ### Linux ### 86 | *~ 87 | 88 | # KDE directory preferences 89 | .directory 90 | 91 | # Linux trash folder which might appear on any partition or disk 92 | .Trash-* 93 | 94 | 95 | ### Windows ### 96 | # Windows image file caches 97 | Thumbs.db 98 | ehthumbs.db 99 | 100 | # Folder config file 101 | Desktop.ini 102 | 103 | # Recycle Bin used on file shares 104 | $RECYCLE.BIN/ 105 | 106 | # Windows Installer files 107 | *.cab 108 | *.msi 109 | *.msm 110 | *.msp 111 | 112 | # Windows shortcuts 113 | *.lnk 114 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/nlohmannjson"] 2 | path = lib/nlohmannjson 3 | url = https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent.git 4 | [submodule "lib/asio"] 5 | path = lib/asio 6 | url = https://github.com/chriskohlhoff/asio.git 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(discordpp) 3 | 4 | if (CMAKE_CXX_STANDARD LESS 14) 5 | error(${PROJECT_NAME} requires at least C++14) 6 | endif () 7 | 8 | ################### 9 | 10 | option(DISCORDPP_USE_BOOST "set ON to use Boost.Asio instead of standalone Asio" OFF) 11 | 12 | set(ALL_DISCORDPP_LIBRARIES "discordpp" PARENT_SCOPE) 13 | set(ALL_DISCORDPP_PLUGINS "" PARENT_SCOPE) 14 | set(ALL_DISCORDPP_INCLUDES "#include \n" PARENT_SCOPE) 15 | set(JSON_MultipleHeaders OFF) 16 | 17 | add_subdirectory(lib/nlohmannjson) 18 | 19 | include(FetchContent) 20 | FetchContent_Declare( 21 | fmt 22 | GIT_REPOSITORY https://github.com/fmtlib/fmt.git 23 | GIT_TAG master 24 | ) 25 | FetchContent_MakeAvailable(fmt) 26 | 27 | if (NOT ${DISCORDPP_USE_BOOST}) 28 | find_package(Threads REQUIRED) 29 | 30 | add_library(asio INTERFACE) 31 | target_compile_definitions(asio INTERFACE ASIO_STANDALONE) 32 | target_include_directories(asio INTERFACE lib/asio/asio/include) 33 | target_link_libraries(asio INTERFACE Threads::Threads) 34 | set(TARGET_ASIO asio) 35 | endif () 36 | 37 | add_library(${PROJECT_NAME} INTERFACE) 38 | target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) 39 | target_link_libraries(${PROJECT_NAME} INTERFACE 40 | nlohmann_json::nlohmann_json 41 | fmt::fmt ${TARGET_ASIO}) 42 | 43 | function(CREATE_DISCORDPP_INCLUDE) 44 | set(DISCORDPP_INCLUDE_GENERATED ${CMAKE_BINARY_DIR}/include PARENT_SCOPE) 45 | file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/include) 46 | file(WRITE ${CMAKE_BINARY_DIR}/include/discordpp.hh ${ALL_DISCORDPP_INCLUDES}) 47 | endfunction() 48 | 49 | function(CREATE_DISCORDPP_DEFINITIONS) 50 | list(JOIN ALL_DISCORDPP_PLUGINS , ALL_DISCORDPP_PLUGINS_JOINED) 51 | add_compile_definitions(ALL_DISCORDPP_PLUGINS=${ALL_DISCORDPP_PLUGINS_JOINED}) 52 | endfunction() 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Aidan Edwards 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Discord++ 2 | 3 | A Modularized C++ Library for the Discord API 4 | 5 | [![GitHub stars](https://img.shields.io/github/stars/DiscordPP/discordpp?style=for-the-badge)](https://github.com/DiscordPP/discordpp/stargazers)[![Discord](https://img.shields.io/discord/164234463247597568?color=%237289DA&label=Discord&style=for-the-badge)](https://discord.gg/VHAyrvspCx) 6 | 7 | ## Links 8 | 9 | * [Discord Server](https://discord.gg/4stCdkDHw6) 10 | * [Echo: Example / Template Bot](https://github.com/DiscordPP/echo-bot) 11 | 12 | ## Dependencies 13 | 14 | ### Required 15 | 16 | * [Boost](http://www.boost.org/) (If using a Beast module) 17 | * [OpenSSL](https://www.openssl.org) 18 | * A Discord++ REST module 19 | * [REST: Simple-Web-Server](https://github.com/DiscordPP/rest-simpleweb) 20 | * [REST: Beast](https://github.com/DiscordPP/rest-beast) 21 | * A Discord++ WebSocket module 22 | * [WebSocket: Simple-WebSocket-Server](https://github.com/DiscordPP/websocket-simpleweb) 23 | * [WebSocket: Beast](https://github.com/DiscordPP/websocket-beast) 24 | * Currently broken 25 | 26 | ### Included (Git submodules) 27 | 28 | * [nlohmann::json](https://github.com/nlohmann/json) 29 | * [Asio](https://github.com/chriskohlhoff/asio/) (You can remove the submodule if Asio is being provided by Boost) 30 | 31 | ### Recommended Plugins 32 | 33 | * [Plugin: RateLimit](https://github.com/DiscordPP/plugin-ratelimit) handes rate limiting 34 | * Without this plugin, Discord++ exits when encountering a rate limit for your safety 35 | * [Plugin: Overload](https://github.com/DiscordPP/plugin-overload) provides overloads for the websocket `send` function 36 | to create `std::shared_ptr`s for you and provides some sane defaults when you don't need all their arguments. 37 | * [Plugin: Responder](https://github.com/DiscordPP/plugin-responder) provides a simple interface for detecting commands 38 | in the form of a character and a string, e.g. `!help` 39 | * [Plugin: Native](https://github.com/DiscordPP/plugin-netive) provides extensions to the default `call` 40 | , `callJson`, and `callFile` methods specific to different endpoints as well as native C++ objects for Discord's JSON structures 41 | * You can find more plugins on the [#discordpp-plugin](https://github.com/topics/discordpp-plugin) tag 42 | 43 | ## Usage 44 | 45 | See [the Wiki](https://github.com/DiscordPP/discordpp/wiki) for setup and configuration 46 | -------------------------------------------------------------------------------- /discordpp/alias.hh: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Aidan on 10/5/2020. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace discordpp { 13 | using json = nlohmann::json; 14 | 15 | template using sptr = std::shared_ptr; 16 | 17 | using handleEvent = std::function; 18 | using handleRead = std::function; 19 | using handleWrite = std::function; 20 | using handleSent = std::function; 21 | } // namespace discordpp 22 | 23 | namespace discordpp { 24 | using json = nlohmann::json; 25 | 26 | using Nonce = std::variant; 27 | } // namespace discordpp 28 | 29 | namespace nlohmann { 30 | template <> struct adl_serializer { 31 | static void to_json(json &j, const discordpp::Nonce &n) { 32 | std::visit( 33 | [&](auto &&value) { j = std::forward(value); }, n); 34 | } 35 | static void from_json(const json &j, discordpp::Nonce &n) { 36 | if (j.is_number_integer()) { 37 | n = j.get(); 38 | } else if (j.is_string()) { 39 | n = j.get(); 40 | } else { 41 | assert(false && "\"nonce\" wasn't a string or int"); 42 | } 43 | } 44 | }; 45 | } // namespace nlohmann 46 | -------------------------------------------------------------------------------- /discordpp/bot.hh: -------------------------------------------------------------------------------- 1 | // 2 | // Created by aidan on 11/7/15. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "botStruct.hh" 12 | #include "intents.hh" 13 | #include "log.hh" 14 | 15 | #undef CALL_FIELD 16 | 17 | namespace discordpp { 18 | 19 | class Bot : public virtual BotStruct { 20 | std::unique_ptr reconnect_; 21 | std::function reconnect_millis = 22 | [distribution = 23 | std::make_shared>(0, 5000), 24 | generator = std::make_shared( 25 | std::chrono::system_clock::now().time_since_epoch().count())]() { 26 | return (*distribution)(*generator); 27 | }; 28 | std::unique_ptr pacemaker_; 29 | std::unique_ptr heartrate_; 30 | std::string session_id_ = ""; 31 | int sequence_ = -1; 32 | int needACK_ = -1; 33 | 34 | public: 35 | // This temporarily blocks sending the NONE intent on API 6 until it is 36 | // inactive 37 | bool sendNoneIntent = false; 38 | uint16_t intents = intents::NONE; 39 | 40 | unsigned int api = 9; 41 | 42 | // Bot sharding 43 | unsigned int shardID = 0; 44 | unsigned int numShards = 1; 45 | 46 | Bot() { 47 | needInit["Bot"] = true; 48 | 49 | handlers.insert({"READY", [this](json data) { 50 | session_id_ = 51 | data["session_id"].get(); 52 | ready_ = true; 53 | }}); 54 | } 55 | 56 | virtual void initBot(unsigned int apiVersionIn, const std::string &tokenIn, 57 | std::shared_ptr aiocIn) { 58 | apiVersion = apiVersionIn; 59 | token = tokenIn; 60 | aioc = aiocIn; 61 | needInit["Bot"] = false; 62 | } 63 | 64 | void reconnect(const std::string &reason, 65 | const bool resume = true) override { 66 | log::log(log::error, [reason](std::ostream *log) { 67 | *log << "Reconnecting because \"" << reason << "\" ...\n"; 68 | }); 69 | if (!resume) { 70 | sequence_ = -1; 71 | session_id_ = ""; 72 | } 73 | pacemaker_->cancel(); 74 | needACK_ = -1; 75 | reconnecting_ = true; 76 | disconnect(); 77 | } 78 | 79 | protected: 80 | void sendHeartbeat(const error_code e) { 81 | if (!connected_ || e) { 82 | return; 83 | } 84 | if (needACK_ > 1) { 85 | log::log(log::error, [this](std::ostream *log) { 86 | *log << "Discord Servers did not respond to " << needACK_ 87 | << " heartbeat" << (needACK_ == 1 ? "" : "s") 88 | << " within " 89 | << std::chrono::milliseconds(*heartrate_).count() 90 | << "ms; aborting connection.\n"; 91 | }); 92 | reconnect("Discord did not acknowledge too many heartbeats"); 93 | } else if (needACK_ > 0) { 94 | log::log(log::warning, [this](std::ostream *log) { 95 | *log << "Discord Servers did not respond to " << needACK_ 96 | << " heartbeat" << (needACK_ == 1 ? "" : "s") << " within " 97 | << std::chrono::milliseconds(*heartrate_).count() 98 | << "ms but we're letting this one slip.\n"; 99 | }); 100 | } 101 | needACK_++; 102 | if (showHeartbeats) { 103 | std::cout << "Sending heartbeat..." << std::endl; 104 | } 105 | pacemaker_ = std::make_unique( 106 | *aioc, std::chrono::steady_clock::now() + *heartrate_); 107 | pacemaker_->async_wait( 108 | [this](const error_code ec) { sendHeartbeat(ec); }); 109 | if (sequence_ >= 0) { 110 | send(1, std::make_shared(sequence_), nullptr); 111 | } else { 112 | send(1, nullptr, nullptr); 113 | } 114 | } 115 | 116 | virtual void receivePayload(json payload) override { 117 | log::log(log::trace, [payload](std::ostream *log) { 118 | *log << "Recieved Payload: " << payload.dump(4) << '\n'; 119 | }); 120 | 121 | switch (payload["op"].get()) { 122 | case 0: // Dispatch: dispatches an event 123 | sequence_ = payload["s"].get(); 124 | if (handlers.find(payload["t"].get()) == 125 | handlers.end()) { 126 | if (debugUnhandled) { 127 | std::cerr << "No handlers defined for " << payload["t"] 128 | << "\n"; 129 | } 130 | } else { 131 | for (auto handler = 132 | handlers.lower_bound(payload["t"].get()); 133 | handler != 134 | handlers.upper_bound(payload["t"].get()); 135 | handler++) { 136 | handler->second(payload["d"]); 137 | } 138 | } 139 | break; 140 | case 1: // Heartbeat: used for ping checking 141 | log::log(log::info, [](std::ostream *log) { 142 | *log << "Discord Servers requested a heartbeat, which is not " 143 | "implemented.\n"; 144 | }); 145 | break; 146 | case 7: // Reconnect: used to tell clients to reconnect to the 147 | // gateway 148 | log::log(log::info, [](std::ostream *log) { 149 | *log << "Discord Servers requested a reconnect.\n"; 150 | }); 151 | reconnect("The gateway is restarting"); 152 | break; 153 | case 9: // Invalid Session: used to notify client they have an 154 | // invalid session id 155 | log::log(log::warning, [](std::ostream *log) { 156 | *log << "Discord Servers notified of an invalid session ID.\n"; 157 | }); 158 | reconnect_ = std::make_unique( 159 | *aioc, std::chrono::steady_clock::now() + 160 | std::chrono::milliseconds(reconnect_millis())); 161 | reconnect_->async_wait([this](const error_code) { 162 | reconnect("The session is invalid", false); 163 | }); 164 | break; 165 | case 10: // Hello: sent immediately after connecting, 166 | // contains heartbeat and server debug information 167 | heartrate_ = std::make_unique( 168 | payload["d"]["heartbeat_interval"].get()); 169 | needACK_ = 0; 170 | sendHeartbeat( 171 | #ifdef ASIO_STANDALONE 172 | {} 173 | #else 174 | boost::system::errc::make_error_code( 175 | boost::system::errc::success) 176 | #endif 177 | ); 178 | if (sequence_ >= 0) { 179 | send(6, 180 | std::make_shared(json({ 181 | {"token", token}, 182 | {"session_id", session_id_}, 183 | {"seq", sequence_}, 184 | })), 185 | nullptr); 186 | } else { 187 | auto identify = 188 | std::make_shared(json({{"token", token}, 189 | {"properties", 190 | { 191 | {"$browser", "discordpp"}, 192 | {"$device", "discordpp"}, 193 | }}})); 194 | 195 | #if defined(_WIN32) || defined(_WIN64) 196 | (*identify)["properties"]["$os"] = "windows"; 197 | #elif defined(__APPLE__) || defined(__MACH__) 198 | (*identify)["properties"]["$os"] = "osx"; 199 | #elif defined(__linux__) 200 | (*identify)["properties"]["$os"] = "linux"; 201 | #elif defined(__FreeBSD__) 202 | (*identify)["properties"]["$os"] = "freebsd"; 203 | #elif defined(__unix) || defined(__unix__) 204 | (*identify)["properties"]["$os"] = "unix"; 205 | #else 206 | (*identify)["properties"]["$os"] = "other"; 207 | #endif 208 | 209 | if (intents != intents::NONE || api >= 8 || sendNoneIntent) { 210 | (*identify)["intents"] = intents; 211 | } 212 | 213 | if (numShards > 1) { 214 | assert(shardID < numShards); 215 | (*identify)["shard"] = json::array({shardID, numShards}); 216 | } 217 | 218 | send(2, identify, nullptr); 219 | } 220 | break; 221 | case 11: // Heartbeat ACK: sent immediately following a client 222 | // heartbeat that was received 223 | needACK_ = false; 224 | if (showHeartbeats) { 225 | std::cout << "Heartbeat Sucessful." << std::endl; 226 | } 227 | break; 228 | default: 229 | log::log(log::warning, [payload](std::ostream *log) { 230 | *log << "Unexpected opcode " << payload["op"] << "! Message:\n" 231 | << payload.dump(4) << '\n'; 232 | }); 233 | } 234 | } 235 | 236 | // REST ////////////////////// 237 | }; 238 | } // namespace discordpp 239 | -------------------------------------------------------------------------------- /discordpp/botStruct.hh: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Aidan on 6/21/2018. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #ifdef ASIO_STANDALONE 12 | #include 13 | #else 14 | #include 15 | namespace asio = boost::asio; 16 | #endif 17 | 18 | #define JSON_USE_IMPLICIT_CONVERSIONS 0 19 | #include 20 | 21 | #include "alias.hh" 22 | #include "enum.hh" 23 | #include "log.hh" 24 | #include "snowflake.hh" 25 | #include "util.hh" 26 | 27 | namespace discordpp { 28 | #ifdef ASIO_STANDALONE 29 | using error_code = std::error_code; 30 | #else 31 | using error_code = boost::system::error_code; 32 | #endif 33 | 34 | class BotStruct { 35 | public: 36 | bool debugUnhandled = true; 37 | bool showHeartbeats = true; 38 | std::multimap handlers; 39 | 40 | virtual ~BotStruct(){}; 41 | 42 | class RenderedCall; 43 | 44 | #define Bot BotStruct 45 | 46 | #define BASECALL 47 | #define Class Call 48 | #define function call 49 | #include "macros/defineCallOpen.hh" 50 | NEW_BASIC_RENDERABLE_FIELD(std::string, method, ) 51 | NEW_BASIC_RENDERABLE_FIELD(std::string, target, ) 52 | NEW_BASIC_RENDERABLE_FIELD(std::string, type, ) 53 | NEW_BASIC_RENDERABLE_FIELD(std::string, body, ) 54 | NEW_BASIC_RENDERABLE_FIELD(handleWrite, onWrite, ) 55 | NEW_BASIC_RENDERABLE_FIELD(handleRead, onRead, ) 56 | #include "macros/defineCallClose.hh" 57 | 58 | #define Parent Call 59 | #define Class JsonCall 60 | #define function callJson 61 | #include "macros/defineCallOpen.hh" 62 | NEW_RENDERABLE_FIELD(json, payload, USEDBY(body)) 63 | FORWARD_FIELD(std::string, method, ) 64 | FORWARD_FIELD(std::string, target, ) 65 | STATIC_FIELD(std::string, type, "application/json") 66 | HIDE_FIELD(body) 67 | FORWARD_FIELD(handleWrite, onWrite, ) 68 | FORWARD_FIELD(handleRead, onRead, ) 69 | 70 | protected: 71 | virtual sptr render_payload() { 72 | return std::make_shared(*_payload); 73 | } 74 | sptr render_body() override { 75 | return std::make_shared(get_payload()->dump()); 76 | } 77 | #include "macros/defineCallClose.hh" 78 | 79 | #define Parent JsonCall 80 | #define Class FileCall 81 | #define function callFile 82 | #include "macros/defineCallOpen.hh" 83 | NEW_BASIC_RENDERABLE_FIELD(std::string, filename, USEDBY(body)) 84 | NEW_BASIC_RENDERABLE_FIELD(std::string, filetype, USEDBY(body)) 85 | NEW_FIELD(std::string, file, USEDBY(body, boundary)) 86 | FORWARD_FIELD(json, payload, USEDBY(boundary)) 87 | FORWARD_FIELD(std::string, method, ) 88 | FORWARD_FIELD(std::string, target, ) 89 | FORWARD_FIELD(handleWrite, onWrite, ) 90 | FORWARD_FIELD(handleRead, onRead, ) 91 | 92 | protected: 93 | sptr render_type() override { 94 | return std::make_shared( 95 | "multipart/form-data; boundary=" + *render_boundary()); 96 | } 97 | 98 | protected: 99 | sptr _rendered_boundary = nullptr; 100 | sptr render_boundary() { 101 | return _rendered_boundary 102 | ? _rendered_boundary 103 | : _rendered_boundary = std::make_shared( 104 | util::generate_boundary( 105 | get_payload() ? get_payload()->dump() : "", 106 | _file)); 107 | } 108 | 109 | sptr render_body() override { 110 | auto boundary = render_boundary(); 111 | auto body = std::make_shared("--"); 112 | *body += *boundary; 113 | if (get_payload()) { 114 | *body += "\r\nContent-Disposition: form-data; name=\"payload_json\"" 115 | "\r\nContent-Type: application/json\r\n\r\n"; 116 | *body += get_payload()->dump(); 117 | *body += "\r\n--"; 118 | *body += *boundary; 119 | } 120 | if (_file) { 121 | *body += "\r\nContent-Disposition: form-data; name=\"file\"; " 122 | "filename=\""; 123 | *body += *_filename; 124 | *body += "\"\r\nContent-Type: "; 125 | *body += *_filetype; 126 | *body += "\r\n\r\n"; 127 | *body += *_file; 128 | *body += "\r\n--"; 129 | *body += *boundary; 130 | } 131 | *body += "--"; 132 | return std::const_pointer_cast(body); 133 | } 134 | 135 | void clear_boundary() { 136 | _rendered_boundary = nullptr; 137 | clear_type(); 138 | clear_body(); 139 | } 140 | #include "macros/defineCallClose.hh" 141 | 142 | #undef Bot 143 | 144 | #define FIELDS \ 145 | FIELD(std::string, method) \ 146 | SEPARATOR \ 147 | FIELD(std::string, target) \ 148 | SEPARATOR \ 149 | FIELD(std::string, type) \ 150 | SEPARATOR \ 151 | FIELD(std::string, body) \ 152 | SEPARATOR \ 153 | FIELD(handleWrite, onWrite) \ 154 | SEPARATOR \ 155 | FIELD(handleRead, onRead) 156 | 157 | class RenderedCall { 158 | public: 159 | #define FIELD(type, name) name(src->get_##name()) 160 | #define SEPARATOR , 161 | explicit RenderedCall(Call *src) : FIELDS {} 162 | #undef SEPARATOR 163 | #undef FIELD 164 | 165 | #define SEPARATOR , 166 | #define FIELD(type, name) const sptr &name 167 | explicit RenderedCall(FIELDS) 168 | #undef FIELD 169 | #define FIELD(type, name) name(name) 170 | : FIELDS { 171 | } 172 | #undef FIELD 173 | #undef SEPARATOR 174 | 175 | #define FIELD(type, name) const sptr name; 176 | #define SEPARATOR 177 | FIELDS 178 | #undef SEPARATOR 179 | #undef FIELD 180 | }; 181 | 182 | #undef FIELDS 183 | 184 | virtual void send(const int opcode, sptr payload, 185 | sptr callback) = 0; 186 | 187 | void run() { 188 | for (const auto &module : needInit) { 189 | if (module.second) { 190 | log::log(log::error, [module](std::ostream *log) { 191 | *log << "Forgot to initialize: " << module.first << '\n'; 192 | }); 193 | exit(1); 194 | } 195 | } 196 | runctd(); 197 | } 198 | 199 | protected: 200 | virtual void runctd() { 201 | log::log(log::error, [](std::ostream *log) { 202 | *log << "Starting run loop" << '\n'; 203 | }); 204 | work = std::make_unique>( 206 | asio::make_work_guard(*aioc)); 207 | aioc->run(); 208 | log::log(log::error, 209 | [](std::ostream *log) { *log << "Ending run loop" << '\n'; }); 210 | } 211 | 212 | virtual void connect() = 0; 213 | virtual void disconnect() { 214 | connected_ = false; 215 | ready_ = false; 216 | }; 217 | virtual void reconnect(const std::string &reason, 218 | const bool resume = true) = 0; 219 | 220 | virtual void doCall(sptr call) = 0; 221 | virtual void receivePayload(json payload) = 0; 222 | 223 | std::map needInit; 224 | unsigned int apiVersion = -1; 225 | std::unique_ptr> 226 | work; 227 | sptr aioc; 228 | std::string token; 229 | bool connecting_ = false; 230 | bool connected_ = false; 231 | bool reconnecting_ = false; 232 | bool ready_ = false; 233 | 234 | std::string user_agent_ = "DiscordBot (https://github.com/DiscordPP, 1)"; 235 | std::string encoding_ = "json"; 236 | virtual json parsePayload(const std::string& payload){ 237 | return json::parse(payload); 238 | }; 239 | virtual std::string buildPayload(const json& payload){ 240 | return payload.dump(); 241 | }; 242 | 243 | virtual void hasRateLimitPlugin() = 0; 244 | }; 245 | } // namespace discordpp 246 | -------------------------------------------------------------------------------- /discordpp/enum.hh: -------------------------------------------------------------------------------- 1 | // Generated by Discord++'s Plugin Native Gen: last commit d032f47 on 2023-02-20 23:08:27-06:00 2 | // https://github.com/DiscordPP/plugin-native-gen 3 | 4 | // Based on JSON of Discord's API: commit 21a92fa on 2023-02-24 01:18:50-06:00 5 | // https://github.com/DiscordPP/discord-api-json 6 | 7 | // Parsed by Discord++'s parser: commit aa52939 on 2023-02-24 01:19:25-06:00 8 | // https://github.com/DiscordPP/discord-api-parser 9 | 10 | // From Discord's official API docs: commit 796b772 on 2023-02-23 08:02:34-08:00 11 | // https://github.com/discord/discord-api-docs 12 | 13 | 14 | #pragma once 15 | 16 | namespace discordpp { 17 | 18 | // Application Commands // 19 | 20 | enum class ApplicationCommandType : int { 21 | CHAT_INPUT = 1, 22 | USER = 2, 23 | MESSAGE = 3 24 | }; 25 | 26 | enum class ApplicationCommandOptionType : int { 27 | SUB_COMMAND = 1, 28 | SUB_COMMAND_GROUP = 2, 29 | STRING = 3, 30 | INTEGER = 4, 31 | BOOLEAN = 5, 32 | USER = 6, 33 | CHANNEL = 7, 34 | ROLE = 8, 35 | MENTIONABLE = 9, 36 | NUMBER = 10, 37 | ATTACHMENT = 11 38 | }; 39 | 40 | enum class ApplicationCommandPermissionType : int { 41 | ROLE = 1, 42 | USER = 2, 43 | CHANNEL = 3 44 | }; 45 | 46 | 47 | // Message Components // 48 | 49 | enum class ButtonStyle : int { 50 | Primary = 1, 51 | Secondary = 2, 52 | Success = 3, 53 | Danger = 4, 54 | Link = 5 55 | }; 56 | 57 | enum class TextInputStyle : int { 58 | Short = 1, 59 | Paragraph = 2 60 | }; 61 | 62 | 63 | // Receiving and Responding // 64 | 65 | enum class InteractionType : int { 66 | PING = 1, 67 | APPLICATION_COMMAND = 2, 68 | MESSAGE_COMPONENT = 3, 69 | APPLICATION_COMMAND_AUTOCOMPLETE = 4, 70 | MODAL_SUBMIT = 5 71 | }; 72 | 73 | enum class InteractionCallbackType : int { 74 | PONG = 1, 75 | CHANNEL_MESSAGE_WITH_SOURCE = 4, 76 | DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE = 5, 77 | DEFERRED_UPDATE_MESSAGE = 6, 78 | UPDATE_MESSAGE = 7, 79 | APPLICATION_COMMAND_AUTOCOMPLETE_RESULT = 8, 80 | MODAL = 9 81 | }; 82 | 83 | 84 | // Application // 85 | 86 | enum class ApplicationFlags : long int { 87 | GATEWAY_PRESENCE = 1 << 12, 88 | GATEWAY_PRESENCE_LIMITED = 1 << 13, 89 | GATEWAY_GUILD_MEMBERS = 1 << 14, 90 | GATEWAY_GUILD_MEMBERS_LIMITED = 1 << 15, 91 | VERIFICATION_PENDING_GUILD_LIMIT = 1 << 16, 92 | EMBEDDED = 1 << 17, 93 | GATEWAY_MESSAGE_CONTENT = 1 << 18, 94 | GATEWAY_MESSAGE_CONTENT_LIMITED = 1 << 19, 95 | APPLICATION_COMMAND_BADGE = 1 << 23 96 | }; 97 | 98 | 99 | // Application Role Connection Metadata // 100 | 101 | enum class ApplicationRoleConnectionMetadataType : int { 102 | INTEGER_LESS_THAN_OR_EQUAL = 1, 103 | INTEGER_GREATER_THAN_OR_EQUAL = 2, 104 | INTEGER_EQUAL = 3, 105 | INTEGER_NOT_EQUAL = 4, 106 | DATETIME_LESS_THAN_OR_EQUAL = 5, 107 | DATETIME_GREATER_THAN_OR_EQUAL = 6, 108 | BOOLEAN_EQUAL = 7, 109 | BOOLEAN_NOT_EQUAL = 8 110 | }; 111 | 112 | 113 | // Audit Log // 114 | 115 | enum class AuditLogEvent : int { 116 | GUILD_UPDATE = 1, 117 | CHANNEL_CREATE = 10, 118 | CHANNEL_UPDATE = 11, 119 | CHANNEL_DELETE = 12, 120 | CHANNEL_OVERWRITE_CREATE = 13, 121 | CHANNEL_OVERWRITE_UPDATE = 14, 122 | CHANNEL_OVERWRITE_DELETE = 15, 123 | MEMBER_KICK = 20, 124 | MEMBER_PRUNE = 21, 125 | MEMBER_BAN_ADD = 22, 126 | MEMBER_BAN_REMOVE = 23, 127 | MEMBER_UPDATE = 24, 128 | MEMBER_ROLE_UPDATE = 25, 129 | MEMBER_MOVE = 26, 130 | MEMBER_DISCONNECT = 27, 131 | BOT_ADD = 28, 132 | ROLE_CREATE = 30, 133 | ROLE_UPDATE = 31, 134 | ROLE_DELETE = 32, 135 | INVITE_CREATE = 40, 136 | INVITE_UPDATE = 41, 137 | INVITE_DELETE = 42, 138 | WEBHOOK_CREATE = 50, 139 | WEBHOOK_UPDATE = 51, 140 | WEBHOOK_DELETE = 52, 141 | EMOJI_CREATE = 60, 142 | EMOJI_UPDATE = 61, 143 | EMOJI_DELETE = 62, 144 | MESSAGE_DELETE = 72, 145 | MESSAGE_BULK_DELETE = 73, 146 | MESSAGE_PIN = 74, 147 | MESSAGE_UNPIN = 75, 148 | INTEGRATION_CREATE = 80, 149 | INTEGRATION_UPDATE = 81, 150 | INTEGRATION_DELETE = 82, 151 | STAGE_INSTANCE_CREATE = 83, 152 | STAGE_INSTANCE_UPDATE = 84, 153 | STAGE_INSTANCE_DELETE = 85, 154 | STICKER_CREATE = 90, 155 | STICKER_UPDATE = 91, 156 | STICKER_DELETE = 92, 157 | GUILD_SCHEDULED_EVENT_CREATE = 100, 158 | GUILD_SCHEDULED_EVENT_UPDATE = 101, 159 | GUILD_SCHEDULED_EVENT_DELETE = 102, 160 | THREAD_CREATE = 110, 161 | THREAD_UPDATE = 111, 162 | THREAD_DELETE = 112, 163 | APPLICATION_COMMAND_PERMISSION_UPDATE = 121, 164 | AUTO_MODERATION_RULE_CREATE = 140, 165 | AUTO_MODERATION_RULE_UPDATE = 141, 166 | AUTO_MODERATION_RULE_DELETE = 142, 167 | AUTO_MODERATION_BLOCK_MESSAGE = 143, 168 | AUTO_MODERATION_FLAG_TO_CHANNEL = 144, 169 | AUTO_MODERATION_USER_COMMUNICATION_DISABLED = 145 170 | }; 171 | 172 | 173 | // Auto Moderation // 174 | 175 | enum class TriggerType : int { 176 | KEYWORD = 1, 177 | SPAM = 3, 178 | KEYWORD_PRESET = 4, 179 | MENTION_SPAM = 5 180 | }; 181 | 182 | enum class KeywordPresetType : int { 183 | PROFANITY = 1, 184 | SEXUAL_CONTENT = 2, 185 | SLURS = 3 186 | }; 187 | 188 | enum class EventType : int { 189 | MESSAGE_SEND = 1 190 | }; 191 | 192 | enum class ActionType : int { 193 | BLOCK_MESSAGE = 1, 194 | SEND_ALERT_MESSAGE = 2, 195 | TIMEOUT = 3 196 | }; 197 | 198 | 199 | // Channel // 200 | 201 | enum class ChannelType : int { 202 | GUILD_TEXT = 0, 203 | DM = 1, 204 | GUILD_VOICE = 2, 205 | GROUP_DM = 3, 206 | GUILD_CATEGORY = 4, 207 | GUILD_ANNOUNCEMENT = 5, 208 | ANNOUNCEMENT_THREAD = 10, 209 | PUBLIC_THREAD = 11, 210 | PRIVATE_THREAD = 12, 211 | GUILD_STAGE_VOICE = 13, 212 | GUILD_DIRECTORY = 14, 213 | GUILD_FORUM = 15 214 | }; 215 | 216 | enum class VideoQualityMode : int { 217 | AUTO = 1, 218 | FULL = 2 219 | }; 220 | 221 | enum class ChannelFlags : long int { 222 | PINNED = 1 << 1, 223 | REQUIRE_TAG = 1 << 4 224 | }; 225 | 226 | enum class SortOrderType : int { 227 | LATEST_ACTIVITY = 0, 228 | CREATION_DATE = 1 229 | }; 230 | 231 | enum class ForumLayoutType : int { 232 | NOT_SET = 0, 233 | LIST_VIEW = 1, 234 | GALLERY_VIEW = 2 235 | }; 236 | 237 | enum class MessageType : int { 238 | DEFAULT = 0, 239 | RECIPIENT_ADD = 1, 240 | RECIPIENT_REMOVE = 2, 241 | CALL = 3, 242 | CHANNEL_NAME_CHANGE = 4, 243 | CHANNEL_ICON_CHANGE = 5, 244 | CHANNEL_PINNED_MESSAGE = 6, 245 | USER_JOIN = 7, 246 | GUILD_BOOST = 8, 247 | GUILD_BOOST_TIER_1 = 9, 248 | GUILD_BOOST_TIER_2 = 10, 249 | GUILD_BOOST_TIER_3 = 11, 250 | CHANNEL_FOLLOW_ADD = 12, 251 | GUILD_DISCOVERY_DISQUALIFIED = 14, 252 | GUILD_DISCOVERY_REQUALIFIED = 15, 253 | GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING = 16, 254 | GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING = 17, 255 | THREAD_CREATED = 18, 256 | REPLY = 19, 257 | CHAT_INPUT_COMMAND = 20, 258 | THREAD_STARTER_MESSAGE = 21, 259 | GUILD_INVITE_REMINDER = 22, 260 | CONTEXT_MENU_COMMAND = 23, 261 | AUTO_MODERATION_ACTION = 24, 262 | ROLE_SUBSCRIPTION_PURCHASE = 25, 263 | INTERACTION_PREMIUM_UPSELL = 26, 264 | STAGE_START = 27, 265 | STAGE_END = 28, 266 | STAGE_SPEAKER = 29, 267 | STAGE_TOPIC = 31, 268 | GUILD_APPLICATION_PREMIUM_SUBSCRIPTION = 32 269 | }; 270 | 271 | enum class MessageActivityType : int { 272 | JOIN = 1, 273 | SPECTATE = 2, 274 | LISTEN = 3, 275 | JOIN_REQUEST = 5 276 | }; 277 | 278 | enum class MessageFlags : long int { 279 | CROSSPOSTED = 1 << 0, 280 | IS_CROSSPOST = 1 << 1, 281 | SUPPRESS_EMBEDS = 1 << 2, 282 | SOURCE_MESSAGE_DELETED = 1 << 3, 283 | URGENT = 1 << 4, 284 | HAS_THREAD = 1 << 5, 285 | EPHEMERAL = 1 << 6, 286 | LOADING = 1 << 7, 287 | FAILED_TO_MENTION_SOME_ROLES_IN_THREAD = 1 << 8, 288 | SUPPRESS_NOTIFICATIONS = 1 << 12 289 | }; 290 | 291 | enum class EmbedType { 292 | rich, 293 | image, 294 | video, 295 | gifv, 296 | article, 297 | link 298 | }; 299 | NLOHMANN_JSON_SERIALIZE_ENUM( 300 | EmbedType, 301 | { 302 | {EmbedType::rich, "rich"}, 303 | {EmbedType::image, "image"}, 304 | {EmbedType::video, "video"}, 305 | {EmbedType::gifv, "gifv"}, 306 | {EmbedType::article, "article"}, 307 | {EmbedType::link, "link"} 308 | } 309 | ); 310 | 311 | enum class AllowedMentionType { 312 | Role_Mentions, 313 | User_Mentions, 314 | Everyone_Mentions 315 | }; 316 | NLOHMANN_JSON_SERIALIZE_ENUM( 317 | AllowedMentionType, 318 | { 319 | {AllowedMentionType::Role_Mentions, "roles"}, 320 | {AllowedMentionType::User_Mentions, "users"}, 321 | {AllowedMentionType::Everyone_Mentions, "everyone"} 322 | } 323 | ); 324 | 325 | 326 | // Guild // 327 | 328 | enum class DefaultMessageNotificationLevel : int { 329 | ALL_MESSAGES = 0, 330 | ONLY_MENTIONS = 1 331 | }; 332 | 333 | enum class ExplicitContentFilterLevel : int { 334 | DISABLED = 0, 335 | MEMBERS_WITHOUT_ROLES = 1, 336 | ALL_MEMBERS = 2 337 | }; 338 | 339 | enum class MFALevel : int { 340 | NONE = 0, 341 | ELEVATED = 1 342 | }; 343 | 344 | enum class VerificationLevel : int { 345 | NONE = 0, 346 | LOW = 1, 347 | MEDIUM = 2, 348 | HIGH = 3, 349 | VERY_HIGH = 4 350 | }; 351 | 352 | enum class GuildNSFWLevel : int { 353 | DEFAULT = 0, 354 | EXPLICIT = 1, 355 | SAFE = 2, 356 | AGE_RESTRICTED = 3 357 | }; 358 | 359 | enum class PremiumTier : int { 360 | NONE = 0, 361 | TIER_1 = 1, 362 | TIER_2 = 2, 363 | TIER_3 = 3 364 | }; 365 | 366 | enum class SystemChannelFlags : long int { 367 | SUPPRESS_JOIN_NOTIFICATIONS = 1 << 0, 368 | SUPPRESS_PREMIUM_SUBSCRIPTIONS = 1 << 1, 369 | SUPPRESS_GUILD_REMINDER_NOTIFICATIONS = 1 << 2, 370 | SUPPRESS_JOIN_NOTIFICATION_REPLIES = 1 << 3, 371 | SUPPRESS_ROLE_SUBSCRIPTION_PURCHASE_NOTIFICATIONS = 1 << 4, 372 | SUPPRESS_ROLE_SUBSCRIPTION_PURCHASE_NOTIFICATION_REPLIES = 1 << 5 373 | }; 374 | 375 | enum class GuildFeature { 376 | ANIMATED_BANNER, 377 | ANIMATED_ICON, 378 | APPLICATION_COMMAND_PERMISSIONS_V2, 379 | AUTO_MODERATION, 380 | BANNER, 381 | COMMUNITY, 382 | CREATOR_MONETIZABLE_PROVISIONAL, 383 | CREATOR_STORE_PAGE, 384 | DEVELOPER_SUPPORT_SERVER, 385 | DISCOVERABLE, 386 | FEATURABLE, 387 | INVITES_DISABLED, 388 | INVITE_SPLASH, 389 | MEMBER_VERIFICATION_GATE_ENABLED, 390 | MORE_STICKERS, 391 | NEWS, 392 | PARTNERED, 393 | PREVIEW_ENABLED, 394 | ROLE_ICONS, 395 | ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE, 396 | ROLE_SUBSCRIPTIONS_ENABLED, 397 | TICKETED_EVENTS_ENABLED, 398 | VANITY_URL, 399 | VERIFIED, 400 | VIP_REGIONS, 401 | WELCOME_SCREEN_ENABLED 402 | }; 403 | NLOHMANN_JSON_SERIALIZE_ENUM( 404 | GuildFeature, 405 | { 406 | {GuildFeature::ANIMATED_BANNER, "ANIMATED_BANNER"}, 407 | {GuildFeature::ANIMATED_ICON, "ANIMATED_ICON"}, 408 | {GuildFeature::APPLICATION_COMMAND_PERMISSIONS_V2, "APPLICATION_COMMAND_PERMISSIONS_V2"}, 409 | {GuildFeature::AUTO_MODERATION, "AUTO_MODERATION"}, 410 | {GuildFeature::BANNER, "BANNER"}, 411 | {GuildFeature::COMMUNITY, "COMMUNITY"}, 412 | {GuildFeature::CREATOR_MONETIZABLE_PROVISIONAL, "CREATOR_MONETIZABLE_PROVISIONAL"}, 413 | {GuildFeature::CREATOR_STORE_PAGE, "CREATOR_STORE_PAGE"}, 414 | {GuildFeature::DEVELOPER_SUPPORT_SERVER, "DEVELOPER_SUPPORT_SERVER"}, 415 | {GuildFeature::DISCOVERABLE, "DISCOVERABLE"}, 416 | {GuildFeature::FEATURABLE, "FEATURABLE"}, 417 | {GuildFeature::INVITES_DISABLED, "INVITES_DISABLED"}, 418 | {GuildFeature::INVITE_SPLASH, "INVITE_SPLASH"}, 419 | {GuildFeature::MEMBER_VERIFICATION_GATE_ENABLED, "MEMBER_VERIFICATION_GATE_ENABLED"}, 420 | {GuildFeature::MORE_STICKERS, "MORE_STICKERS"}, 421 | {GuildFeature::NEWS, "NEWS"}, 422 | {GuildFeature::PARTNERED, "PARTNERED"}, 423 | {GuildFeature::PREVIEW_ENABLED, "PREVIEW_ENABLED"}, 424 | {GuildFeature::ROLE_ICONS, "ROLE_ICONS"}, 425 | {GuildFeature::ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE, "ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE"}, 426 | {GuildFeature::ROLE_SUBSCRIPTIONS_ENABLED, "ROLE_SUBSCRIPTIONS_ENABLED"}, 427 | {GuildFeature::TICKETED_EVENTS_ENABLED, "TICKETED_EVENTS_ENABLED"}, 428 | {GuildFeature::VANITY_URL, "VANITY_URL"}, 429 | {GuildFeature::VERIFIED, "VERIFIED"}, 430 | {GuildFeature::VIP_REGIONS, "VIP_REGIONS"}, 431 | {GuildFeature::WELCOME_SCREEN_ENABLED, "WELCOME_SCREEN_ENABLED"} 432 | } 433 | ); 434 | 435 | enum class MutableGuildFeature { 436 | COMMUNITY, 437 | INVITES_DISABLED, 438 | DISCOVERABLE 439 | }; 440 | NLOHMANN_JSON_SERIALIZE_ENUM( 441 | MutableGuildFeature, 442 | { 443 | {MutableGuildFeature::COMMUNITY, "COMMUNITY"}, 444 | {MutableGuildFeature::INVITES_DISABLED, "INVITES_DISABLED"}, 445 | {MutableGuildFeature::DISCOVERABLE, "DISCOVERABLE"} 446 | } 447 | ); 448 | 449 | enum class GuildMemberFlags : long int { 450 | DID_REJOIN = 1 << 0, 451 | COMPLETED_ONBOARDING = 1 << 1, 452 | BYPASSES_VERIFICATION = 1 << 2, 453 | STARTED_ONBOARDING = 1 << 3 454 | }; 455 | 456 | enum class IntegrationExpireBehavior : int { 457 | Remove_role = 0, 458 | Kick = 1 459 | }; 460 | 461 | enum class WidgetStyleOption { 462 | shield, 463 | banner1, 464 | banner2, 465 | banner3, 466 | banner4 467 | }; 468 | NLOHMANN_JSON_SERIALIZE_ENUM( 469 | WidgetStyleOption, 470 | { 471 | {WidgetStyleOption::shield, "shield"}, 472 | {WidgetStyleOption::banner1, "banner1"}, 473 | {WidgetStyleOption::banner2, "banner2"}, 474 | {WidgetStyleOption::banner3, "banner3"}, 475 | {WidgetStyleOption::banner4, "banner4"} 476 | } 477 | ); 478 | 479 | 480 | // Guild Scheduled Event // 481 | 482 | enum class GuildScheduledEventPrivacyLevel : int { 483 | GUILD_ONLY = 2 484 | }; 485 | 486 | enum class GuildScheduledEventEntityType : int { 487 | STAGE_INSTANCE = 1, 488 | VOICE = 2, 489 | EXTERNAL = 3 490 | }; 491 | 492 | enum class GuildScheduledEventStatus : int { 493 | SCHEDULED = 1, 494 | ACTIVE = 2, 495 | COMPLETED = 3, 496 | CANCELED = 4 497 | }; 498 | 499 | 500 | // Invite // 501 | 502 | enum class InviteTargetType : int { 503 | STREAM = 1, 504 | EMBEDDED_APPLICATION = 2 505 | }; 506 | 507 | 508 | // Stage Instance // 509 | 510 | enum class PrivacyLevel : int { 511 | PUBLIC = 1, 512 | GUILD_ONLY = 2 513 | }; 514 | 515 | 516 | // Sticker // 517 | 518 | enum class StickerType : int { 519 | STANDARD = 1, 520 | GUILD = 2 521 | }; 522 | 523 | enum class StickerFormatType : int { 524 | PNG = 1, 525 | APNG = 2, 526 | LOTTIE = 3, 527 | GIF = 4 528 | }; 529 | 530 | 531 | // User // 532 | 533 | enum class UserFlags : long int { 534 | STAFF = 1 << 0, 535 | PARTNER = 1 << 1, 536 | HYPESQUAD = 1 << 2, 537 | BUG_HUNTER_LEVEL_1 = 1 << 3, 538 | HYPESQUAD_ONLINE_HOUSE_1 = 1 << 6, 539 | HYPESQUAD_ONLINE_HOUSE_2 = 1 << 7, 540 | HYPESQUAD_ONLINE_HOUSE_3 = 1 << 8, 541 | PREMIUM_EARLY_SUPPORTER = 1 << 9, 542 | TEAM_PSEUDO_USER = 1 << 10, 543 | BUG_HUNTER_LEVEL_2 = 1 << 14, 544 | VERIFIED_BOT = 1 << 16, 545 | VERIFIED_DEVELOPER = 1 << 17, 546 | CERTIFIED_MODERATOR = 1 << 18, 547 | BOT_HTTP_INTERACTIONS = 1 << 19, 548 | ACTIVE_DEVELOPER = 1 << 22 549 | }; 550 | 551 | enum class PremiumType : int { 552 | None = 0, 553 | Nitro_Classic = 1, 554 | Nitro = 2, 555 | Nitro_Basic = 3 556 | }; 557 | 558 | enum class Service { 559 | Battle_net, 560 | eBay, 561 | Epic_Games, 562 | Facebook, 563 | GitHub, 564 | Instagram, 565 | League_of_Legends, 566 | PayPal, 567 | PlayStation_Network, 568 | Reddit, 569 | Riot_Games, 570 | Spotify, 571 | Skype, 572 | Steam, 573 | TikTok, 574 | Twitch, 575 | Twitter, 576 | Xbox, 577 | YouTube 578 | }; 579 | NLOHMANN_JSON_SERIALIZE_ENUM( 580 | Service, 581 | { 582 | {Service::Battle_net, "battlenet"}, 583 | {Service::eBay, "ebay"}, 584 | {Service::Epic_Games, "epicgames"}, 585 | {Service::Facebook, "facebook"}, 586 | {Service::GitHub, "github"}, 587 | {Service::Instagram, "instagram"}, 588 | {Service::League_of_Legends, "leagueoflegends"}, 589 | {Service::PayPal, "paypal"}, 590 | {Service::PlayStation_Network, "playstation"}, 591 | {Service::Reddit, "reddit"}, 592 | {Service::Riot_Games, "riotgames"}, 593 | {Service::Spotify, "spotify"}, 594 | {Service::Skype, "skype"}, 595 | {Service::Steam, "steam"}, 596 | {Service::TikTok, "tiktok"}, 597 | {Service::Twitch, "twitch"}, 598 | {Service::Twitter, "twitter"}, 599 | {Service::Xbox, "xbox"}, 600 | {Service::YouTube, "youtube"} 601 | } 602 | ); 603 | 604 | enum class VisibilityType : int { 605 | None = 0, 606 | Everyone = 1 607 | }; 608 | 609 | 610 | // Webhook // 611 | 612 | enum class WebhookType : int { 613 | Incoming = 1, 614 | Channel_Follower = 2, 615 | Application = 3 616 | }; 617 | 618 | 619 | // Gateway // 620 | 621 | enum class GatewayCommand { 622 | Identify, 623 | Resume, 624 | Heartbeat, 625 | Request_Guild_Members, 626 | Update_Voice_State, 627 | Update_Presence 628 | }; 629 | NLOHMANN_JSON_SERIALIZE_ENUM( 630 | GatewayCommand, 631 | { 632 | {GatewayCommand::Identify, "Identify"}, 633 | {GatewayCommand::Resume, "Resume"}, 634 | {GatewayCommand::Heartbeat, "Heartbeat"}, 635 | {GatewayCommand::Request_Guild_Members, "Request Guild Members"}, 636 | {GatewayCommand::Update_Voice_State, "Update Voice State"}, 637 | {GatewayCommand::Update_Presence, "Update Presence"} 638 | } 639 | ); 640 | 641 | enum class GatewayEvent { 642 | Hello, 643 | Ready, 644 | Resumed, 645 | Reconnect, 646 | Invalid_Session, 647 | Application_Command_Permissions_Update, 648 | Auto_Moderation_Rule_Create, 649 | Auto_Moderation_Rule_Update, 650 | Auto_Moderation_Rule_Delete, 651 | Auto_Moderation_Action_Execution, 652 | Channel_Create, 653 | Channel_Update, 654 | Channel_Delete, 655 | Channel_Pins_Update, 656 | Thread_Create, 657 | Thread_Update, 658 | Thread_Delete, 659 | Thread_List_Sync, 660 | Thread_Member_Update, 661 | Thread_Members_Update, 662 | Guild_Create, 663 | Guild_Update, 664 | Guild_Delete, 665 | Guild_Ban_Add, 666 | Guild_Ban_Remove, 667 | Guild_Emojis_Update, 668 | Guild_Stickers_Update, 669 | Guild_Integrations_Update, 670 | Guild_Member_Add, 671 | Guild_Member_Remove, 672 | Guild_Member_Update, 673 | Guild_Members_Chunk, 674 | Guild_Role_Create, 675 | Guild_Role_Update, 676 | Guild_Role_Delete, 677 | Guild_Scheduled_Event_Create, 678 | Guild_Scheduled_Event_Update, 679 | Guild_Scheduled_Event_Delete, 680 | Guild_Scheduled_Event_User_Add, 681 | Guild_Scheduled_Event_User_Remove, 682 | Integration_Create, 683 | Integration_Update, 684 | Integration_Delete, 685 | Interaction_Create, 686 | Invite_Create, 687 | Invite_Delete, 688 | Message_Create, 689 | Message_Update, 690 | Message_Delete, 691 | Message_Delete_Bulk, 692 | Message_Reaction_Add, 693 | Message_Reaction_Remove, 694 | Message_Reaction_Remove_All, 695 | Message_Reaction_Remove_Emoji, 696 | Presence_Update, 697 | Stage_Instance_Create, 698 | Stage_Instance_Delete, 699 | Stage_Instance_Update, 700 | Typing_Start, 701 | User_Update, 702 | Voice_State_Update, 703 | Voice_Server_Update, 704 | Webhooks_Update 705 | }; 706 | NLOHMANN_JSON_SERIALIZE_ENUM( 707 | GatewayEvent, 708 | { 709 | {GatewayEvent::Hello, "Hello"}, 710 | {GatewayEvent::Ready, "Ready"}, 711 | {GatewayEvent::Resumed, "Resumed"}, 712 | {GatewayEvent::Reconnect, "Reconnect"}, 713 | {GatewayEvent::Invalid_Session, "Invalid Session"}, 714 | {GatewayEvent::Application_Command_Permissions_Update, "Application Command Permissions Update"}, 715 | {GatewayEvent::Auto_Moderation_Rule_Create, "Auto Moderation Rule Create"}, 716 | {GatewayEvent::Auto_Moderation_Rule_Update, "Auto Moderation Rule Update"}, 717 | {GatewayEvent::Auto_Moderation_Rule_Delete, "Auto Moderation Rule Delete"}, 718 | {GatewayEvent::Auto_Moderation_Action_Execution, "Auto Moderation Action Execution"}, 719 | {GatewayEvent::Channel_Create, "Channel Create"}, 720 | {GatewayEvent::Channel_Update, "Channel Update"}, 721 | {GatewayEvent::Channel_Delete, "Channel Delete"}, 722 | {GatewayEvent::Channel_Pins_Update, "Channel Pins Update"}, 723 | {GatewayEvent::Thread_Create, "Thread Create"}, 724 | {GatewayEvent::Thread_Update, "Thread Update"}, 725 | {GatewayEvent::Thread_Delete, "Thread Delete"}, 726 | {GatewayEvent::Thread_List_Sync, "Thread List Sync"}, 727 | {GatewayEvent::Thread_Member_Update, "Thread Member Update"}, 728 | {GatewayEvent::Thread_Members_Update, "Thread Members Update"}, 729 | {GatewayEvent::Guild_Create, "Guild Create"}, 730 | {GatewayEvent::Guild_Update, "Guild Update"}, 731 | {GatewayEvent::Guild_Delete, "Guild Delete"}, 732 | {GatewayEvent::Guild_Ban_Add, "Guild Ban Add"}, 733 | {GatewayEvent::Guild_Ban_Remove, "Guild Ban Remove"}, 734 | {GatewayEvent::Guild_Emojis_Update, "Guild Emojis Update"}, 735 | {GatewayEvent::Guild_Stickers_Update, "Guild Stickers Update"}, 736 | {GatewayEvent::Guild_Integrations_Update, "Guild Integrations Update"}, 737 | {GatewayEvent::Guild_Member_Add, "Guild Member Add"}, 738 | {GatewayEvent::Guild_Member_Remove, "Guild Member Remove"}, 739 | {GatewayEvent::Guild_Member_Update, "Guild Member Update"}, 740 | {GatewayEvent::Guild_Members_Chunk, "Guild Members Chunk"}, 741 | {GatewayEvent::Guild_Role_Create, "Guild Role Create"}, 742 | {GatewayEvent::Guild_Role_Update, "Guild Role Update"}, 743 | {GatewayEvent::Guild_Role_Delete, "Guild Role Delete"}, 744 | {GatewayEvent::Guild_Scheduled_Event_Create, "Guild Scheduled Event Create"}, 745 | {GatewayEvent::Guild_Scheduled_Event_Update, "Guild Scheduled Event Update"}, 746 | {GatewayEvent::Guild_Scheduled_Event_Delete, "Guild Scheduled Event Delete"}, 747 | {GatewayEvent::Guild_Scheduled_Event_User_Add, "Guild Scheduled Event User Add"}, 748 | {GatewayEvent::Guild_Scheduled_Event_User_Remove, "Guild Scheduled Event User Remove"}, 749 | {GatewayEvent::Integration_Create, "Integration Create"}, 750 | {GatewayEvent::Integration_Update, "Integration Update"}, 751 | {GatewayEvent::Integration_Delete, "Integration Delete"}, 752 | {GatewayEvent::Interaction_Create, "Interaction Create"}, 753 | {GatewayEvent::Invite_Create, "Invite Create"}, 754 | {GatewayEvent::Invite_Delete, "Invite Delete"}, 755 | {GatewayEvent::Message_Create, "Message Create"}, 756 | {GatewayEvent::Message_Update, "Message Update"}, 757 | {GatewayEvent::Message_Delete, "Message Delete"}, 758 | {GatewayEvent::Message_Delete_Bulk, "Message Delete Bulk"}, 759 | {GatewayEvent::Message_Reaction_Add, "Message Reaction Add"}, 760 | {GatewayEvent::Message_Reaction_Remove, "Message Reaction Remove"}, 761 | {GatewayEvent::Message_Reaction_Remove_All, "Message Reaction Remove All"}, 762 | {GatewayEvent::Message_Reaction_Remove_Emoji, "Message Reaction Remove Emoji"}, 763 | {GatewayEvent::Presence_Update, "Presence Update"}, 764 | {GatewayEvent::Stage_Instance_Create, "Stage Instance Create"}, 765 | {GatewayEvent::Stage_Instance_Delete, "Stage Instance Delete"}, 766 | {GatewayEvent::Stage_Instance_Update, "Stage Instance Update"}, 767 | {GatewayEvent::Typing_Start, "Typing Start"}, 768 | {GatewayEvent::User_Update, "User Update"}, 769 | {GatewayEvent::Voice_State_Update, "Voice State Update"}, 770 | {GatewayEvent::Voice_Server_Update, "Voice Server Update"}, 771 | {GatewayEvent::Webhooks_Update, "Webhooks Update"} 772 | } 773 | ); 774 | 775 | enum class StatusType { 776 | online, 777 | dnd, 778 | idle, 779 | invisible, 780 | offline 781 | }; 782 | NLOHMANN_JSON_SERIALIZE_ENUM( 783 | StatusType, 784 | { 785 | {StatusType::online, "online"}, 786 | {StatusType::dnd, "dnd"}, 787 | {StatusType::idle, "idle"}, 788 | {StatusType::invisible, "invisible"}, 789 | {StatusType::offline, "offline"} 790 | } 791 | ); 792 | 793 | enum class ActivityType : int { 794 | Game = 0, 795 | Streaming = 1, 796 | Listening = 2, 797 | Watching = 3, 798 | Custom = 4, 799 | Competing = 5 800 | }; 801 | 802 | enum class ActivityFlags : long int { 803 | INSTANCE = 1 << 0, 804 | JOIN = 1 << 1, 805 | SPECTATE = 1 << 2, 806 | JOIN_REQUEST = 1 << 3, 807 | SYNC = 1 << 4, 808 | PLAY = 1 << 5, 809 | PARTY_PRIVACY_FRIENDS = 1 << 6, 810 | PARTY_PRIVACY_VOICE_CHANNEL = 1 << 7, 811 | EMBEDDED = 1 << 8 812 | }; 813 | 814 | 815 | // Gateway Events // 816 | 817 | enum class SendEvent { 818 | Identify, 819 | Resume, 820 | Heartbeat, 821 | Request_Guild_Members, 822 | Update_Voice_State, 823 | Update_Presence 824 | }; 825 | NLOHMANN_JSON_SERIALIZE_ENUM( 826 | SendEvent, 827 | { 828 | {SendEvent::Identify, "Identify"}, 829 | {SendEvent::Resume, "Resume"}, 830 | {SendEvent::Heartbeat, "Heartbeat"}, 831 | {SendEvent::Request_Guild_Members, "Request Guild Members"}, 832 | {SendEvent::Update_Voice_State, "Update Voice State"}, 833 | {SendEvent::Update_Presence, "Update Presence"} 834 | } 835 | ); 836 | 837 | enum class ReceiveEvent { 838 | Hello, 839 | Ready, 840 | Resumed, 841 | Reconnect, 842 | Invalid_Session, 843 | Application_Command_Permissions_Update, 844 | Auto_Moderation_Rule_Create, 845 | Auto_Moderation_Rule_Update, 846 | Auto_Moderation_Rule_Delete, 847 | Auto_Moderation_Action_Execution, 848 | Channel_Create, 849 | Channel_Update, 850 | Channel_Delete, 851 | Channel_Pins_Update, 852 | Thread_Create, 853 | Thread_Update, 854 | Thread_Delete, 855 | Thread_List_Sync, 856 | Thread_Member_Update, 857 | Thread_Members_Update, 858 | Guild_Create, 859 | Guild_Update, 860 | Guild_Delete, 861 | Guild_Audit_Log_Entry_Create, 862 | Guild_Ban_Add, 863 | Guild_Ban_Remove, 864 | Guild_Emojis_Update, 865 | Guild_Stickers_Update, 866 | Guild_Integrations_Update, 867 | Guild_Member_Add, 868 | Guild_Member_Remove, 869 | Guild_Member_Update, 870 | Guild_Members_Chunk, 871 | Guild_Role_Create, 872 | Guild_Role_Update, 873 | Guild_Role_Delete, 874 | Guild_Scheduled_Event_Create, 875 | Guild_Scheduled_Event_Update, 876 | Guild_Scheduled_Event_Delete, 877 | Guild_Scheduled_Event_User_Add, 878 | Guild_Scheduled_Event_User_Remove, 879 | Integration_Create, 880 | Integration_Update, 881 | Integration_Delete, 882 | Interaction_Create, 883 | Invite_Create, 884 | Invite_Delete, 885 | Message_Create, 886 | Message_Update, 887 | Message_Delete, 888 | Message_Delete_Bulk, 889 | Message_Reaction_Add, 890 | Message_Reaction_Remove, 891 | Message_Reaction_Remove_All, 892 | Message_Reaction_Remove_Emoji, 893 | Presence_Update, 894 | Stage_Instance_Create, 895 | Stage_Instance_Update, 896 | Stage_Instance_Delete, 897 | Typing_Start, 898 | User_Update, 899 | Voice_State_Update, 900 | Voice_Server_Update, 901 | Webhooks_Update 902 | }; 903 | NLOHMANN_JSON_SERIALIZE_ENUM( 904 | ReceiveEvent, 905 | { 906 | {ReceiveEvent::Hello, "Hello"}, 907 | {ReceiveEvent::Ready, "Ready"}, 908 | {ReceiveEvent::Resumed, "Resumed"}, 909 | {ReceiveEvent::Reconnect, "Reconnect"}, 910 | {ReceiveEvent::Invalid_Session, "Invalid Session"}, 911 | {ReceiveEvent::Application_Command_Permissions_Update, "Application Command Permissions Update"}, 912 | {ReceiveEvent::Auto_Moderation_Rule_Create, "Auto Moderation Rule Create"}, 913 | {ReceiveEvent::Auto_Moderation_Rule_Update, "Auto Moderation Rule Update"}, 914 | {ReceiveEvent::Auto_Moderation_Rule_Delete, "Auto Moderation Rule Delete"}, 915 | {ReceiveEvent::Auto_Moderation_Action_Execution, "Auto Moderation Action Execution"}, 916 | {ReceiveEvent::Channel_Create, "Channel Create"}, 917 | {ReceiveEvent::Channel_Update, "Channel Update"}, 918 | {ReceiveEvent::Channel_Delete, "Channel Delete"}, 919 | {ReceiveEvent::Channel_Pins_Update, "Channel Pins Update"}, 920 | {ReceiveEvent::Thread_Create, "Thread Create"}, 921 | {ReceiveEvent::Thread_Update, "Thread Update"}, 922 | {ReceiveEvent::Thread_Delete, "Thread Delete"}, 923 | {ReceiveEvent::Thread_List_Sync, "Thread List Sync"}, 924 | {ReceiveEvent::Thread_Member_Update, "Thread Member Update"}, 925 | {ReceiveEvent::Thread_Members_Update, "Thread Members Update"}, 926 | {ReceiveEvent::Guild_Create, "Guild Create"}, 927 | {ReceiveEvent::Guild_Update, "Guild Update"}, 928 | {ReceiveEvent::Guild_Delete, "Guild Delete"}, 929 | {ReceiveEvent::Guild_Audit_Log_Entry_Create, "Guild Audit Log Entry Create"}, 930 | {ReceiveEvent::Guild_Ban_Add, "Guild Ban Add"}, 931 | {ReceiveEvent::Guild_Ban_Remove, "Guild Ban Remove"}, 932 | {ReceiveEvent::Guild_Emojis_Update, "Guild Emojis Update"}, 933 | {ReceiveEvent::Guild_Stickers_Update, "Guild Stickers Update"}, 934 | {ReceiveEvent::Guild_Integrations_Update, "Guild Integrations Update"}, 935 | {ReceiveEvent::Guild_Member_Add, "Guild Member Add"}, 936 | {ReceiveEvent::Guild_Member_Remove, "Guild Member Remove"}, 937 | {ReceiveEvent::Guild_Member_Update, "Guild Member Update"}, 938 | {ReceiveEvent::Guild_Members_Chunk, "Guild Members Chunk"}, 939 | {ReceiveEvent::Guild_Role_Create, "Guild Role Create"}, 940 | {ReceiveEvent::Guild_Role_Update, "Guild Role Update"}, 941 | {ReceiveEvent::Guild_Role_Delete, "Guild Role Delete"}, 942 | {ReceiveEvent::Guild_Scheduled_Event_Create, "Guild Scheduled Event Create"}, 943 | {ReceiveEvent::Guild_Scheduled_Event_Update, "Guild Scheduled Event Update"}, 944 | {ReceiveEvent::Guild_Scheduled_Event_Delete, "Guild Scheduled Event Delete"}, 945 | {ReceiveEvent::Guild_Scheduled_Event_User_Add, "Guild Scheduled Event User Add"}, 946 | {ReceiveEvent::Guild_Scheduled_Event_User_Remove, "Guild Scheduled Event User Remove"}, 947 | {ReceiveEvent::Integration_Create, "Integration Create"}, 948 | {ReceiveEvent::Integration_Update, "Integration Update"}, 949 | {ReceiveEvent::Integration_Delete, "Integration Delete"}, 950 | {ReceiveEvent::Interaction_Create, "Interaction Create"}, 951 | {ReceiveEvent::Invite_Create, "Invite Create"}, 952 | {ReceiveEvent::Invite_Delete, "Invite Delete"}, 953 | {ReceiveEvent::Message_Create, "Message Create"}, 954 | {ReceiveEvent::Message_Update, "Message Update"}, 955 | {ReceiveEvent::Message_Delete, "Message Delete"}, 956 | {ReceiveEvent::Message_Delete_Bulk, "Message Delete Bulk"}, 957 | {ReceiveEvent::Message_Reaction_Add, "Message Reaction Add"}, 958 | {ReceiveEvent::Message_Reaction_Remove, "Message Reaction Remove"}, 959 | {ReceiveEvent::Message_Reaction_Remove_All, "Message Reaction Remove All"}, 960 | {ReceiveEvent::Message_Reaction_Remove_Emoji, "Message Reaction Remove Emoji"}, 961 | {ReceiveEvent::Presence_Update, "Presence Update"}, 962 | {ReceiveEvent::Stage_Instance_Create, "Stage Instance Create"}, 963 | {ReceiveEvent::Stage_Instance_Update, "Stage Instance Update"}, 964 | {ReceiveEvent::Stage_Instance_Delete, "Stage Instance Delete"}, 965 | {ReceiveEvent::Typing_Start, "Typing Start"}, 966 | {ReceiveEvent::User_Update, "User Update"}, 967 | {ReceiveEvent::Voice_State_Update, "Voice State Update"}, 968 | {ReceiveEvent::Voice_Server_Update, "Voice Server Update"}, 969 | {ReceiveEvent::Webhooks_Update, "Webhooks Update"} 970 | } 971 | ); 972 | 973 | 974 | // OAuth2 // 975 | 976 | enum class OAuth2Scope { 977 | activities_read, 978 | activities_write, 979 | applications_builds_read, 980 | applications_builds_upload, 981 | applications_commands, 982 | applications_commands_update, 983 | applications_commands_permissions_update, 984 | applications_entitlements, 985 | applications_store_update, 986 | bot, 987 | connections, 988 | dm_channels_read, 989 | email, 990 | gdm_join, 991 | guilds, 992 | guilds_join, 993 | guilds_members_read, 994 | identify, 995 | messages_read, 996 | relationships_read, 997 | role_connections_write, 998 | rpc, 999 | rpc_activities_write, 1000 | rpc_notifications_read, 1001 | rpc_voice_read, 1002 | rpc_voice_write, 1003 | voice, 1004 | webhook_incoming 1005 | }; 1006 | NLOHMANN_JSON_SERIALIZE_ENUM( 1007 | OAuth2Scope, 1008 | { 1009 | {OAuth2Scope::activities_read, "activities.read"}, 1010 | {OAuth2Scope::activities_write, "activities.write"}, 1011 | {OAuth2Scope::applications_builds_read, "applications.builds.read"}, 1012 | {OAuth2Scope::applications_builds_upload, "applications.builds.upload"}, 1013 | {OAuth2Scope::applications_commands, "applications.commands"}, 1014 | {OAuth2Scope::applications_commands_update, "applications.commands.update"}, 1015 | {OAuth2Scope::applications_commands_permissions_update, "applications.commands.permissions.update"}, 1016 | {OAuth2Scope::applications_entitlements, "applications.entitlements"}, 1017 | {OAuth2Scope::applications_store_update, "applications.store.update"}, 1018 | {OAuth2Scope::bot, "bot"}, 1019 | {OAuth2Scope::connections, "connections"}, 1020 | {OAuth2Scope::dm_channels_read, "dm_channels.read"}, 1021 | {OAuth2Scope::email, "email"}, 1022 | {OAuth2Scope::gdm_join, "gdm.join"}, 1023 | {OAuth2Scope::guilds, "guilds"}, 1024 | {OAuth2Scope::guilds_join, "guilds.join"}, 1025 | {OAuth2Scope::guilds_members_read, "guilds.members.read"}, 1026 | {OAuth2Scope::identify, "identify"}, 1027 | {OAuth2Scope::messages_read, "messages.read"}, 1028 | {OAuth2Scope::relationships_read, "relationships.read"}, 1029 | {OAuth2Scope::role_connections_write, "role_connections.write"}, 1030 | {OAuth2Scope::rpc, "rpc"}, 1031 | {OAuth2Scope::rpc_activities_write, "rpc.activities.write"}, 1032 | {OAuth2Scope::rpc_notifications_read, "rpc.notifications.read"}, 1033 | {OAuth2Scope::rpc_voice_read, "rpc.voice.read"}, 1034 | {OAuth2Scope::rpc_voice_write, "rpc.voice.write"}, 1035 | {OAuth2Scope::voice, "voice"}, 1036 | {OAuth2Scope::webhook_incoming, "webhook.incoming"} 1037 | } 1038 | ); 1039 | 1040 | enum class BotAuthParameter { 1041 | client_id, 1042 | scope, 1043 | permissions, 1044 | guild_id, 1045 | disable_guild_select 1046 | }; 1047 | NLOHMANN_JSON_SERIALIZE_ENUM( 1048 | BotAuthParameter, 1049 | { 1050 | {BotAuthParameter::client_id, "client_id"}, 1051 | {BotAuthParameter::scope, "scope"}, 1052 | {BotAuthParameter::permissions, "permissions"}, 1053 | {BotAuthParameter::guild_id, "guild_id"}, 1054 | {BotAuthParameter::disable_guild_select, "disable_guild_select"} 1055 | } 1056 | ); 1057 | 1058 | 1059 | // Permissions // 1060 | 1061 | enum class BitwisePermissionFlags : long int { 1062 | CREATE_INSTANT_INVITE = 0x0000000000000001, 1063 | KICK_MEMBERS = 0x0000000000000002, 1064 | BAN_MEMBERS = 0x0000000000000004, 1065 | ADMINISTRATOR = 0x0000000000000008, 1066 | MANAGE_CHANNELS = 0x0000000000000010, 1067 | MANAGE_GUILD = 0x0000000000000020, 1068 | ADD_REACTIONS = 0x0000000000000040, 1069 | VIEW_AUDIT_LOG = 0x0000000000000080, 1070 | PRIORITY_SPEAKER = 0x0000000000000100, 1071 | STREAM = 0x0000000000000200, 1072 | VIEW_CHANNEL = 0x0000000000000400, 1073 | SEND_MESSAGES = 0x0000000000000800, 1074 | SEND_TTS_MESSAGES = 0x0000000000001000, 1075 | MANAGE_MESSAGES = 0x0000000000002000, 1076 | EMBED_LINKS = 0x0000000000004000, 1077 | ATTACH_FILES = 0x0000000000008000, 1078 | READ_MESSAGE_HISTORY = 0x0000000000010000, 1079 | MENTION_EVERYONE = 0x0000000000020000, 1080 | USE_EXTERNAL_EMOJIS = 0x0000000000040000, 1081 | VIEW_GUILD_INSIGHTS = 0x0000000000080000, 1082 | CONNECT = 0x0000000000100000, 1083 | SPEAK = 0x0000000000200000, 1084 | MUTE_MEMBERS = 0x0000000000400000, 1085 | DEAFEN_MEMBERS = 0x0000000000800000, 1086 | MOVE_MEMBERS = 0x0000000001000000, 1087 | USE_VAD = 0x0000000002000000, 1088 | CHANGE_NICKNAME = 0x0000000004000000, 1089 | MANAGE_NICKNAMES = 0x0000000008000000, 1090 | MANAGE_ROLES = 0x0000000010000000, 1091 | MANAGE_WEBHOOKS = 0x0000000020000000, 1092 | MANAGE_EMOJIS_AND_STICKERS = 0x0000000040000000, 1093 | USE_APPLICATION_COMMANDS = 0x0000000080000000, 1094 | REQUEST_TO_SPEAK = 0x0000000100000000, 1095 | MANAGE_EVENTS = 0x0000000200000000, 1096 | MANAGE_THREADS = 0x0000000400000000, 1097 | CREATE_PUBLIC_THREADS = 0x0000000800000000, 1098 | CREATE_PRIVATE_THREADS = 0x0000001000000000, 1099 | USE_EXTERNAL_STICKERS = 0x0000002000000000, 1100 | SEND_MESSAGES_IN_THREADS = 0x0000004000000000, 1101 | USE_EMBEDDED_ACTIVITIES = 0x0000008000000000, 1102 | MODERATE_MEMBERS = 0x0000010000000000 1103 | }; 1104 | 1105 | 1106 | // Teams // 1107 | 1108 | enum class MembershipStateEnum : int { 1109 | INVITED = 1, 1110 | ACCEPTED = 2 1111 | }; 1112 | 1113 | 1114 | // Voice Connections // 1115 | 1116 | enum class Speaking : long int { 1117 | Microphone = 1 << 0, 1118 | Soundshare = 1 << 1, 1119 | Priority = 1 << 2 1120 | }; 1121 | 1122 | } // namespace discordpp 1123 | -------------------------------------------------------------------------------- /discordpp/intents.hh: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Aidan on 11/22/2020. 3 | // 4 | 5 | #ifndef ECHO_BOT_INTENTS_HH 6 | #define ECHO_BOT_INTENTS_HH 7 | 8 | namespace discordpp{ 9 | namespace intents{ 10 | const uint16_t NONE = 0; 11 | 12 | const uint16_t GUILDS = 1u << 0u; 13 | // GUILD_CREATE 14 | // GUILD_UPDATE 15 | // GUILD_DELETE 16 | // GUILD_ROLE_CREATE 17 | // GUILD_ROLE_UPDATE 18 | // GUILD_ROLE_DELETE 19 | // CHANNEL_CREATE 20 | // CHANNEL_UPDATE 21 | // CHANNEL_DELETE 22 | // CHANNEL_PINS_UPDATE 23 | 24 | const uint16_t GUILD_MEMBERS = 1u << 1u; 25 | // GUILD_MEMBER_ADD 26 | // GUILD_MEMBER_UPDATE 27 | // GUILD_MEMBER_REMOVE 28 | 29 | const uint16_t GUILD_BANS = 1u << 2u; 30 | // GUILD_BAN_ADD 31 | // GUILD_BAN_REMOVE 32 | 33 | const uint16_t GUILD_EMOJIS = 1u << 3u; 34 | // GUILD_EMOJIS_UPDATE 35 | 36 | const uint16_t GUILD_INTEGRATIONS = 1u << 4u; 37 | // GUILD_INTEGRATIONS_UPDATE 38 | 39 | const uint16_t GUILD_WEBHOOKS = 1u << 5u; 40 | // WEBHOOKS_UPDATE 41 | 42 | const uint16_t GUILD_INVITES = 1u << 6u; 43 | // INVITE_CREATE 44 | // INVITE_DELETE 45 | 46 | const uint16_t GUILD_VOICE_STATES = 1u << 7u; 47 | // VOICE_STATE_UPDATE 48 | 49 | const uint16_t GUILD_PRESENCES = 1u << 8u; 50 | // PRESENCE_UPDATE 51 | 52 | const uint16_t GUILD_MESSAGES = 1u << 9u; 53 | // MESSAGE_CREATE 54 | // MESSAGE_UPDATE 55 | // MESSAGE_DELETE 56 | // MESSAGE_DELETE_BULK 57 | 58 | const uint16_t GUILD_MESSAGE_REACTIONS = 1u << 10u; 59 | // MESSAGE_REACTION_ADD 60 | // MESSAGE_REACTION_REMOVE 61 | // MESSAGE_REACTION_REMOVE_ALL 62 | // MESSAGE_REACTION_REMOVE_EMOJI 63 | 64 | const uint16_t GUILD_MESSAGE_TYPING = 1u << 11u; 65 | // TYPING_START 66 | 67 | const uint16_t DIRECT_MESSAGES = 1u << 12u; 68 | // MESSAGE_CREATE 69 | // MESSAGE_UPDATE 70 | // MESSAGE_DELETE 71 | // CHANNEL_PINS_UPDATE 72 | 73 | const uint16_t DIRECT_MESSAGE_REACTIONS = 1u << 13u; 74 | // MESSAGE_REACTION_ADD 75 | // MESSAGE_REACTION_REMOVE 76 | // MESSAGE_REACTION_REMOVE_ALL 77 | // MESSAGE_REACTION_REMOVE_EMOJI 78 | 79 | const uint16_t DIRECT_MESSAGE_TYPING = 1u << 14u; 80 | // TYPING_START 81 | } 82 | } 83 | 84 | #endif // ECHO_BOT_INTENTS_HH 85 | -------------------------------------------------------------------------------- /discordpp/log.hh: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Aidan on 5/27/2020. 3 | // 4 | 5 | #ifndef ECHO_BOT_LOG_HH 6 | #define ECHO_BOT_LOG_HH 7 | 8 | #include 9 | #include 10 | 11 | namespace discordpp { 12 | namespace log { 13 | using handleLog = std::function; 14 | 15 | enum level { trace, debug, info, warning, error, fatal }; 16 | inline level filter = warning; 17 | inline std::ostream *out = &std::cout; 18 | 19 | inline void log(level l, handleLog msg) { 20 | if (l >= filter) { 21 | msg(out); 22 | } 23 | } 24 | } // namespace log 25 | } // namespace discordpp 26 | 27 | #endif // ECHO_BOT_LOG_HH 28 | -------------------------------------------------------------------------------- /discordpp/macros.hh: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Aidan on 2/24/2021. 3 | // 4 | 5 | #pragma once 6 | 7 | // https://stackoverflow.com/a/26408195 8 | // get number of arguments with __DPP_NARG__ 9 | #define __DPP_NARG__(...) __DPP_NARG_I_(__VA_ARGS__, __DPP_RSEQ_N()) 10 | #define __DPP_NARG_I_(...) __DPP_ARG_N(__VA_ARGS__) 11 | #define __DPP_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ 12 | _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, \ 13 | _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ 14 | _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, \ 15 | _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, \ 16 | _58, _59, _60, _61, _62, _63, N, ...) \ 17 | N 18 | #define __DPP_RSEQ_N() \ 19 | 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, \ 20 | 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, \ 21 | 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, \ 22 | 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 23 | 24 | // general definition for any function name 25 | #define _DPP_VFUNC_(name, n) name##n 26 | #define _DPP_VFUNC(name, n) _DPP_VFUNC_(name, n) 27 | #define DPP_VFUNC(func, ...) \ 28 | _DPP_VFUNC(func, __DPP_NARG__(__VA_ARGS__))(__VA_ARGS__) 29 | 30 | // https://stackoverflow.com/a/11994395 31 | // Make a FOREACH macro 32 | #define DPP_FE_0(WHAT) 33 | #define DPP_FE_1(WHAT, X) WHAT(X) 34 | #define DPP_FE_2(WHAT, X, ...) WHAT(X) DPP_FE_1(WHAT, __VA_ARGS__) 35 | #define DPP_FE_3(WHAT, X, ...) WHAT(X) DPP_FE_2(WHAT, __VA_ARGS__) 36 | #define DPP_FE_4(WHAT, X, ...) WHAT(X) DPP_FE_3(WHAT, __VA_ARGS__) 37 | #define DPP_FE_5(WHAT, X, ...) WHAT(X) DPP_FE_4(WHAT, __VA_ARGS__) 38 | #define DPP_FE_6(WHAT, X, ...) WHAT(X) DPP_FE_5(WHAT, __VA_ARGS__) 39 | #define DPP_FE_7(WHAT, X, ...) WHAT(X) DPP_FE_6(WHAT, __VA_ARGS__) 40 | #define DPP_FE_8(WHAT, X, ...) WHAT(X) DPP_FE_7(WHAT, __VA_ARGS__) 41 | #define DPP_FE_9(WHAT, X, ...) WHAT(X) DPP_FE_8(WHAT, __VA_ARGS__) 42 | #define DPP_FE_10(WHAT, X, ...) WHAT(X) DPP_FE_9(WHAT, __VA_ARGS__) 43 | #define DPP_FE_11(WHAT, X, ...) WHAT(X) DPP_FE_10(WHAT, __VA_ARGS__) 44 | #define DPP_FE_12(WHAT, X, ...) WHAT(X) DPP_FE_11(WHAT, __VA_ARGS__) 45 | #define DPP_FE_13(WHAT, X, ...) WHAT(X) DPP_FE_12(WHAT, __VA_ARGS__) 46 | #define DPP_FE_14(WHAT, X, ...) WHAT(X) DPP_FE_13(WHAT, __VA_ARGS__) 47 | #define DPP_FE_15(WHAT, X, ...) WHAT(X) DPP_FE_14(WHAT, __VA_ARGS__) 48 | #define DPP_FE_16(WHAT, X, ...) WHAT(X) DPP_FE_15(WHAT, __VA_ARGS__) 49 | #define DPP_FE_17(WHAT, X, ...) WHAT(X) DPP_FE_16(WHAT, __VA_ARGS__) 50 | #define DPP_FE_18(WHAT, X, ...) WHAT(X) DPP_FE_17(WHAT, __VA_ARGS__) 51 | #define DPP_FE_19(WHAT, X, ...) WHAT(X) DPP_FE_18(WHAT, __VA_ARGS__) 52 | #define DPP_FE_20(WHAT, X, ...) WHAT(X) DPP_FE_19(WHAT, __VA_ARGS__) 53 | #define DPP_FE_21(WHAT, X, ...) WHAT(X) DPP_FE_20(WHAT, __VA_ARGS__) 54 | #define DPP_FE_22(WHAT, X, ...) WHAT(X) DPP_FE_21(WHAT, __VA_ARGS__) 55 | #define DPP_FE_23(WHAT, X, ...) WHAT(X) DPP_FE_22(WHAT, __VA_ARGS__) 56 | #define DPP_FE_24(WHAT, X, ...) WHAT(X) DPP_FE_23(WHAT, __VA_ARGS__) 57 | #define DPP_FE_25(WHAT, X, ...) WHAT(X) DPP_FE_24(WHAT, __VA_ARGS__) 58 | //... repeat as needed 59 | 60 | #define DPP_GET_MACRO(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \ 61 | _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, \ 62 | _24, _25, NAME, ...) \ 63 | NAME 64 | #define DPP_FOR_EACH(action, ...) \ 65 | DPP_GET_MACRO(_0, __VA_ARGS__, DPP_FE_25, DPP_FE_24, DPP_FE_23, DPP_FE_22, \ 66 | DPP_FE_21, DPP_FE_20, DPP_FE_19, DPP_FE_18, DPP_FE_17, \ 67 | DPP_FE_16, DPP_FE_15, DPP_FE_14, DPP_FE_13, DPP_FE_12, \ 68 | DPP_FE_11, DPP_FE_10, DPP_FE_9, DPP_FE_8, DPP_FE_7, \ 69 | DPP_FE_6, DPP_FE_5, DPP_FE_4, DPP_FE_3, DPP_FE_2, DPP_FE_1, \ 70 | DPP_FE_0) \ 71 | (action, __VA_ARGS__) 72 | 73 | #define DPP_XSTR(s) DPP_STR(s) 74 | #define DPP_STR(s) #s 75 | 76 | #define ARR(...) __VA_ARGS__ 77 | 78 | //#define SET_RENDERED_NULL(X) _rendered_##X = nullptr; 79 | 80 | #define BOT_DEF_OPEN(plugin) plugin < 81 | #define BOT_DEF_CLOSE(plugin) > 82 | #define BOT_DEF(...) \ 83 | DPP_FOR_EACH(BOT_DEF_OPEN, __VA_ARGS__) \ 84 | discordpp::Bot DPP_FOR_EACH(BOT_DEF_CLOSE, __VA_ARGS__) 85 | -------------------------------------------------------------------------------- /discordpp/macros/defineCallClose.hh: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Aidan on 3/10/2021. 3 | // 4 | 5 | #ifndef DEFINE_CALL_OPEN 6 | #error There is no open Call definition 7 | #endif 8 | } 9 | ; 10 | 11 | #define CALLFUNC(name) \ 12 | auto name() { return sptr(new Class(this)); } 13 | 14 | DPP_FOR_EACH(CALLFUNC, function); 15 | #undef CALLFUNC 16 | 17 | #undef PFR 18 | #undef PFO 19 | #undef PFR1 20 | #undef PFO1 21 | #undef PFR2 22 | #undef PFO2 23 | #undef QSR 24 | #undef QSO 25 | #undef QSR1 26 | #undef QSO1 27 | #undef QSR2 28 | #undef QSO2 29 | #undef REQUIRE_VAR 30 | 31 | #undef TARGET_STRING 32 | 33 | #undef AUTO_PAYLOAD 34 | #undef AUTO_TARGET 35 | #undef SET_NULL 36 | #undef USEDBY 37 | #undef NEW_FIELD 38 | #undef NEW_RENDERABLE_FIELD 39 | #undef NEW_CUSTOM_RENDERABLE_FIELD 40 | #undef NEW_BASIC_RENDERABLE_FIELD 41 | #undef HIDE_FIELD 42 | #undef STATIC_FIELD 43 | #undef FORWARD_FIELD 44 | 45 | #undef BASECALL 46 | #undef Parent 47 | #undef Class 48 | #undef function 49 | #undef Fields 50 | #undef DEFINE_CALL_OPEN -------------------------------------------------------------------------------- /discordpp/macros/defineCallOpen.hh: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Aidan on 3/10/2021. 3 | // 4 | 5 | #include 6 | #include "../macros.hh" 7 | 8 | #ifdef DEFINE_CALL_OPEN 9 | #error There is already an open Call definition 10 | #endif 11 | #define DEFINE_CALL_OPEN 12 | 13 | #ifndef Bot 14 | #error The call needs to be in a bot 15 | #endif 16 | #ifndef BASECALL 17 | #ifndef Parent 18 | #error The call needs a parent 19 | #endif 20 | #endif 21 | #ifndef Class 22 | #error The call needs a class name 23 | #endif 24 | #ifndef function 25 | #error The call needs a function name 26 | #endif 27 | 28 | public: 29 | #ifdef BASECALL 30 | class Class : public std::enable_shared_from_this { 31 | friend RenderedCall; 32 | #else 33 | class Class : public Parent { 34 | #endif 35 | friend Bot; 36 | 37 | #ifdef BASECALL 38 | protected: 39 | explicit Class(BotStruct *bot) : bot_(bot) {} 40 | 41 | // https://stackoverflow.com/a/32172486 42 | template std::shared_ptr shared_from_base() { 43 | return std::static_pointer_cast(shared_from_this()); 44 | } 45 | 46 | public: 47 | auto render() { return std::make_shared(this); } 48 | auto run() { 49 | bot_->doCall(render()); 50 | return shared_from_this(); 51 | } 52 | 53 | private: 54 | BotStruct *bot_; 55 | #else 56 | protected: 57 | explicit Class(BotStruct *bot) : Parent(bot) {} 58 | 59 | public: 60 | auto run() { return std::static_pointer_cast(Parent::run()); } 61 | #endif 62 | 63 | //#define SET_NULL(usedby) _rendered_##usedby = nullptr; 64 | #define SET_CLEAR(usedby) clear_##usedby(); 65 | #define AND_CLEAR(usedby, name) \ 66 | usedby; \ 67 | SET_CLEAR(name); 68 | #define USEDBY(...) DPP_FOR_EACH(SET_CLEAR, __VA_ARGS__) 69 | 70 | #define NEW_FIELD(type, name, usedby) \ 71 | public: \ 72 | auto name(sptr name##In) { \ 73 | usedby; \ 74 | _##name = std::move(name##In); \ 75 | return shared_from_base(); \ 76 | } \ 77 | auto name(const type &name##In) { \ 78 | return name(std::make_shared(name##In)); \ 79 | } \ 80 | \ 81 | protected: \ 82 | sptr _##name = nullptr; 83 | 84 | #define NEW_RENDERABLE_FIELD(type, name, usedby) \ 85 | NEW_FIELD(type, name, AND_CLEAR(usedby, name)) \ 86 | protected: \ 87 | sptr _rendered_##name = nullptr; \ 88 | \ 89 | void clear_##name() { \ 90 | _rendered_##name = nullptr; \ 91 | usedby; \ 92 | } \ 93 | \ 94 | private: \ 95 | virtual sptr get_##name() { \ 96 | return _rendered_##name ? _rendered_##name \ 97 | : _rendered_##name = render_##name(); \ 98 | } 99 | 100 | #define NEW_CUSTOM_RENDERABLE_FIELD(type, name, usedby) \ 101 | NEW_RENDERABLE_FIELD(type, name, usedby) 102 | 103 | #define NEW_BASIC_RENDERABLE_FIELD(type, name, usedby) \ 104 | NEW_RENDERABLE_FIELD(type, name, usedby) \ 105 | protected: \ 106 | virtual sptr render_##name() { \ 107 | return _##name ? std::make_shared(*_##name) : nullptr; \ 108 | } 109 | 110 | #define PFR2(KEY, VAR) \ 111 | if (!_##VAR) { \ 112 | throw std::logic_error(DPP_XSTR(Class) " needs " #VAR); \ 113 | } \ 114 | out[KEY] = *_##VAR; 115 | #define PFO2(KEY, VAR) \ 116 | if (_##VAR) { \ 117 | out[KEY] = *_##VAR; \ 118 | } 119 | #define PFR1(VAR) PFR2(#VAR, VAR) 120 | #define PFO1(VAR) PFO2(#VAR, VAR) 121 | #define PFR(...) DPP_VFUNC(PFR, __VA_ARGS__) 122 | #define PFO(...) DPP_VFUNC(PFO, __VA_ARGS__) 123 | 124 | #define AUTO_PAYLOAD(PFIELDS) \ 125 | HIDE_FIELD(payload) \ 126 | protected: \ 127 | sptr render_payload() override { \ 128 | json out; \ 129 | PFIELDS \ 130 | return std::make_shared(std::move(out)); \ 131 | } 132 | 133 | #define REQUIRE_VAR(VAR) \ 134 | if (!_##VAR) { \ 135 | throw std::logic_error(DPP_XSTR(Class) " needs " #VAR); \ 136 | } 137 | #define TARGET_STRING(VAR) , to_string(*_##VAR) 138 | 139 | #define QSO2(KEY, VAR) \ 140 | if (_##VAR) { \ 141 | out += fmt::format("{}" KEY "={}", first ? "?" : "&", *_##VAR); \ 142 | first = false; \ 143 | } 144 | #define QSR2(KEY, VAR) \ 145 | REQUIRE_VAR(VAR) \ 146 | QSO2(KEY, VAR) 147 | #define QSO1(VAR) QSO2(#VAR, VAR) 148 | #define QSR1(VAR) QSR2(#VAR, VAR) 149 | #define QSO(...) DPP_VFUNC(QSO, __VA_ARGS__) 150 | #define QSR(...) DPP_VFUNC(QSR, __VA_ARGS__) 151 | 152 | #define AUTO_TARGET(TPath, TArgs, QSArgs) \ 153 | HIDE_FIELD(target) \ 154 | protected: \ 155 | sptr render_target() override { \ 156 | DPP_FOR_EACH(REQUIRE_VAR, TArgs) \ 157 | std::string out = \ 158 | fmt::format(TPath DPP_FOR_EACH(TARGET_STRING, TArgs)); \ 159 | bool first = true; \ 160 | QSArgs; \ 161 | return std::make_shared(out); \ 162 | } 163 | 164 | #ifdef Parent 165 | #define HIDE_FIELD(name) \ 166 | protected: \ 167 | using Parent::name; 168 | 169 | #define STATIC_FIELD(type, name, value) \ 170 | HIDE_FIELD(name) \ 171 | sptr render_##name() override { \ 172 | static auto name = std::make_shared(value); \ 173 | return name; \ 174 | } 175 | 176 | #define FORWARD_FIELD(type, name, usedby) \ 177 | public: \ 178 | auto name(sptr name##In) { \ 179 | usedby; \ 180 | return std::static_pointer_cast(Parent::name(name##In)); \ 181 | } \ 182 | auto name(const type &name##In) { \ 183 | return name(std::make_shared(name##In)); \ 184 | } 185 | #endif 186 | -------------------------------------------------------------------------------- /discordpp/snowflake.hh: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Aidan on 9/1/2021. 3 | // 4 | 5 | #pragma once 6 | #define JSON_USE_IMPLICIT_CONVERSIONS 0 7 | 8 | #include 9 | 10 | namespace discordpp { 11 | using json = nlohmann::json; 12 | 13 | template inline std::string to_string(const T &t) { 14 | return std::move(std::to_string(t)); 15 | } 16 | 17 | template <> inline std::string to_string(const std::string &s) { 18 | return s; 19 | } 20 | 21 | struct Snowflake { 22 | Snowflake() : _value(0) {} 23 | Snowflake(uint64_t value) : _value(value) {} 24 | Snowflake(std::string value) : _value(std::stoull(value)) {} 25 | Snowflake(const Snowflake &) = default; 26 | 27 | operator uint64_t &() { return _value; } 28 | 29 | operator uint64_t() const { return _value; } 30 | 31 | operator std::string() const { return to_string(_value); } 32 | 33 | Snowflake &operator=(uint64_t val) { 34 | _value = val; 35 | return *this; 36 | } 37 | 38 | Snowflake &operator=(const std::string &str) { 39 | _value = std::stoull(str); 40 | return *this; 41 | } 42 | 43 | Snowflake &operator=(const Snowflake &s) { 44 | _value = s._value; 45 | return *this; 46 | } 47 | 48 | friend void to_json(nlohmann::json &j, const Snowflake &s) { j = s._value; } 49 | friend void from_json(const nlohmann::json &j, Snowflake &s) { 50 | s._value = std::stoull(j.get()); 51 | } 52 | 53 | protected: 54 | uint64_t _value; 55 | }; 56 | } // namespace discordpp 57 | -------------------------------------------------------------------------------- /discordpp/util.hh: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Aidan on 2/26/2021. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "alias.hh" 8 | #include 9 | #include 10 | 11 | namespace discordpp { 12 | namespace util { 13 | // Adapted from https://stackoverflow.com/a/63359171 14 | inline std::string rand_str(int length) { 15 | static const std::string chars{ 16 | "abcdefghijklmnopqrstuvwxyz" 17 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 18 | "1234567890"}; // "!@#$%^&*()`~-_=+[{]{|;:'",<.>/?" 19 | static std::random_device rd; 20 | static std::mt19937 generator(rd()); 21 | 22 | std::string output; 23 | output.reserve(length); 24 | 25 | while (length > 0) { 26 | auto randNumb = generator(); 27 | while (randNumb > chars.length() && length--) { 28 | output.push_back(chars[randNumb % chars.length()]); 29 | randNumb /= chars.length(); 30 | } 31 | } 32 | return output; 33 | } 34 | 35 | inline std::string generate_boundary(const std::string &payload, 36 | sptr file) { 37 | std::string out = rand_str(8); 38 | while ((file && file->find(out) != std::string::npos) || 39 | payload.find(out) != std::string::npos) { 40 | out += rand_str(out.length()); 41 | } 42 | return out; 43 | } 44 | } // namespace util 45 | } // namespace discordpp 46 | 47 | // Begin https://github.com/nlohmann/json/issues/1261#issuecomment-426209912 48 | namespace detail 49 | { 50 | template 51 | struct variant_switch 52 | { 53 | template 54 | void operator()(int index, nlohmann::json const &value, Variant &v) const 55 | { 56 | if (index == N) 57 | v = value.get>(); 58 | else 59 | variant_switch{}(index, value, v); 60 | } 61 | }; 62 | 63 | template <> 64 | struct variant_switch<0> 65 | { 66 | template 67 | void operator()(int index, nlohmann::json const &value, Variant &v) const 68 | { 69 | if (index == 0) 70 | v = value.get>(); 71 | else 72 | { 73 | throw std::runtime_error( 74 | "while converting json to variant: invalid index"); 75 | } 76 | } 77 | }; 78 | } 79 | 80 | namespace nlohmann { 81 | // From https://www.kdab.com/jsonify-with-nlohmann-json/ 82 | // Try to set the value of type T into the variant data. If it fails, do nothing 83 | template 84 | void variant_from_json(const nlohmann::json &j, std::variant &data) { 85 | try { 86 | data = j.get(); 87 | } catch (...) { 88 | } 89 | } 90 | 91 | template 92 | struct adl_serializer> 93 | { 94 | static void to_json(nlohmann::json &j, const std::variant &data) { 95 | // Will call j = v automatically for the right type 96 | std::visit([&j](const auto &v) { j = v; }, data); 97 | } 98 | 99 | static void from_json(const nlohmann::json &j, std::variant &data) { 100 | // Call variant_from_json for all types, only one will succeed 101 | (variant_from_json(j, data), ...); 102 | } 103 | }; 104 | } 105 | 106 | namespace nlohmann { 107 | // https://github.com/nlohmann/json/issues/1749#issuecomment-772996219 108 | template 109 | struct adl_serializer> { 110 | static void to_json(nlohmann::json &j, const std::optional &v) { 111 | if(v.has_value()){ 112 | j = v.value(); 113 | }else{ 114 | j = nullptr; 115 | } 116 | } 117 | 118 | static void from_json(const nlohmann::json &j, std::optional &v) { 119 | if (j.is_null()) { 120 | v = std::nullopt; 121 | }else { 122 | v = j.get(); 123 | } 124 | } 125 | }; 126 | 127 | /*template struct adl_serializer>> { 128 | static void to_json(json &j, const std::vector> &v) { 129 | j = json::array(); 130 | for (auto t : v) { 131 | j.push_back(*t); 132 | } 133 | } 134 | 135 | static void from_json(const json &j, std::vector> &v) { 136 | if (!j.is_array()) { 137 | throw json::type_error::create(317, "j must be an array", j); 138 | } 139 | for (auto t : j) { 140 | v.push_back(std::make_shared(j.get())); 141 | } 142 | } 143 | };*/ 144 | } // namespace nlohmann 145 | -------------------------------------------------------------------------------- /lib/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DiscordPP/discordpp/b8e47884bfe8f64bc67c2e4e808649d5f12669f8/lib/.gitkeep --------------------------------------------------------------------------------