├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ ├── ccpp.yml │ └── documentation.yml ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── azure-pipelines.yml ├── buildtools ├── Makefile.3ds ├── Makefile.linux ├── Readme.md └── cmake │ ├── DownloadProject.CMakeLists.cmake.in │ ├── DownloadProject.cmake │ ├── LICENSE │ └── sleepy-discord-config.cmake.in ├── examples ├── hello │ ├── CMakeLists.txt │ └── example0.cpp ├── rock-paper-scissors │ ├── CMakeLists.txt │ └── main.cpp ├── slash-commands │ ├── CMakeLists.txt │ └── main.cpp ├── sound-player │ ├── CMakeLists.txt │ ├── IO_file.h │ └── main.cpp └── wasm_example │ ├── build.bat │ ├── how_to_get_lib.txt │ ├── index.html │ ├── mod.js │ ├── session.js │ ├── wasm_example.vcxproj │ ├── wasm_session.h │ ├── wasm_websocket.cpp │ ├── wasm_websocket.h │ └── websocket.js ├── include └── sleepy_discord │ ├── IncludeNonexistent │ ├── asio.hpp │ ├── boost │ │ └── asio.hpp │ ├── cpr │ │ └── cpr.h │ ├── opus.h │ ├── sodium.h │ └── version.h │ ├── asio_include.h │ ├── asio_schedule.h │ ├── asio_udp.h │ ├── asio_websocket.h │ ├── asio_websocketconnection.h │ ├── attachment.h │ ├── audit_log.h │ ├── beast_session.h │ ├── cache.h │ ├── channel.h │ ├── client.h │ ├── common_return_types.h │ ├── compression.h │ ├── cpr_session.h │ ├── custom_connection.h │ ├── custom_session.h │ ├── custom_udp_client.h │ ├── discord_object_interface.h │ ├── embed.h │ ├── error.h │ ├── gateway.h │ ├── generic_compression.h │ ├── http.h │ ├── invite.h │ ├── json_wrapper.h │ ├── message.h │ ├── message_receiver.h │ ├── net_endian.h │ ├── nonstd │ ├── optional.hpp │ └── string_view.hpp │ ├── permissions.h │ ├── rapidjson │ ├── allocators.h │ ├── cursorstreamwrapper.h │ ├── document.h │ ├── encodedstream.h │ ├── encodings.h │ ├── error │ │ ├── en.h │ │ └── error.h │ ├── filereadstream.h │ ├── filewritestream.h │ ├── fwd.h │ ├── internal │ │ ├── biginteger.h │ │ ├── diyfp.h │ │ ├── dtoa.h │ │ ├── ieee754.h │ │ ├── itoa.h │ │ ├── meta.h │ │ ├── pow10.h │ │ ├── regex.h │ │ ├── stack.h │ │ ├── strfunc.h │ │ ├── strtod.h │ │ └── swap.h │ ├── istreamwrapper.h │ ├── memorybuffer.h │ ├── memorystream.h │ ├── msinttypes │ │ ├── inttypes.h │ │ └── stdint.h │ ├── ostreamwrapper.h │ ├── pointer.h │ ├── prettywriter.h │ ├── rapidjson.h │ ├── reader.h │ ├── schema.h │ ├── stream.h │ ├── stringbuffer.h │ └── writer.h │ ├── rate_limiter.h │ ├── server.h │ ├── session.h │ ├── slash_commands.h │ ├── sleepy_discord.h │ ├── snowflake.h │ ├── stage_instance.h │ ├── standard_config.h │ ├── standard_config_header.h │ ├── thread.h │ ├── timer.h │ ├── udp.h │ ├── udp_client.h │ ├── user.h │ ├── version-non.h.in │ ├── version.h.in │ ├── version_helper.h │ ├── voice.h │ ├── voice_connection.h │ ├── webhook.h │ ├── websocket.h │ ├── websocket_connection.h │ └── zlib_compression.h └── sleepy_discord ├── CMakeLists.txt ├── asio_udp.cpp ├── asio_websocket.cpp ├── attachment.cpp ├── channel.cpp ├── client.cpp ├── cpr_session.cpp ├── default_functions.cpp ├── embed.cpp ├── endpoints.cpp ├── gateway.cpp ├── http.cpp ├── invite.cpp ├── json_wrapper.cpp ├── make_version.h.js ├── message.cpp ├── permissions.cpp ├── sd_error.cpp ├── server.cpp ├── slash_commands.cpp ├── stage_instance.cpp ├── thread.cpp ├── user.cpp ├── version.cpp ├── voice.cpp ├── voice_connection.cpp ├── webhook.cpp └── zlib_compression.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | session.h linguist-vendored -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [yourWaifu] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | # patreon: # Replace with a single Patreon username 5 | # open_collective: # Replace with a single Open Collective username 6 | # ko_fi: # Replace with a single Ko-fi username 7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | # liberapay: # Replace with a single Liberapay username 10 | # issuehunt: # Replace with a single IssueHunt username 11 | # otechie: # Replace with a single Otechie username 12 | # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/workflows/ccpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | name: Build on ${{ matrix.os }} 9 | runs-on: ${{ matrix.os }} 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest] 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: install dependency packages 17 | run: sudo apt install -y clang libc++-dev libc++abi-dev ninja-build libcurl4-openssl-dev 18 | - name: build folder 19 | run: mkdir build 20 | - name: configure 21 | run: | 22 | cd build 23 | CC=/usr/bin/clang CXX=/usr/bin/clang++ CXXFLAGS=-stdlib=libc++ cmake .. -G Ninja -DBUILD_SLEEPY_DISCORD_EXAMPLES=1 24 | - name: ninja 25 | run: | 26 | cd build 27 | ninja 28 | -------------------------------------------------------------------------------- /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | name: documentation 2 | 3 | on: 4 | pull_request: 5 | branches: [develop, master] 6 | push: 7 | branches: [develop] 8 | 9 | jobs: 10 | checks: 11 | if: github.event_name != 'push' 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v1 15 | - uses: actions/setup-node@v1 16 | with: 17 | node-version: '14.x' 18 | - name: install dependency packages 19 | run: sudo apt install -y doxygen 20 | - name: set up site 21 | run: | 22 | git clone https://github.com/yourWaifu/sleepy-discord-docs.git 23 | cd sleepy-discord-docs 24 | cp Doxyfile ../ 25 | cd .. 26 | echo "Run Doxygen" 27 | doxygen 28 | echo "Move Doxygen Files" 29 | mkdir sleepy-discord-docs/xml 30 | mv xml/* sleepy-discord-docs/xml 31 | echo "Download Doxybook2" 32 | cd sleepy-discord-docs 33 | curl -o doxybook2.zip -LO "https://github.com/matusnovak/doxybook2/releases/download/v1.4.0/doxybook2-linux-amd64-v1.4.0.zip" 34 | unzip -j "doxybook2.zip" "bin/doxybook2" -d "." 35 | echo "Run Doxybook2" 36 | mkdir docs/reference 37 | ./doxybook2 --input ./xml --output ./docs/reference --config ./doxybook.config.json --templates templates/ 38 | - name: Test Build 39 | run: | 40 | cd sleepy-discord-docs 41 | if [ -e yarn.lock ]; then 42 | yarn install --frozen-lockfile 43 | elif [ -e package-lock.json ]; then 44 | npm ci 45 | else 46 | npm i 47 | fi 48 | npx tsc --p reference-generator-tsconfig.json 49 | npm run build 50 | gh-release: 51 | if: github.event_name != 'pull_request' 52 | runs-on: ubuntu-latest 53 | steps: 54 | - uses: actions/checkout@v1 55 | - uses: actions/setup-node@v1 56 | with: 57 | node-version: '14.x' 58 | - name: Add key to allow access to repository 59 | env: 60 | SSH_AUTH_SOCK: /tmp/ssh_agent.sock 61 | run: | 62 | mkdir -p ~/.ssh 63 | ssh-keyscan github.com >> ~/.ssh/known_hosts 64 | echo "${{ secrets.GH_PAGES_DEPLOY }}" > ~/.ssh/id_ed25519 65 | chmod 600 ~/.ssh/id_ed25519 66 | cat <> ~/.ssh/config 67 | Host github.com 68 | HostName github.com 69 | IdentityFile ~/.ssh/id_ed25519 70 | EOT 71 | - name: install dependency packages 72 | run: sudo apt install -y doxygen 73 | - name: set up site 74 | run: | 75 | git clone https://github.com/yourWaifu/sleepy-discord-docs.git 76 | cd sleepy-discord-docs 77 | cp Doxyfile ../ 78 | cd .. 79 | echo "Run Doxygen" 80 | doxygen 81 | echo "Move Doxygen Files" 82 | mkdir sleepy-discord-docs/xml 83 | mv xml/* sleepy-discord-docs/xml 84 | echo "Download Doxybook2" 85 | cd sleepy-discord-docs 86 | curl -o doxybook2.zip -LO "https://github.com/matusnovak/doxybook2/releases/download/v1.4.0/doxybook2-linux-amd64-v1.4.0.zip" 87 | unzip -j "doxybook2.zip" "bin/doxybook2" -d "." 88 | echo "Run Doxybook2" 89 | mkdir docs/reference 90 | ./doxybook2 --input ./xml --output ./docs/reference --config ./doxybook.config.json --templates templates/ 91 | - name: Release to GitHub Pages 92 | env: 93 | USE_SSH: true 94 | GIT_USER: git 95 | GIT_PASS: ${{ secrets.GITHUB_TOKEN }} 96 | run: | 97 | cd sleepy-discord-docs 98 | git config --global user.email "actions@gihub.com" 99 | git config --global user.name "gh-actions" 100 | if [ -e yarn.lock ]; then 101 | yarn install --frozen-lockfile 102 | elif [ -e package-lock.json ]; then 103 | npm ci 104 | else 105 | npm i 106 | fi 107 | npx tsc --p reference-generator-tsconfig.json 108 | npx docusaurus deploy -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore all CMAKE files 2 | CMakeCache.txt 3 | CMakeFiles/ 4 | CMakeScripts/ 5 | Makefile 6 | cmake_install.cmake 7 | install_manifest.txt 8 | CTestTestfile.cmake 9 | 10 | # Compiled Object files 11 | *.slo 12 | *.lo 13 | *.o 14 | *.obj 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Compiled Dynamic libraries 21 | *.so 22 | *.dylib 23 | *.dll 24 | 25 | # Fortran module files 26 | *.mod 27 | *.smod 28 | 29 | # Compiled Static libraries 30 | *.lai 31 | *.la 32 | *.a 33 | *.lib 34 | 35 | # Executables 36 | *.exe 37 | *.out 38 | *.app 39 | 40 | ## Ignore Visual Studio temporary files, build results, and 41 | ## files generated by popular Visual Studio add-ons. 42 | 43 | # User-specific files 44 | *.suo 45 | *.user 46 | *.userosscache 47 | *.sln.docstates 48 | 49 | # User-specific files (MonoDevelop/Xamarin Studio) 50 | *.userprefs 51 | 52 | # Build results 53 | [Dd]ebug/ 54 | [Dd]ebugPublic/ 55 | [Rr]elease/ 56 | [Rr]eleases/ 57 | x64/ 58 | x86/ 59 | build/ 60 | bld/ 61 | [Bb]in/ 62 | [Oo]bj/ 63 | 64 | # Visual Studio 2015 cache/options directory 65 | .vs/ 66 | 67 | # All Visual Studio files 68 | Win32/ 69 | *.VC.db 70 | 71 | 72 | # MSTest test Results 73 | [Tt]est[Rr]esult*/ 74 | [Bb]uild[Ll]og.* 75 | 76 | # NUNIT 77 | *.VisualState.xml 78 | TestResult.xml 79 | 80 | # Build Results of an ATL Project 81 | [Dd]ebugPS/ 82 | [Rr]eleasePS/ 83 | dlldata.c 84 | 85 | # DNX 86 | project.lock.json 87 | artifacts/ 88 | 89 | *_i.c 90 | *_p.c 91 | *_i.h 92 | *.ilk 93 | *.meta 94 | *.obj 95 | *.pch 96 | *.pdb 97 | *.pgc 98 | *.pgd 99 | *.rsp 100 | *.sbr 101 | *.tlb 102 | *.tli 103 | *.tlh 104 | *.tmp 105 | *.tmp_proj 106 | *.log 107 | *.vspscc 108 | *.vssscc 109 | .builds 110 | *.pidb 111 | *.svclog 112 | *.scc 113 | 114 | # Chutzpah Test files 115 | _Chutzpah* 116 | 117 | # Visual C++ cache files 118 | ipch/ 119 | *.aps 120 | *.ncb 121 | *.opensdf 122 | *.sdf 123 | *.cachefile 124 | 125 | # Visual Studio profiler 126 | *.psess 127 | *.vsp 128 | *.vspx 129 | 130 | # TFS 2012 Local Workspace 131 | $tf/ 132 | 133 | # Guidance Automation Toolkit 134 | *.gpState 135 | 136 | # ReSharper is a .NET coding add-in 137 | _ReSharper*/ 138 | *.[Rr]e[Ss]harper 139 | *.DotSettings.user 140 | 141 | # JustCode is a .NET coding add-in 142 | .JustCode 143 | 144 | # TeamCity is a build add-in 145 | _TeamCity* 146 | 147 | # DotCover is a Code Coverage Tool 148 | *.dotCover 149 | 150 | # NCrunch 151 | _NCrunch_* 152 | .*crunch*.local.xml 153 | 154 | # MightyMoose 155 | *.mm.* 156 | AutoTest.Net/ 157 | 158 | # Web workbench (sass) 159 | .sass-cache/ 160 | 161 | # Installshield output folder 162 | [Ee]xpress/ 163 | 164 | # DocProject is a documentation generator add-in 165 | DocProject/buildhelp/ 166 | DocProject/Help/*.HxT 167 | DocProject/Help/*.HxC 168 | DocProject/Help/*.hhc 169 | DocProject/Help/*.hhk 170 | DocProject/Help/*.hhp 171 | DocProject/Help/Html2 172 | DocProject/Help/html 173 | 174 | # Click-Once directory 175 | publish/ 176 | 177 | # Publish Web Output 178 | *.[Pp]ublish.xml 179 | *.azurePubxml 180 | ## TODO: Comment the next line if you want to checkin your 181 | ## web deploy settings but do note that will include unencrypted 182 | ## passwords 183 | #*.pubxml 184 | 185 | *.publishproj 186 | 187 | # NuGet Packages 188 | *.nupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/packages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/packages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/packages/repositories.config 195 | 196 | # Windows Azure Build Output 197 | csx/ 198 | *.build.csdef 199 | 200 | # Windows Store app package directory 201 | AppPackages/ 202 | 203 | # Visual Studio cache files 204 | # files ending in .cache can be ignored 205 | *.[Cc]ache 206 | # but keep track of directories ending in .cache 207 | !*.[Cc]ache/ 208 | 209 | # Others 210 | ClientBin/ 211 | [Ss]tyle[Cc]op.* 212 | ~$* 213 | *~ 214 | *.dbmdl 215 | *.dbproj.schemaview 216 | *.pfx 217 | *.publishsettings 218 | node_modules/ 219 | orleans.codegen.cs 220 | 221 | # RIA/Silverlight projects 222 | Generated_Code/ 223 | 224 | # Backup & report files from converting an old project file 225 | # to a newer Visual Studio version. Backup files are not needed, 226 | # because we have git ;-) 227 | _UpgradeReport_Files/ 228 | Backup*/ 229 | UpgradeLog*.XML 230 | UpgradeLog*.htm 231 | 232 | # SQL Server files 233 | *.mdf 234 | *.ldf 235 | 236 | # Business Intelligence projects 237 | *.rdl.data 238 | *.bim.layout 239 | *.bim_*.settings 240 | 241 | # Microsoft Fakes 242 | FakesAssemblies/ 243 | 244 | # Node.js Tools for Visual Studio 245 | .ntvs_analysis.dat 246 | 247 | # Visual Studio 6 build log 248 | *.plg 249 | 250 | # Visual Studio 6 workspace options file 251 | *.opt 252 | 253 | # LightSwitch generated files 254 | GeneratedArtifacts/ 255 | _Pvt_Extensions/ 256 | ModelManifest.xml 257 | 258 | #vs code 259 | .vscode/ 260 | 261 | #datebase files 262 | *.db 263 | *.opendb 264 | 265 | # Visual Studio CMake files 266 | out/ 267 | CMakeSettings.json 268 | 269 | #my files 270 | deps/ 271 | /discord token.txt 272 | include/sleepy_discord/version.h 273 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: bionic 2 | sudo: required 3 | language: cpp 4 | 5 | addons: 6 | apt: 7 | sources: 8 | - ubuntu-toolchain-r-test 9 | - sourceline: 'deb https://apt.kitware.com/ubuntu/ bionic main' 10 | key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' 11 | packages: 12 | - gcc-5 13 | - g++-5 14 | - libcurl4-openssl-dev 15 | 16 | before_install: 17 | #travis ci has it's own version of cmake that we need to replace 18 | - mkdir $HOME/usr 19 | - export PATH="$HOME/usr/bin:$PATH" 20 | - curl -sSL https://github.com/Kitware/CMake/releases/download/v3.18.3/cmake-3.18.3-Linux-x86_64.sh --output cmake-install.sh 21 | - chmod +x cmake-install.sh 22 | - ./cmake-install.sh --prefix=$HOME/usr --exclude-subdir --skip-license 23 | 24 | install: 25 | - export CXX="g++-5" CC="gcc-5"; 26 | 27 | script: 28 | - g++-5 --version 29 | - cd buildtools 30 | - cmake --version 31 | - cmake .. -DSLEEPY_DISCORD_BUILD_EXAMPLES=1 32 | - make 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Sleepy Flower Girl 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 | # Sleepy Discord 2 | C++ library for Discord 3 | 4 | [![Discord Server](https://discordapp.com/api/guilds/566681036935790615/widget.png?style=banner2)](https://discord.gg/5VDrVfK) 5 | 6 | # [Documentation](https://yourwaifu.dev/sleepy-discord/docs/) 7 | [Getting Started](https://yourwaifu.dev/sleepy-discord/docs/)
8 | 9 | If you like to edit them, [please check out the docs repo](https://github.com/yourWaifu/sleepy-discord-docs). 10 | 11 | ## Build Status 12 | | Build | Windows MSVC | Ubuntu GCC | Ubuntu Clang | Docs | 13 | | ------ | ------- | ------ | ----- | ---- | 14 | | Master | [![Build Status](https://dev.azure.com/wuhao64/sleepy-discord/_apis/build/status/yourWaifu.sleepy-discord?branchName=master)](https://dev.azure.com/wuhao64/sleepy-discord/_build/?definitionId=2) | [![Build Status](https://travis-ci.org/yourWaifu/sleepy-discord.svg?branch=master)](https://travis-ci.org/yourWaifu/sleepy-discord) | [![C/C++ CI](https://github.com/yourWaifu/sleepy-discord/actions/workflows/ccpp.yml/badge.svg?branch=master)](https://github.com/yourWaifu/sleepy-discord/actions/workflows/ccpp.yml) | N/A | 15 | | Develop | [![Build Status](https://dev.azure.com/wuhao64/sleepy-discord/_apis/build/status/yourWaifu.sleepy-discord?branchName=develop)](https://dev.azure.com/wuhao64/sleepy-discord/_build/latest?definitionId=2) | [![Build Status](https://travis-ci.org/yourWaifu/sleepy-discord.svg?branch=develop)](https://travis-ci.org/yourWaifu/sleepy-discord) | [![C/C++ CI](https://github.com/yourWaifu/sleepy-discord/actions/workflows/ccpp.yml/badge.svg?branch=develop)](https://github.com/yourWaifu/sleepy-discord/actions/workflows/ccpp.yml) | [![documentation](https://github.com/yourWaifu/sleepy-discord/actions/workflows/documentation.yml/badge.svg?branch=develop)](https://github.com/yourWaifu/sleepy-discord/actions/workflows/documentation.yml) 16 | 17 | # Why? 18 | Just for the novelty of using a C++ library for Discord. I would also love for this thing to work on many things like consoles and maybe some microcontrollers. 19 | 20 | # Example 21 | ```cpp 22 | #include "sleepy_discord/sleepy_discord.h" 23 | 24 | class MyClientClass : public SleepyDiscord::DiscordClient { 25 | public: 26 | using SleepyDiscord::DiscordClient::DiscordClient; 27 | void onMessage(SleepyDiscord::Message message) override { 28 | if (message.startsWith("whcg hello")) 29 | sendMessage(message.channelID, "Hello " + message.author.username); 30 | } 31 | }; 32 | 33 | int main() { 34 | MyClientClass client("token", SleepyDiscord::USER_CONTROLED_THREADS); 35 | client.setIntents(SleepyDiscord::Intent::SERVER_MESSAGES); 36 | client.run(); 37 | } 38 | ``` 39 | Input: Message received 40 | ``` 41 | whcg hello 42 | ``` 43 | Possible Output: Message sent 44 | ``` 45 | Hello Sleepy Flower Girl 46 | ``` 47 | 48 | More complex examples: 49 | - [Rock Paper Scissors](https://github.com/yourWaifu/sleepy-discord/blob/master/examples/rock-paper-scissors/main.cpp) 50 | - [Unofficial Discord 3DS Client](https://github.com/yourWaifu/Unofficial-Discord-3DS-Client) 51 | - [WebAssembly Client](https://github.com/yourWaifu/sleepy-discord/tree/master/examples/wasm_example) (Work In Progress) 52 | # Will Updating the library break my bot? 53 | 54 | Yes, and for now I don't plan on making 0.0 versions backwards compatible with 1.0 versions or later. 55 | 56 | # Requirements 57 | Sleepy Discord doesn't require you to use any libraries, so that you can use any library you wish or your own code. However, Sleepy Discord provides native support for a few libraries and it is recommend you use those instead of writing your own. 58 | 59 | * [OpenSSL](https://www.openssl.org/) 60 | * [cpr](https://github.com/whoshuu/cpr) 61 | * [ASIO](https://think-async.com/Asio/) 62 | 63 | # Develop Branch 64 | For the cutting edge of Sleepy Discord, check out the develop branch. Please use the develop branch with caution because it may not even be able to compile or it is 100% not tested at all. Other then that, the branch is used for code that may not work. Also check to see if it's not behind the master branch, unless you want to use an older version of Sleepy Discord. 65 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # .NET Desktop 2 | # Build and run tests for .NET Desktop or Windows classic desktop solutions. 3 | # Add steps that publish symbols, save build artifacts, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net 5 | 6 | pool: 7 | vmImage: 'windows-2022' 8 | 9 | variables: 10 | solution: 'build/*.sln' 11 | buildPlatform: 'x86' 12 | buildConfiguration: 'Release' 13 | 14 | steps: 15 | #To Do: Do both 32 bit and 64 bit 16 | 17 | - script: | 18 | git clone https://github.com/Microsoft/vcpkg.git 19 | cd vcpkg 20 | .\bootstrap-vcpkg.bat 21 | .\vcpkg integrate install 22 | call RefreshEnv.cmd 23 | displayName: 'Vcpkg Setup' 24 | 25 | - script: | 26 | cd vcpkg 27 | .\vcpkg install openssl:x86-windows-static 28 | displayName: 'OpenSSL Install' 29 | 30 | - task: CMake@1 31 | inputs: 32 | CMakeArgs: .. -A Win32 -DBUILD_SLEEPY_DISCORD_EXAMPLES=1 -DCMAKE_TOOLCHAIN_FILE=D:\a\1\s\vcpkg\scripts\buildsystems\vcpkg.cmake -DOPENSSL_USE_STATIC_LIBS=TRUE -DOPENSSL_ROOT_DIR="D:\a\1\s\vcpkg\installed\x86-windows-static" -DBUILD_CPR_TESTS=OFF 33 | 34 | - task: CMake@1 35 | inputs: 36 | CMakeArgs: --build . --config Release 37 | -------------------------------------------------------------------------------- /buildtools/Makefile.linux: -------------------------------------------------------------------------------- 1 | .SUFFIXES: 2 | .SUFFIXES: .c .cpp .o .a 3 | 4 | CC = gcc # c compiler 5 | CXX = g++ # c++ compiler 6 | AR = ar rv 7 | CPPFLAGS = -Wall -fPIC -c $(foreach dir, $(INCLUDE), -I$(dir)) 8 | override CFLAGS += 9 | override CXXFLAGS += -std=c++11 10 | SRCDIR = ../sleepy_discord 11 | INCLUDE = ../include/sleepy_discord ../deps/include ../include/sleepy_discord/IncludeNonexistent 12 | DESTDIR = . 13 | COBJS = $(patsubst %.c,%.o,$(wildcard $(SRCDIR)/*.c)) 14 | CXXOBJS = $(patsubst %.cpp,%.o,$(wildcard $(SRCDIR)/*.cpp)) 15 | CPROBJS = $(patsubst %.cpp,%.o,$(wildcard ../deps/cpr/cpr/*.cpp)) 16 | 17 | all: libsleepy_discord.a libcpr-patch libcpr.a 18 | 19 | clean: 20 | rm -f $(DESTDIR)/*.a 21 | rm -f $(COBJS) 22 | rm -f $(CXXOBJS) 23 | rm -f $(CPROBJS) 24 | 25 | libsleepy_discord.a: $(COBJS) $(CXXOBJS) 26 | $(AR) $@ $^ 27 | 28 | libcpr.a: $(CPROBJS) 29 | $(AR) $@ $^ 30 | 31 | libcpr-patch: 32 | # duplicate case value in lines 25,26 33 | sed -i 's/.*VER.*//; s/.*REM.*//' ../deps/cpr/cpr/error.cpp 34 | -------------------------------------------------------------------------------- /buildtools/Readme.md: -------------------------------------------------------------------------------- 1 | # Building Sleepy Discord 2 | 3 | In this folder you'll find build tools for building Sleepy Discord 4 | 5 | # Makefile.3ds 6 | 7 | This is for building the library for the 3ds. You may need devkitpro for this. 8 | 9 | To compile using this file run the following command: 10 | ``` 11 | make -f Makefile.3ds 12 | ``` 13 | 14 | # Makefile.linux 15 | 16 | This is for building the library for linux. 17 | 18 | To compile, use the following command: 19 | ``` 20 | make -f Makefile.linux 21 | ``` -------------------------------------------------------------------------------- /buildtools/cmake/DownloadProject.CMakeLists.cmake.in: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved MIT License. See accompanying 2 | # file LICENSE or https://github.com/Crascit/DownloadProject for details. 3 | 4 | cmake_minimum_required(VERSION 2.8.2) 5 | 6 | project(${DL_ARGS_PROJ}-download NONE) 7 | 8 | include(ExternalProject) 9 | ExternalProject_Add(${DL_ARGS_PROJ}-download 10 | ${DL_ARGS_UNPARSED_ARGUMENTS} 11 | SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" 12 | BINARY_DIR "${DL_ARGS_BINARY_DIR}" 13 | CONFIGURE_COMMAND "" 14 | BUILD_COMMAND "" 15 | INSTALL_COMMAND "" 16 | TEST_COMMAND "" 17 | ) -------------------------------------------------------------------------------- /buildtools/cmake/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Crascit 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 | 23 | -------------------------------------------------------------------------------- /buildtools/cmake/sleepy-discord-config.cmake.in: -------------------------------------------------------------------------------- 1 | # Config file for Sleepy Discord 2 | # To be used with VCPKG 3 | 4 | # Defines 5 | # SLEEPY_DISCORD_FOUND - true when the module was found 6 | # SLEEPY_DISCORD_INCLUDE_DIR - library's include directory 7 | # SLEEPY_DISCORD_INCLUDE_DIRS - all include directories 8 | # SLEEPY_DISCORD_LIB - result from find library 9 | # SLEEPY_DISCORD_CONFIG - public compile definitions used for configuring the library 10 | # SLEEPY_DISCORD_DEPS - list of required packages 11 | 12 | # Example Useage 13 | # add_subdirectory(sleepy-discord) 14 | # configure_file( 15 | # sleepy-discord/buildtools/cmake/sleepy-discord-config.cmake.in 16 | # "example/path/to/sleepy-discord-config.cmake" 17 | # @ONLY) 18 | 19 | # !!!WARNING!!! 20 | # This is an auto generated file 21 | # Please make sure you editing the right file so changes don't get overwriten 22 | 23 | @PACKAGE_INIT@ 24 | 25 | set(SLEEPY_DISCORD_CONFIG "@LIB_CONFIG_STR@") 26 | list(APPEND SLEEPY_DISCORD_CONFIG SLEEPY_DISCORD_CMAKE) 27 | set(SLEEPY_DISCORD_INCLUDE_DIRS "@PACKAGE_LIBRARIES_INCLUDE_DIRS_STR@") 28 | set(SLEEPY_DISCORD_DEPS "@REQUIRED_PACKAGES_STR@") 29 | set(SLEEPY_FILES_TO_FIND "@FILES_TO_FIND_STR@") 30 | 31 | if(SLEEPY_FILES_TO_FIND STREQUAL "") 32 | # This variable is usually empty 33 | # However, I belive this is needed for some libraries 34 | else() 35 | foreach(file in LISTS SLEEPY_FILES_TO_FIND) 36 | find_path(SLEEPY_DISCORD_INCLUDE_DIR NAMES file) 37 | if (SLEEPY_DISCORD_INCLUDE_DIR) 38 | list(APPEND SLEEPY_DISCORD_INCLUDE_DIRS ${SLEEPY_DISCORD_INCLUDE_DIR}) 39 | endif() 40 | endforeach() 41 | endif() 42 | 43 | find_library(SLEEPY_DISCORD_LIB NAMES sleepy-discord) 44 | if(SLEEPY_DISCORD_LIB) 45 | set(SLEEPY_DISCORD_FOUND True) 46 | 47 | foreach(dep IN LISTS SLEEPY_DISCORD_DEPS) 48 | find_package("${dep}" REQUIRED) 49 | endforeach() 50 | 51 | add_library(sleepy-discord STATIC IMPORTED) 52 | 53 | set_target_properties(sleepy-discord PROPERTIES 54 | INTERFACE_INCLUDE_DIRECTORIES "${SLEEPY_DISCORD_INCLUDE_DIRS}" 55 | IMPORTED_LINK_INTERFACE_LIBRARIES "@LIBRARIES_TO_LINK_STR@" 56 | INTERFACE_COMPILE_DEFINITIONS "${SLEEPY_DISCORD_CONFIG}" 57 | IMPORTED_LOCATION "${SLEEPY_DISCORD_LIB}" 58 | CXX_STANDARD_REQUIRED ON 59 | INTERFACE_COMPILE_FEATURES "cxx_std_11;cxx_return_type_deduction" 60 | ) 61 | 62 | check_required_components(sleepy-discord) 63 | else() 64 | set(SLEEPY_DISCORD_FOUND False) 65 | endif() -------------------------------------------------------------------------------- /examples/hello/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.6) 2 | project(hello-example) 3 | 4 | if(NOT SLEEPY_DISCORD_CMAKE) 5 | add_subdirectory(../../ ${CMAKE_CURRENT_BINARY_DIR}/sleepy-discord) 6 | endif() 7 | 8 | add_executable(hello-example 9 | example0.cpp 10 | ) 11 | 12 | target_link_libraries(hello-example 13 | sleepy-discord 14 | ) -------------------------------------------------------------------------------- /examples/hello/example0.cpp: -------------------------------------------------------------------------------- 1 | #include "sleepy_discord/sleepy_discord.h" 2 | 3 | class MyClientClass : public SleepyDiscord::DiscordClient { 4 | public: 5 | using SleepyDiscord::DiscordClient::DiscordClient; 6 | void onMessage(SleepyDiscord::Message message) override { 7 | if (message.startsWith("whcg hello")) 8 | sendMessage(message.channelID, "Hello " + message.author.username); 9 | } 10 | }; 11 | 12 | int main() { 13 | MyClientClass client("token", SleepyDiscord::USER_CONTROLED_THREADS); 14 | client.setIntents(SleepyDiscord::Intent::SERVER_MESSAGES, SleepyDiscord::Intent::MESSAGE_CONTENT); 15 | client.run(); 16 | } 17 | -------------------------------------------------------------------------------- /examples/rock-paper-scissors/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.6) 2 | project(rock-paper-scissors) 3 | 4 | add_executable(rock-paper-scissors main.cpp) 5 | 6 | add_subdirectory(../../ ${CMAKE_CURRENT_BINARY_DIR}/sleepy-discord) 7 | target_link_libraries(rock-paper-scissors sleepy-discord) -------------------------------------------------------------------------------- /examples/rock-paper-scissors/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sleepy_discord/sleepy_discord.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | class GameClient : public SleepyDiscord::DiscordClient { 8 | private: 9 | enum State { 10 | NA = 0, 11 | GET_READY = 1, //Game is starting 12 | SHOOT = 2, //waiting for answer 13 | ENDED = 3 14 | }; 15 | struct Game { 16 | SleepyDiscord::User player; 17 | std::shared_ptr state; 18 | SleepyDiscord::Timer endGameTimer; 19 | std::mutex mutex; 20 | 21 | Game(const SleepyDiscord::User& gamePlayer) : 22 | player(gamePlayer), state(std::make_shared(NA)) {} 23 | //This is needed when we want to copy a game 24 | Game(const Game& game) : 25 | player(game.player), state(game.state), endGameTimer(game.endGameTimer) {} 26 | #ifdef _DEBUG 27 | ~Game() { 28 | std::cout << "DUBUG: game removed\n"; 29 | } 30 | #endif 31 | 32 | //void run(std::function startGame) { 33 | // thread = std::thread(startGame, this); 34 | //} 35 | }; 36 | std::list games; 37 | 38 | enum Weapon { 39 | ROCK = 0, 40 | PAPER = 1, 41 | SCISSORS = 2 42 | }; 43 | 44 | enum winState { 45 | WIN = 1, 46 | TIE = 0, 47 | LOSE = 2 48 | }; 49 | /* 50 | ROCK - SCISSORS = 0 - 2 = -2 -> (-2 + 3) % 3 = WIN 51 | PAPER - SCISSORS = 1 - 2 = -1 -> (-1 + 3) % 3 = LOSE 52 | ROCK - PAPER = 0 - 1 = -1 -> (-1 + 3) % 3 = LOSE 53 | PAPER - ROCK = 1 - 0 = 1 -> ( 1 + 3) % 3 = WIN 54 | SCISSORS - PAPER = 2 - 1 = 1 -> ( 1 + 3) % 3 = WIN 55 | SCISSORS - ROCK = 2 - 0 = 2 -> ( 2 + 3) % 3 = LOSE 56 | */ 57 | //#ifdef _DEBUG 58 | void onHeartbeat() { 59 | std::cout << "heartbeat sent\n"; 60 | } 61 | void onHeartbeatAck() { 62 | std::cout << "heartbeat acknowledged\n"; 63 | } 64 | //#endif 65 | public: 66 | using SleepyDiscord::DiscordClient::DiscordClient; 67 | void onMessage(SleepyDiscord::Message message) { 68 | if (message.startsWith("test hello")) { 69 | games.push_back(Game(message.author)); //create a game put it on the end of the list of games 70 | #ifdef _DEBUG 71 | std::cout << "DUBUG: New game created. Number of games: " << games.size() << '\n'; 72 | #endif 73 | std::list::iterator game = --(games.end()); 74 | const std::lock_guard lock(game->mutex); 75 | *game->state = GET_READY; 76 | SleepyDiscord::Message countMessage = sendMessage(message.channelID, "**ROCK!**"); 77 | schedule([this, countMessage]() { 78 | this->editMessage(countMessage, "**PAPER!**"); 79 | }, 1000); 80 | schedule([this, countMessage]() { 81 | this->editMessage(countMessage, "**SCISSORS!**"); 82 | }, 2000); 83 | schedule([this, game, countMessage]() { 84 | const std::lock_guard lock(game->mutex); 85 | *game->state = SHOOT; 86 | this->editMessage(countMessage, "**SHOOT!**"); 87 | }, 3000); 88 | game->endGameTimer = schedule([this, game, message]() { 89 | game->mutex.lock(); 90 | if (*game->state != ENDED) { 91 | *game->state = ENDED; 92 | sendMessage(message.channelID, "You lose.\nWhen I say ``shoot``, you pick ``rock``, ``paper``, or ``scissors``"); 93 | } 94 | game->mutex.unlock(); 95 | this->games.erase(game); 96 | }, 4000); 97 | return; 98 | } 99 | 100 | if (games.empty()) return; 101 | 102 | //get the player's choice 103 | Weapon playerChoice; 104 | if (message.content == "rock" || message.content == ":fist:" ) playerChoice = ROCK; 105 | else if (message.content == "paper" || message.content == ":raised_hand:") playerChoice = PAPER; 106 | else if (message.content == "scissors" || message.content == ":v:" ) playerChoice = SCISSORS; 107 | else return; //go back if there's no choice was detected 108 | for (Game& game : games) { 109 | const std::lock_guard lock(game.mutex); 110 | if (game.player == message.author) { 111 | #ifdef _DEBUG 112 | std::cout << "DUBUG: Player detected " << game.player.username << " state: " << *game.state << '\n'; 113 | #endif 114 | switch (*game.state) { 115 | case SHOOT: { 116 | *game.state = ENDED; //game state is set to end here, so that "you lose" isn't sent after a weapon was picked 117 | Weapon botChoice = static_cast(rand() % 3); //random number 0 to 2 118 | switch (botChoice) { 119 | case ROCK: sendMessage(message.channelID, ":fist:"); break; 120 | case PAPER: sendMessage(message.channelID, ":raised_hand:"); break; 121 | case SCISSORS: sendMessage(message.channelID, ":v:"); break; 122 | } 123 | switch ((playerChoice - botChoice + 3) % 3) { 124 | case LOSE: sendMessage(message.channelID, ":smiley: I won, and you lost!"); break; 125 | case TIE: sendMessage(message.channelID, ":neutral_face: It's a tie"); break; 126 | case WIN: sendMessage(message.channelID, ":frowning: I lost, and you won"); break; 127 | } 128 | } break; 129 | case GET_READY: sendMessage(message.channelID, "Not yet, I didn't get to say ``shoot``."); break; 130 | default: sendMessage(message.channelID, "Error: unknown state"); break; 131 | } 132 | } 133 | } 134 | } 135 | }; 136 | 137 | int main() { 138 | srand(static_cast(time(0))); //create seed to make random numbers 139 | GameClient client("Your Token Goes Here", SleepyDiscord::USER_CONTROLED_THREADS); 140 | client.setIntents( 141 | SleepyDiscord::Intent::SERVER_MESSAGES, 142 | SleepyDiscord::Intent::DIRECT_MESSAGES, 143 | SleepyDiscord::Intent::MESSAGE_CONTENT); 144 | client.run(); 145 | } -------------------------------------------------------------------------------- /examples/slash-commands/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.6) 2 | project(slash-commands) 3 | 4 | add_executable(slash-commands main.cpp) 5 | 6 | if(NOT SLEEPY_DISCORD_CMAKE) 7 | # library installed via VCPKG 8 | find_package(sleepy-discord) 9 | endif() 10 | target_link_libraries(slash-commands sleepy-discord) -------------------------------------------------------------------------------- /examples/slash-commands/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sleepy_discord/sleepy_discord.h" 2 | 3 | //Discord client code 4 | class Client; 5 | 6 | namespace Command { 7 | using Verb = std::function< 8 | void( 9 | Client&, 10 | SleepyDiscord::Interaction& 11 | ) 12 | >; 13 | struct Command { 14 | std::string name; 15 | Verb verb; 16 | }; 17 | using MappedCommands = std::unordered_map; 18 | using MappedCommand = MappedCommands::value_type; 19 | static MappedCommands all; 20 | static void addCommand(Command command) { 21 | all.emplace(command.name, command); 22 | } 23 | } 24 | 25 | class Client : public SleepyDiscord::DiscordClient 26 | { 27 | public: 28 | using SleepyDiscord::DiscordClient::DiscordClient; 29 | 30 | void onReady(SleepyDiscord::Ready ready) override { 31 | static int connectCount = 0; 32 | connectCount += 1; 33 | if (connectCount == 1) { 34 | onFirstConnect(); 35 | } 36 | } 37 | 38 | void onFirstConnect() { 39 | { 40 | Command::Command test{ 41 | "test", []( 42 | Client& client, 43 | SleepyDiscord::Interaction& interaction 44 | ) { 45 | SleepyDiscord::Interaction::Response<> response; 46 | response.type = SleepyDiscord::Interaction::CallbackType::ChannelMessageWithSource; 47 | response.data.content = "Hello!"; 48 | client.createInteractionResponse(interaction.ID, interaction.token, response); 49 | return; 50 | } 51 | }; 52 | createGlobalAppCommand(getID(), test.name, "tests commands"); 53 | Command::addCommand(test); 54 | } 55 | 56 | { 57 | Command::Command add{ 58 | "add", []( 59 | Client& client, 60 | SleepyDiscord::Interaction& interaction 61 | ) { 62 | double answer = 0; 63 | for (auto& option : interaction.data.options) { 64 | double num; 65 | if (option.get(num)) { 66 | answer += num; 67 | } 68 | } 69 | SleepyDiscord::Interaction::Response<> response; 70 | response.type = SleepyDiscord::Interaction::CallbackType::ChannelMessageWithSource; 71 | response.data.content = std::to_string(answer); 72 | client.createInteractionResponse(interaction.ID, interaction.token, response); 73 | return; 74 | } 75 | }; 76 | 77 | std::vector options; 78 | 79 | SleepyDiscord::AppCommand::Option left; 80 | left.name = "left"; 81 | left.isRequired = true; 82 | left.description = "The number to the left of the + sign"; 83 | left.type = SleepyDiscord::AppCommand::Option::TypeHelper::getType(); 84 | options.push_back(std::move(left)); 85 | 86 | SleepyDiscord::AppCommand::Option right; 87 | right.name = "right"; 88 | right.isRequired = true; 89 | right.description = "The number to the right of the + sign"; 90 | right.type = SleepyDiscord::AppCommand::Option::TypeHelper::getType(); 91 | options.push_back(std::move(right)); 92 | 93 | createGlobalAppCommand(getID(), add.name, "sum of two number", std::move(options)); 94 | Command::addCommand(add); 95 | } 96 | } 97 | 98 | void onInteraction(SleepyDiscord::Interaction interaction) override { 99 | auto foundCommand = Command::all.find(interaction.data.name); 100 | if (foundCommand == Command::all.end()) { 101 | //not found 102 | SleepyDiscord::Interaction::Response<> response; 103 | response.type = SleepyDiscord::Interaction::CallbackType::ChannelMessageWithSource; 104 | response.data.content = "Couldn't find command"; 105 | response.data.flags = SleepyDiscord::InteractionAppCommandCallbackData::Flags::Ephemeral; 106 | createInteractionResponse(interaction, interaction.token, response); 107 | return; 108 | } 109 | foundCommand->second.verb(*this, interaction); 110 | } 111 | private: 112 | }; 113 | 114 | int main() 115 | { 116 | Client client("token goes here", SleepyDiscord::USER_CONTROLED_THREADS); 117 | client.setIntents(0); 118 | client.run(); 119 | 120 | return 0; 121 | } -------------------------------------------------------------------------------- /examples/sound-player/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.6) 2 | project(sound-player) 3 | 4 | if(NOT SLEEPY_DISCORD_CMAKE) 5 | set(ENABLE_VOICE ON CACHE BOOL "") 6 | add_subdirectory(../../ ${CMAKE_CURRENT_BINARY_DIR}/sleepy-discord) 7 | endif() 8 | 9 | add_executable(sound-player main.cpp) 10 | 11 | if(NOT ENABLE_VOICE) 12 | message(FATAL_ERROR "ENABLE_VOICE needs to be set to on to be able to compile sound-player example.") 13 | endif() 14 | 15 | target_link_libraries(sound-player sleepy-discord) -------------------------------------------------------------------------------- /examples/sound-player/IO_file.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //This is c++11 code, so there's no std filesystem 6 | 7 | class File { 8 | public: 9 | File(const char* path) : file(path, std::ios::binary | std::ios::ate) { 10 | /*std::ios::ate seeks to the end 11 | This tells us where the input position indicator is 12 | giving us the size */ 13 | size = file.tellg(); 14 | /*sets the input position indicator to the begining 15 | when the input position indicator reaches the end, a 16 | eof flag is set and so clear() fixes that. */ 17 | file.clear(); 18 | file.seekg(0, std::ios::beg); 19 | } 20 | 21 | File(std::string& path) : File(path.c_str()) {} 22 | 23 | ~File() = default; 24 | 25 | template 26 | const void get(std::vector& vector) { 27 | const std::size_t numOfElements = size / sizeof(Type); 28 | vector.resize(numOfElements); 29 | file.read(reinterpret_cast(vector.data()), size); 30 | } 31 | 32 | template 33 | const void get(Type* buffer) { 34 | file.read(reinterpret_cast(buffer), size); 35 | } 36 | 37 | const std::size_t getSize() { 38 | return size; 39 | } 40 | 41 | private: 42 | std::ifstream file; 43 | std::size_t size; 44 | }; -------------------------------------------------------------------------------- /examples/wasm_example/build.bat: -------------------------------------------------------------------------------- 1 | cd ..\..\buildtools 2 | emmake make -f Makefile.linux CXX="emcc -O2 -s WASM=1" AR="emcc -O2 -o" SUFFIX=.o FLAGS="-DSLEEPY_CUSTOM_CLIENT" ISCUSTOM="TRUE" 3 | xcopy libsleepy_discord.o ..\examples\wasm_example /y 4 | cd ..\examples\wasm_example 5 | em++ -O2 -std=c++11 -I ../../include -I ../../include/sleepy_discord/IncludeNonexistent libsleepy_discord.o wasm_websocket.cpp --pre-js mod.js --js-library websocket.js --js-library session.js -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 --bind -o wasm_discord.js -------------------------------------------------------------------------------- /examples/wasm_example/how_to_get_lib.txt: -------------------------------------------------------------------------------- 1 | emsdk_env --build=Release 2 | cd ..\..\nsprojects\sleepy_discord\buildtools 3 | emmake make -f Makefile.linux CXX="emcc -O2 -s WASM=1" CXXFLAGS="-std=c++11 -DSLEEPY_ONE_THREAD" AR="emcc -O2 -o" SUFFIX=.o 4 | xcopy libsleepy_discord.o ..\examples\wasm_example /y 5 | cd ..\examples\wasm_example 6 | em++ -O2 -std=c++11 -I ../../include -I ../../include/sleepy_discord/IncludeNonexistent libsleepy_discord.o wasm_websocket.cpp --pre-js mod.js --js-library websocket.js --js-library session.js -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 --bind -o wasm_discord.js 7 | -------------------------------------------------------------------------------- /examples/wasm_example/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/wasm_example/mod.js: -------------------------------------------------------------------------------- 1 | //The Module is global, making it great for storing all sorts of things 2 | var Module = { 3 | 'print': function (text) { console.log(text); } 4 | }; 5 | 6 | Module.webSocketsList = []; 7 | Module.HTTPRequestList = []; 8 | Module.heartbeatIntervals = []; 9 | Module.destroyHandleFromList = function(handle, listOfHandles) { 10 | listOfHandles[handle] = null; 11 | //remove all trailing nulls (objects that have been destroyed) 12 | while (listOfHandles[listOfHandles.length - 1] == null) { 13 | listOfHandles.pop(); 14 | if (listOfHandles.length == 0) return; 15 | } 16 | }; 17 | Module.toCharStar = function(source) { 18 | var lengthInBytes = lengthBytesUTF8(source) + 1; 19 | var target = _malloc(lengthInBytes); 20 | stringToUTF8(source, target, lengthInBytes + 1); 21 | return target; 22 | }; -------------------------------------------------------------------------------- /examples/wasm_example/session.js: -------------------------------------------------------------------------------- 1 | function _performRequest(methodName, url, header, headerSize, sizeofPointer, body) { 2 | var handle = Module.HTTPRequestList.length; 3 | Module.HTTPRequestList.push(new XMLHttpRequest()); 4 | Module.HTTPRequestList[handle].open(Pointer_stringify(methodName), Pointer_stringify(url), false); 5 | 6 | //add headers 7 | var headerEndPointer = (sizeofPointer * headerSize) + header; 8 | for (var i = header; i < headerEndPointer; i += sizeofPointer * 2) { 9 | Module.HTTPRequestList[handle].setRequestHeader( 10 | Pointer_stringify(getValue(i, "*")), //name 11 | Pointer_stringify(getValue(i + sizeofPointer, "*")) //value 12 | ); 13 | } 14 | 15 | Module.HTTPRequestList[handle].send(Pointer_stringify(body)); 16 | 17 | console.log(Module.HTTPRequestList[handle].responseText); 18 | 19 | return handle; 20 | } 21 | 22 | function _getResponseStatusCode(handle) { 23 | return Module.HTTPRequestList[handle].status; 24 | } 25 | 26 | function _getResponseBody(handle) { 27 | return Module.toCharStar(Module.HTTPRequestList[handle].responseText); 28 | } 29 | 30 | function _getResponseHeaders(handle) { 31 | console.log(Module.HTTPRequestList[handle].getAllResponseHeaders()); 32 | return Module.toCharStar(Module.HTTPRequestList[handle].getAllResponseHeaders()); 33 | } 34 | 35 | function _destroySession(handle) { 36 | Module.destroyHandleFromList(handle, Module.HTTPRequestList); 37 | } 38 | 39 | mergeInto(LibraryManager.library, { 40 | performRequest : _performRequest , 41 | getResponseStatusCode: _getResponseStatusCode, 42 | getResponseBody : _getResponseBody , 43 | getResponseHeader : _getResponseHeaders , 44 | destroySession : _destroySession 45 | }); -------------------------------------------------------------------------------- /examples/wasm_example/wasm_session.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "sleepy_discord/session.h" 4 | #include 5 | #include //TODO remove after debugging 6 | 7 | extern "C" { 8 | extern int performRequest(const char* methodName, const char* url, const char** header, int headerSize, int sizeofPointer, const char* body); 9 | extern int getResponseStatusCode(int handle); 10 | extern char* getResponseBody(int handle); 11 | extern char* getResponseHeader(int handle); 12 | extern void destroySession(int handle); 13 | } 14 | 15 | class WebSession : public SleepyDiscord::GenericSession { 16 | private: 17 | const std::string* url = nullptr; 18 | const std::string* body = nullptr; 19 | std::vector header; 20 | 21 | char* responseBody = nullptr; 22 | 23 | SleepyDiscord::Response request(SleepyDiscord::RequestMethod method) { 24 | int handle = performRequest(getMethodName(method), url->data(), &header[0], header.size(), sizeof(const char *), body->data()); 25 | for (const char* p : header) { 26 | std::cout << p << '\n'; 27 | } 28 | 29 | int responseCode = getResponseStatusCode(handle); 30 | 31 | char* rawResponseHeader = getResponseHeader(handle); 32 | std::string rawHeader = rawResponseHeader; 33 | std::map responseHeader; 34 | //basically copied straight from my 3DS port with a different condition for the for loop 35 | //TODO: I should make function for this to stop code reuse 36 | const std::string newLine = "\r\n"; 37 | size_t offset = 0; 38 | for (size_t newLinePos = rawHeader.find(newLine, offset); //variable for the end of header 39 | offset < rawHeader.length(); //condition 40 | newLinePos = rawHeader.find(newLine, offset)) { 41 | const std::string headerFieldLeft = rawHeader.substr(offset, rawHeader.find(':', offset) - offset); 42 | offset += headerFieldLeft.length(); 43 | while (rawHeader[++offset] == ' '); //ignore whitespace 44 | const std::string headerFieldRight = rawHeader.substr(offset, newLinePos - offset); 45 | responseHeader[headerFieldLeft] = headerFieldRight; 46 | offset = newLinePos + newLine.length(); 47 | } 48 | 49 | responseBody = getResponseBody(handle); 50 | 51 | //clean up 52 | destroySession(handle); 53 | free(rawResponseHeader); 54 | 55 | return { responseCode, responseBody, responseHeader }; 56 | } 57 | 58 | public: 59 | WebSession() {} 60 | ~WebSession() { 61 | //Strings converted from JS were allocated and need to be freed 62 | if (responseBody != nullptr) free(responseBody); 63 | } 64 | inline void setUrl(const std::string& _url) { url = &_url; } 65 | inline void setBody(const std::string* jsonParamters) { body = jsonParamters; } 66 | inline void setHeader(const std::vector& _header) { 67 | header.reserve(_header.size() * 2); 68 | for (unsigned int i = 0; i < _header.size(); ++i) { 69 | header.push_back(_header[i].name); 70 | header.push_back(_header[i].value.data()); 71 | } 72 | } 73 | inline void setMultipart(const std::initializer_list& parts) {} 74 | inline SleepyDiscord::Response Post () { return request(SleepyDiscord::Post ); } 75 | inline SleepyDiscord::Response Patch () { return request(SleepyDiscord::Patch ); } 76 | inline SleepyDiscord::Response Delete() { return request(SleepyDiscord::Delete); } 77 | inline SleepyDiscord::Response Get () { return request(SleepyDiscord::Get ); } 78 | inline SleepyDiscord::Response Put () { return request(SleepyDiscord::Put ); } 79 | }; 80 | 81 | //init the custom session 82 | SleepyDiscord::CustomInit SleepyDiscord::Session::init = 83 | []()->SleepyDiscord::GenericSession* { return new WebSession; }; -------------------------------------------------------------------------------- /examples/wasm_example/wasm_websocket.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "wasm_websocket.h" 3 | #include "wasm_session.h" 4 | 5 | /*This needs to have global scope, so that JS can make calls to them*/ 6 | std::list clientList; 7 | std::list assignmentList; 8 | 9 | WebAssemblyDiscordClient::WebAssemblyDiscordClient(const std::string token) { 10 | std::cout << "cWebAssemblyDiscordClient" << '\n'; 11 | clientList.push_front(this); 12 | start(token, 1); 13 | } 14 | 15 | WebAssemblyDiscordClient::~WebAssemblyDiscordClient() { 16 | std::cout << "c~WebAssemblyDiscordClient" << '\n'; 17 | WebSocketHandle& handle = connection.get(); 18 | } 19 | 20 | SleepyDiscord::Timer WebAssemblyDiscordClient::schedule( 21 | SleepyDiscord::TimedTask code, const time_t milliseconds 22 | ) { 23 | assignmentList.emplace_front(code); 24 | Assignment& assignment = assignmentList.front(); 25 | assignment.jobID = setTimer(&assignment, milliseconds); 26 | return SleepyDiscord::Timer([assignment]() { 27 | stopTimer(assignment.jobID); 28 | assignmentList.remove(assignment); 29 | }); 30 | } 31 | 32 | //insures that we call functions of the correct client 33 | DiscordClient* getClient(const int& handle) { 34 | for (DiscordClient* c : clientList) //find client with the same handle 35 | if (c->connection.get() == handle) 36 | return c; 37 | return nullptr; 38 | } 39 | 40 | //see WebAssemblyDiscordClient::passMessageToClient 41 | extern "C" EMSCRIPTEN_KEEPALIVE void passMessageToClient(int handle, char* message) { 42 | DiscordClient* client = getClient(handle); 43 | if (client == nullptr) { 44 | free(message); 45 | return; 46 | } 47 | client->passMessageToClient(message); 48 | //Memory is allocated when converting JS strings to char arrays 49 | free(message); 50 | } 51 | 52 | //see WebAssemblyDiscordClient::doAssignment 53 | extern "C" EMSCRIPTEN_KEEPALIVE void doAssignment(Assignment* assignment) { 54 | assignment->task(); 55 | assignmentList.remove(*assignment); 56 | } 57 | 58 | #include "sleepy_discord/standard_config.h" -------------------------------------------------------------------------------- /examples/wasm_example/wasm_websocket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #define SLEEPY_CUSTOM_CLIENT 7 | #include "sleepy_discord/sleepy_discord.h" 8 | #include 9 | #include 10 | 11 | #define SLEEPY_DO_NOT_INCLUDE_STANDARD_SLEEP //without this, the broswer will crash 12 | 13 | struct Assignment { 14 | public: 15 | Assignment(SleepyDiscord::TimedTask code) : task(code) {} 16 | 17 | inline bool operator==(const Assignment& right) const { 18 | return jobID == right.jobID; 19 | } 20 | 21 | int jobID; 22 | SleepyDiscord::TimedTask task; 23 | }; 24 | 25 | extern "C" { 26 | extern void sendWebSocket(int handle, const char* message); 27 | extern void closeWebSocket(int handle, unsigned int code, const char* reason); 28 | extern int connectWebSocket(const char* uri); 29 | extern void runWebSocket(int handle); 30 | extern int setTimer(Assignment* assignment, int heartbeatInterval); 31 | extern void stopTimer(int jobID); 32 | } 33 | 34 | struct WebSocketHandle : public SleepyDiscord::GenericWebsocketConnection { 35 | public: 36 | WebSocketHandle(int _handle, SleepyDiscord::GenericMessageReceiver*& processor) : 37 | handle(_handle), messageProcessor(processor) {} 38 | 39 | inline operator int() const { 40 | return handle; 41 | } 42 | 43 | inline bool operator==(const WebSocketHandle& right) const { 44 | return handle == right.handle; 45 | } 46 | 47 | inline bool operator==(const int& right) const { 48 | return handle == right; 49 | } 50 | 51 | private: 52 | int handle; 53 | SleepyDiscord::GenericMessageReceiver*& messageProcessor; 54 | }; 55 | 56 | class WebAssemblyDiscordClient : public SleepyDiscord::BaseDiscordClient { 57 | public: 58 | WebAssemblyDiscordClient() {} 59 | WebAssemblyDiscordClient(const std::string token); 60 | ~WebAssemblyDiscordClient(); 61 | 62 | /*Since the websocket connection is done in JS, JS needs a way to pass 63 | the message from JS to the client class when Discord sents data to the 64 | client */ 65 | void passMessageToClient(std::string message) { 66 | processMessage(message); //note: threads are made in JS 67 | } 68 | 69 | void run() override { 70 | std::cout << "crun" << '\n'; 71 | std::cout << "crun end" << '\n'; 72 | } 73 | protected: 74 | //gives us the standard way of outputing the error 75 | #include "sleepy_discord/standard_config_header.h" 76 | private: 77 | 78 | bool connect( //see docs for info 79 | const std::string & uri, 80 | SleepyDiscord::GenericMessageReceiver* messageProcessor, 81 | SleepyDiscord::WebsocketConnection& connection 82 | ) override { 83 | std::cout << "cconnect" << '\n'; 84 | connection.forward( 85 | connectWebSocket(uri.data()), 86 | messageProcessor 87 | ); 88 | std::cout << "cconnect end" << static_cast(connection.get()) << '\n'; 89 | return false; //to do make connect return false on error 90 | } 91 | 92 | void disconnect( //see docs for info 93 | unsigned int code, 94 | const std::string reason, 95 | SleepyDiscord::WebsocketConnection& connection 96 | ) override { 97 | std::cout << "cdisconnect" << '\n'; 98 | closeWebSocket(connection.get(), code, reason.data()); 99 | } 100 | 101 | void send( 102 | std::string message, 103 | SleepyDiscord::WebsocketConnection& connection 104 | ) override { 105 | std::cout << "csend" << '\n'; 106 | sendWebSocket(connection.get(), message.data()); 107 | } 108 | 109 | SleepyDiscord::Timer schedule( 110 | SleepyDiscord::TimedTask code, const time_t milliseconds 111 | ) override; 112 | 113 | SLEEPY_LOCK_CLIENT_FUNCTIONS 114 | }; 115 | 116 | typedef WebAssemblyDiscordClient DiscordClient; 117 | 118 | extern "C" EMSCRIPTEN_KEEPALIVE void passMessageToClient(int handle, char* message); 119 | extern "C" EMSCRIPTEN_KEEPALIVE void doAssignment(Assignment* assignment); 120 | 121 | 122 | EMSCRIPTEN_BINDINGS(client) { 123 | emscripten::class_("WebAssemblyDiscordClient") 124 | .constructor() 125 | .function("run", &WebAssemblyDiscordClient::run) 126 | ; 127 | } 128 | -------------------------------------------------------------------------------- /examples/wasm_example/websocket.js: -------------------------------------------------------------------------------- 1 | function _sendWebSocket(handle, message) { 2 | console.log("send"); 3 | if (typeof Module.webSocketsList[handle].send !== "function") return; 4 | Module.webSocketsList[handle].send(Pointer_stringify(message)); 5 | } 6 | 7 | function _closeWebSocket(handle, code, reason) { 8 | console.log("close"); 9 | Module.webSocketsList[handle].close(code, Pointer_stringify(reason)); 10 | //clean up 11 | clearInterval(Module.heartbeatIntervals[handle]); 12 | Module.destroyHandleFromList(handle, Module.webSocketsList ); 13 | Module.destroyHandleFromList(handle, Module.heartbeatIntervals); 14 | } 15 | 16 | function _connectWebSocket(uri) { 17 | console.log("connect " + Pointer_stringify(uri)); 18 | var handle = Module.webSocketsList.length; 19 | Module.webSocketsList.push(new WebSocket(Pointer_stringify(uri))); 20 | Module.webSocketsList[handle].onopen = function (event) { 21 | console.log("onopen"); 22 | }; 23 | Module.webSocketsList[handle].onmessage = function (event) { 24 | _passMessageToClient(handle, Module.toCharStar(event.data)); 25 | }; 26 | Module.webSocketsList[handle].onerror = function (event) { 27 | console.log("onerror"); 28 | }; 29 | Module.webSocketsList[handle].onclose = function (event) { 30 | console.log("onclose"); 31 | }; 32 | 33 | //this will become interval object later, see _heartbeat 34 | Module.heartbeatIntervals.push("for later"); 35 | 36 | return handle; 37 | } 38 | 39 | function _runWebSocket(handle) { 40 | console.log("run"); 41 | } 42 | 43 | function _setTimer(assignment, milliseconds) { 44 | console.log("setTimer" + milliseconds); 45 | return setTimeout(function() { _doAssignment(assignment); }, milliseconds); 46 | } 47 | 48 | function _stopTimer(jobID) { 49 | console.log("stopTimer" + jobID); 50 | clearTimeout(jobID); 51 | } 52 | 53 | mergeInto(LibraryManager.library, { 54 | sendWebSocket : _sendWebSocket , 55 | closeWebSocket : _closeWebSocket , 56 | connectWebSocket : _connectWebSocket, 57 | runWebSocket : _runWebSocket , 58 | setTimer : _setTimer , 59 | stopTimer : _stopTimer 60 | }); -------------------------------------------------------------------------------- /include/sleepy_discord/IncludeNonexistent/asio.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define NONEXISTENT_ASIO -------------------------------------------------------------------------------- /include/sleepy_discord/IncludeNonexistent/boost/asio.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define NONEXISTENT_BOOST_ASIO -------------------------------------------------------------------------------- /include/sleepy_discord/IncludeNonexistent/cpr/cpr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define NONEXISTENT_CPR -------------------------------------------------------------------------------- /include/sleepy_discord/IncludeNonexistent/opus.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define NONEXISTENT_OPUS -------------------------------------------------------------------------------- /include/sleepy_discord/IncludeNonexistent/sodium.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define NONEXISTENT_SODIUM 3 | 4 | inline int sodium_init(void) { return -1; } 5 | -------------------------------------------------------------------------------- /include/sleepy_discord/IncludeNonexistent/version.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define NONEXISTANT_VERSION_H 3 | -------------------------------------------------------------------------------- /include/sleepy_discord/asio_include.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if !defined(NONEXISTENT_ASIO) 4 | #ifdef _WIN32 5 | #include 6 | #elif defined(unix) || defined(__unix__) || defined(__unix) 7 | #include 8 | #endif 9 | 10 | #if !defined(SLEEPY_USE_BOOST) && !defined(EXISTENT_BOOST_ASIO) 11 | #define ASIO_STANDALONE 12 | #include 13 | #ifdef NONEXISTENT_ASIO 14 | #undef ASIO_STANDALONE 15 | #define SLEEPY_USE_BOOST 16 | #endif 17 | #endif 18 | 19 | # if defined(ASIO_STANDALONE) 20 | # include 21 | namespace SleepyDiscord { 22 | using namespace ::asio; 23 | } 24 | #elif defined(SLEEPY_USE_BOOST) || defined(EXISTENT_BOOST_ASIO) 25 | #include 26 | #ifndef NONEXISTENT_BOOST_ASIO 27 | #undef NONEXISTENT_ASIO 28 | #define SLEEPY_USE_BOOST_ASIO 29 | namespace SleepyDiscord { 30 | namespace asio { 31 | using namespace boost::asio; 32 | using boost::system::error_code; 33 | } 34 | } 35 | #ifdef ASIO_STANDALONE 36 | #undef ASIO_STANDALONE 37 | #endif 38 | #endif 39 | #endif 40 | #endif -------------------------------------------------------------------------------- /include/sleepy_discord/asio_schedule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "asio_include.h" 3 | #include "timer.h" 4 | 5 | namespace SleepyDiscord { 6 | class GenericScheduleHandler { 7 | public: 8 | virtual ~GenericScheduleHandler() = default; 9 | virtual Timer schedule(TimedTask code, const time_t milliseconds) = 0; 10 | }; 11 | 12 | #ifndef NONEXISTENT_ASIO 13 | 14 | class ASIOBasedScheduleHandler : public GenericScheduleHandler { 15 | public: 16 | virtual ~ASIOBasedScheduleHandler() = default; 17 | virtual asio::io_context& getIOContext() = 0; 18 | }; 19 | 20 | class ASIOScheduleHandler : public ASIOBasedScheduleHandler { 21 | public: 22 | ASIOScheduleHandler(std::shared_ptr _io): 23 | io(_io) {} 24 | virtual ~ASIOScheduleHandler() = default; 25 | 26 | inline asio::io_context& getIOContext() override { 27 | return *io; 28 | } 29 | 30 | static void handleTimer(const asio::error_code &ec, std::function& code) { 31 | if (ec != asio::error::operation_aborted) { 32 | code(); 33 | } 34 | } 35 | 36 | inline static Timer schedule(asio::io_context& io, TimedTask code, const time_t milliseconds) { 37 | auto timer = std::make_shared(io, asio::chrono::milliseconds(milliseconds)); 38 | timer->async_wait(std::bind(&handleTimer, std::placeholders::_1, code)); 39 | return Timer([timer]() { 40 | timer->cancel(); 41 | }); 42 | } 43 | 44 | inline Timer schedule(TimedTask code, const time_t milliseconds) override { 45 | return ASIOScheduleHandler::schedule(*io, std::move(code), std::move(milliseconds)); 46 | } 47 | 48 | inline void run() { 49 | io->run(); 50 | } 51 | 52 | private: 53 | std::shared_ptr io; 54 | }; 55 | #endif 56 | } 57 | -------------------------------------------------------------------------------- /include/sleepy_discord/asio_udp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "asio_include.h" 3 | #ifndef NONEXISTENT_ASIO 4 | #include "udp.h" 5 | #if defined(SLEEPY_USE_BOOST_ASIO) 6 | #include 7 | #else 8 | #include 9 | #endif 10 | 11 | namespace SleepyDiscord { 12 | 13 | class BaseDiscordClient; 14 | 15 | class ASIOUDPClient : public GenericUDPClient { 16 | public: 17 | //ASIOUDPClient(); 18 | ASIOUDPClient(BaseDiscordClient& client); 19 | ASIOUDPClient(asio::io_context& context); 20 | bool connect(const std::string& to , const uint16_t port) override; 21 | void send( 22 | const uint8_t* buffer, 23 | size_t bufferLength, 24 | SendHandler handler = []() {} 25 | ) override; 26 | void receive(ReceiveHandler handler) override; 27 | private: 28 | asio::io_context* iOContext; 29 | asio::ip::udp::socket uDPSocket; 30 | asio::ip::udp::resolver resolver; 31 | asio::ip::udp::endpoint endpoint; 32 | 33 | void handle_receive(const std::error_code &, std::size_t bytes_transferred, ReceiveHandler handler); 34 | 35 | constexpr static std::size_t bufferSize = 1 << 16; 36 | uint8_t buffer[bufferSize]; 37 | }; 38 | 39 | typedef ASIOUDPClient UDPClient; 40 | }; 41 | #endif -------------------------------------------------------------------------------- /include/sleepy_discord/asio_websocket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "client.h" 3 | #include "message_receiver.h" 4 | #include "asio_schedule.h" 5 | #include "asio_websocketconnection.h" 6 | 7 | namespace SleepyDiscord { 8 | 9 | class ASIOWebSocketDiscordClient : public BaseDiscordClient { 10 | public: 11 | ASIOWebSocketDiscordClient() = default; 12 | ASIOWebSocketDiscordClient(const std::string token, const char _n = 0) 13 | : ASIOWebSocketDiscordClient(std::make_shared(), token) {} 14 | ASIOWebSocketDiscordClient(std::shared_ptr _ioContext, const std::string token) : 15 | ioContext(_ioContext) 16 | { 17 | setup(_ioContext, token); 18 | } 19 | ~ASIOWebSocketDiscordClient() {} 20 | 21 | std::shared_ptr ioContext; 22 | void setup(std::shared_ptr _ioContext, const std::string token) { 23 | if (workGuard && workGuard->owns_work()) { 24 | onError(GENERAL_ERROR, "can't set io context while client has work"); 25 | return; 26 | } 27 | 28 | ioContext = _ioContext; 29 | setScheduleHandler(ioContext); 30 | 31 | start(token); 32 | } 33 | 34 | void run() override { 35 | if (!ioContext) { // shouldn't happen but can if default constructor is used without setup 36 | onError(SleepyDiscord::GENERAL_ERROR, "Can't run Discord Client without async IO or Discord token."); 37 | return; 38 | } 39 | 40 | BaseDiscordClient::connect(); 41 | workGuard = std::make_shared>(asio::make_work_guard(*ioContext)); 42 | ioContext->run(); 43 | } 44 | 45 | Timer schedule(TimedTask code, const time_t milliseconds) override { 46 | return ASIOScheduleHandler::schedule(*ioContext, std::move(code), milliseconds); 47 | } 48 | 49 | void postTask(PostableTask code) override { 50 | asio::post(code); 51 | } 52 | protected: 53 | #include "standard_config_header.h" 54 | private: 55 | 56 | std::shared_ptr> workGuard; 57 | 58 | bool connect(const std::string& uri, 59 | GenericMessageReceiver& messageProcessor, 60 | WebsocketConnection& connection 61 | ) override { 62 | // set up websocket events 63 | // The connection object will own the eventListener 64 | // we can capture messageProcessor because the messageProcessor outlives the connection object 65 | ASIOWebSocketConnection::EventReceiver eventListener; 66 | eventListener.setOnMessage([&messageProcessor](std::vector data) { // copy stream to vector 67 | auto message = std::make_shared(data.begin(), data.end()); // copy again to string, dumb but it's simple and memory safe. I'll fix it later, just a temp solution 68 | messageProcessor.processMessage(WebSocketMessage{ WebSocketMessage::text, *message, message }); 69 | }); 70 | eventListener.setOnClose([&messageProcessor](uint16_t code, std::string _) { 71 | messageProcessor.processCloseCode(static_cast(code)); 72 | }); 73 | eventListener.setOnOpen([&messageProcessor]() { 74 | messageProcessor.initialize(); 75 | }); 76 | 77 | auto sharedConnection = std::make_shared(std::move(eventListener)); 78 | connection = sharedConnection; 79 | sharedConnection->connect(uri, ioContext); 80 | return true; 81 | } 82 | 83 | void disconnect(unsigned int code, const std::string reason, WebsocketConnection& _connection) override { 84 | if (auto websocketConnection = _connection.lock()) { 85 | bool startedDisconnect = websocketConnection->disconnect(code, reason); 86 | if (startedDisconnect) { 87 | std::cout << "disconnecting\n"; 88 | } 89 | else { 90 | // likly already disconnecting 91 | } 92 | } 93 | } 94 | 95 | void send(std::string message, WebsocketConnection& _connection) override { 96 | if (auto websocketConnection = _connection.lock()) { 97 | websocketConnection->send(message, WebSocketMessage::text, nullptr); 98 | } 99 | } 100 | 101 | void stopClient() override { 102 | workGuard.reset(); 103 | ioContext->stop(); 104 | } 105 | }; 106 | 107 | typedef ASIOWebSocketDiscordClient DiscordClient; 108 | } -------------------------------------------------------------------------------- /include/sleepy_discord/attachment.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "snowflake.h" 4 | #include "discord_object_interface.h" 5 | 6 | namespace SleepyDiscord { 7 | struct Attachment : public IdentifiableDiscordObject { 8 | public: 9 | Attachment() = default; 10 | //~Attachment(); 11 | //Attachment(const std::string * rawJSON); 12 | Attachment(const json::Value& json); 13 | Attachment(const nonstd::string_view& json) : 14 | Attachment(json::fromJSON(json)) { 15 | } 16 | //Attachment(const json::Values values); 17 | std::string filename; 18 | uint64_t size = 0; 19 | std::string url; 20 | std::string proxy_url; 21 | uint64_t height = 0; 22 | uint64_t width = 0; 23 | //const static std::initializer_list fields; 24 | JSONStructStart 25 | std::make_tuple( 26 | json::pair(&Attachment::ID , "id" , json::REQUIRIED_FIELD), 27 | json::pair(&Attachment::filename , "filename" , json::REQUIRIED_FIELD), 28 | json::pair(&Attachment::size , "size" , json::REQUIRIED_FIELD), 29 | json::pair(&Attachment::url , "url" , json::REQUIRIED_FIELD), 30 | json::pair(&Attachment::proxy_url, "proxy_url", json::REQUIRIED_FIELD), 31 | json::pair(&Attachment::height , "height" , json::NULLABLE_FIELD ), 32 | json::pair(&Attachment::width , "width" , json::NULLABLE_FIELD ) 33 | ); 34 | JSONStructEnd 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /include/sleepy_discord/beast_session.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NONEXISTENT_BEAST 4 | #include "http.h" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace SleepyDiscord { 10 | class BeastSession : public GenericSession { 11 | 12 | public: 13 | inline void setUrl(const std::string& url) { 14 | session.SetUrl(cpr::Url{ url }); 15 | } 16 | inline void setBody(const std::string* jsonParameters) { 17 | session.SetBody(cpr::Body{ *jsonParameters }); 18 | } 19 | void setHeader(const std::vector& header); 20 | void setMultipart(const std::vector& parts); 21 | void setResponseCallback(const ResponseCallback& callback) { 22 | responseCallback = callback; 23 | } 24 | Response request(RequestMethod method); 25 | private: 26 | Response perform(RequestMethod method); 27 | //cpr::Session session; 28 | //muiltpart is needs to be here when uploading images, 29 | //so that it's not deallocated when making the request 30 | //cpr::Multipart muiltpart = {}; 31 | ResponseCallback responseCallback; 32 | }; 33 | 34 | typedef BeastSession Session; 35 | } 36 | #endif -------------------------------------------------------------------------------- /include/sleepy_discord/cache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "snowflake.h" 5 | #include "server.h" 6 | #include "channel.h" 7 | 8 | namespace SleepyDiscord { 9 | template 10 | using CacheParent = std::unordered_map::RawType, _Type>; 11 | 12 | //This is basicity an unordered_map made to work with the library 13 | //only works with Discord Object with an id 14 | template 15 | struct Cache : public CacheParent<_Type> { 16 | public: 17 | using Type = _Type; 18 | using Parent = CacheParent<_Type>; 19 | using std::unordered_map::RawType, _Type>::unordered_map; 20 | using Key = typename Snowflake::RawType; 21 | Cache() : Parent() {} 22 | Cache(Parent map) : Parent(map) {} 23 | template 24 | Cache(InputIterator first, InputIterator last) { 25 | for (InputIterator it = first; it != last; ++it) { 26 | emplace(*it); 27 | } 28 | } 29 | 30 | class const_iterator { 31 | public: 32 | using Value = typename Parent::const_iterator; 33 | //standard iterator values 34 | using self_type = const_iterator; 35 | using value_type = Type; 36 | using reference = Type&; 37 | using pointer = Type*; 38 | using iterator_category = typename Value::iterator_category; 39 | using difference_type = typename Value::difference_type; 40 | const_iterator(Value iter) : value(iter) {} 41 | inline self_type operator++() { return value++; } 42 | inline self_type operator++(int junk) { return value.operator++(junk); } 43 | inline reference operator*() { return value->second; } 44 | inline pointer operator->() { return &value->second; } 45 | inline bool operator==(const self_type& right) { return value == right.value; } 46 | inline bool operator!=(const self_type& right) { return value != value.value; } 47 | inline Value getParent() { return value; } 48 | private: 49 | Value value; 50 | }; 51 | 52 | class iterator { 53 | public: 54 | using Value = typename Parent::iterator; 55 | //standard iterator values 56 | using self_type = iterator; 57 | using value_type = Type; 58 | using reference = Type&; 59 | using pointer = Type*; 60 | using iterator_category = typename Value::iterator_category; 61 | using difference_type = typename Value::difference_type; 62 | iterator(Value iter) : value(iter) {} 63 | inline self_type operator++() { return value++; } 64 | inline self_type operator++(int junk) { return value.operator++(junk); } 65 | inline reference operator*() { return value->second; } 66 | inline pointer operator->() { return &value->second; } 67 | inline bool operator==(const self_type& right) { return value == right.value; } 68 | inline bool operator!=(const self_type& right) { return value != right.value; } 69 | inline operator const_iterator() { return const_iterator(value); } 70 | inline Value getParent() { return value; } 71 | private: 72 | Value value; 73 | }; 74 | 75 | inline iterator begin() { 76 | return iterator(Parent::begin()); 77 | } 78 | 79 | inline iterator end() { 80 | return iterator(Parent::end()); 81 | } 82 | 83 | inline const_iterator begin() const { 84 | return const_iterator(Parent::begin()); 85 | } 86 | 87 | inline const_iterator end() const { 88 | return const_iterator(Parent::begin()); 89 | } 90 | 91 | //Worse then linear time 92 | template 93 | const_iterator findOneWithObject(Container Type::*list, const Snowflake& objectID) { 94 | return const_iterator( 95 | std::find_if(Parent::begin(), Parent::end(), [list, &objectID](typename Parent::value_type& thing) { 96 | auto result = objectID.findObject(thing.second.*list); 97 | return result != (thing.second.*list).end(); 98 | }) 99 | ); 100 | } 101 | 102 | std::pair insert(Type& value) { 103 | std::pair pair = Parent::insert(typename Parent::value_type(value.ID, value)); 104 | return {iterator(pair.first), pair.second}; 105 | } 106 | 107 | template 108 | std::pair emplace(const json::Value& value) { 109 | const json::Value& ID = value["id"]; 110 | std::pair pair = Parent::emplace(std::string(ID.GetString(), ID.GetStringLength()), value); 111 | return {iterator(pair.first), pair.second}; 112 | } 113 | 114 | iterator find(const Key& key) { 115 | return iterator(Parent::find(key)); 116 | } 117 | 118 | const_iterator find(const Key& key) const { 119 | return const_iterator(Parent::find(key)); 120 | } 121 | 122 | iterator erase(const_iterator pos) { 123 | return iterator(Parent::erase(pos.getParent())); 124 | } 125 | 126 | iterator erase(const_iterator first, const_iterator last) { 127 | return iterator(Parent::erase(first.getParent(), last.getParent())); 128 | } 129 | 130 | //In the case of push_back needed 131 | //remove /**/ 132 | /* 133 | //Does not add to the end, this is just for compatability for 134 | //some SleepyDiscord functions 135 | inline void push_back(const Type& value) { 136 | insert(value); 137 | } 138 | 139 | inline void push_back(Type&& value) { 140 | insert(value); 141 | } 142 | */ 143 | }; 144 | } -------------------------------------------------------------------------------- /include/sleepy_discord/common_return_types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "http.h" 4 | #include "json_wrapper.h" 5 | #include "error.h" 6 | 7 | namespace SleepyDiscord { 8 | struct StandardResponse : Response { //This is here for possiable future use 9 | explicit StandardResponse(const Response& response) : Response(response) {} 10 | }; 11 | 12 | struct BooleanResponse : public StandardResponse { 13 | public: 14 | using StandardResponse::StandardResponse; 15 | using Callback = std::function; 16 | using Type = bool; 17 | BooleanResponse(const Response& response, const Callback callback) : 18 | StandardResponse(response), wasSuccessful(callback) { } 19 | 20 | inline operator Type() const { 21 | return wasSuccessful(*this) || !error(); 22 | } 23 | 24 | Type operator*() const { 25 | return operator Type(); 26 | } 27 | 28 | inline Type cast() { 29 | return operator Type(); 30 | } 31 | 32 | //this isn't a function so that we can override it during construction. 33 | //this isn't a virtual function because then we need lots of child classes 34 | //this isn't used in a template because then the user would have to write the right error handling function 35 | const Callback wasSuccessful = [](const Response& /*response*/) { return true; }; 36 | }; 37 | 38 | typedef BooleanResponse BoolResponse; 39 | 40 | template 41 | inline const BooleanResponse::Callback SuccessCodeFn() { 42 | return [](const Response& response) {return response.statusCode == Code; }; 43 | } 44 | 45 | inline const BooleanResponse::Callback EmptyRespFn() { 46 | return SuccessCodeFn(); 47 | } 48 | 49 | inline const BooleanResponse::Callback StandardRespFn() { 50 | return SuccessCodeFn(); 51 | } 52 | 53 | 54 | template 55 | struct ObjectResponse : public StandardResponse { 56 | using StandardResponse::StandardResponse; 57 | using Type = _Type; 58 | 59 | operator Type() { //to do use references instead of pointers 60 | return error() ? Type() : Type(text); 61 | } 62 | 63 | Type& operator*() const { 64 | return operator Type(); 65 | } 66 | 67 | inline Type cast() { 68 | return operator Type(); 69 | } 70 | 71 | inline bool cast(Type& value) { 72 | if (error()) 73 | return false; 74 | rapidjson::Document doc; 75 | rapidjson::ParseResult isOK = 76 | doc.Parse(text.c_str(), text.length()); 77 | if (!isOK) 78 | return false; 79 | value = Type(doc); 80 | return true; 81 | } 82 | }; 83 | 84 | 85 | struct ArrayResponseWrapper : public StandardResponse { 86 | using StandardResponse::StandardResponse; 87 | using Type = std::string; 88 | inline operator const std::string&() const { 89 | return text; 90 | } 91 | inline rapidjson::Document getDoc() { 92 | rapidjson::Document arr; //ARR, I'm a pirate 93 | arr.Parse(text.data(), text.length()); 94 | return arr; 95 | } 96 | template 97 | inline rapidjson::ParseResult getDoc(Callback& callback) { 98 | rapidjson::Document arr; 99 | rapidjson::ParseResult isOK = 100 | arr.Parse(text.data(), text.length()); 101 | if (isOK) callback(arr); 102 | return isOK; 103 | } 104 | }; 105 | 106 | template 107 | using ArrayResponse = json::ArrayWrapper; 108 | 109 | struct StringResponse : public StandardResponse { 110 | using StandardResponse::StandardResponse; 111 | using Type = std::string; 112 | inline operator const Type&() const { 113 | return text; 114 | } 115 | }; 116 | 117 | using VoidResponse = StringResponse; 118 | } 119 | -------------------------------------------------------------------------------- /include/sleepy_discord/compression.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(EXISTENT_ZLIB_NG) || defined(EXISTENT_ZLIB) 4 | #include "zlib_compression.h" 5 | #else 6 | #include "generic_compression.h" 7 | #endif // EXISTENT_ZLIB_NG -------------------------------------------------------------------------------- /include/sleepy_discord/cpr_session.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(SLEEPY_DISCORD_CMAKE) 4 | #if defined(EXISTENT_CPR) 5 | #include 6 | #else 7 | #define NONEXISTENT_CPR 8 | #endif 9 | #else 10 | #include 11 | #endif 12 | 13 | #ifndef NONEXISTENT_CPR 14 | #include "http.h" 15 | 16 | namespace SleepyDiscord { 17 | class CPRSession : public GenericSession { 18 | public: 19 | inline void setUrl(const std::string& url) { 20 | session.SetUrl(cpr::Url{ url }); 21 | } 22 | inline void setBody(const std::string* jsonParameters) { 23 | session.SetBody(cpr::Body{ *jsonParameters }); 24 | } 25 | void setHeader(const std::vector& header); 26 | void setMultipart(const std::vector& parts); 27 | void setResponseCallback(const ResponseCallback& callback) { 28 | responseCallback = callback; 29 | } 30 | Response request(RequestMethod method); 31 | private: 32 | Response perform(RequestMethod method); 33 | cpr::Session session; 34 | //muiltpart is needs to be here when uploading images, 35 | //so that it's not deallocated when making the request 36 | cpr::Multipart muiltpart = {}; 37 | ResponseCallback responseCallback; 38 | }; 39 | 40 | typedef CPRSession Session; 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/sleepy_discord/custom_connection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "websocket.h" 4 | 5 | namespace SleepyDiscord { 6 | typedef std::shared_ptr WebsocketConnection; 7 | } -------------------------------------------------------------------------------- /include/sleepy_discord/custom_session.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "http.h" 4 | 5 | namespace SleepyDiscord { 6 | typedef GenericSession* (*const CustomInit)(); //keep compatibility with old code 7 | typedef CustomInit CustomInitSession; 8 | 9 | class CustomSession : public GenericSession { 10 | public: 11 | static CustomInitSession init; 12 | CustomSession() : session(init()) {} 13 | inline void setUrl(const std::string& url) { session->setUrl(url); } 14 | inline void setBody(const std::string* jsonParamters) { session->setBody(jsonParamters); } 15 | inline void setHeader(const std::vector& header) { 16 | session->setHeader(header); 17 | } 18 | inline void setMultipart(const std::vector& parts) { 19 | session->setMultipart(parts); 20 | } 21 | inline void setResponseCallback(const ResponseCallback& callback) { 22 | session->setResponseCallback(callback); 23 | } 24 | inline Response request(RequestMethod method) { 25 | return session->request(method); 26 | } 27 | private: 28 | std::unique_ptr session; //pointer to session 29 | }; 30 | 31 | typedef CustomSession Session; 32 | } 33 | -------------------------------------------------------------------------------- /include/sleepy_discord/custom_udp_client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "udp.h" 4 | 5 | namespace SleepyDiscord { 6 | typedef GenericUDPClient* (*const CustomInitUDPClient)(); 7 | 8 | class CustomUDPClient : public GenericUDPClient { 9 | protected: 10 | static CustomInitUDPClient init; 11 | CustomUDPClient() : client(init()) {} 12 | inline bool connect(const std::string& to, const uint16_t port) override { 13 | return client->connect(to, port); 14 | } 15 | inline void send( 16 | const uint8_t* buffer, 17 | size_t bufferLength, 18 | SendHandler handler = []() {} 19 | ) override { 20 | return client->send(buffer, bufferLength, handler); 21 | } 22 | inline void receive(ReceiveHandler handler) override { 23 | return client->receive(handler); 24 | } 25 | private: 26 | std::unique_ptr client; 27 | }; 28 | 29 | typedef CustomUDPClient UDPClient; 30 | } -------------------------------------------------------------------------------- /include/sleepy_discord/discord_object_interface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "json_wrapper.h" 4 | #include "snowflake.h" 5 | #include "error.h" 6 | #include "http.h" 7 | 8 | namespace SleepyDiscord { 9 | class BaseDiscordClient; 10 | 11 | class DiscordObject { 12 | 13 | }; 14 | 15 | struct EmptyDiscordObject { 16 | EmptyDiscordObject() = default; 17 | EmptyDiscordObject(const nonstd::string_view& rawJSON) : 18 | EmptyDiscordObject(json::fromJSON(rawJSON)) {} 19 | EmptyDiscordObject(const json::Value & json) : 20 | EmptyDiscordObject(json::fromJSON(json)) {} 21 | 22 | JSONStructStart 23 | std::make_tuple(); 24 | JSONStructEnd 25 | }; 26 | 27 | template 28 | class IdentifiableDiscordObject : public DiscordObject { 29 | public: 30 | IdentifiableDiscordObject() = default; 31 | IdentifiableDiscordObject(Snowflake id) : ID(id) {} 32 | 33 | using Parent = IdentifiableDiscordObject; 34 | using Identifier = Snowflake; 35 | 36 | Snowflake ID; 37 | 38 | inline operator Snowflake&() { 39 | return ID; 40 | } 41 | 42 | inline bool empty() const { 43 | return ID.empty(); 44 | } 45 | 46 | void merge(Derived& changes) { 47 | json::mergeObj(*this, changes); 48 | } 49 | 50 | template 51 | inline bool operator==(const Snowflake& right) const { 52 | return ID == static_cast>(right); 53 | } 54 | 55 | template 56 | inline bool operator!=(const Snowflake& right) const { 57 | return ID != static_cast>(right); 58 | } 59 | 60 | inline bool operator==(const Snowflake& right) const { 61 | return operator==(right); 62 | } 63 | 64 | inline bool operator!=(const Snowflake& right) const { 65 | return operator!=(right); 66 | } 67 | 68 | inline bool operator==(const IdentifiableDiscordObject& right) const { 69 | return ID == right.ID; 70 | } 71 | 72 | inline bool operator!=(const IdentifiableDiscordObject& right) const { 73 | return ID != right.ID; 74 | } 75 | 76 | inline const Time getTimestamp() { 77 | return ID.timestamp(); 78 | } 79 | }; 80 | 81 | //constexpr unsigned int index(std::initializer_list names, const char * name, unsigned int i = 0) { 82 | // for (const char *const n : names) 83 | // if (strcmp(n, name) != 0) ++i; 84 | // else break; 85 | // return i; 86 | //}//sadly this doesn't work on c++11, leaving this here for the future 87 | 88 | template class Container, typename Type> //forces this be done at compile time, I think, and hope it does 89 | constexpr unsigned int index(Container names, Type * name, unsigned int i = 0) { 90 | return i + names.begin() != names.end() && strcmp(*(i + names.begin()), name) != 0 ? index(names, name, i + 1) : i; 91 | } 92 | 93 | template 94 | std::vector<_DiscordObject> JSON_getArray(const std::string* _source) { 95 | return json::ArrayWrapper<_DiscordObject>(*_source); 96 | } 97 | 98 | //somethings I need it to be a reference 99 | template 100 | inline std::vector<_DiscordObject> JSON_getArray(const Type& _source) { 101 | return json::ArrayWrapper<_DiscordObject>(_source); 102 | } 103 | 104 | template 105 | inline std::list<_DiscordObject> JSON_getList(const Type& _source) { 106 | return json::ArrayWrapper<_DiscordObject>(_source); 107 | } 108 | } -------------------------------------------------------------------------------- /include/sleepy_discord/error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace SleepyDiscord { 4 | enum ErrorCode { 5 | ERROR_ZERO = 0, 6 | 7 | //HTTP Response/Error Codes 8 | SWITCHING_PROTOCOLS = 101, //The server has acknowledged a request to switch protocols 9 | OK = 200, //The request completed successfully 10 | CREATED = 201, //The entity was created successfully 11 | NO_CONTENT = 204, //The request completed successfully but returned no content 12 | NOT_MODIFIED = 304, //The entity was not modified(no action was taken) 13 | BAD_REQUEST = 400, //The request was improperly formatted, or the server couldn't understand it 14 | UNAUTHORIZED = 401, //The Authorization header was missing or invalid 15 | FORBIDDEN = 403, //The Authorization token you passed did not have permission to the resource 16 | NOT_FOUND = 404, //The resource at the location specified doesn't exist 17 | METHOD_NOT_ALLOWED = 405, //The HTTP method used is not valid for the location specified 18 | TOO_MANY_REQUESTS = 429, //You've made too many requests, see Rate Limiting https://discordapp.com/developers/docs/reference#rate-limiting 19 | GATEWAY_UNAVAILABLE = 502, //There was not a gateway available to process your request.Wait a bit and retry 20 | //SERVER_ERROR = 5xx //The server had an error processing your request(these are rare) 21 | 22 | //JSON Error Response 23 | 24 | //Disconnections 25 | UNKNOWN_ERROR = 4000, //We're not sure what went wrong. Try reconnecting? 26 | UNKNOWN_OPCODE = 4001, //You sent an invalid Gateway OP Code.Don't do that! 27 | DECODE_ERROR = 4002, //You sent an invalid payload to us.Don't do that! 28 | NOT_AUTHENTICATED = 4003, //You sent us a payload prior to identifying. 29 | AUTHENTICATION_FAILED = 4004, //The account token sent with your identify payload is incorrect. 30 | ALREADY_AUTHENTICATED = 4005, //You sent more than one identify payload.Don't do that! 31 | SESSION_NO_LONGER_VALID = 4006, //Your session is no longer valid. 32 | INVALID_SEQ = 4007, //The sequence sent when resuming the session was invalid.Reconnect and start a new session. 33 | RATE_LIMITED = 4008, //Woah nelly!You're sending payloads to us too quickly. Slow it down! 34 | SESSION_TIMEOUT = 4009, //Your session timed out.Reconnect and start a new one. 35 | INVALID_SHARD = 4010, //You sent us an invalid shard when identifying. 36 | SHARDING_REQUIRED = 4011, //The session would have handled too many guilds - you are required to shard your connection in order to connect. 37 | UNKNOWN_PROTOCOL = 4012, //We didn't recognize the protocol you sent. 38 | INVALID_INTENTS = 4013, //You sent an invalid version for the gateway. 39 | DISALLOWED_INTENTS = 4014, //You sent a disallowed intent for a Gateway Intent. 40 | VOICE_SERVER_CRASHED = 4015, //The server crashed. Our bad! Try resuming. 41 | UNKNOWN_ENCRYPTION_MODE = 4016, //We didn't recognize your encryption. 42 | 43 | //Sleepy Errors 44 | RECONNECTING = 4900, 45 | CONNECT_FAILED = 5000, //Failed to connect to the Discord api after 4 trys 46 | EVENT_UNKNOWN = 5001, //Unexpected or unknown event occurred 47 | GATEWAY_FAILED = 5002, //Could not get the gateway 48 | GENERAL_ERROR = 5003, //Used when you are too lazy to use a error code 49 | LAZY_ERROR = 5004, //Used when you are too lazy to use a error code and message 50 | ERROR_NOTE = 5005, //Comes after an error to give more detail about an error in the message 51 | VOICE_NO_SODIUM = 5006, //Failed to init libsodium. Try linking libsodium? 52 | VOICE_NO_OPUS = 5007, //Failed to init libopus. Try linking libopus? 53 | CANT_SCHEDULE = 5008, //The Discord Client's scheduleHandler is not set 54 | }; 55 | } -------------------------------------------------------------------------------- /include/sleepy_discord/generic_compression.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace SleepyDiscord { 5 | class GenericCompression { 6 | public: 7 | virtual ~GenericCompression() = default; 8 | virtual void uncompress(const std::string& compressed) = 0; 9 | virtual void getOutput(std::string& uncompressedOut) = 0; 10 | virtual void resetStream() = 0; 11 | virtual bool streamEnded() = 0; 12 | }; 13 | } -------------------------------------------------------------------------------- /include/sleepy_discord/http.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "error.h" 8 | 9 | //important note, all requests on sync mode throw on an http error 10 | 11 | namespace SleepyDiscord { 12 | //http variables and functions 13 | //request functions 14 | enum RequestMethod { 15 | Post = 0, 16 | Patch = 1, 17 | Delete = 2, 18 | Get = 3, 19 | Put = 4 20 | }; 21 | 22 | class BaseDiscordClient; 23 | 24 | //copied from cpr 25 | struct caseInsensitiveCompare { 26 | bool operator()(const std::string& a, const std::string& b) const noexcept; 27 | }; 28 | 29 | struct Response { 30 | std::string text; 31 | int32_t statusCode = 0; 32 | std::map header; 33 | time_t birth = 0; 34 | inline bool error() const { 35 | return BAD_REQUEST <= statusCode; 36 | } 37 | Response() = default; 38 | Response(int32_t _statusCode) : statusCode(_statusCode) {} 39 | }; 40 | 41 | struct filePathPart { 42 | const std::string filePath; 43 | }; 44 | 45 | struct Part { 46 | Part(const std::string _name, const std::string _value) : 47 | name(_name), value(_value), isFile(false) {} 48 | Part(const std::string _name, const filePathPart _file) : 49 | name(_name), value(_file.filePath), isFile(true) {} 50 | const std::string name; 51 | const std::string value; 52 | const bool isFile; //if isFile is true then value is the filepath 53 | }; 54 | 55 | typedef std::initializer_list Multipart; 56 | 57 | struct HeaderPair { 58 | const char *const name; 59 | std::string value = ""; 60 | HeaderPair(const char* _name) : name(_name) {} 61 | HeaderPair(const char* _name, std::string _value) : name(_name), value(_value) {} 62 | }; 63 | 64 | class GenericSession { 65 | public: 66 | using ResponseCallback = std::function; 67 | virtual void setUrl(const std::string& url) = 0; 68 | virtual void setBody(const std::string* jsonParameters) = 0; 69 | virtual void setHeader(const std::vector& header) = 0; 70 | virtual void setMultipart(const std::vector& parts) = 0; 71 | virtual void setResponseCallback(const ResponseCallback& callback) = 0; 72 | virtual Response request(RequestMethod method) = 0; 73 | }; 74 | 75 | //Use this to convert RequestMethod into a string 76 | const char* getMethodName(const RequestMethod& method); 77 | 78 | std::string escapeURL(const std::string& string); 79 | }; 80 | -------------------------------------------------------------------------------- /include/sleepy_discord/invite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "discord_object_interface.h" 4 | #include "user.h" 5 | #include "server.h" 6 | #include "channel.h" 7 | #include "snowflake.h" 8 | 9 | namespace SleepyDiscord { 10 | /* 11 | Invite Structure Represents a code that when used, adds a user to a guild. 12 | 13 | Field Type Description 14 | code string the invite code (unique ID) 15 | guild a invite guild object the guild this invite is for 16 | channel a invite channel object the channel this invite is for 17 | */ 18 | struct Invite : public DiscordObject { 19 | public: 20 | Invite() = default; 21 | //~Invite(); 22 | //Invite(const std::string * rawJson); 23 | Invite(const json::Value & json); 24 | Invite(const nonstd::string_view& json) : 25 | Invite(json::fromJSON(json)) {} 26 | //Invite(const json::Values values); 27 | std::string code; 28 | Server server; 29 | Channel channel; 30 | 31 | //const static std::initializer_list fields; 32 | JSONStructStart 33 | std::make_tuple( 34 | json::pair(&Invite::code , "code" , json::REQUIRIED_FIELD), 35 | json::pair(&Invite::server , "guild" , json::OPTIONAL_FIELD ), 36 | json::pair(&Invite::channel, "channel", json::REQUIRIED_FIELD) 37 | ); 38 | JSONStructEnd 39 | }; 40 | 41 | /* 42 | Invite Metadata Structure 43 | 44 | Field Type Description 45 | inviter a user object user who created the invite 46 | uses integer number of times this invite has been used 47 | max_uses integer max number of times this invite can be used 48 | max_age integer duration (in seconds) after which the invite expires 49 | temporary bool whether this invite only grants temporary membership 50 | created_at datetime when this invite was created 51 | revoked bool whether this invite is revoked 52 | */ 53 | struct InviteMetadata : public DiscordObject { 54 | InviteMetadata() = default; 55 | //~InviteMetadata(); 56 | //InviteMetadata(const std::string * rawJson); 57 | //InviteMetadata(const json::Values values); 58 | InviteMetadata(const json::Value & json); 59 | InviteMetadata(const nonstd::string_view& json) : 60 | InviteMetadata(json::fromJSON(json)) {} 61 | User inviter; 62 | int uses = 0; 63 | int max_users = 0; 64 | int max_age = 0; 65 | bool isTemporary; 66 | std::string createAt; 67 | bool revoked; 68 | 69 | //const static std::initializer_list fields; 70 | JSONStructStart 71 | std::make_tuple( 72 | json::pair(&InviteMetadata::inviter , "inviter" , json::REQUIRIED_FIELD), 73 | json::pair(&InviteMetadata::uses , "uses" , json::REQUIRIED_FIELD), 74 | json::pair(&InviteMetadata::max_users , "max_uses" , json::REQUIRIED_FIELD), 75 | json::pair(&InviteMetadata::max_age , "max_age" , json::REQUIRIED_FIELD), 76 | json::pair(&InviteMetadata::isTemporary, "temporary" , json::REQUIRIED_FIELD), 77 | json::pair(&InviteMetadata::createAt , "created_at", json::REQUIRIED_FIELD), 78 | json::pair(&InviteMetadata::revoked , "revoked" , json::REQUIRIED_FIELD) 79 | ); 80 | JSONStructEnd 81 | }; 82 | } -------------------------------------------------------------------------------- /include/sleepy_discord/message_receiver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "websocket_connection.h" 4 | #include "timer.h" 5 | 6 | namespace SleepyDiscord { 7 | struct WebSocketMessage { 8 | enum OPCode { 9 | continuation = 0x0, 10 | text = 0x1, 11 | binary = 0x2, 12 | close = 0x8, 13 | ping = 0x9, 14 | pong = 0xA, 15 | }; 16 | using OPCodeType = OPCode; 17 | OPCodeType opCode = text; 18 | const std::string& payload; 19 | //since we are using a reference, we need to keep the payload in memory 20 | std::shared_ptr lifetime; //not might to be read from 21 | }; 22 | 23 | class GenericMessageReceiver { 24 | public: 25 | virtual ~GenericMessageReceiver() = default; 26 | virtual void initialize() {} //called when ready to recevie messages 27 | virtual void handleFailToConnect() {} //called when connection has failed to start 28 | virtual void processMessage(const std::string & message) = 0; //called when recevicing a message 29 | virtual void processCloseCode(const int16_t /*code*/) {} 30 | virtual void processMessage(const WebSocketMessage message) { 31 | processMessage(message.payload); 32 | } 33 | WebsocketConnection connection; //maybe this should be set to protected? 34 | protected: 35 | int consecutiveReconnectsCount = 0; 36 | Timer reconnectTimer; 37 | 38 | inline const time_t getRetryDelay() { 39 | return consecutiveReconnectsCount < 50 ? consecutiveReconnectsCount * 5000 : 5000 * 50; 40 | } 41 | }; 42 | } -------------------------------------------------------------------------------- /include/sleepy_discord/net_endian.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #if __cplusplus >= 202002L 6 | #include 7 | #define SLEEPY_ENDIAN_IF if constexpr 8 | #else 9 | #define SLEEPY_ENDIAN_IF if 10 | #endif 11 | 12 | namespace SleepyDiscord { 13 | 14 | enum class Endian 15 | { 16 | Little = 0, 17 | Big = 1, 18 | Unknown, // Could be PowerPC, which uses per-page endianness 19 | }; 20 | 21 | constexpr Endian getSystemEndian() { 22 | #ifdef __cpp_lib_endian 23 | return std::endian::native == std::endian::big ? Endian::Big : 24 | std::endian::native == std::endian::little ? Endian::Little : 25 | Endian::Unknown; // could be PowerPC 26 | #elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) 27 | return Endian::Little; 28 | #elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) 29 | return Endian::Big; 30 | #else 31 | return Endian::Unknown; 32 | #endif 33 | } 34 | 35 | template 36 | const std::array getByteOrder2() { 37 | const short bytes{ 0x0100 }; 38 | const void* address{ static_cast(&bytes) }; 39 | const Byte* byteOrder{ static_cast(address) }; 40 | return std::array{byteOrder[0], byteOrder[1]}; 41 | } 42 | 43 | template 44 | const std::array getByteOrder8() { 45 | const long long bytes{ 0x0706050403020100 }; 46 | const void* address{ static_cast(&bytes) }; 47 | const char* byteOrder{ static_cast(address) }; 48 | std::array output{}; 49 | std::memcpy(output.data(), byteOrder, output.size()); 50 | return output; 51 | } 52 | 53 | template 54 | struct EndianTyped { 55 | using IntegerType = Integer; 56 | Integer raw; 57 | }; 58 | 59 | // you don't need to know the endianness, bitshifting works across endians 60 | 61 | template 62 | uint16_t net2System16(const std::array value) { 63 | static_assert(sizeof(uint16_t) == 2, "uint16_t must be 2 bytes large"); 64 | constexpr Endian systemEndian = getSystemEndian(); 65 | SLEEPY_ENDIAN_IF (Endian::Big == systemEndian) { 66 | uint16_t output; 67 | std::memcpy(&output, value.data(), value.size()); 68 | return output; 69 | } 70 | 71 | return ( 72 | ((static_cast(value[1]) << 0) & static_cast(0x00FF)) | \ 73 | ((static_cast(value[0]) << 8) & static_cast(0xFF00)) 74 | ); 75 | } 76 | 77 | template 78 | uint64_t net2System64(const std::array value) { 79 | static_assert(sizeof(uint64_t) == 8, "uint16_t must be 8 bytes large"); 80 | constexpr Endian systemEndian = getSystemEndian(); 81 | SLEEPY_ENDIAN_IF(Endian::Big == systemEndian) { 82 | uint64_t output; 83 | std::memcpy(&output, value.data(), value.size()); 84 | return output; 85 | } 86 | 87 | return( 88 | ((static_cast(value[7]) << 0) & 0x00000000000000FFLL) | \ 89 | ((static_cast(value[6]) << 8) & 0x000000000000FF00LL) | \ 90 | ((static_cast(value[5]) << 16) & 0x0000000000FF0000LL) | \ 91 | ((static_cast(value[4]) << 24) & 0x00000000FF000000LL) | \ 92 | ((static_cast(value[3]) << 32) & 0x000000FF00000000LL) | \ 93 | ((static_cast(value[2]) << 40) & 0x0000FF0000000000LL) | \ 94 | ((static_cast(value[1]) << 48) & 0x00FF000000000000LL) | \ 95 | ((static_cast(value[0]) << 56) & 0xFF00000000000000LL) 96 | ); 97 | } 98 | 99 | template 100 | std::array system2net16(const uint16_t value) { 101 | static_assert(sizeof(uint16_t) == 2, "uint16_t must be 8 bytes large"); 102 | std::array output{}; 103 | 104 | constexpr Endian systemEndian = getSystemEndian(); 105 | SLEEPY_ENDIAN_IF (systemEndian == Endian::Big) { 106 | std::memcpy(output.data(), &value, output.size()); 107 | return output; 108 | } 109 | 110 | output[1] = static_cast((value << 0) & static_cast(0x00FF)); 111 | output[0] = static_cast((value << 8) & static_cast(0xFF00)); 112 | return output; 113 | } 114 | 115 | template 116 | std::array system2net64(const uint64_t value) { 117 | static_assert(sizeof(uint64_t) == 8, "uint16_t must be 8 bytes large"); 118 | std::array output{}; 119 | 120 | constexpr Endian systemEndian = getSystemEndian(); 121 | SLEEPY_ENDIAN_IF (systemEndian == Endian::Big) { 122 | std::memcpy(output.data(), &value, output.size()); 123 | return output; 124 | } 125 | 126 | output[7] = static_cast((value << 0) & 0x00000000000000FFLL); 127 | output[6] = static_cast((value << 8) & 0x000000000000FF00LL); 128 | output[5] = static_cast((value << 16) & 0x0000000000FF0000LL); 129 | output[4] = static_cast((value << 24) & 0x00000000FF000000LL); 130 | output[3] = static_cast((value << 32) & 0x000000FF00000000LL); 131 | output[2] = static_cast((value << 40) & 0x0000FF0000000000LL); 132 | output[1] = static_cast((value << 48) & 0x00FF000000000000LL); 133 | output[0] = static_cast((value << 56) & 0xFF00000000000000LL); 134 | return output; 135 | } 136 | 137 | } -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/cursorstreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ 16 | #define RAPIDJSON_CURSORSTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | 20 | #if defined(__GNUC__) 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(effc++) 23 | #endif 24 | 25 | #if defined(_MSC_VER) && _MSC_VER <= 1800 26 | RAPIDJSON_DIAG_PUSH 27 | RAPIDJSON_DIAG_OFF(4702) // unreachable code 28 | RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated 29 | #endif 30 | 31 | RAPIDJSON_NAMESPACE_BEGIN 32 | 33 | 34 | //! Cursor stream wrapper for counting line and column number if error exists. 35 | /*! 36 | \tparam InputStream Any stream that implements Stream Concept 37 | */ 38 | template > 39 | class CursorStreamWrapper : public GenericStreamWrapper { 40 | public: 41 | typedef typename Encoding::Ch Ch; 42 | 43 | CursorStreamWrapper(InputStream& is): 44 | GenericStreamWrapper(is), line_(1), col_(0) {} 45 | 46 | // counting line and column number 47 | Ch Take() { 48 | Ch ch = this->is_.Take(); 49 | if(ch == '\n') { 50 | line_ ++; 51 | col_ = 0; 52 | } else { 53 | col_ ++; 54 | } 55 | return ch; 56 | } 57 | 58 | //! Get the error line number, if error exists. 59 | size_t GetLine() const { return line_; } 60 | //! Get the error column number, if error exists. 61 | size_t GetColumn() const { return col_; } 62 | 63 | private: 64 | size_t line_; //!< Current Line 65 | size_t col_; //!< Current Column 66 | }; 67 | 68 | #if defined(_MSC_VER) && _MSC_VER <= 1800 69 | RAPIDJSON_DIAG_POP 70 | #endif 71 | 72 | #if defined(__GNUC__) 73 | RAPIDJSON_DIAG_POP 74 | #endif 75 | 76 | RAPIDJSON_NAMESPACE_END 77 | 78 | #endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ 79 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/error/en.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ERROR_EN_H_ 16 | #define RAPIDJSON_ERROR_EN_H_ 17 | 18 | #include "error.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(switch-enum) 23 | RAPIDJSON_DIAG_OFF(covered-switch-default) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Maps error code of parsing into error message. 29 | /*! 30 | \ingroup RAPIDJSON_ERRORS 31 | \param parseErrorCode Error code obtained in parsing. 32 | \return the error message. 33 | \note User can make a copy of this function for localization. 34 | Using switch-case is safer for future modification of error codes. 35 | */ 36 | inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { 37 | switch (parseErrorCode) { 38 | case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); 39 | 40 | case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); 41 | case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); 42 | 43 | case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); 44 | 45 | case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); 46 | case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); 47 | case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); 48 | 49 | case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); 50 | 51 | case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); 52 | case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); 53 | case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); 54 | case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); 55 | case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); 56 | 57 | case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); 58 | case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); 59 | case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); 60 | 61 | case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); 62 | case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); 63 | 64 | default: return RAPIDJSON_ERROR_STRING("Unknown error."); 65 | } 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #ifdef __clang__ 71 | RAPIDJSON_DIAG_POP 72 | #endif 73 | 74 | #endif // RAPIDJSON_ERROR_EN_H_ 75 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/filereadstream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEREADSTREAM_H_ 16 | #define RAPIDJSON_FILEREADSTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | RAPIDJSON_DIAG_OFF(unreachable-code) 25 | RAPIDJSON_DIAG_OFF(missing-noreturn) 26 | #endif 27 | 28 | RAPIDJSON_NAMESPACE_BEGIN 29 | 30 | //! File byte stream for input using fread(). 31 | /*! 32 | \note implements Stream concept 33 | */ 34 | class FileReadStream { 35 | public: 36 | typedef char Ch; //!< Character type (byte). 37 | 38 | //! Constructor. 39 | /*! 40 | \param fp File pointer opened for read. 41 | \param buffer user-supplied buffer. 42 | \param bufferSize size of buffer in bytes. Must >=4 bytes. 43 | */ 44 | FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 45 | RAPIDJSON_ASSERT(fp_ != 0); 46 | RAPIDJSON_ASSERT(bufferSize >= 4); 47 | Read(); 48 | } 49 | 50 | Ch Peek() const { return *current_; } 51 | Ch Take() { Ch c = *current_; Read(); return c; } 52 | size_t Tell() const { return count_ + static_cast(current_ - buffer_); } 53 | 54 | // Not implemented 55 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 56 | void Flush() { RAPIDJSON_ASSERT(false); } 57 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 58 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 59 | 60 | // For encoding detection only. 61 | const Ch* Peek4() const { 62 | return (current_ + 4 <= bufferLast_) ? current_ : 0; 63 | } 64 | 65 | private: 66 | void Read() { 67 | if (current_ < bufferLast_) 68 | ++current_; 69 | else if (!eof_) { 70 | count_ += readCount_; 71 | readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); 72 | bufferLast_ = buffer_ + readCount_ - 1; 73 | current_ = buffer_; 74 | 75 | if (readCount_ < bufferSize_) { 76 | buffer_[readCount_] = '\0'; 77 | ++bufferLast_; 78 | eof_ = true; 79 | } 80 | } 81 | } 82 | 83 | std::FILE* fp_; 84 | Ch *buffer_; 85 | size_t bufferSize_; 86 | Ch *bufferLast_; 87 | Ch *current_; 88 | size_t readCount_; 89 | size_t count_; //!< Number of characters read 90 | bool eof_; 91 | }; 92 | 93 | RAPIDJSON_NAMESPACE_END 94 | 95 | #ifdef __clang__ 96 | RAPIDJSON_DIAG_POP 97 | #endif 98 | 99 | #endif // RAPIDJSON_FILESTREAM_H_ 100 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/filewritestream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEWRITESTREAM_H_ 16 | #define RAPIDJSON_FILEWRITESTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(unreachable-code) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of C file stream for output using fwrite(). 29 | /*! 30 | \note implements Stream concept 31 | */ 32 | class FileWriteStream { 33 | public: 34 | typedef char Ch; //!< Character type. Only support char. 35 | 36 | FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { 37 | RAPIDJSON_ASSERT(fp_ != 0); 38 | } 39 | 40 | void Put(char c) { 41 | if (current_ >= bufferEnd_) 42 | Flush(); 43 | 44 | *current_++ = c; 45 | } 46 | 47 | void PutN(char c, size_t n) { 48 | size_t avail = static_cast(bufferEnd_ - current_); 49 | while (n > avail) { 50 | std::memset(current_, c, avail); 51 | current_ += avail; 52 | Flush(); 53 | n -= avail; 54 | avail = static_cast(bufferEnd_ - current_); 55 | } 56 | 57 | if (n > 0) { 58 | std::memset(current_, c, n); 59 | current_ += n; 60 | } 61 | } 62 | 63 | void Flush() { 64 | if (current_ != buffer_) { 65 | size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); 66 | if (result < static_cast(current_ - buffer_)) { 67 | // failure deliberately ignored at this time 68 | // added to avoid warn_unused_result build errors 69 | } 70 | current_ = buffer_; 71 | } 72 | } 73 | 74 | // Not implemented 75 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 76 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 77 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 78 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 79 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 80 | 81 | private: 82 | // Prohibit copy constructor & assignment operator. 83 | FileWriteStream(const FileWriteStream&); 84 | FileWriteStream& operator=(const FileWriteStream&); 85 | 86 | std::FILE* fp_; 87 | char *buffer_; 88 | char *bufferEnd_; 89 | char *current_; 90 | }; 91 | 92 | //! Implement specialized version of PutN() with memset() for better performance. 93 | template<> 94 | inline void PutN(FileWriteStream& stream, char c, size_t n) { 95 | stream.PutN(c, n); 96 | } 97 | 98 | RAPIDJSON_NAMESPACE_END 99 | 100 | #ifdef __clang__ 101 | RAPIDJSON_DIAG_POP 102 | #endif 103 | 104 | #endif // RAPIDJSON_FILESTREAM_H_ 105 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/fwd.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FWD_H_ 16 | #define RAPIDJSON_FWD_H_ 17 | 18 | #include "rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | 22 | // encodings.h 23 | 24 | template struct UTF8; 25 | template struct UTF16; 26 | template struct UTF16BE; 27 | template struct UTF16LE; 28 | template struct UTF32; 29 | template struct UTF32BE; 30 | template struct UTF32LE; 31 | template struct ASCII; 32 | template struct AutoUTF; 33 | 34 | template 35 | struct Transcoder; 36 | 37 | // allocators.h 38 | 39 | class CrtAllocator; 40 | 41 | template 42 | class MemoryPoolAllocator; 43 | 44 | // stream.h 45 | 46 | template 47 | struct GenericStringStream; 48 | 49 | typedef GenericStringStream > StringStream; 50 | 51 | template 52 | struct GenericInsituStringStream; 53 | 54 | typedef GenericInsituStringStream > InsituStringStream; 55 | 56 | // stringbuffer.h 57 | 58 | template 59 | class GenericStringBuffer; 60 | 61 | typedef GenericStringBuffer, CrtAllocator> StringBuffer; 62 | 63 | // filereadstream.h 64 | 65 | class FileReadStream; 66 | 67 | // filewritestream.h 68 | 69 | class FileWriteStream; 70 | 71 | // memorybuffer.h 72 | 73 | template 74 | struct GenericMemoryBuffer; 75 | 76 | typedef GenericMemoryBuffer MemoryBuffer; 77 | 78 | // memorystream.h 79 | 80 | struct MemoryStream; 81 | 82 | // reader.h 83 | 84 | template 85 | struct BaseReaderHandler; 86 | 87 | template 88 | class GenericReader; 89 | 90 | typedef GenericReader, UTF8, CrtAllocator> Reader; 91 | 92 | // writer.h 93 | 94 | template 95 | class Writer; 96 | 97 | // prettywriter.h 98 | 99 | template 100 | class PrettyWriter; 101 | 102 | // document.h 103 | 104 | template 105 | struct GenericMember; 106 | 107 | template 108 | class GenericMemberIterator; 109 | 110 | template 111 | struct GenericStringRef; 112 | 113 | template 114 | class GenericValue; 115 | 116 | typedef GenericValue, MemoryPoolAllocator > Value; 117 | 118 | template 119 | class GenericDocument; 120 | 121 | typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; 122 | 123 | // pointer.h 124 | 125 | template 126 | class GenericPointer; 127 | 128 | typedef GenericPointer Pointer; 129 | 130 | // schema.h 131 | 132 | template 133 | class IGenericRemoteSchemaDocumentProvider; 134 | 135 | template 136 | class GenericSchemaDocument; 137 | 138 | typedef GenericSchemaDocument SchemaDocument; 139 | typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; 140 | 141 | template < 142 | typename SchemaDocumentType, 143 | typename OutputHandler, 144 | typename StateAllocator> 145 | class GenericSchemaValidator; 146 | 147 | typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; 148 | 149 | RAPIDJSON_NAMESPACE_END 150 | 151 | #endif // RAPIDJSON_RAPIDJSONFWD_H_ 152 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/internal/ieee754.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_IEEE754_ 16 | #define RAPIDJSON_IEEE754_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | class Double { 24 | public: 25 | Double() {} 26 | Double(double d) : d_(d) {} 27 | Double(uint64_t u) : u_(u) {} 28 | 29 | double Value() const { return d_; } 30 | uint64_t Uint64Value() const { return u_; } 31 | 32 | double NextPositiveDouble() const { 33 | RAPIDJSON_ASSERT(!Sign()); 34 | return Double(u_ + 1).Value(); 35 | } 36 | 37 | bool Sign() const { return (u_ & kSignMask) != 0; } 38 | uint64_t Significand() const { return u_ & kSignificandMask; } 39 | int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } 40 | 41 | bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } 42 | bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } 43 | bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } 44 | bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } 45 | bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } 46 | 47 | uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } 48 | int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } 49 | uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } 50 | 51 | static int EffectiveSignificandSize(int order) { 52 | if (order >= -1021) 53 | return 53; 54 | else if (order <= -1074) 55 | return 0; 56 | else 57 | return order + 1074; 58 | } 59 | 60 | private: 61 | static const int kSignificandSize = 52; 62 | static const int kExponentBias = 0x3FF; 63 | static const int kDenormalExponent = 1 - kExponentBias; 64 | static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); 65 | static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); 66 | static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); 67 | static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); 68 | 69 | union { 70 | double d_; 71 | uint64_t u_; 72 | }; 73 | }; 74 | 75 | } // namespace internal 76 | RAPIDJSON_NAMESPACE_END 77 | 78 | #endif // RAPIDJSON_IEEE754_ 79 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/internal/pow10.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_POW10_ 16 | #define RAPIDJSON_POW10_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | //! Computes integer powers of 10 in double (10.0^n). 24 | /*! This function uses lookup table for fast and accurate results. 25 | \param n non-negative exponent. Must <= 308. 26 | \return 10.0^n 27 | */ 28 | inline double Pow10(int n) { 29 | static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 30 | 1e+0, 31 | 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 32 | 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 33 | 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 34 | 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 35 | 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 36 | 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 37 | 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 38 | 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 39 | 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 40 | 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 41 | 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 42 | 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 43 | 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 44 | 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 45 | 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 46 | 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 47 | }; 48 | RAPIDJSON_ASSERT(n >= 0 && n <= 308); 49 | return e[n]; 50 | } 51 | 52 | } // namespace internal 53 | RAPIDJSON_NAMESPACE_END 54 | 55 | #endif // RAPIDJSON_POW10_ 56 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/internal/strfunc.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ 16 | #define RAPIDJSON_INTERNAL_STRFUNC_H_ 17 | 18 | #include "../stream.h" 19 | #include 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | namespace internal { 23 | 24 | //! Custom strlen() which works on different character types. 25 | /*! \tparam Ch Character type (e.g. char, wchar_t, short) 26 | \param s Null-terminated input string. 27 | \return Number of characters in the string. 28 | \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. 29 | */ 30 | template 31 | inline SizeType StrLen(const Ch* s) { 32 | RAPIDJSON_ASSERT(s != 0); 33 | const Ch* p = s; 34 | while (*p) ++p; 35 | return SizeType(p - s); 36 | } 37 | 38 | template <> 39 | inline SizeType StrLen(const char* s) { 40 | return SizeType(std::strlen(s)); 41 | } 42 | 43 | template <> 44 | inline SizeType StrLen(const wchar_t* s) { 45 | return SizeType(std::wcslen(s)); 46 | } 47 | 48 | //! Returns number of code points in a encoded string. 49 | template 50 | bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { 51 | RAPIDJSON_ASSERT(s != 0); 52 | RAPIDJSON_ASSERT(outCount != 0); 53 | GenericStringStream is(s); 54 | const typename Encoding::Ch* end = s + length; 55 | SizeType count = 0; 56 | while (is.src_ < end) { 57 | unsigned codepoint; 58 | if (!Encoding::Decode(is, &codepoint)) 59 | return false; 60 | count++; 61 | } 62 | *outCount = count; 63 | return true; 64 | } 65 | 66 | } // namespace internal 67 | RAPIDJSON_NAMESPACE_END 68 | 69 | #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ 70 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/internal/swap.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_SWAP_H_ 16 | #define RAPIDJSON_INTERNAL_SWAP_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #if defined(__clang__) 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(c++98-compat) 23 | #endif 24 | 25 | RAPIDJSON_NAMESPACE_BEGIN 26 | namespace internal { 27 | 28 | //! Custom swap() to avoid dependency on C++ header 29 | /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. 30 | \note This has the same semantics as std::swap(). 31 | */ 32 | template 33 | inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { 34 | T tmp = a; 35 | a = b; 36 | b = tmp; 37 | } 38 | 39 | } // namespace internal 40 | RAPIDJSON_NAMESPACE_END 41 | 42 | #if defined(__clang__) 43 | RAPIDJSON_DIAG_POP 44 | #endif 45 | 46 | #endif // RAPIDJSON_INTERNAL_SWAP_H_ 47 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/istreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ISTREAMWRAPPER_H_ 16 | #define RAPIDJSON_ISTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | #elif defined(_MSC_VER) 25 | RAPIDJSON_DIAG_PUSH 26 | RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized 27 | #endif 28 | 29 | RAPIDJSON_NAMESPACE_BEGIN 30 | 31 | //! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. 32 | /*! 33 | The classes can be wrapped including but not limited to: 34 | 35 | - \c std::istringstream 36 | - \c std::stringstream 37 | - \c std::wistringstream 38 | - \c std::wstringstream 39 | - \c std::ifstream 40 | - \c std::fstream 41 | - \c std::wifstream 42 | - \c std::wfstream 43 | 44 | \tparam StreamType Class derived from \c std::basic_istream. 45 | */ 46 | 47 | template 48 | class BasicIStreamWrapper { 49 | public: 50 | typedef typename StreamType::char_type Ch; 51 | BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} 52 | 53 | Ch Peek() const { 54 | typename StreamType::int_type c = stream_.peek(); 55 | return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : static_cast('\0'); 56 | } 57 | 58 | Ch Take() { 59 | typename StreamType::int_type c = stream_.get(); 60 | if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { 61 | count_++; 62 | return static_cast(c); 63 | } 64 | else 65 | return '\0'; 66 | } 67 | 68 | // tellg() may return -1 when failed. So we count by ourself. 69 | size_t Tell() const { return count_; } 70 | 71 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 72 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 73 | void Flush() { RAPIDJSON_ASSERT(false); } 74 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 75 | 76 | // For encoding detection only. 77 | const Ch* Peek4() const { 78 | RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. 79 | int i; 80 | bool hasError = false; 81 | for (i = 0; i < 4; ++i) { 82 | typename StreamType::int_type c = stream_.get(); 83 | if (c == StreamType::traits_type::eof()) { 84 | hasError = true; 85 | stream_.clear(); 86 | break; 87 | } 88 | peekBuffer_[i] = static_cast(c); 89 | } 90 | for (--i; i >= 0; --i) 91 | stream_.putback(peekBuffer_[i]); 92 | return !hasError ? peekBuffer_ : 0; 93 | } 94 | 95 | private: 96 | BasicIStreamWrapper(const BasicIStreamWrapper&); 97 | BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); 98 | 99 | StreamType& stream_; 100 | size_t count_; //!< Number of characters read. Note: 101 | mutable Ch peekBuffer_[4]; 102 | }; 103 | 104 | typedef BasicIStreamWrapper IStreamWrapper; 105 | typedef BasicIStreamWrapper WIStreamWrapper; 106 | 107 | #if defined(__clang__) || defined(_MSC_VER) 108 | RAPIDJSON_DIAG_POP 109 | #endif 110 | 111 | RAPIDJSON_NAMESPACE_END 112 | 113 | #endif // RAPIDJSON_ISTREAMWRAPPER_H_ 114 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/memorybuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYBUFFER_H_ 16 | #define RAPIDJSON_MEMORYBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | 23 | //! Represents an in-memory output byte stream. 24 | /*! 25 | This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. 26 | 27 | It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. 28 | 29 | Differences between MemoryBuffer and StringBuffer: 30 | 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 31 | 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. 32 | 33 | \tparam Allocator type for allocating memory buffer. 34 | \note implements Stream concept 35 | */ 36 | template 37 | struct GenericMemoryBuffer { 38 | typedef char Ch; // byte 39 | 40 | GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 41 | 42 | void Put(Ch c) { *stack_.template Push() = c; } 43 | void Flush() {} 44 | 45 | void Clear() { stack_.Clear(); } 46 | void ShrinkToFit() { stack_.ShrinkToFit(); } 47 | Ch* Push(size_t count) { return stack_.template Push(count); } 48 | void Pop(size_t count) { stack_.template Pop(count); } 49 | 50 | const Ch* GetBuffer() const { 51 | return stack_.template Bottom(); 52 | } 53 | 54 | size_t GetSize() const { return stack_.GetSize(); } 55 | 56 | static const size_t kDefaultCapacity = 256; 57 | mutable internal::Stack stack_; 58 | }; 59 | 60 | typedef GenericMemoryBuffer<> MemoryBuffer; 61 | 62 | //! Implement specialized version of PutN() with memset() for better performance. 63 | template<> 64 | inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { 65 | std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 71 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/memorystream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYSTREAM_H_ 16 | #define RAPIDJSON_MEMORYSTREAM_H_ 17 | 18 | #include "stream.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(unreachable-code) 23 | RAPIDJSON_DIAG_OFF(missing-noreturn) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Represents an in-memory input byte stream. 29 | /*! 30 | This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. 31 | 32 | It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. 33 | 34 | Differences between MemoryStream and StringStream: 35 | 1. StringStream has encoding but MemoryStream is a byte stream. 36 | 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. 37 | 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). 38 | \note implements Stream concept 39 | */ 40 | struct MemoryStream { 41 | typedef char Ch; // byte 42 | 43 | MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} 44 | 45 | Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } 46 | Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } 47 | size_t Tell() const { return static_cast(src_ - begin_); } 48 | 49 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 50 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 51 | void Flush() { RAPIDJSON_ASSERT(false); } 52 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 53 | 54 | // For encoding detection only. 55 | const Ch* Peek4() const { 56 | return Tell() + 4 <= size_ ? src_ : 0; 57 | } 58 | 59 | const Ch* src_; //!< Current read position. 60 | const Ch* begin_; //!< Original head of the string. 61 | const Ch* end_; //!< End of stream. 62 | size_t size_; //!< Size of the stream. 63 | }; 64 | 65 | RAPIDJSON_NAMESPACE_END 66 | 67 | #ifdef __clang__ 68 | RAPIDJSON_DIAG_POP 69 | #endif 70 | 71 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 72 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/ostreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_OSTREAMWRAPPER_H_ 16 | #define RAPIDJSON_OSTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. 29 | /*! 30 | The classes can be wrapped including but not limited to: 31 | 32 | - \c std::ostringstream 33 | - \c std::stringstream 34 | - \c std::wpstringstream 35 | - \c std::wstringstream 36 | - \c std::ifstream 37 | - \c std::fstream 38 | - \c std::wofstream 39 | - \c std::wfstream 40 | 41 | \tparam StreamType Class derived from \c std::basic_ostream. 42 | */ 43 | 44 | template 45 | class BasicOStreamWrapper { 46 | public: 47 | typedef typename StreamType::char_type Ch; 48 | BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} 49 | 50 | void Put(Ch c) { 51 | stream_.put(c); 52 | } 53 | 54 | void Flush() { 55 | stream_.flush(); 56 | } 57 | 58 | // Not implemented 59 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 60 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 61 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 62 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 63 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 64 | 65 | private: 66 | BasicOStreamWrapper(const BasicOStreamWrapper&); 67 | BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); 68 | 69 | StreamType& stream_; 70 | }; 71 | 72 | typedef BasicOStreamWrapper OStreamWrapper; 73 | typedef BasicOStreamWrapper WOStreamWrapper; 74 | 75 | #ifdef __clang__ 76 | RAPIDJSON_DIAG_POP 77 | #endif 78 | 79 | RAPIDJSON_NAMESPACE_END 80 | 81 | #endif // RAPIDJSON_OSTREAMWRAPPER_H_ 82 | -------------------------------------------------------------------------------- /include/sleepy_discord/rapidjson/stringbuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_STRINGBUFFER_H_ 16 | #define RAPIDJSON_STRINGBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 22 | #include // std::move 23 | #endif 24 | 25 | #include "internal/stack.h" 26 | 27 | #if defined(__clang__) 28 | RAPIDJSON_DIAG_PUSH 29 | RAPIDJSON_DIAG_OFF(c++98-compat) 30 | #endif 31 | 32 | RAPIDJSON_NAMESPACE_BEGIN 33 | 34 | //! Represents an in-memory output stream. 35 | /*! 36 | \tparam Encoding Encoding of the stream. 37 | \tparam Allocator type for allocating memory buffer. 38 | \note implements Stream concept 39 | */ 40 | template 41 | class GenericStringBuffer { 42 | public: 43 | typedef typename Encoding::Ch Ch; 44 | 45 | GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 46 | 47 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 48 | GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} 49 | GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { 50 | if (&rhs != this) 51 | stack_ = std::move(rhs.stack_); 52 | return *this; 53 | } 54 | #endif 55 | 56 | void Put(Ch c) { *stack_.template Push() = c; } 57 | void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } 58 | void Flush() {} 59 | 60 | void Clear() { stack_.Clear(); } 61 | void ShrinkToFit() { 62 | // Push and pop a null terminator. This is safe. 63 | *stack_.template Push() = '\0'; 64 | stack_.ShrinkToFit(); 65 | stack_.template Pop(1); 66 | } 67 | 68 | void Reserve(size_t count) { stack_.template Reserve(count); } 69 | Ch* Push(size_t count) { return stack_.template Push(count); } 70 | Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } 71 | void Pop(size_t count) { stack_.template Pop(count); } 72 | 73 | const Ch* GetString() const { 74 | // Push and pop a null terminator. This is safe. 75 | *stack_.template Push() = '\0'; 76 | stack_.template Pop(1); 77 | 78 | return stack_.template Bottom(); 79 | } 80 | 81 | //! Get the size of string in bytes in the string buffer. 82 | size_t GetSize() const { return stack_.GetSize(); } 83 | 84 | //! Get the length of string in Ch in the string buffer. 85 | size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } 86 | 87 | static const size_t kDefaultCapacity = 256; 88 | mutable internal::Stack stack_; 89 | 90 | private: 91 | // Prohibit copy constructor & assignment operator. 92 | GenericStringBuffer(const GenericStringBuffer&); 93 | GenericStringBuffer& operator=(const GenericStringBuffer&); 94 | }; 95 | 96 | //! String buffer with UTF8 encoding 97 | typedef GenericStringBuffer > StringBuffer; 98 | 99 | template 100 | inline void PutReserve(GenericStringBuffer& stream, size_t count) { 101 | stream.Reserve(count); 102 | } 103 | 104 | template 105 | inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { 106 | stream.PutUnsafe(c); 107 | } 108 | 109 | //! Implement specialized version of PutN() with memset() for better performance. 110 | template<> 111 | inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { 112 | std::memset(stream.stack_.Push(n), c, n * sizeof(c)); 113 | } 114 | 115 | RAPIDJSON_NAMESPACE_END 116 | 117 | #if defined(__clang__) 118 | RAPIDJSON_DIAG_POP 119 | #endif 120 | 121 | #endif // RAPIDJSON_STRINGBUFFER_H_ 122 | -------------------------------------------------------------------------------- /include/sleepy_discord/rate_limiter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "client.h" 3 | 4 | namespace SleepyDiscord { 5 | 6 | class Route { 7 | public: 8 | using Bucket = std::string; 9 | Route(const std::string route, const std::initializer_list& _values = {}); 10 | Route(const char* route); 11 | inline const std::string& url() { 12 | return _url; 13 | } 14 | const Bucket bucket(RequestMethod method); 15 | inline operator const std::string&() { 16 | return url(); 17 | } 18 | inline const std::string& getPath() { 19 | return path; 20 | } 21 | 22 | private: 23 | const std::string path; 24 | std::string _url; 25 | const std::initializer_list& values; 26 | 27 | //for the snowflake part, discord class should do 28 | std::unordered_map::RawType> 29 | majorParameters = { 30 | { "channel.id", {} }, 31 | { "guild.id" , {} }, 32 | { "webhook.id", {} } 33 | }; 34 | }; 35 | 36 | //note: all rate limiter data needs to be handled in a sync manner 37 | template 38 | struct RateLimiter { 39 | std::atomic isGlobalRateLimited = { false }; 40 | std::atomic nextRetry = { 0 }; 41 | void limitBucket(const Route::Bucket& bucket, const std::string& xBucket, double timestamp) { 42 | std::lock_guard lock(mutex); 43 | buckets[bucket] = xBucket; 44 | limits[xBucket].nextTry = timestamp; 45 | } 46 | 47 | const double getLiftTime(Route::Bucket& bucket, const double& currentTime) { 48 | if (isGlobalRateLimited && currentTime < nextRetry) 49 | return nextRetry; 50 | isGlobalRateLimited = false; 51 | std::lock_guard lock(mutex); 52 | auto actualBucket = buckets.find(bucket); 53 | if (actualBucket != buckets.end()) { 54 | auto rateLimit = limits.find(actualBucket->second); 55 | if (rateLimit != limits.end()) { 56 | if (currentTime < rateLimit->second.nextTry) 57 | return rateLimit->second.nextTry; 58 | limits.erase(rateLimit); 59 | } 60 | buckets.erase(actualBucket); 61 | } 62 | return 0; 63 | } 64 | //isLimited also returns the next Retry timestamp 65 | 66 | struct RateLimit { 67 | public: 68 | void doWaitingRequest() { 69 | if (awaitingRequest.empty()) 70 | return; 71 | RateLimiter& rateLimiter = awaitingRequest.front().client.rateLimiter; 72 | 73 | std::lock_guard lock(rateLimiter.mutex); 74 | awaitingRequest.remove_if([](typename Client::Request& request){ 75 | request.client.postTask(request); 76 | return true; 77 | }); 78 | } 79 | private: 80 | friend RateLimiter; 81 | std::list awaitingRequest; 82 | double nextTry = 0; 83 | static constexpr int defaultLimit = 1; 84 | int limit = defaultLimit; 85 | int remaining = defaultLimit; 86 | Timer expireTimer; 87 | }; 88 | 89 | class HandleAwaitAfterRequest { 90 | public: 91 | HandleAwaitAfterRequest(RateLimiter::RateLimit& limit) 92 | : rateLimit(limit) {} 93 | ~HandleAwaitAfterRequest() { 94 | rateLimit.doWaitingRequest(); 95 | } 96 | private: 97 | RateLimiter::RateLimit& rateLimit; 98 | }; 99 | 100 | private: 101 | std::unordered_map buckets; 102 | std::unordered_map limits; 103 | std::mutex mutex; 104 | }; 105 | } -------------------------------------------------------------------------------- /include/sleepy_discord/session.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "http.h" 3 | 4 | //custom dynamic 5 | #ifdef SLEEPY_CUSTOM_SESSION 6 | #include "custom_session.h" 7 | 8 | //defined 9 | #elif defined(SLEEPY_SESSION) || defined(SLEEPY_SESSION_INCLUDE) 10 | #ifdef SLEEPY_SESSION_INCLUDE 11 | #include SLEEPY_SESSION_INCLUDE 12 | #endif 13 | #ifdef SLEEPY_SESSION 14 | typedef SLEEPY_SESSION Session 15 | #endif 16 | 17 | //defaults 18 | #elif defined(SLEEPY_DISCORD_CMAKE) 19 | #if defined(EXISTENT_CPR) 20 | #include "cpr_session.h" 21 | #elif defined(EXISTENT_BEAST) 22 | #include "" 23 | #else 24 | #include "custom_session.h" 25 | #endif 26 | #else 27 | #include "cpr_session.h" 28 | #ifdef NONEXISTENT_CPR 29 | 30 | //last resort 31 | #include "custom_session.h" 32 | #endif 33 | #endif -------------------------------------------------------------------------------- /include/sleepy_discord/sleepy_discord.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SLEEPY_DEFINE_CUSTOM_CLIENT \ 4 | namespace SleepyDiscord {\ 5 | typedef BaseDiscordClient DiscordClient;\ 6 | } 7 | 8 | #ifdef SLEEPY_CUSTOM_CLIENT 9 | #include "client.h" 10 | SLEEPY_DEFINE_CUSTOM_CLIENT 11 | #elif defined(SLEEPY_DISCORD_CMAKE) 12 | #if defined(EXISTENT_ASIO) 13 | #include "asio_websocket.h" 14 | #else 15 | #include "client.h" 16 | SLEEPY_DEFINE_CUSTOM_CLIENT 17 | #endif 18 | #else 19 | #include "asio_websocket.h" 20 | #ifdef NONEXISTENT_ASIO 21 | #include "client.h" 22 | SLEEPY_DEFINE_CUSTOM_CLIENT 23 | #endif 24 | #endif 25 | 26 | namespace SleepyDiscord { 27 | 28 | } -------------------------------------------------------------------------------- /include/sleepy_discord/snowflake.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) 6 | #include 7 | #endif 8 | #include "nonstd/string_view.hpp" 9 | #include "json_wrapper.h" 10 | 11 | namespace SleepyDiscord { 12 | using Time = int64_t; 13 | 14 | //Stops you from mixing up different types of ids, like using a message_id as a user_id 15 | template 16 | struct Snowflake { 17 | using RawType = std::string; 18 | 19 | Snowflake( ) = default; 20 | Snowflake(const std::string & snow ) : raw( snow ) {} 21 | Snowflake(const std::string * snow ) : raw(*snow ) {} 22 | Snowflake(const char * snow ) : raw( snow ) {} 23 | Snowflake(const nonstd::string_view & snow ) : raw(snow.data(), snow.length() ) {} 24 | Snowflake(const Snowflake & flake ) : Snowflake(flake.string( )) {} 25 | Snowflake(const DiscordObject & object) : Snowflake(object. ID ) {} 26 | Snowflake(const DiscordObject * object) : Snowflake(object->ID ) {} 27 | Snowflake(const int64_t number) : Snowflake(std::to_string(number )) {} 28 | Snowflake(const json::Value & value ) : 29 | Snowflake(value.IsString() ? json::toStdString(value) : std::string()) {} 30 | ~Snowflake() = default; 31 | 32 | inline bool operator==(const Snowflake& right) const { 33 | return raw == right.raw; 34 | } 35 | 36 | inline bool operator!=(const Snowflake& right) const { 37 | return raw != right.raw; 38 | } 39 | 40 | inline bool operator==(const char* right) const { 41 | return raw == right; 42 | } 43 | 44 | inline bool operator!=(const char* right) const { 45 | return raw != right; 46 | } 47 | 48 | inline operator const std::string&() const { return raw; } 49 | 50 | inline const std::string& string() const { return operator const std::string&(); } 51 | inline const int64_t number() const { return std::stoll(raw); } 52 | 53 | std::chrono::time_point timestamp() const { 54 | #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) 55 | if (raw == "") throw std::invalid_argument("invalid snow in Snowflake"); 56 | #endif 57 | return std::chrono::time_point(std::chrono::milliseconds((std::stoll(raw) >> 22) + discordEpoch)); 58 | } 59 | 60 | inline const bool empty() const { return raw.empty(); } 61 | 62 | inline json::Value serialize(typename json::Value::AllocatorType& alloc) const { 63 | return json::ClassTypeHelper::fromType(raw, alloc); 64 | } 65 | 66 | static inline const bool isType(const typename json::Value& value) { 67 | return value.IsString(); 68 | } 69 | 70 | template 71 | inline iterator findObject(iterator begin, iterator end) const { 72 | return std::find_if(begin, end, [&](const DiscordObject& object) { 73 | return operator==(static_cast(object)); 74 | }); 75 | } 76 | 77 | //Magical code from stackflow 78 | //https://stackoverflow.com/a/87846 79 | template 80 | struct HasAFindFunction { 81 | using SuccessType = char; 82 | using FailureType = int; 83 | template struct Magic {}; 84 | template static SuccessType Test(Magic<_Container, &_Container::find>*); 85 | template static FailureType Test(...); 86 | static const bool Value = sizeof(Test(0)) == sizeof(SuccessType); 87 | }; 88 | 89 | template 90 | auto findObject(Container& objects, std::true_type) const -> decltype(objects.begin()) { 91 | return objects.find(operator const std::string&()); 92 | } 93 | 94 | template 95 | auto findObject(Container& objects, std::false_type) const -> decltype(objects.begin()) { 96 | return findObject(objects.begin(), objects.end()); 97 | } 98 | 99 | template 100 | auto findObject(Container& objects) const -> decltype(objects.begin()) { 101 | return findObject(objects, std::integral_constant::Value>()); 102 | } 103 | 104 | private: 105 | RawType raw = {}; 106 | static const Time discordEpoch = 1420070400000; //the first second of 2015 since epoch 107 | }; 108 | 109 | template 110 | inline std::string operator+(const char * left, Snowflake& right) { 111 | return left + right.operator const std::string&(); 112 | } 113 | 114 | template 115 | inline bool operator==(const char * left, Snowflake& right) { 116 | return left == right.operator const std::string&().c_str(); 117 | } 118 | 119 | template 120 | inline bool operator!=(const char * left, Snowflake& right) { 121 | return left != right.operator const std::string&().c_str(); 122 | } 123 | } 124 | 125 | namespace std { 126 | template 127 | struct hash> { 128 | inline size_t operator()(const SleepyDiscord::Snowflake& snowflake) const { 129 | return std::hash{}(static_cast(snowflake)); 130 | } 131 | }; 132 | } -------------------------------------------------------------------------------- /include/sleepy_discord/stage_instance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "discord_object_interface.h" 3 | #include "server.h" 4 | 5 | namespace SleepyDiscord { 6 | struct StageInstance : IdentifiableDiscordObject { 7 | StageInstance() = default; 8 | ~StageInstance() = default; 9 | StageInstance(const json::Value & json); 10 | StageInstance(const nonstd::string_view& json) : 11 | StageInstance(json::fromJSON(json)) {} 12 | 13 | Snowflake serverID; 14 | Snowflake channelID; 15 | std::string topic; 16 | using PrivacyLevelRaw = int; 17 | enum class PrivacyLevel : PrivacyLevelRaw { 18 | NotSet = -1, //made up for the library 19 | PUBLIC = 1, 20 | SERVER_ONLY = 2 21 | }; 22 | PrivacyLevel privacyLevel = PrivacyLevel::NotSet; 23 | bool discoverableDisabled = false; 24 | 25 | JSONStructStart 26 | std::make_tuple( 27 | json::pair (&StageInstance::ID , "id" , json::REQUIRIED_FIELD), 28 | json::pair (&StageInstance::serverID , "guild_id" , json::REQUIRIED_FIELD), 29 | json::pair (&StageInstance::channelID , "channel_id" , json::REQUIRIED_FIELD), 30 | json::pair (&StageInstance::topic , "topic" , json::OPTIONAL_FIELD ), 31 | json::pair(&StageInstance::privacyLevel , "privacy_level" , json::OPTIONAL_FIELD ), 32 | json::pair (&StageInstance::discoverableDisabled, "discoverable_disabled", json::OPTIONAL_FIELD ) 33 | ); 34 | JSONStructEnd 35 | }; 36 | 37 | template<> 38 | struct GetDefault { 39 | static inline const StageInstance::PrivacyLevel get() { 40 | return StageInstance::PrivacyLevel::NotSet; 41 | } 42 | }; 43 | } -------------------------------------------------------------------------------- /include/sleepy_discord/standard_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SLEEPY_DO_NOT_INCLUDE_STANDARD_ONERROR 3 | void DiscordClient::onError(SleepyDiscord::ErrorCode errorCode, const std::string errorMessage) { 4 | if (errorCode != 0) 5 | std::cout << "Error " << errorCode << ": " + errorMessage + '\n'; 6 | else 7 | std::cout << "Error: " + errorMessage + '\n'; 8 | } 9 | #endif 10 | 11 | #ifndef SLEEPY_DO_NOT_INCLUDE_STANDARD_SLEEP 12 | void DiscordClient::sleep(const unsigned int milliseconds) { 13 | std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); 14 | } 15 | #endif -------------------------------------------------------------------------------- /include/sleepy_discord/standard_config_header.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SLEEPY_DO_NOT_INCLUDE_STANDARD_ONERROR 3 | virtual void onError(SleepyDiscord::ErrorCode errorCode, const std::string errorMessage) override; 4 | #endif 5 | 6 | #ifndef SLEEPY_DO_NOT_INCLUDE_STANDARD_SLEEP 7 | virtual void sleep(const unsigned int milliseconds) override; 8 | #endif -------------------------------------------------------------------------------- /include/sleepy_discord/thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "discord_object_interface.h" 3 | #include "server.h" 4 | #include "channel.h" 5 | #include "user.h" 6 | 7 | namespace SleepyDiscord { 8 | struct ThreadMember : IdentifiableDiscordObject { 9 | ThreadMember() = default; 10 | ThreadMember(const nonstd::string_view& json) : 11 | ThreadMember(json::fromJSON(json)) {} 12 | ThreadMember(const json::Value& json); 13 | 14 | Snowflake userID; 15 | std::string joinTimestamp; 16 | int flags = 0; 17 | ServerMember member; 18 | 19 | JSONStructStart 20 | std::make_tuple( 21 | json::pair(&ThreadMember::ID, "id", json::OPTIONAL_FIELD), 22 | json::pair(&ThreadMember::userID, "user_id", json::OPTIONAL_FIELD), 23 | json::pair(&ThreadMember::joinTimestamp, "join_timestamp", json::OPTIONAL_FIELD), 24 | json::pair(&ThreadMember::member, "member", json::OPTIONAL_FIELD) 25 | ); 26 | JSONStructEnd 27 | }; 28 | 29 | struct ThreadListSync : public DiscordObject { 30 | ThreadListSync() = default; 31 | ThreadListSync(const nonstd::string_view& json) : 32 | ThreadListSync(json::fromJSON(json)) {} 33 | ThreadListSync(const json::Value& json); 34 | 35 | Snowflake serverID; 36 | std::vector> channelIDs; 37 | std::vector threads; 38 | std::vector members; 39 | 40 | JSONStructStart 41 | std::make_tuple( 42 | json::pair (&ThreadListSync::serverID , "guild_id", json::REQUIRIED_FIELD), 43 | json::pair(&ThreadListSync::channelIDs, "channel_ids", json::OPTIONAL_FIELD), 44 | json::pair(&ThreadListSync::threads , "channel_ids", json::OPTIONAL_FIELD), 45 | json::pair(&ThreadListSync::members , "members", json::OPTIONAL_FIELD) 46 | ); 47 | JSONStructEnd 48 | }; 49 | 50 | struct ThreadMembersUpdate : public IdentifiableDiscordObject { 51 | ThreadMembersUpdate() = default; 52 | ThreadMembersUpdate(const nonstd::string_view& json) : 53 | ThreadMembersUpdate(json::fromJSON(json)) {} 54 | ThreadMembersUpdate(const json::Value& json); 55 | 56 | Snowflake serverID; 57 | int memberCount = 0; 58 | std::vector addedMembers; 59 | std::vector> removedMemberIDs; 60 | 61 | JSONStructStart 62 | std::make_tuple( 63 | json::pair(&ThreadMembersUpdate::ID, "id", json::REQUIRIED_FIELD), 64 | json::pair(&ThreadMembersUpdate::serverID, "guild_id", json::OPTIONAL_FIELD), 65 | json::pair(&ThreadMembersUpdate::addedMembers, "added_members", json::OPTIONAL_FIELD), 66 | json::pair(&ThreadMembersUpdate::memberCount, "memberCount", json::OPTIONAL_FIELD), 67 | json::pair(&ThreadMembersUpdate::removedMemberIDs, "removed_member_ids", json::OPTIONAL_FIELD) 68 | ); 69 | JSONStructEnd 70 | }; 71 | } -------------------------------------------------------------------------------- /include/sleepy_discord/timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace SleepyDiscord { 5 | typedef std::function TimedTask; 6 | 7 | struct Timer { 8 | public: 9 | typedef std::function StopTimerFunction; 10 | Timer() {} 11 | Timer(StopTimerFunction stopTimer) : 12 | implStop(stopTimer) {} 13 | inline void stop() { implStop(); implStop = nullptr; } 14 | inline bool isValid() const { return implStop != nullptr; } 15 | private: 16 | StopTimerFunction implStop; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /include/sleepy_discord/udp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace SleepyDiscord { 8 | class GenericUDPClient { 9 | public: 10 | typedef std::function SendHandler; 11 | typedef std::function&)> ReceiveHandler; 12 | 13 | virtual bool connect(const std::string& to, const uint16_t port) = 0; 14 | virtual void send( 15 | const uint8_t* buffer, 16 | size_t bufferLength, 17 | SendHandler handler = [](){} 18 | ) = 0; 19 | virtual void receive(ReceiveHandler handler) = 0; 20 | 21 | inline void send(const std::vector buffer, SendHandler handler = [](){}) { 22 | send(&buffer[0], buffer.size(), handler); 23 | } 24 | }; 25 | } -------------------------------------------------------------------------------- /include/sleepy_discord/udp_client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "udp.h" 3 | 4 | #ifdef SLEEPY_CUSTOM_UDP_CLIENT 5 | #include "custom_udp_client.h" 6 | #elif defined(SLEEPY_UDP_CLIENT) 7 | typedef SLEEPY_UDP_CLIENT UDPClient 8 | #elif defined(SLEEPY_DISCORD_CMAKE) 9 | #if defined(EXISTENT_ASIO) 10 | #include "asio_udp.h" 11 | #else 12 | #include "custom_udp_client.h" 13 | #endif 14 | #else 15 | #include "asio_udp.h" 16 | #ifdef NONEXISTENT_ASIO 17 | #include "custom_udp_client.h" 18 | #endif 19 | #endif 20 | -------------------------------------------------------------------------------- /include/sleepy_discord/user.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "discord_object_interface.h" 4 | #include "snowflake.h" 5 | #include "permissions.h" 6 | 7 | namespace SleepyDiscord { 8 | /* 9 | User Structure 10 | 11 | Field Type Description Required OAuth2 Scope 12 | id snowflake the user's id identify 13 | username string the user's username, not unique across the platform identify 14 | discriminator string the user's 4-digit discord-tag identify 15 | avatar string the user's avatar hash identify 16 | bot bool whether the user belongs to an OAuth2 application identify 17 | mfa_enabled bool whether the user has two factor enabled on their account identify 18 | verified bool whether the email on this account has been verified email 19 | email string the user's email email 20 | */ 21 | struct User : public IdentifiableDiscordObject { 22 | public: 23 | User() = default; 24 | //~User(); 25 | //User(const std::string * rawJSON); 26 | User(const nonstd::string_view& json) : 27 | User(json::fromJSON(json)) {} 28 | User(const json::Value& json); 29 | //User(const json::Values values); 30 | 31 | enum class Flags { 32 | None = 0, 33 | Discord_Employee = 1 << 0, 34 | Discord_Partner = 1 << 1, 35 | HypeSquad_Events = 1 << 2, 36 | Bug_Hunter_Level_1 = 1 << 3, 37 | House_Bravery = 1 << 6, 38 | House_Brilliance = 1 << 7, 39 | House_Balance = 1 << 8, 40 | Early_Supporter = 1 << 9, 41 | Team_User = 1 << 10, 42 | System = 1 << 12, 43 | Bug_Hunter_Level_2 = 1 << 14, 44 | Verified_Bot = 1 << 16, 45 | Verified_Bot_Developer = 1 << 17, 46 | Discord_Certified_Moderator = 1 << 18, 47 | }; 48 | 49 | enum class PremiumType : int { 50 | None = 0, 51 | Nitro_Classic = 1, 52 | Nitro = 2, 53 | }; 54 | 55 | std::string username; 56 | std::string discriminator; 57 | std::string avatar; //base64 encoded jpeg image 58 | //these are optional 59 | bool bot = false; 60 | bool mfa_enabled = false; //true if two-factor authentication is enabled 61 | bool verified = false; //true if email has been verified 62 | std::string email = ""; 63 | std::string locale = ""; //the user's chosen language 64 | Flags flags = Flags::None; 65 | PremiumType premiumType = PremiumType::None; 66 | Flags publieFlags = Flags::None; 67 | 68 | JSONStructStart 69 | std::make_tuple( 70 | json::pair (&User::ID , "id" , json::REQUIRIED_FIELD ), 71 | json::pair (&User::username , "username" , json::OPTIONAL_FIELD ), 72 | json::pair (&User::discriminator, "discriminator", json::OPTIONAL_FIELD ), 73 | json::pair (&User::avatar , "avatar" , json::OPTIONAL_NULLABLE_FIELD), 74 | json::pair (&User::bot , "bot" , json::OPTIONAL_FIELD ), 75 | json::pair (&User::mfa_enabled , "mfa_enabled" , json::OPTIONAL_FIELD ), 76 | json::pair (&User::verified , "verified" , json::OPTIONAL_FIELD ), 77 | json::pair (&User::locale , "locale" , json::OPTIONAL_FIELD ), 78 | json::pair(&User::flags , "flags" , json::OPTIONAL_FIELD ), 79 | json::pair(&User::premiumType , "premium_type" , json::OPTIONAL_FIELD ), 80 | json::pair(&User::publieFlags , "public_flags" , json::OPTIONAL_FIELD ), 81 | json::pair (&User::email , "email" , json::OPTIONAL_FIELD ) 82 | ); 83 | JSONStructEnd 84 | }; 85 | 86 | /*Connection Structure The connection object that the user has attached. 87 | 88 | Field Type Description 89 | id string id of the connection account 90 | name string the username of the connection account 91 | type string the service of the connection (twitch, youtube) 92 | revoked bool whether the connection is revoked 93 | integrations array an array of partial server integrations 94 | */ 95 | struct Connection : public IdentifiableDiscordObject { 96 | public: 97 | Connection() = default; 98 | Connection(const nonstd::string_view& json) : 99 | Connection(json::fromJSON(json)) {} 100 | Connection(const json::Value& json); 101 | std::string name; 102 | std::string type; 103 | bool revoked; 104 | 105 | JSONStructStart 106 | std::make_tuple( 107 | json::pair(&Connection::ID , "id" , json::REQUIRIED_FIELD), 108 | json::pair(&Connection::name , "name" , json::REQUIRIED_FIELD), 109 | json::pair(&Connection::type , "type" , json::REQUIRIED_FIELD), 110 | json::pair(&Connection::revoked, "revoked", json::REQUIRIED_FIELD) 111 | ); 112 | JSONStructEnd 113 | }; 114 | } 115 | -------------------------------------------------------------------------------- /include/sleepy_discord/version-non.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | !!!!!! WARNING !!!!!! 3 | version.h is an auto generated file. Any changes in version.h while be replaced. 4 | However, version-non.h.in, not be confused with version.h, is ok to make changes to. 5 | */ 6 | 7 | #pragma once 8 | 9 | #define NONEXISTANT_GIT_INFO -------------------------------------------------------------------------------- /include/sleepy_discord/version.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | !!!!!! WARNING !!!!!! 3 | version.h is an auto generated file. Any changes in version.h while be replaced. 4 | However, version.h.in, not be confused with version.h, is ok to make changes to. 5 | */ 6 | 7 | #pragma once 8 | 9 | #define SLEEPY_DISCORD_VERSION_BUILD ${SLEEPY_DISCORD_VERSION_BUILD} 10 | #define SLEEPY_DISCORD_VERSION_BRANCH "${SLEEPY_DISCORD_VERSION_BRANCH}" 11 | #define SLEEPY_DISCORD_VERSION_HASH "${SLEEPY_DISCORD_VERSION_HASH}" 12 | #define SLEEPY_DISCORD_VERSION_IS_MASTER ${SLEEPY_DISCORD_VERSION_IS_MASTER} 13 | #define SLEEPY_DISCORD_VERSION_DESCRIPTION_CONCAT "${SLEEPY_DISCORD_VERSION_DESCRIPTION_CONCAT}" 14 | #define SLEEPY_DISCORD_VERSION_DESCRIPTION "${SLEEPY_DISCORD_VERSION_DESCRIPTION}" -------------------------------------------------------------------------------- /include/sleepy_discord/version_helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef NONEXISTANT_GIT_INFO 3 | #include "version.h" 4 | #endif 5 | #include 6 | namespace SleepyDiscord { 7 | 8 | //thanks https://stackoverflow.com/a/5459929 9 | //convert preprocessor number into a string 10 | //for example: 11 | //#define SLEEPY_DISCORD_VERSION_BUILD 540 12 | //SLEEPY_DISCORD_VERSION_STR(BUILD) gives us "540" 13 | #define SLEEPY_STR_HELPER(x) #x 14 | #define SLEEPY_STR_HELPER2(x) SLEEPY_STR_HELPER(x) 15 | #define SLEEPY_STR_HELPER3(x, y) x##y 16 | #define SLEEPY_DISCORD_VERSION_STR(x) \ 17 | SLEEPY_STR_HELPER2(SLEEPY_STR_HELPER3(SLEEPY_DISCORD_VERSION_ , x)) 18 | 19 | //please only use defines when you want to check version via preprocessors 20 | //uses xxxxyyyyyy format, which can be converted to xxxx.yyyyyy 21 | #define SLEEPY_DISCORD_VERSION_NUM 0 22 | 23 | #if defined NONEXISTANT_VERSION_H || defined NONEXISTANT_GIT_INFO 24 | #define SLEEPY_DISCORD_VERSION_BUILD 0 25 | #define SLEEPY_DISCORD_VERSION_BRANCH "unknown branch" 26 | #define SLEEPY_DISCORD_VERSION_HASH "unknown revision" 27 | #define SLEEPY_DISCORD_VERSION_IS_MASTER 0 28 | //letter to use for concat description 29 | #define SLEEPY_DISCORD_VERSION_DESCRIPTION_CONCAT " " 30 | #define SLEEPY_DISCORD_VERSION_DESCRIPTION "unknown" 31 | #endif 32 | 33 | #define SLEEPY_DISCORD_VERSION \ 34 | SLEEPY_DISCORD_VERSION_STR(NUM) "-"\ 35 | SLEEPY_DISCORD_VERSION_STR(BUILD) " "\ 36 | SLEEPY_DISCORD_VERSION_BRANCH \ 37 | SLEEPY_DISCORD_VERSION_DESCRIPTION_CONCAT \ 38 | SLEEPY_DISCORD_VERSION_DESCRIPTION 39 | 40 | constexpr unsigned int versionNum = SLEEPY_DISCORD_VERSION_NUM; 41 | constexpr unsigned int revisionNum = SLEEPY_DISCORD_VERSION_BUILD; 42 | //for some reason const fixes a warning about convering a char* to a const char* 43 | constexpr const char* description = SLEEPY_DISCORD_VERSION_DESCRIPTION; 44 | constexpr const char* branch = SLEEPY_DISCORD_VERSION_BRANCH; 45 | constexpr const char* revision = SLEEPY_DISCORD_VERSION_HASH; 46 | constexpr const char* version = SLEEPY_DISCORD_VERSION; 47 | constexpr bool isMaster = SLEEPY_DISCORD_VERSION_IS_MASTER; 48 | constexpr const char* userAgent = 49 | "DiscordBot (https://github.com/yourWaifu/SleepyDiscord, " \ 50 | SLEEPY_DISCORD_VERSION_STR(NUM) \ 51 | ") " \ 52 | SLEEPY_DISCORD_VERSION \ 53 | ; 54 | 55 | //Features 56 | //Remember to list features in both preprocessers and unordered_set 57 | #define SLEEPY_FEATURE_AVAILABLE_FEATURE_LIST 58 | #define SLEEPY_FEATURE_LIST_OF_AVAILABLE_FEATURES 59 | #define SLEEPY_FEATURE_V8_API 60 | #define SLEEPY_FEATURE_V10_API 61 | /* 62 | * The following prevents code from linking, so it's disabled for now 63 | std::unordered_set availableFeatures{ 64 | "Available Feature List", 65 | "List of Available Features", 66 | "V8 Discord API", 67 | "V10 Discord API", 68 | }; 69 | inline bool isFeatureAvaiable(std::string& featureName) { 70 | return availableFeatures.find(featureName) != availableFeatures.end(); 71 | } 72 | */ 73 | } 74 | -------------------------------------------------------------------------------- /include/sleepy_discord/voice.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "discord_object_interface.h" 3 | #include "snowflake.h" 4 | #include "channel.h" 5 | 6 | namespace SleepyDiscord { 7 | //forward declearion 8 | struct Server; 9 | struct Channel; 10 | struct User; 11 | 12 | struct VoiceState : public DiscordObject { 13 | VoiceState() = default; 14 | VoiceState(const nonstd::string_view& json) : 15 | VoiceState(json::fromJSON(json)) {} 16 | VoiceState(const json::Value& json); 17 | Snowflake serverID; 18 | Snowflake channelID; 19 | Snowflake userID; 20 | std::string sessionID; 21 | bool deaf = false; 22 | bool mute = false; 23 | bool selfDeaf = false; 24 | bool selfMute = false; 25 | bool suppress = false; 26 | JSONStructStart 27 | std::make_tuple( 28 | json::pair(&VoiceState::serverID , "guild_id" , json::OPTIONAL_FIELD ), 29 | json::pair(&VoiceState::channelID, "channel_id", json::NULLABLE_FIELD ), 30 | json::pair(&VoiceState::userID , "user_id" , json::REQUIRIED_FIELD), 31 | json::pair(&VoiceState::sessionID, "session_id", json::REQUIRIED_FIELD), 32 | json::pair(&VoiceState::deaf , "deaf" , json::REQUIRIED_FIELD), 33 | json::pair(&VoiceState::mute , "mute" , json::REQUIRIED_FIELD), 34 | json::pair(&VoiceState::selfDeaf , "self_deaf" , json::REQUIRIED_FIELD), 35 | json::pair(&VoiceState::selfMute , "self_mute" , json::REQUIRIED_FIELD), 36 | json::pair(&VoiceState::suppress , "suppress" , json::REQUIRIED_FIELD) 37 | ); 38 | JSONStructEnd 39 | }; 40 | 41 | /* 42 | Voice Region Structure 43 | Field Type Description 44 | id string unique ID for the region 45 | name string name of the region 46 | sample_hostname string an example hostname for the region 47 | sample_port integer an example port for the region 48 | vip bool true if this is a vip-only server 49 | optimal bool true for a single server that is closest to the current user's client 50 | deprecated bool whether this is a deprecated voice region (avoid switching to these) 51 | custom bool whether this is a custom voice region (used for events/etc) 52 | */ 53 | struct VoiceRegion : IdentifiableDiscordObject { 54 | VoiceRegion() = default; 55 | //VoiceRegion(const std::string * rawJson); 56 | VoiceRegion(const nonstd::string_view& json) : 57 | VoiceRegion(json::fromJSON(json)) {} 58 | VoiceRegion(const json::Value& json); 59 | //VoiceRegion(const json::Values values); 60 | std::string name; 61 | bool vip = false; 62 | bool optimal = false; 63 | bool deprecated = false; 64 | bool custom = false; 65 | //const static std::initializer_list fields; 66 | JSONStructStart 67 | std::make_tuple( 68 | json::pair(&VoiceRegion::ID , "id" , json::REQUIRIED_FIELD), 69 | json::pair(&VoiceRegion::name , "name" , json::REQUIRIED_FIELD), 70 | json::pair(&VoiceRegion::vip , "vip" , json::REQUIRIED_FIELD), 71 | json::pair(&VoiceRegion::optimal , "optimal" , json::REQUIRIED_FIELD), 72 | json::pair(&VoiceRegion::deprecated , "deprecated", json::REQUIRIED_FIELD), 73 | json::pair(&VoiceRegion::custom , "custom" , json::REQUIRIED_FIELD) 74 | ); 75 | JSONStructEnd 76 | }; 77 | 78 | /* 79 | Voice Server Update Event Fields 80 | Field Type Description 81 | token string voice connection token 82 | guild_id snowflake the guild this voice server update is for 83 | endpoint string the voice server host 84 | */ 85 | struct VoiceServerUpdate : DiscordObject { 86 | VoiceServerUpdate() = default; 87 | //VoiceServerUpdate(const std::string * rawJson); 88 | VoiceServerUpdate(const nonstd::string_view& json) : 89 | VoiceServerUpdate(json::fromJSON(json)) {} 90 | VoiceServerUpdate(const json::Value& json); 91 | //VoiceServerUpdate(const json::Values values); 92 | std::string token; 93 | Snowflake serverID; 94 | std::string endpoint; 95 | //const static std::initializer_list fields; 96 | JSONStructStart 97 | std::make_tuple( 98 | json::pair(&VoiceServerUpdate::token , "token" , json::REQUIRIED_FIELD), 99 | json::pair(&VoiceServerUpdate::serverID, "guild_id", json::REQUIRIED_FIELD), 100 | json::pair(&VoiceServerUpdate::endpoint, "endpoint", json::REQUIRIED_FIELD) 101 | ); 102 | JSONStructEnd 103 | }; 104 | } -------------------------------------------------------------------------------- /include/sleepy_discord/webhook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "discord_object_interface.h" 3 | #include "user.h" 4 | #include "server.h" 5 | #include "channel.h" 6 | #include "snowflake.h" 7 | 8 | namespace SleepyDiscord { 9 | /*Webhook Structure 10 | Field Type Description 11 | id snowflake the id of the webhook 12 | guild_id snowflake? the guild id this webhook is for 13 | channel_id snowflake the channel id this webhook is for 14 | user User? the user this webhook was created by (not returned when getting a webhook with its token) 15 | name ?string the default name of the webhook 16 | avatar ?string the default avatar of the webhook 17 | token string the secure token of the webhook 18 | */ 19 | struct Webhook : public IdentifiableDiscordObject { 20 | public: 21 | Webhook() = default; 22 | Webhook(const json::Value & json); 23 | Webhook(const nonstd::string_view& json) : 24 | Webhook(json::fromJSON(json)) {} 25 | 26 | enum WebhookType { 27 | INCOMING = 1, 28 | CHANNEL_FOLLOWER = 2, 29 | }; 30 | WebhookType type = static_cast(0); 31 | Snowflake serverID; 32 | Snowflake channelID; 33 | User user; 34 | std::string name; 35 | std::string avatar; 36 | std::string token; 37 | JSONStructStart 38 | std::make_tuple( 39 | json::pair(&Webhook::ID , "id" , json::REQUIRIED_FIELD), 40 | json::pair(&Webhook::serverID , "guild_id" , json::OPTIONAL_FIELD ), 41 | json::pair(&Webhook::channelID, "channel_id", json::REQUIRIED_FIELD), 42 | json::pair(&Webhook::user , "user" , json::OPTIONAL_FIELD ), 43 | json::pair(&Webhook::name , "name" , json::NULLABLE_FIELD ), 44 | json::pair(&Webhook::avatar , "avatar" , json::NULLABLE_FIELD ), 45 | json::pair(&Webhook::token , "token" , json::OPTIONAL_FIELD ) 46 | ); 47 | JSONStructEnd 48 | }; 49 | } -------------------------------------------------------------------------------- /include/sleepy_discord/websocket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace SleepyDiscord { 5 | struct GenericWebsocketConnection { 6 | }; 7 | } -------------------------------------------------------------------------------- /include/sleepy_discord/websocket_connection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //custom dynamic 4 | #ifdef SLEEPY_CUSTOM_WEBSOCKETS_CONNECTION 5 | #include "custom_connection.h" 6 | 7 | //defined 8 | #elif defined(SLEEPY_WEBSOCKETS_CONNECTION_INCLUDE) || defined(SLEEPY_WEBSOCKETS_CONNECTION) 9 | #ifdef SLEEPY_WEBSOCKETS_CONNECTION_INCLUDE 10 | #include SLEEPY_WEBSOCKETS_CONNECTION_INCLUDE 11 | #endif 12 | #ifdef SLEEPY_WEBSOCKETS_CONNECTION 13 | typedef SLEEPY_SESSION Session 14 | #endif 15 | 16 | #elif defined(SLEEPY_DISCORD_CMAKE) 17 | #if defined(EXISTENT_ASIO) 18 | #include "asio_websocketconnection.h" 19 | #else 20 | #include "custom_connection.h" 21 | #endif 22 | 23 | //defaults 24 | #else 25 | #ifndef SLEEPY_LOCK_EXISTENT_TO 26 | #include "asio_websocketconnection.h" 27 | #ifdef NONEXISTENT_ASIO 28 | //last resort 29 | #include "custom_connection.h" 30 | #endif 31 | #elif SLEEPY_LOCK_EXISTENT_TO == SLEEPY_ASIO 32 | #include "asio_websocketconnection.h" 33 | #else 34 | //last resort 35 | #include "custom_connection.h" 36 | #endif 37 | #endif -------------------------------------------------------------------------------- /include/sleepy_discord/zlib_compression.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "generic_compression.h" 3 | #ifdef EXISTENT_ZLIB 4 | #include "zlib.h" 5 | #elif defined(EXISTENT_ZLIB_NG) 6 | #include "zlib-ng/zlib-ng.h" 7 | #endif 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace SleepyDiscord { 14 | //This Queue is basicly a single linked list with the back and size stored 15 | //Needed for storing the output before copying it over into one string 16 | struct OutputQueue { 17 | constexpr static size_t chunkSize = 16 * 1024; 18 | using Data = std::array; 19 | using Buffer = std::pair; 20 | 21 | using Queue = std::forward_list; 22 | using Iterator = std::forward_list::iterator; 23 | using ConstIterator = std::forward_list::const_iterator; 24 | 25 | Queue queue; //needed when output is larger then buffer 26 | Iterator _back = queue.before_begin(); //both back and size would require looking for them 27 | Queue::size_type _size = 0; //to avoid looking for size, we store it. Same goes for back 28 | 29 | ~OutputQueue() = default; 30 | 31 | bool empty() const { return queue.empty(); } 32 | 33 | //allocates more memory 34 | template 35 | Iterator emplace_back(Args&&... args) { 36 | Iterator result = queue.emplace_after(_back, std::forward(args)...); 37 | if (_back != result) { //if did anything 38 | _back = result; 39 | _size += 1; 40 | } 41 | return result; 42 | } 43 | 44 | Buffer& front() { 45 | return queue.front(); 46 | } 47 | Buffer& back() { 48 | return *_back; 49 | } 50 | 51 | Iterator begin() noexcept { 52 | return queue.begin(); 53 | } 54 | Iterator end() noexcept { 55 | return queue.end(); 56 | } 57 | 58 | ConstIterator begin() const noexcept { 59 | return queue.begin(); 60 | } 61 | ConstIterator end() const noexcept { 62 | return queue.end(); 63 | } 64 | 65 | Queue::size_type size() const noexcept { 66 | return _size; 67 | } 68 | 69 | void resize(Queue::size_type count) { 70 | queue.resize(count); 71 | _size = 0; 72 | //linear time complexity but count is usally 1 73 | for (Iterator it = begin(); it != end(); ++it) { 74 | _size += 1; 75 | _back = it; 76 | } 77 | } 78 | }; 79 | 80 | #ifdef EXISTENT_ZLIB 81 | namespace ZLib { 82 | using Stream = z_stream; 83 | using Btye = Bytef; 84 | using ConstByte = z_const Bytef; 85 | inline int inflateInitStream(Stream* stream) { return inflateInit(stream); } 86 | inline int inflateEndStream(Stream* stream) { return inflateEnd(stream); } 87 | inline int inflateResetStream(Stream* stream) { return inflateReset(stream); } 88 | inline int inflateStream(Stream* stream, int mode) { return inflate(stream, mode); } 89 | } 90 | #elif defined(EXISTENT_ZLIB_NG) 91 | namespace ZLib { 92 | using Stream = zng_stream; 93 | using Btye = uint8_t; 94 | using ConstByte = const uint8_t; 95 | inline int inflateInitStream(Stream* stream) { return zng_inflateInit(stream); } 96 | inline int inflateEndStream(Stream* stream) { return zng_inflateEnd(stream); } 97 | inline int inflateResetStream(Stream* stream) { return zng_inflateReset(stream); } 98 | inline int inflateStream(Stream* stream, int mode) { return zng_inflate(stream, mode); } 99 | } 100 | #endif 101 | 102 | class ZLibCompression : public GenericCompression { 103 | public: 104 | using Output = OutputQueue; 105 | 106 | ZLibCompression(); 107 | 108 | ~ZLibCompression() { 109 | ZLib::inflateEndStream(&stream); 110 | } 111 | 112 | ZLib::Stream stream; 113 | int statusCode; 114 | 115 | Output output; 116 | std::mutex mutex; //only allow one thread to uncompress 117 | 118 | void uncompress(const std::string& compressed) override; 119 | void getOutput(std::string& uncompressedOut) override; 120 | 121 | inline void resetStream() override { 122 | ZLib::inflateResetStream(&stream); 123 | } 124 | 125 | inline bool streamEnded() override { 126 | return statusCode == Z_STREAM_END; 127 | } 128 | }; 129 | 130 | using DefaultCompression = ZLibCompression; 131 | #define SLEEPY_DEFAULT_COMPRESSION ZLibCompression 132 | } -------------------------------------------------------------------------------- /sleepy_discord/asio_udp.cpp: -------------------------------------------------------------------------------- 1 | #include "asio_udp.h" 2 | #ifndef NONEXISTENT_ASIO 3 | 4 | #include "client.h" 5 | 6 | namespace SleepyDiscord { 7 | //Note: you need to be using a ASIOBasedScheduleHandler for this to work 8 | ASIOUDPClient::ASIOUDPClient(BaseDiscordClient& client) : 9 | ASIOUDPClient(static_cast(client.getScheduleHandler()).getIOContext()) 10 | {} 11 | 12 | ASIOUDPClient::ASIOUDPClient(asio::io_context& context) : 13 | iOContext(&context), 14 | uDPSocket(context, asio::ip::udp::endpoint(asio::ip::udp::v4(), 0)), 15 | resolver (context) 16 | { 17 | 18 | } 19 | 20 | bool ASIOUDPClient::connect(const std::string & to, const uint16_t port) { 21 | if (iOContext == nullptr) return false; 22 | endpoint = *(resolver.resolve(asio::ip::udp::v4(), to, std::to_string(port)).begin()); 23 | return true; 24 | } 25 | 26 | void handle_send( 27 | const std::error_code& /*error*/, 28 | std::size_t /*bytes_transferred*/, 29 | GenericUDPClient::SendHandler handler 30 | ) { 31 | handler(); 32 | } 33 | 34 | void ASIOUDPClient::send( 35 | const uint8_t* _buffer, 36 | size_t bufferLength, 37 | SendHandler handler 38 | ) { 39 | if (iOContext == nullptr) return; 40 | uDPSocket.async_send_to(asio::buffer(_buffer, bufferLength), endpoint, 41 | std::bind(&handle_send, std::placeholders::_1, std::placeholders::_2, handler) 42 | ); 43 | } 44 | 45 | void ASIOUDPClient::receive(ReceiveHandler handler) { 46 | if (iOContext == nullptr) return; 47 | uDPSocket.async_receive_from(asio::buffer(buffer, bufferSize), endpoint, 0, 48 | std::bind( 49 | &ASIOUDPClient::handle_receive, this, std::placeholders::_1, 50 | std::placeholders::_2, handler 51 | ) 52 | ); 53 | } 54 | 55 | void ASIOUDPClient::handle_receive( 56 | const std::error_code& /*error*/, 57 | std::size_t bytes_transferred, 58 | ReceiveHandler handler 59 | ) { 60 | handler(std::vector(buffer, buffer + bytes_transferred)); 61 | } 62 | }; 63 | 64 | #endif -------------------------------------------------------------------------------- /sleepy_discord/asio_websocket.cpp: -------------------------------------------------------------------------------- 1 | #include "asio_websocket.h" 2 | 3 | namespace SleepyDiscord { 4 | #include "standard_config.h" 5 | } -------------------------------------------------------------------------------- /sleepy_discord/attachment.cpp: -------------------------------------------------------------------------------- 1 | #include "attachment.h" 2 | 3 | namespace SleepyDiscord { 4 | Attachment::Attachment(const json::Value& json) : 5 | Attachment(json::fromJSON(json)) { 6 | } 7 | } -------------------------------------------------------------------------------- /sleepy_discord/channel.cpp: -------------------------------------------------------------------------------- 1 | #include "channel.h" 2 | 3 | namespace SleepyDiscord { 4 | Channel::~Channel() { 5 | 6 | } 7 | 8 | Channel::Channel(const json::Value& json) : 9 | Channel(json::fromJSON(json)) { 10 | } 11 | 12 | Overwrite::Overwrite(const json::Value& json) : 13 | Overwrite(json::fromJSON(json)) { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /sleepy_discord/cpr_session.cpp: -------------------------------------------------------------------------------- 1 | #include "cpr_session.h" 2 | #ifndef NONEXISTENT_CPR 3 | 4 | namespace SleepyDiscord { 5 | void CPRSession::setHeader(const std::vector& header) { 6 | cpr::Header head; 7 | for (HeaderPair pair : header) 8 | head.insert({ pair.name, pair.value }); 9 | session.SetHeader(head); 10 | } 11 | 12 | void CPRSession::setMultipart(const std::vector& parts) { 13 | std::vector cprParts; 14 | for (Part const & m : parts) { 15 | if (m.isFile) cprParts.push_back(cpr::Part(m.name, cpr::File(m.value))); 16 | else cprParts.push_back(cpr::Part(m.name, m.value)); 17 | } 18 | 19 | muiltpart.parts = cprParts; 20 | session.SetMultipart(muiltpart); 21 | } 22 | 23 | Response CPRSession::request(RequestMethod method) { 24 | return perform(method); 25 | } 26 | 27 | Response CPRSession::perform(RequestMethod method) { 28 | cpr::Response response; 29 | switch (method) { 30 | case Post : response = session.Post (); break; 31 | case Patch : response = session.Patch (); break; 32 | case Delete: response = session.Delete(); break; 33 | case Get : response = session.Get (); break; 34 | case Put : response = session.Put (); break; 35 | default : return Response(); break; 36 | } 37 | 38 | Response target; 39 | target.statusCode = response.status_code; 40 | target.text = response.text; 41 | for (std::pair i : response.header) { 42 | target.header.insert(i); 43 | } 44 | return target; 45 | } 46 | } 47 | #endif 48 | -------------------------------------------------------------------------------- /sleepy_discord/default_functions.cpp: -------------------------------------------------------------------------------- 1 | #include "client.h" 2 | 3 | #if _MSC_VER && !__INTEL_COMPILER 4 | #pragma warning( disable: 4100 ) //warns about unused parameters with names 5 | #pragma warning( disable: 4458 ) //warns about variables that hide class members 6 | #endif 7 | 8 | namespace SleepyDiscord { 9 | void BaseDiscordClient::onReady(Ready readyData) { 10 | 11 | } 12 | 13 | void BaseDiscordClient::onResumed() { 14 | 15 | } 16 | 17 | void BaseDiscordClient::onDeleteServer(UnavailableServer server) { 18 | 19 | } 20 | 21 | void BaseDiscordClient::onEditServer(Server server) { 22 | 23 | } 24 | 25 | void BaseDiscordClient::onBan(Snowflake serverID, User user) { 26 | 27 | } 28 | 29 | void BaseDiscordClient::onUnban(Snowflake serverID, User user) { 30 | 31 | } 32 | 33 | void BaseDiscordClient::onMember(Snowflake serverID, ServerMember member) { 34 | 35 | } 36 | 37 | void BaseDiscordClient::onRemoveMember(Snowflake serverID, User user) { 38 | 39 | } 40 | 41 | 42 | void BaseDiscordClient::onEditMember(Snowflake serverID, User user, std::vector> roles, std::string nick) { 43 | 44 | } 45 | 46 | void BaseDiscordClient::onRole(Snowflake serverID, Role role) { 47 | 48 | } 49 | 50 | void BaseDiscordClient::onDeleteRole(Snowflake serverID, Snowflake roleID) { 51 | 52 | } 53 | 54 | void BaseDiscordClient::onEditRole(Snowflake serverID, Role role) { 55 | 56 | } 57 | 58 | void BaseDiscordClient::onEditEmojis(Snowflake serverID, std::vector emojis) { 59 | 60 | } 61 | 62 | void BaseDiscordClient::onMemberChunk(ServerMembersChunk memberChunk) { 63 | 64 | } 65 | 66 | void BaseDiscordClient::onDeleteChannel(Channel channel) { 67 | 68 | } 69 | 70 | void BaseDiscordClient::onEditChannel(Channel channel) { 71 | 72 | } 73 | 74 | void BaseDiscordClient::onPinMessage(Snowflake channelID, std::string lastPinTimestamp) { 75 | 76 | } 77 | 78 | void BaseDiscordClient::onPresenceUpdate(PresenceUpdate presenseUpdate) { 79 | 80 | } 81 | 82 | void BaseDiscordClient::onEditUser(User user) { 83 | 84 | } 85 | 86 | 87 | void BaseDiscordClient::onEditUserSettings(const json::Value& jsonMessage) { 88 | 89 | } 90 | 91 | void BaseDiscordClient::onEditVoiceState(VoiceState& state) { 92 | 93 | } 94 | 95 | void BaseDiscordClient::onTyping(Snowflake channelID, Snowflake userID, time_t timestamp) { 96 | 97 | } 98 | 99 | void BaseDiscordClient::onDeleteMessages(Snowflake channelID, std::vector> messages) { 100 | 101 | } 102 | 103 | void BaseDiscordClient::onEditMessage(MessageRevisions revisioins) { 104 | 105 | } 106 | 107 | void BaseDiscordClient::onEditVoiceServer(VoiceServerUpdate& voiceServerUpdate) { 108 | 109 | } 110 | 111 | void BaseDiscordClient::onReaction(Snowflake userID, Snowflake channelID, Snowflake messageID, Emoji emoji) { 112 | 113 | } 114 | 115 | void BaseDiscordClient::onDeleteReaction(Snowflake userID, Snowflake channelID, Snowflake messageID, Emoji emoji) { 116 | 117 | } 118 | 119 | void BaseDiscordClient::onDeleteAllReaction(Snowflake serverID, Snowflake channelID, Snowflake messageID) { 120 | 121 | } 122 | 123 | void BaseDiscordClient::onMessage(Message message) { 124 | 125 | } 126 | 127 | void BaseDiscordClient::onHeartbeat() { 128 | 129 | } 130 | 131 | void BaseDiscordClient::onHeartbeatAck() { 132 | 133 | } 134 | 135 | void BaseDiscordClient::onServer(Server jsonMessage) { 136 | 137 | } 138 | 139 | void BaseDiscordClient::onChannel(Channel channel) { 140 | 141 | } 142 | 143 | void BaseDiscordClient::onUnknownEvent(std::string name, const json::Value& data) { 144 | 145 | } 146 | 147 | void BaseDiscordClient::onInvaldSession() { 148 | 149 | } 150 | 151 | void BaseDiscordClient::onDisconnect() { 152 | 153 | } 154 | 155 | void BaseDiscordClient::onResume() { 156 | 157 | } 158 | 159 | void BaseDiscordClient::runAsync() { 160 | 161 | } 162 | 163 | void BaseDiscordClient::run() { 164 | 165 | } 166 | 167 | void BaseDiscordClient::onQuit() { 168 | 169 | } 170 | 171 | void SleepyDiscord::BaseDiscordClient::onResponse(Response response) { 172 | } 173 | 174 | void BaseDiscordClient::sleep(const unsigned int milliseconds) { 175 | 176 | } 177 | 178 | void BaseDiscordClient::fileRead(const char* path, std::string*const file) { 179 | 180 | } 181 | 182 | void BaseDiscordClient::tick(float deltaTime) { 183 | 184 | } 185 | 186 | void BaseDiscordClient::onError(ErrorCode errorCode, std::string errorMessage) { 187 | 188 | } 189 | 190 | Timer BaseDiscordClient::schedule(TimedTask code, const time_t millisecondsTilDueTime) { 191 | return Timer([]() {}); 192 | } 193 | } -------------------------------------------------------------------------------- /sleepy_discord/embed.cpp: -------------------------------------------------------------------------------- 1 | #include "embed.h" 2 | 3 | namespace SleepyDiscord { 4 | EmbedThumbnail::EmbedThumbnail(const json::Value & json) : 5 | EmbedThumbnail(json::fromJSON(json)) { 6 | } 7 | 8 | EmbedVideo::EmbedVideo(const json::Value & json) : 9 | EmbedVideo(json::fromJSON(json)) { 10 | } 11 | 12 | EmbedImage::EmbedImage(const json::Value & json) : 13 | EmbedImage(json::fromJSON(json)) { 14 | } 15 | 16 | EmbedProvider::EmbedProvider(const json::Value & json) : 17 | EmbedProvider(json::fromJSON(json)) { 18 | } 19 | 20 | EmbedAuthor::EmbedAuthor(const json::Value & json) : 21 | EmbedAuthor(json::fromJSON(json)) { 22 | } 23 | 24 | EmbedFooter::EmbedFooter(const json::Value & json) : 25 | EmbedFooter(json::fromJSON(json)) { 26 | } 27 | 28 | EmbedField::EmbedField(const json::Value & json) : 29 | EmbedField(json::fromJSON(json)) { 30 | } 31 | 32 | Embed::Embed(const json::Value & json) : 33 | Embed(json::fromJSON(json)) { 34 | } 35 | } -------------------------------------------------------------------------------- /sleepy_discord/gateway.cpp: -------------------------------------------------------------------------------- 1 | #include "gateway.h" 2 | 3 | namespace SleepyDiscord { 4 | SessionStartLimit::SessionStartLimit(const json::Value& json) : 5 | SessionStartLimit(json::fromJSON(json)) { 6 | } 7 | Gateway::Gateway(const json::Value& json) : 8 | Gateway(json::fromJSON(json)) { 9 | } 10 | Ready::Ready(const json::Value & json) : 11 | Ready(json::fromJSON(json)) { 12 | } 13 | ActivityTimestamp::ActivityTimestamp(const json::Value & json) : 14 | ActivityTimestamp(json::fromJSON(json)) { 15 | } 16 | ActivityParty::ActivityParty(const json::Value & json) : 17 | ActivityParty(json::fromJSON(json)) { 18 | } 19 | ActivityAssets::ActivityAssets(const json::Value & json) : 20 | ActivityAssets(json::fromJSON(json)) { 21 | } 22 | ActivitySecrets::ActivitySecrets(const json::Value & json) : 23 | ActivitySecrets(json::fromJSON(json)) { 24 | } 25 | Activity::Activity(const json::Value & json) : 26 | Activity(json::fromJSON(json)) { 27 | } 28 | PresenceUpdate::PresenceUpdate(const json::Value & json) : 29 | PresenceUpdate(json::fromJSON(json)) { 30 | } 31 | ServerMembersChunk::ServerMembersChunk(const json::Value & json) : 32 | ServerMembersChunk(json::fromJSON(json)) { 33 | } 34 | } -------------------------------------------------------------------------------- /sleepy_discord/http.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "http.h" 4 | 5 | namespace SleepyDiscord { 6 | //copied from cpr 7 | bool caseInsensitiveCompare::operator()(const std::string& a, const std::string& b) const noexcept { 8 | return std::lexicographical_compare( 9 | a.begin(), a.end(), b.begin(), b.end(), 10 | [](unsigned char ac, unsigned char bc) { return std::tolower(ac) < std::tolower(bc); }); 11 | } 12 | 13 | const char * getMethodName(const RequestMethod & method) { 14 | static constexpr char const * methodNames[] = { "POST", "PATCH", "DELETE", "GET", "PUT" }; 15 | return methodNames[method]; 16 | } 17 | 18 | std::string escapeURL(const std::string& string) { 19 | if (string.empty()) 20 | return string; 21 | std::string target; 22 | target.reserve(string.length()); 23 | 24 | static const auto isUrlUnresered = [](unsigned char character) { 25 | //copied from libcurl 26 | switch(character) { 27 | case '0': case '1': case '2': case '3': case '4': 28 | case '5': case '6': case '7': case '8': case '9': 29 | case 'a': case 'b': case 'c': case 'd': case 'e': 30 | case 'f': case 'g': case 'h': case 'i': case 'j': 31 | case 'k': case 'l': case 'm': case 'n': case 'o': 32 | case 'p': case 'q': case 'r': case 's': case 't': 33 | case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': 34 | case 'A': case 'B': case 'C': case 'D': case 'E': 35 | case 'F': case 'G': case 'H': case 'I': case 'J': 36 | case 'K': case 'L': case 'M': case 'N': case 'O': 37 | case 'P': case 'Q': case 'R': case 'S': case 'T': 38 | case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': 39 | case '-': case '.': case '_': case '~': 40 | return true; 41 | default: 42 | return false; 43 | } 44 | }; 45 | 46 | for (const auto sym : string) { 47 | const unsigned char character = 48 | static_cast(sym); 49 | if (isUrlUnresered(character)) { 50 | target += character; 51 | } else { 52 | //encode 53 | static const std::array hexConvert = {{ 54 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 55 | 'A', 'B', 'C', 'D', 'E', 'F' 56 | }}; 57 | const std::array encoded {{ 58 | '%', 59 | hexConvert[((0xF << 4) & sym) >> 4], 60 | hexConvert[0xF & sym], 61 | 0 62 | }}; 63 | target.append(encoded.data()); 64 | } 65 | } 66 | return target; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /sleepy_discord/invite.cpp: -------------------------------------------------------------------------------- 1 | #include "invite.h" 2 | 3 | namespace SleepyDiscord { 4 | Invite::Invite(const json::Value & json) : 5 | Invite(json::fromJSON(json)) { 6 | } 7 | 8 | InviteMetadata::InviteMetadata(const json::Value & json) : 9 | InviteMetadata(json::fromJSON(json)) { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /sleepy_discord/json_wrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "json_wrapper.h" 2 | #include 3 | #include 4 | 5 | namespace SleepyDiscord { namespace json { 6 | const std::string createJSON(std::initializer_list> json) { 7 | std::string target; 8 | target.reserve(2); //revents crash 9 | for (std::pair pair : json) { 10 | if (pair.second != "") { 11 | target += ",\"" + pair.first + "\":" + pair.second; 12 | } 13 | } 14 | target[0] = '{'; 15 | target.push_back('}'); 16 | return target; 17 | } 18 | 19 | const std::string string(const std::string& s) { 20 | if (s.empty()) 21 | return ""; 22 | rapidjson::StringBuffer buffer; 23 | rapidjson::Writer writer(buffer); 24 | writer.String(s.data(), s.length()); 25 | return std::string(buffer.GetString(), buffer.GetSize()); 26 | } 27 | 28 | const std::string UInteger(const uint64_t num) { 29 | return std::to_string(num & 0x3FFFFFFFFFFFFF); //just in case numbers are larger then 53 bits 30 | } 31 | 32 | const std::string optionalUInteger(const uint64_t num) { 33 | return num ? UInteger(num) : ""; 34 | } 35 | 36 | const std::string integer(const int64_t num) { 37 | return std::to_string(num & 0x803FFFFFFFFFFFFF); //just in case numbers are larger then 53 bits 38 | } 39 | 40 | const std::string optionalInteger(const int64_t num) { 41 | return num ? integer(num) : ""; 42 | } 43 | 44 | const std::string boolean(const bool boolean) { 45 | return boolean ? "true" : "false"; 46 | } 47 | }} -------------------------------------------------------------------------------- /sleepy_discord/make_version.h.js: -------------------------------------------------------------------------------- 1 | /* 2 | !!! NOTE !!! 3 | This is not a noramal javascript script. You much use this using Windows Script Host. 4 | */ 5 | var wscriptShell = new ActiveXObject("WScript.Shell"); 6 | var fileSystem = new ActiveXObject("Scripting.FileSystemObject"); 7 | 8 | // Get git 9 | var git = "git"; 10 | 11 | function testGit() { 12 | try { 13 | wscriptShell.Exec(git + " --version"); 14 | } catch (error) { 15 | return false; 16 | } 17 | return true; 18 | } 19 | 20 | if (!testGit()) { 21 | try { 22 | git = wscriptShell.RegRead("HKLM\\SOFTWARE\\GitForWindows\\InstallPath") + "\\bin\\git.exe"; 23 | } catch (error) { /*do notthing*/ } 24 | if (!testGit()) { 25 | WScript.Echo("Could not find git for windows values in windows registry. Try installing git for windows\n"); 26 | WScript.Quit(1); 27 | } 28 | } 29 | 30 | function readCommandLine(command) { 31 | try { 32 | return wscriptShell.Exec(command).StdOut.ReadLine(); 33 | } catch (error) { 34 | WScript.Echo("Failed to exec " + command); 35 | WScript.Quit(1); 36 | } 37 | } 38 | 39 | var isInGitRepo = readCommandLine(git + " rev-parse --is-inside-work-tree"); 40 | if (isInGitRepo !== "true") { 41 | WScript.Echo("Not in a git repo"); 42 | WScript.Quit(0); 43 | } 44 | var build = readCommandLine(git + " rev-list --count HEAD"); 45 | var branch = readCommandLine(git + " rev-parse --abbrev-ref HEAD"); 46 | var hash = readCommandLine(git + " rev-parse HEAD"); 47 | var isMaster = branch === "master" ? "1" : "0"; 48 | var description = readCommandLine(git + " describe --always --long --dirty"); 49 | var descriptionConcat = description === "" ? "" : " "; 50 | var outputContent = "/*\n\ 51 | !!!!!!WARNING!!!!!!\n\ 52 | version.h is an auto generated file.Any changes in version.h while be replaced.\n\ 53 | However, version.h.in, not be confused with version.h, is ok to make changes to.\n\ 54 | */\n\ 55 | \n\ 56 | #pragma once\n\ 57 | \n\ 58 | #define SLEEPY_DISCORD_VERSION_BUILD " + build + "\n\ 59 | #define SLEEPY_DISCORD_VERSION_BRANCH \"" + branch + "\"\n\ 60 | #define SLEEPY_DISCORD_VERSION_HASH \"" + hash + "\"\n\ 61 | #define SLEEPY_DISCORD_VERSION_IS_MASTER " + isMaster + "\n\ 62 | #define SLEEPY_DISCORD_VERSION_DESCRIPTION_CONCAT \"" + descriptionConcat + "\"\n\ 63 | #define SLEEPY_DISCORD_VERSION_DESCRIPTION \"" + description + "\""; 64 | 65 | var outputFile = "../include/sleepy_discord/version.h"; 66 | var outputFileContent; 67 | try { 68 | outputFileContent = fileSystem.OpenTextFile(outputFile).ReadAll(); 69 | } catch (error) { 70 | outputFileContent = ""; //file doesn't exist 71 | } 72 | 73 | if (outputContent === outputFileContent) { 74 | WScript.Echo(outputFile + " doesn't need to be updated. " + description); 75 | } else { 76 | fileSystem.CreateTextFile(outputFile, true).Write(outputContent); 77 | WScript.Echo(outputFile + " updated to " + description); 78 | } 79 | -------------------------------------------------------------------------------- /sleepy_discord/message.cpp: -------------------------------------------------------------------------------- 1 | #include "message.h" 2 | #include "client.h" 3 | 4 | namespace SleepyDiscord { 5 | Message::Message(json::Value& json) : 6 | Message(json::fromJSON(json)) 7 | {} 8 | 9 | bool Message::startsWith(const std::string& test) { 10 | return content.compare(0, test.length(), test) == 0; 11 | } 12 | 13 | std::size_t Message::length() { 14 | return content.length(); 15 | } 16 | 17 | bool Message::isMentioned(Snowflake userID) { 18 | std::size_t size = mentions.size(); 19 | for (std::size_t i = 0; i < size; i++) 20 | if (mentions[i].ID == userID) return true; 21 | return false; 22 | } 23 | 24 | bool Message::isMentioned(User& _user) { 25 | return isMentioned(_user.ID); 26 | } 27 | 28 | Message Message::send(BaseDiscordClient* client) { 29 | return client->sendMessage(channelID, content, embeds, messageReference, static_cast(tts)); 30 | } 31 | 32 | Message Message::reply(BaseDiscordClient * client, std::string message, Embed embed) 33 | { 34 | return client->sendMessage(channelID, message, { embed }); 35 | } 36 | 37 | Message::Interaction::Interaction(const json::Value& json) : 38 | Interaction(json::fromJSON(json)) 39 | {} 40 | 41 | Emoji::~Emoji() { 42 | } 43 | 44 | Emoji::Emoji(const json::Value& json) : 45 | Emoji(json::fromJSON(json)) { 46 | } 47 | 48 | Reaction::~Reaction() { 49 | } 50 | 51 | Reaction::Reaction(const json::Value& json) : 52 | Reaction(json::fromJSON(json)) { 53 | } 54 | 55 | StickerPack::~StickerPack() {} 56 | StickerPack::StickerPack(const json::Value & json): 57 | StickerPack(json::fromJSON(json)) 58 | {} 59 | 60 | Sticker::~Sticker() {} 61 | Sticker::Sticker(const json::Value & json): 62 | Sticker(json::fromJSON(json)) 63 | {} 64 | 65 | MessageReference::MessageReference(const json::Value & json): 66 | MessageReference(json::fromJSON(json)) 67 | {} 68 | AllowedMentions::AllowedMentions(const json::Value & json): 69 | AllowedMentions(json::fromJSON(json)) 70 | {} 71 | 72 | ActionRow::ActionRow(json::Value& json) : 73 | ActionRow(json::fromJSON(json)) 74 | {} 75 | Button::Button(const json::Value& json) : 76 | Button(json::fromJSON