Compare commits
No commits in common. "main" and "v0.1.0" have entirely different histories.
@ -1,8 +0,0 @@
|
|||||||
Checks:
|
|
||||||
'-*,
|
|
||||||
clang-analyzer-*,
|
|
||||||
modernize-*,
|
|
||||||
performance-*,
|
|
||||||
bugprone-*,
|
|
||||||
cppcoreguidelines-*,
|
|
||||||
-performance-avoid-endl'
|
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,2 @@
|
|||||||
build/
|
build/
|
||||||
.vscode/
|
.vscode/
|
||||||
.cache/
|
|
@ -1,39 +1,34 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
project(sparkle)
|
project(sparkle)
|
||||||
|
|
||||||
#include(GoogleTest)
|
include(GoogleTest)
|
||||||
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
|
||||||
set(SOURCE sources/main.cpp)
|
set(SOURCE sources/main.cpp)
|
||||||
set(LIBS ${CMAKE_SOURCE_DIR}/libs/)
|
set(LIBS ${CMAKE_SOURCE_DIR}/libs/)
|
||||||
set(INCLUDE ${CMAKE_SOURCE_DIR}/include/)
|
set(INCLUDE ${CMAKE_SOURCE_DIR}/include/)
|
||||||
#set(TESTS ${CMAKE_SOURCE_DIR}/tests)
|
set(TESTS ${CMAKE_SOURCE_DIR}/tests)
|
||||||
set(ADDITIONAL_CXX_FLAGS_DEBUG "-march=native -O0 -pipe -Wall -Wextra -Wpedantic -Wconversion -Wuninitialized -Wsign-conversion -Wshadow -fsanitize=address") #-Werror
|
set(CMAKE_C_COMPILER "clang")
|
||||||
set(ADDITIONAL_CXX_FLAGS_RELEASE "-march=native -O2 -pipe -Wall -Wextra -Wpedantic -Wconversion -Wuninitialized -Wsign-conversion -Wshadow -flto=full")
|
set(CMAKE_CXX_COMPILER "clang++")
|
||||||
|
|
||||||
file(GLOB NETWORK_SOURCES libs/network/*.cpp)
|
|
||||||
|
|
||||||
find_package(CURL REQUIRED)
|
find_package(CURL REQUIRED)
|
||||||
find_path(IXWEBSOCKET_INCLUDE_DIR ixwebsocket)
|
find_path(IXWEBSOCKET_INCLUDE_DIR ixwebsocket)
|
||||||
find_library(IXWEBSOCKET_LIBRARIES ixwebsocket)
|
find_library(IXWEBSOCKET_LIBRARIES ixwebsocket)
|
||||||
|
find_program(CMAKE_C_COMPILER clang)
|
||||||
|
find_program(CLANG_CXX_COMPILER clang++)
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE)
|
message(STATUS "ixwebsocket: ${IXWEBSOCKET_LIBRARIES}")
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
message(STATUS "curl: ${CURL_LIBRARIES}")
|
||||||
add_definitions(-DDEBUG)
|
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${ADDITIONAL_CXX_FLAGS_DEBUG}")
|
if(NOT CMAKE_C_COMPILER OR NOT CLANG_CXX_COMPILER)
|
||||||
message(STATUS "cflags: ${CMAKE_CXX_FLAGS_DEBUG}")
|
message(STATUS "clang not found")
|
||||||
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
|
set(CMAKE_C_COMPILER "gcc")
|
||||||
add_definitions(-DRELEASE)
|
set(CMAKE_CXX_COMPILER "g++")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${ADDITIONAL_CXX_FLAGS_RELEASE}")
|
find_program(CMAKE_C_COMPILER clang)
|
||||||
message(STATUS "cflags: ${CMAKE_CXX_FLAGS_RELEASE}")
|
find_program(CLANG_CXX_COMPILER clang++)
|
||||||
|
if(NOT CMAKE_C_COMPILER OR NOT CLANG_CXX_COMPILER)
|
||||||
|
message(FATAL_ERROR "gcc not found")
|
||||||
endif()
|
endif()
|
||||||
elseif(NOT CMAKE_BUILD_TYPE)
|
|
||||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
|
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${ADDITIONAL_CXX_FLAGS_RELEASE}")
|
|
||||||
message(STATUS "cflags: ${CMAKE_CXX_FLAGS_RELEASE}")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT IXWEBSOCKET_INCLUDE_DIR OR NOT IXWEBSOCKET_LIBRARIES)
|
if(NOT IXWEBSOCKET_INCLUDE_DIR OR NOT IXWEBSOCKET_LIBRARIES)
|
||||||
@ -44,12 +39,17 @@ if(NOT CURL_INCLUDE_DIRS OR NOT CURL_LIBRARIES)
|
|||||||
message(FATAL_ERROR "curl not found")
|
message(FATAL_ERROR "curl not found")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
message(STATUS "Current compiler: ${CMAKE_CXX_COMPILER}")
|
add_executable(${PROJECT_NAME} ${SOURCE})
|
||||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
#add_library(sparkles STATIC ${SOURCE})
|
||||||
|
add_executable(tests ${TESTS}/tests.cpp)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${SOURCE} ${NETWORK_SOURCES})
|
#enable_testing()
|
||||||
|
|
||||||
target_precompile_headers(${PROJECT_NAME} PRIVATE ${INCLUDE}pch.hpp)
|
add_test(NAME network COMMAND tests)
|
||||||
|
|
||||||
|
#target_include_directories(sparkles PRIVATE ${LIBS} ${INCLUDE} ${IXWEBSOCKET_INCLUDE_DIR} ${CURL_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
#target_link_libraries(sparkles PRIVATE ${IXWEBSOCKET_LIBRARIES} ${CURL_LIBRARIES})
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||||
${LIBS}
|
${LIBS}
|
||||||
@ -63,22 +63,20 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
|
|||||||
${CURL_LIBRARIES}
|
${CURL_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
#add_library(sparkles STATIC ${SOURCE})
|
target_include_directories(tests PRIVATE
|
||||||
#add_executable(tests ${TESTS}/tests.cpp)
|
${LIBS}
|
||||||
|
${INCLUDE}
|
||||||
|
${IXWEBSOCKET_INCLUDE_DIR}
|
||||||
|
${CURL_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
#enable_testing()
|
target_link_libraries(tests gtest
|
||||||
|
${IXWEBSOCKET_LIBRARIES}
|
||||||
|
${CURL_LIBRARIES}
|
||||||
|
gtest_main
|
||||||
|
)
|
||||||
|
|
||||||
#add_test(NAME NetworkManagerTest COMMAND tests)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
#target_include_directories(tests PRIVATE
|
set(CMAKE_CXX_FLAGS "-march=native -O2 -pipe")
|
||||||
# ${LIBS}
|
#set(CMAKE_CXX_FLAGS "-O0 -pipe")
|
||||||
# ${INCLUDE}
|
|
||||||
# ${IXWEBSOCKET_INCLUDE_DIR}
|
|
||||||
# ${CURL_INCLUDE_DIRS}
|
|
||||||
#)
|
|
||||||
|
|
||||||
#target_link_libraries(tests gtest
|
|
||||||
# ${IXWEBSOCKET_LIBRARIES}
|
|
||||||
# ${CURL_LIBRARIES}
|
|
||||||
# gtest_main
|
|
||||||
#)
|
|
42
README.md
42
README.md
@ -1,26 +1,20 @@
|
|||||||
# Sparkle
|
# Sparkle
|
||||||
Library for creating Discord bots.
|
Library for creating discord bots
|
||||||
## How to Build
|
|
||||||
### Required Libraries
|
|
||||||
- `curl`
|
|
||||||
- `ixwebsocket`
|
|
||||||
- `nlohmann-json`
|
|
||||||
- `cxxopts`
|
|
||||||
### Build Instructions
|
|
||||||
```sh
|
|
||||||
git clone http://applejack.ygg/fluttershy/sparkle.git && cd sparkle
|
|
||||||
cmake -B build && cmake --build build -j$(nproc)
|
|
||||||
build/sparkle -t <BOT_TOKEN>
|
|
||||||
```
|
|
||||||
# ToDo
|
# ToDo
|
||||||
- [x] Websocket support
|
- [x] Websocket support
|
||||||
- [x] Selfbot support
|
- [x] Minimal discord api support
|
||||||
- [x] Easy to use
|
- [x] Selfbot support
|
||||||
- [ ] Optimised for high loads (not tested)
|
- [x] Easy to use
|
||||||
- [ ] Full api support
|
- [ ] Support json extraction from server response
|
||||||
- [ ] Windows support
|
- [ ] Optimised for high loads
|
||||||
- [ ] Sharding
|
- [ ] Full api support
|
||||||
- [ ] Interactions
|
- [ ] Fixes for known bugs
|
||||||
- [ ] Tests
|
- [ ] Windows support
|
||||||
#
|
- [ ] Sharding
|
||||||

|
# How to build
|
||||||
|
```sh
|
||||||
|
git clone http://applejack.ygg/fluttershy/sparkle.git
|
||||||
|
mkdir sparkle/build && cd sparkle/build
|
||||||
|
cmake .. && make -j$(nproc)
|
||||||
|
./sparkle -t <BOT_TOKEN>
|
||||||
|
```
|
||||||
|
10
include/api.h
Normal file
10
include/api.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef INCLUDE_API_H_
|
||||||
|
#define INCLUDE_API_H_
|
||||||
|
#include <api/Author.hpp>
|
||||||
|
#include <api/Message.hpp>
|
||||||
|
#include <api/Channel.hpp>
|
||||||
|
#include <api/Embed.hpp>
|
||||||
|
#include <api/Bot.hpp>
|
||||||
|
#include <api/User.hpp>
|
||||||
|
#include <api/Guild.hpp>
|
||||||
|
#endif
|
@ -1,10 +0,0 @@
|
|||||||
#ifndef INCLUDE_INTERFACE_HPP_
|
|
||||||
#define INCLUDE_INTERFACE_HPP_
|
|
||||||
#include <interface/Author.hpp>
|
|
||||||
#include <interface/Message.hpp>
|
|
||||||
#include <interface/Channel.hpp>
|
|
||||||
#include <interface/Embed.hpp>
|
|
||||||
#include <interface/Bot.hpp>
|
|
||||||
#include <interface/User.hpp>
|
|
||||||
#include <interface/Guild.hpp>
|
|
||||||
#endif
|
|
9
include/includes.h
Normal file
9
include/includes.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef INCLUDE_INCLUDES_H_
|
||||||
|
#define INCLUDE_INCLUDES_H_
|
||||||
|
#include <utils/types.hpp>
|
||||||
|
#include <utils/json.hpp>
|
||||||
|
#include <utils/log.hpp>
|
||||||
|
#include <utils/enums.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#endif
|
@ -1,7 +0,0 @@
|
|||||||
#ifndef INCLUDE_INCLUDES_HPP_
|
|
||||||
#define INCLUDE_INCLUDES_HPP_
|
|
||||||
#include <utils/types.hpp>
|
|
||||||
#include <utils/log.hpp>
|
|
||||||
#include <utils/enums.hpp>
|
|
||||||
#include <utils/functions.hpp>
|
|
||||||
#endif
|
|
5
include/net.h
Normal file
5
include/net.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#ifndef INCLUDE_NET_H_
|
||||||
|
#define INCLUDE_NET_H_
|
||||||
|
#include <gateway/Websocket.hpp>
|
||||||
|
#include <tls/Network.hpp>
|
||||||
|
#endif
|
@ -1,5 +0,0 @@
|
|||||||
#ifndef INCLUDE_NET_HPP_
|
|
||||||
#define INCLUDE_NET_HPP_
|
|
||||||
#include <network/websocket.hpp>
|
|
||||||
#include <network/network.hpp>
|
|
||||||
#endif
|
|
@ -1,12 +0,0 @@
|
|||||||
#ifndef INCLUDE_PCH_HPP_
|
|
||||||
#define INCLUDE_PCH_HPP_
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <functional>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <utils/types.hpp>
|
|
||||||
#include <utils/log.hpp>
|
|
||||||
#include <utils/enums.hpp>
|
|
||||||
#include <utils/functions.hpp>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#endif
|
|
@ -1,3 +0,0 @@
|
|||||||
#ifndef API_ACTIVITY_HPP_
|
|
||||||
#define API_ACTIVITY_HPP_
|
|
||||||
#endif
|
|
57
libs/api/Author.hpp
Normal file
57
libs/api/Author.hpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#ifndef API_AUTHOR_HPP_
|
||||||
|
#define API_AUTHOR_HPP_
|
||||||
|
#include <includes.h>
|
||||||
|
#include <net.h>
|
||||||
|
using std::string, std::cout, std::endl, nlohmann::json;
|
||||||
|
class Author {
|
||||||
|
private:
|
||||||
|
json data;
|
||||||
|
WebSocket& web;
|
||||||
|
NetworkManager& req;
|
||||||
|
public:
|
||||||
|
Author(const json& data) : data(data), web(WebSocket::getInstance()), req(NetworkManager::getInstance()) {}
|
||||||
|
string content() {
|
||||||
|
try {
|
||||||
|
return data["d"]["content"];
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string channel_id() {
|
||||||
|
return data["d"]["channel_id"];
|
||||||
|
}
|
||||||
|
string id() {
|
||||||
|
return data["d"]["author"]["id"];
|
||||||
|
}
|
||||||
|
string global_name() {
|
||||||
|
return data["d"]["author"]["global_name"].dump();
|
||||||
|
}
|
||||||
|
string discriminator() {
|
||||||
|
return data["d"]["author"]["discriminator"];
|
||||||
|
}
|
||||||
|
bool isBot() {
|
||||||
|
try {
|
||||||
|
return data["d"]["author"]["bot"];
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string guild_id() {
|
||||||
|
return data["d"]["guild_id"];
|
||||||
|
}
|
||||||
|
string msg_id() {
|
||||||
|
return data["d"]["id"];
|
||||||
|
}
|
||||||
|
bool isPinned() {
|
||||||
|
return data["d"]["pinned"];
|
||||||
|
}
|
||||||
|
string avatar() {
|
||||||
|
return data["d"]["author"]["avatar"];
|
||||||
|
}
|
||||||
|
string send(const json& msg) {
|
||||||
|
return req.request(HttpMethods::POST, DiscordEndpoints::details::latest + "/channels/" + data["d"]["channel_id"].get<string>() + "/messages", msg.dump());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
39
libs/api/Bot.hpp
Normal file
39
libs/api/Bot.hpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef API_BOT_HPP_
|
||||||
|
#define API_BOT_HPP_
|
||||||
|
#include <includes.h>
|
||||||
|
using std::string, std::cout, std::endl, nlohmann::json;
|
||||||
|
template<typename...Args>
|
||||||
|
class Discord {
|
||||||
|
private:
|
||||||
|
void initializeNets(const json& data) {
|
||||||
|
initializeNetsImpl(data, std::index_sequence_for<Args...>{});
|
||||||
|
}
|
||||||
|
template<unsigned long... Is>
|
||||||
|
void initializeNetsImpl(const json& data, std::index_sequence<Is...>) {
|
||||||
|
net = std::make_tuple(std::make_unique<Args>(data)...);
|
||||||
|
}
|
||||||
|
json data;
|
||||||
|
public:
|
||||||
|
std::tuple<std::unique_ptr<Args>...> net;
|
||||||
|
Discord(const json& data) : data(data) {
|
||||||
|
initializeNets(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class Bot {
|
||||||
|
private:
|
||||||
|
json data;
|
||||||
|
public:
|
||||||
|
Bot(const json& data) : data(data) {};
|
||||||
|
string id() {
|
||||||
|
return data["d"]["id"];
|
||||||
|
}
|
||||||
|
bool isBot() {
|
||||||
|
try {
|
||||||
|
return data["d"]["bot"];
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
17
libs/api/Channel.hpp
Normal file
17
libs/api/Channel.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef API_CHANNEL_HPP_
|
||||||
|
#define API_CHANNEL_HPP_
|
||||||
|
#include <includes.h>
|
||||||
|
#include <net.h>
|
||||||
|
using std::string, std::cout, std::endl, nlohmann::json;
|
||||||
|
class Channel {
|
||||||
|
private:
|
||||||
|
json data;
|
||||||
|
WebSocket& web;
|
||||||
|
NetworkManager& req;
|
||||||
|
public:
|
||||||
|
Channel(const json& data = "") : data(data), web(WebSocket::getInstance()), req(NetworkManager::getInstance()) {}
|
||||||
|
string send(const json& msg) {
|
||||||
|
return req.request(HttpMethods::POST, DiscordEndpoints::details::latest + "/channels/" + data["d"]["channel_id"].get<string>() + "/messages", msg.dump());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
59
libs/api/Embed.hpp
Normal file
59
libs/api/Embed.hpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#ifndef API_EMBED_HPP_
|
||||||
|
#define API_EMBED_HPP_
|
||||||
|
#include <includes.h>
|
||||||
|
using std::string, std::cout, std::endl, nlohmann::json;
|
||||||
|
class EmbedBuilder {
|
||||||
|
private:
|
||||||
|
json embed = {
|
||||||
|
{"content", ""},
|
||||||
|
{"tts", false},
|
||||||
|
{"embeds", json::array()}
|
||||||
|
}, data;
|
||||||
|
public:
|
||||||
|
EmbedBuilder(const json& data) : data(data) {
|
||||||
|
embed = {
|
||||||
|
{"content", ""},
|
||||||
|
{"tts", false},
|
||||||
|
{"embeds", json::array()}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EmbedBuilder& addTitle(const string& title) {
|
||||||
|
if (embed["embeds"].size() == 0) {
|
||||||
|
embed["embeds"].push_back(json::object());
|
||||||
|
}
|
||||||
|
embed["embeds"].back()["title"] = title;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
EmbedBuilder& addDescription(const string& desc) {
|
||||||
|
if (embed["embeds"].size() == 0) {
|
||||||
|
embed["embeds"].push_back(json::object());
|
||||||
|
}
|
||||||
|
embed["embeds"].back()["description"] = desc;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
EmbedBuilder& addColor(const string& color) {
|
||||||
|
if (embed["embeds"].size() == 0) {
|
||||||
|
embed["embeds"].push_back(json::object());
|
||||||
|
}
|
||||||
|
embed["embeds"].back()["color"] = color;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
EmbedBuilder& addUrl(const string& url) {
|
||||||
|
if (embed["embeds"].size() == 0) {
|
||||||
|
embed["embeds"].push_back(json::object());
|
||||||
|
}
|
||||||
|
embed["embeds"].back()["url"] = url;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
EmbedBuilder& addImage(const string& imageurl) {
|
||||||
|
if (embed["embeds"].size() == 0) {
|
||||||
|
embed["embeds"].push_back(json::object());
|
||||||
|
}
|
||||||
|
embed["embeds"].back()["image"] = { {"url", imageurl} };
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
json getEmbed() const {
|
||||||
|
return embed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
15
libs/api/Guild.hpp
Normal file
15
libs/api/Guild.hpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef API_GUILD_HPP_
|
||||||
|
#define API_GUILD_HPP_
|
||||||
|
#include <includes.h>
|
||||||
|
//#include <net.h>
|
||||||
|
using std::string, std::cout, std::endl, nlohmann::json;
|
||||||
|
class Guild {
|
||||||
|
private:
|
||||||
|
json data;
|
||||||
|
public:
|
||||||
|
Guild(const json& data) : data(data) {}
|
||||||
|
string id() {
|
||||||
|
return data["d"]["user"]["id"];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
29
libs/api/Message.hpp
Normal file
29
libs/api/Message.hpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef API_MESSAGE_HPP_
|
||||||
|
#define API_MESSAGE_HPP_
|
||||||
|
#include <includes.h>
|
||||||
|
#include <net.h>
|
||||||
|
using std::string, std::cout, std::endl, nlohmann::json;
|
||||||
|
class Message {
|
||||||
|
private:
|
||||||
|
json data;
|
||||||
|
WebSocket& web;
|
||||||
|
NetworkManager& req;
|
||||||
|
public:
|
||||||
|
Message(const json& data) : data(data), web(WebSocket::getInstance()), req(NetworkManager::getInstance()) {};
|
||||||
|
string send(const string& id, const json& msg) {
|
||||||
|
return req.request(HttpMethods::POST, DiscordEndpoints::details::latest + "/channels/" + id + "/messages", msg.dump());
|
||||||
|
}
|
||||||
|
string getMessages(const string& id, const string& count, const string& before = "") {
|
||||||
|
if (before.empty()) {
|
||||||
|
return req.request(HttpMethods::GET, DiscordEndpoints::details::latest + "/channels/" + id + "/messages?limit=" + count);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return req.request(HttpMethods::GET, DiscordEndpoints::details::latest + "/channels/" + id + "/messages?before=" + before + "&limit=" + count);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
string deleteMessage(const string& channel_id, const string& message_id) {
|
||||||
|
return req.request(HttpMethods::DELETE, DiscordEndpoints::details::latest + "/channels/" + channel_id + "/messages/" + message_id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
40
libs/api/User.hpp
Normal file
40
libs/api/User.hpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef API_USER_HPP_
|
||||||
|
#define API_USER_HPP_
|
||||||
|
#include <includes.h>
|
||||||
|
#include <net.h>
|
||||||
|
#include <vector>
|
||||||
|
using std::string, std::cout, std::endl, nlohmann::json;
|
||||||
|
class User {
|
||||||
|
private:
|
||||||
|
json data;
|
||||||
|
WebSocket& web;
|
||||||
|
NetworkManager& req;
|
||||||
|
public:
|
||||||
|
User(const json& data = "") : data(data), web(WebSocket::getInstance()), req(NetworkManager::getInstance()) {}
|
||||||
|
json extract(const std::vector<string>& keys) {
|
||||||
|
std::vector<string> d = { "d" };
|
||||||
|
d.insert(d.end(), keys.begin(), keys.end());
|
||||||
|
json current = data;
|
||||||
|
for (const auto& key : d) {
|
||||||
|
if (current.contains(key)) {
|
||||||
|
current = current[key];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "Key not found.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
virtual string me() {
|
||||||
|
return req.request(HttpMethods::GET, DiscordEndpoints::details::latest + "/users/@me");
|
||||||
|
}
|
||||||
|
bool isBot() {
|
||||||
|
try {
|
||||||
|
return data["d"]["author"]["bot"];
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
123
libs/gateway/Websocket.hpp
Normal file
123
libs/gateway/Websocket.hpp
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#ifndef GATEWAY_WEBSOCKET_HPP_
|
||||||
|
#define GATEWAY_WEBSOCKET_HPP_
|
||||||
|
#include <includes.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
#include <ixwebsocket/IXNetSystem.h>
|
||||||
|
#include <ixwebsocket/IXWebSocket.h>
|
||||||
|
using std::string, std::cout, std::endl, nlohmann::json;
|
||||||
|
using namespace std::chrono;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
class WebSocket {
|
||||||
|
private:
|
||||||
|
bool isBot;
|
||||||
|
int intents;
|
||||||
|
std::string token;
|
||||||
|
ix::WebSocket webSocket;
|
||||||
|
json payload = { {"op", 1},{"d", nullptr} }, id;
|
||||||
|
std::unordered_map<std::string, std::function<void(const json&)>> eventHandlers;
|
||||||
|
WebSocket& operator=(const WebSocket&) = delete;
|
||||||
|
WebSocket(const WebSocket&) = delete;
|
||||||
|
WebSocket(const std::string& token, const int& intents, bool& isBot) {
|
||||||
|
WebSocket::token = token;
|
||||||
|
WebSocket::intents = intents;
|
||||||
|
WebSocket::isBot = isBot;
|
||||||
|
id = {
|
||||||
|
{"op", 2},
|
||||||
|
{"d", {
|
||||||
|
{"token", token},
|
||||||
|
{"intents", intents},
|
||||||
|
{"properties", {
|
||||||
|
{"os", "linux"},
|
||||||
|
{"browser", "firefox"},
|
||||||
|
{"device", "firefox"}
|
||||||
|
}},
|
||||||
|
//{"compress", 1},
|
||||||
|
{"presence", {
|
||||||
|
{"activities", json::array({
|
||||||
|
{
|
||||||
|
//{"name", "asdsadsadsadsa"},
|
||||||
|
//{"type", 2}
|
||||||
|
}
|
||||||
|
})},
|
||||||
|
{"status", "idle"},
|
||||||
|
{"since", 91879201},
|
||||||
|
{"afk", false}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
};
|
||||||
|
ix::initNetSystem();
|
||||||
|
webSocket.setUrl("wss://gateway.discord.gg/?v=10&encoding=json");
|
||||||
|
webSocket.setHandshakeTimeout(5);
|
||||||
|
Log::create(INFO, WEBSOCKET, "ixwebsocket init");
|
||||||
|
webSocket.setOnMessageCallback([this, res = json(), heartbeat_interval = 0, connected = false](const ix::WebSocketMessagePtr& msg) mutable {
|
||||||
|
if (msg->type == ix::WebSocketMessageType::Message) {
|
||||||
|
res = json::parse(msg->str);
|
||||||
|
Log::create(INFO, WEBSOCKET, res["op"].dump() + " " + res["t"].dump());
|
||||||
|
switch (res["op"].get<int>()) {
|
||||||
|
case 10:
|
||||||
|
heartbeat_interval = res["d"]["heartbeat_interval"].get<int>();
|
||||||
|
!connected ? connected = true, webSocket.send(id.dump()) : 0;
|
||||||
|
std::thread([this, &heartbeat_interval, &connected]() {
|
||||||
|
while (connected && heartbeat_interval != -1) {
|
||||||
|
Log::create(INFO, WEBSOCKET, "Heartbeat " + std::to_string(heartbeat_interval));
|
||||||
|
std::this_thread::sleep_for(milliseconds(heartbeat_interval));
|
||||||
|
webSocket.send(payload.dump());
|
||||||
|
}
|
||||||
|
}).detach();
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
if (eventHandlers.find(res["t"].get<std::string>()) != eventHandlers.end()) {
|
||||||
|
eventHandlers[res["t"].get<std::string>()](res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
webSocket.start();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
void sendPresenceUpdate(int statusType, const std::string& activityName) {
|
||||||
|
json prsUpdate = {
|
||||||
|
{"op", 3},
|
||||||
|
{"d", {
|
||||||
|
{"since", 0},
|
||||||
|
{"activities", json::array({{"name", activityName}, {"type", 2}})},
|
||||||
|
{"status", statusType == 1 ? "online" : "idle"},
|
||||||
|
{"afk", false}
|
||||||
|
}}
|
||||||
|
};
|
||||||
|
webSocket.send(prsUpdate.dump());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
static WebSocket& getInstance(const std::string& token = "", const int intents = 0, bool bot = true) {
|
||||||
|
Log::create(WARNING, WEBSOCKET, "Instance event");
|
||||||
|
static WebSocket instance(token, intents, bot);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
~WebSocket() {
|
||||||
|
webSocket.close();
|
||||||
|
ix::uninitNetSystem();
|
||||||
|
}
|
||||||
|
std::string getToken() const {
|
||||||
|
return isBot ? std::string("Bot " + WebSocket::token) : WebSocket::token;
|
||||||
|
}
|
||||||
|
int getIntents() const {
|
||||||
|
return WebSocket::intents;
|
||||||
|
}
|
||||||
|
void on(const string& event, std::function<void(const json&)> handler) {
|
||||||
|
eventHandlers[event] = [handler](const json& message) {
|
||||||
|
handler(message.get<json>());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
void once(const string& event, std::function<void(const json&)> handler) {
|
||||||
|
eventHandlers[event] = [event, handler, isCalled = false](const json& message) mutable {
|
||||||
|
isCalled == false ? isCalled = true : 0, handler(message.get<json>());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
void start() {
|
||||||
|
while (1) std::this_thread::sleep_for(1ms);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
@ -1,45 +0,0 @@
|
|||||||
#ifndef INTERFACE_AUTHOR_HPP_
|
|
||||||
#define INTERFACE_AUTHOR_HPP_
|
|
||||||
#include <pch.hpp>
|
|
||||||
#include <network.hpp>
|
|
||||||
class Author {
|
|
||||||
private:
|
|
||||||
const nlohmann::json& data;
|
|
||||||
WebSocket& web;
|
|
||||||
NetworkManager& req;
|
|
||||||
public:
|
|
||||||
_deprecated_t("requires update")
|
|
||||||
struct Channel {
|
|
||||||
std::string channel_id;
|
|
||||||
std::string global_name;
|
|
||||||
std::string id;
|
|
||||||
std::string content;
|
|
||||||
std::string avatar;
|
|
||||||
std::string guild_id;
|
|
||||||
std::string discriminator;
|
|
||||||
std::string message_id;
|
|
||||||
bool isPinned;
|
|
||||||
bool isBot;
|
|
||||||
} authorData;
|
|
||||||
const std::string channel_id, global_name, id, content, avatar, guild_id, discriminator, message_id;
|
|
||||||
bool isPinned, isBot;
|
|
||||||
Author(const nlohmann::json& data)
|
|
||||||
: data(data),
|
|
||||||
web(WebSocket::getInstance()),
|
|
||||||
req(NetworkManager::getInstance()),
|
|
||||||
channel_id(functions::testValue<std::string>(data, { "d", "channel_id" }).value_or("")),
|
|
||||||
global_name(functions::testValue<std::string>(data, { "d", "author", "global_name" }).value_or("")),
|
|
||||||
id(functions::testValue<std::string>(data, { "d", "author", "id" }).value_or("")),
|
|
||||||
content(functions::testValue<std::string>(data, { "d", "content" }).value_or("")),
|
|
||||||
avatar(functions::testValue<std::string>(data, { "d", "author", "avatar" }).value_or("")),
|
|
||||||
guild_id(functions::testValue<std::string>(data, { "d", "guild_id" }).value_or("")),
|
|
||||||
discriminator(functions::testValue<std::string>(data, { "d", "author", "discriminator" }).value_or("")),
|
|
||||||
message_id(functions::testValue<std::string>(data, { "d", "id" }).value_or("")),
|
|
||||||
isPinned(functions::testValue<bool>(data, { "d", "pinned" }).value_or(false)),
|
|
||||||
isBot(functions::testValue<bool>(data, { "d", "author", "bot" }).value_or(false)) {
|
|
||||||
}
|
|
||||||
auto send(const nlohmann::json& msg) -> std::string {
|
|
||||||
return req.request(HttpMethods::POST, DiscordEndpoints::details::latest + "/channels/" + data["d"]["channel_id"].get<std::string>() + "/messages", msg.dump());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1,36 +0,0 @@
|
|||||||
#ifndef INTERFACE_BOT_HPP_
|
|
||||||
#define INTERFACE_BOT_HPP_
|
|
||||||
#include <pch.hpp>
|
|
||||||
template<typename...Args>
|
|
||||||
class Discord {
|
|
||||||
private:
|
|
||||||
const nlohmann::json& data;
|
|
||||||
std::tuple<std::unique_ptr<Args>...> net;
|
|
||||||
public:
|
|
||||||
Discord(const nlohmann::json& data) : data(data), net(std::make_tuple(std::make_unique<Args>(data)...)) {}
|
|
||||||
template<class T>
|
|
||||||
_deprecated_t("Use ctx() instead")
|
|
||||||
auto& get() const {
|
|
||||||
return *std::get<std::unique_ptr<T>>(net);
|
|
||||||
}
|
|
||||||
const auto& ctx() const {
|
|
||||||
return net;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
class Bot {
|
|
||||||
private:
|
|
||||||
const nlohmann::json& data;
|
|
||||||
public:
|
|
||||||
Bot(const nlohmann::json& data) : data(data) {};
|
|
||||||
std::string id() const {
|
|
||||||
return data["d"]["id"];
|
|
||||||
}
|
|
||||||
bool isBot() const {
|
|
||||||
try {
|
|
||||||
return data["d"]["bot"];
|
|
||||||
} catch (...) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1,16 +0,0 @@
|
|||||||
#ifndef INTERFACE_CHANNEL_HPP_
|
|
||||||
#define INTERFACE_CHANNEL_HPP_
|
|
||||||
#include <pch.hpp>
|
|
||||||
#include <network.hpp>
|
|
||||||
class Channel {
|
|
||||||
private:
|
|
||||||
const nlohmann::json& data;
|
|
||||||
WebSocket& web;
|
|
||||||
NetworkManager& req;
|
|
||||||
public:
|
|
||||||
Channel(const nlohmann::json& data) : data(data), web(WebSocket::getInstance()), req(NetworkManager::getInstance()) {}
|
|
||||||
std::string send(const nlohmann::json& msg) {
|
|
||||||
return req.request(HttpMethods::POST, DiscordEndpoints::details::latest + "/channels/" + data["d"]["channel_id"].get<std::string>() + "/messages", msg.dump());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1,58 +0,0 @@
|
|||||||
#ifndef INTERFACE_EMBED_HPP_
|
|
||||||
#define INTERFACE_EMBED_HPP_
|
|
||||||
#include <pch.hpp>
|
|
||||||
class EmbedBuilder {
|
|
||||||
private:
|
|
||||||
nlohmann::json embed = {
|
|
||||||
{"content", ""},
|
|
||||||
{"tts", false},
|
|
||||||
{"embeds", nlohmann::json::array()}
|
|
||||||
}, data;
|
|
||||||
public:
|
|
||||||
EmbedBuilder(const nlohmann::json& data) : data(data) {
|
|
||||||
embed = {
|
|
||||||
{"content", ""},
|
|
||||||
{"tts", false},
|
|
||||||
{"embeds", nlohmann::json::array()}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
EmbedBuilder& addTitle(const std::string& title) {
|
|
||||||
if (embed["embeds"].size() == 0) {
|
|
||||||
embed["embeds"].emplace_back(nlohmann::json::object());
|
|
||||||
}
|
|
||||||
embed["embeds"].back()["title"] = title;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
EmbedBuilder& addDescription(const std::string& desc) {
|
|
||||||
if (embed["embeds"].size() == 0) {
|
|
||||||
embed["embeds"].emplace_back(nlohmann::json::object());
|
|
||||||
}
|
|
||||||
embed["embeds"].back()["description"] = desc;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
EmbedBuilder& addColor(const std::string& color) {
|
|
||||||
if (embed["embeds"].size() == 0) {
|
|
||||||
embed["embeds"].emplace_back(nlohmann::json::object());
|
|
||||||
}
|
|
||||||
embed["embeds"].back()["color"] = color;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
EmbedBuilder& addUrl(const std::string& url) {
|
|
||||||
if (embed["embeds"].size() == 0) {
|
|
||||||
embed["embeds"].emplace_back(nlohmann::json::object());
|
|
||||||
}
|
|
||||||
embed["embeds"].back()["url"] = url;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
EmbedBuilder& addImage(const std::string& imageurl) {
|
|
||||||
if (embed["embeds"].size() == 0) {
|
|
||||||
embed["embeds"].emplace_back(nlohmann::json::object());
|
|
||||||
}
|
|
||||||
embed["embeds"].back()["image"] = { {"url", imageurl} };
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
nlohmann::json getEmbed() const {
|
|
||||||
return embed;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1,14 +0,0 @@
|
|||||||
#ifndef INTERFACE_GUILD_HPP_
|
|
||||||
#define INTERFACE_GUILD_HPP_
|
|
||||||
#include <pch.hpp>
|
|
||||||
#include <network.hpp>
|
|
||||||
class Guild {
|
|
||||||
private:
|
|
||||||
nlohmann::json data;
|
|
||||||
public:
|
|
||||||
Guild(const nlohmann::json& data) : data(data) {}
|
|
||||||
std::string id() const {
|
|
||||||
return data["d"]["user"]["id"];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1,38 +0,0 @@
|
|||||||
#ifndef INTERFACE_MESSAGE_HPP_
|
|
||||||
#define INTERFACE_MESSAGE_HPP_
|
|
||||||
#include <pch.hpp>
|
|
||||||
#include <network.hpp>
|
|
||||||
class Message {
|
|
||||||
private:
|
|
||||||
const nlohmann::json& data;
|
|
||||||
WebSocket& web;
|
|
||||||
NetworkManager& req;
|
|
||||||
public:
|
|
||||||
Message(const nlohmann::json& json) : data(json), web(WebSocket::getInstance()), req(NetworkManager::getInstance()) {};
|
|
||||||
auto send(const std::string& id, const nlohmann::json& msg) -> std::string {
|
|
||||||
return req.request(HttpMethods::POST, DiscordEndpoints::details::latest + "/channels/" + id + "/messages", msg.dump());
|
|
||||||
}
|
|
||||||
auto getMessages(const std::string& id, const std::string& count, const std::string& before = "") -> std::string {
|
|
||||||
if (before.empty()) {
|
|
||||||
return req.request(HttpMethods::GET, DiscordEndpoints::details::latest + "/channels/" + id + "/messages?limit=" + count);
|
|
||||||
} else {
|
|
||||||
return req.request(HttpMethods::GET, DiscordEndpoints::details::latest + "/channels/" + id + "/messages?before=" + before + "&limit=" + count);
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
auto deleteMessage(const std::string& channel_id, const std::string& message_id) -> std::string {
|
|
||||||
return req.request(HttpMethods::DELETE, DiscordEndpoints::details::latest + "/channels/" + channel_id + "/messages/" + message_id);
|
|
||||||
}
|
|
||||||
_nodiscard auto pack(const nlohmann::json& key, const std::string& value) const -> nlohmann::json {
|
|
||||||
return { { key, value } };
|
|
||||||
}
|
|
||||||
struct Api {
|
|
||||||
const nlohmann::json& data;
|
|
||||||
NetworkManager& req;
|
|
||||||
Api(const nlohmann::json& json) : data(json), req(NetworkManager::getInstance()) {};
|
|
||||||
_nodiscard auto latency() const -> unsigned long {
|
|
||||||
return req.getLatency();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1,37 +0,0 @@
|
|||||||
#ifndef INTERFACE_USER_HPP_
|
|
||||||
#define INTERFACE_USER_HPP_
|
|
||||||
#include <pch.hpp>
|
|
||||||
#include <network.hpp>
|
|
||||||
#include <vector>
|
|
||||||
class User {
|
|
||||||
private:
|
|
||||||
const nlohmann::json& data;
|
|
||||||
WebSocket& web;
|
|
||||||
NetworkManager& req;
|
|
||||||
public:
|
|
||||||
User(const nlohmann::json& data) : data(data), web(WebSocket::getInstance()), req(NetworkManager::getInstance()),
|
|
||||||
isBot(false) {
|
|
||||||
auto botValue = functions::testValue<bool>(data, { "d", "user", "bot" });
|
|
||||||
if (botValue.has_value()) {
|
|
||||||
isBot = botValue.value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool isBot;
|
|
||||||
auto extract(const std::vector<std::string>& keys) -> nlohmann::json {
|
|
||||||
std::vector<std::string> d = { "d" };
|
|
||||||
d.insert(d.end(), keys.begin(), keys.end());
|
|
||||||
nlohmann::json current = data;
|
|
||||||
for (const auto& key : d) {
|
|
||||||
if (current.contains(key)) {
|
|
||||||
current = current[key];
|
|
||||||
} else {
|
|
||||||
return "Key not found.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
};
|
|
||||||
auto me() -> std::string {
|
|
||||||
return req.request(HttpMethods::GET, DiscordEndpoints::details::latest + "/users/@me");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1,50 +0,0 @@
|
|||||||
#include "network.hpp"
|
|
||||||
NetworkManager::NetworkManager() : curl(curl_easy_init(), curl_easy_cleanup), res(CURLE_OK), web(WebSocket::getInstance()) {
|
|
||||||
Log::create(INFO, NETWORK, "Network init");
|
|
||||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
|
||||||
if (!curl) {
|
|
||||||
Log::create(CRITICAL, NETWORK, "Failed to initialize CURL");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NetworkManager::~NetworkManager() {
|
|
||||||
curl_global_cleanup();
|
|
||||||
}
|
|
||||||
auto NetworkManager::WriteCallback(void* contents, unsigned long size, unsigned long nmemb, void* userp) -> unsigned long {
|
|
||||||
(static_cast<std::string*>(userp))->append(static_cast<char*>(contents), size * nmemb);
|
|
||||||
return size * nmemb;
|
|
||||||
}
|
|
||||||
auto NetworkManager::getInstance() -> NetworkManager& {
|
|
||||||
Log::create(INFO, NETWORK, "Instance event");
|
|
||||||
static NetworkManager instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
auto NetworkManager::getLatency() const -> unsigned long {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
auto NetworkManager::request(const std::string& method, const std::string& path, const std::string& data) -> std::string {
|
|
||||||
std::string response;
|
|
||||||
if (curl) {
|
|
||||||
curl_easy_setopt(curl.get(), CURLOPT_URL, path.c_str());
|
|
||||||
curl_easy_setopt(curl.get(), CURLOPT_CUSTOMREQUEST, method.c_str());
|
|
||||||
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, data.c_str());
|
|
||||||
curl_slist* headers = nullptr;
|
|
||||||
headers = curl_slist_append(headers, "Accept: application/json");
|
|
||||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
|
||||||
headers = curl_slist_append(headers, ("Authorization: " + web.getToken()).c_str());
|
|
||||||
headers = curl_slist_append(headers, "User-Agent: DiscordBot");
|
|
||||||
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, headers);
|
|
||||||
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, WriteCallback);
|
|
||||||
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &response);
|
|
||||||
curl_easy_setopt(curl.get(), CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3ONLY);
|
|
||||||
res = curl_easy_perform(curl.get());
|
|
||||||
if (res != 0) {
|
|
||||||
Log::create(ERROR, NETWORK, "curl_easy_perform() failed: " + std::string(curl_easy_strerror(res)));
|
|
||||||
}
|
|
||||||
curl_slist_free_all(headers);
|
|
||||||
}
|
|
||||||
#ifdef DEBUG
|
|
||||||
Log::create(INFO, NETWORK, response);
|
|
||||||
#endif
|
|
||||||
return response;
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
#ifndef TLS_NETWORK_HPP_
|
|
||||||
#define TLS_NETWORK_HPP_
|
|
||||||
#include <pch.hpp>
|
|
||||||
#include <network/websocket.hpp>
|
|
||||||
#include <curl/curl.h>
|
|
||||||
class NetworkManager {
|
|
||||||
private:
|
|
||||||
std::unique_ptr<void, decltype(&curl_easy_cleanup)> curl;
|
|
||||||
CURLcode res;
|
|
||||||
WebSocket& web;
|
|
||||||
NetworkManager();
|
|
||||||
~NetworkManager();
|
|
||||||
static auto WriteCallback(void* contents, unsigned long size, unsigned long nmemb, void* userp) -> unsigned long;
|
|
||||||
public:
|
|
||||||
auto operator=(const NetworkManager&)->NetworkManager& = delete;
|
|
||||||
auto operator=(NetworkManager&&)->NetworkManager& = delete;
|
|
||||||
NetworkManager(NetworkManager&&) = delete;
|
|
||||||
NetworkManager(const NetworkManager&) = delete;
|
|
||||||
static auto getInstance() -> NetworkManager&;
|
|
||||||
[[nodiscard]] auto getLatency() const -> unsigned long;
|
|
||||||
auto request(const std::string& method, const std::string& path, const std::string& data = "") -> std::string;
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1,127 +0,0 @@
|
|||||||
#include "websocket.hpp"
|
|
||||||
void EventEmitter::emit(const std::string& event, const nlohmann::json& data) {
|
|
||||||
if (auto it = handlers.find(event); it != handlers.end()) {
|
|
||||||
std::for_each(it->second.begin(), it->second.end(), [&data](const auto& handler) {
|
|
||||||
handler(data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void EventEmitter::getEvents() const {
|
|
||||||
Log::create(CRITICAL, WEBSOCKET, "Event list");
|
|
||||||
for (const auto& handler : handlers) {
|
|
||||||
Log::create(INFO, WEBSOCKET, handler.first);
|
|
||||||
}
|
|
||||||
Log::create(CRITICAL, WEBSOCKET, "End of list");
|
|
||||||
}
|
|
||||||
void EventEmitter::start() const {
|
|
||||||
while (true) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
||||||
}
|
|
||||||
void EventEmitter::on(const std::string& event, eventHandlers handler) {
|
|
||||||
handlers[event].emplace_back(std::move(handler));
|
|
||||||
}
|
|
||||||
void EventEmitter::once(const std::string& event, const eventHandlers& handler) {
|
|
||||||
auto wrappedHandler = [this, event, handler](const nlohmann::json& data) {
|
|
||||||
handler(data);
|
|
||||||
off(event, handler);
|
|
||||||
};
|
|
||||||
handlers[event].emplace_back(std::move(wrappedHandler));
|
|
||||||
}
|
|
||||||
void EventEmitter::off(const std::string& event, eventHandlers handler) {
|
|
||||||
if (auto it = handlers.find(event); it != handlers.cend()) {
|
|
||||||
it->second.erase(std::ranges::remove_if(it->second, [&handler](const eventHandlers& h) {
|
|
||||||
return h.target<eventHandlers>() == handler.target<eventHandlers>();
|
|
||||||
}).begin(), it->second.cend());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WebSocket::WebSocket(const std::string& token, int intents, bool isBot) : token(token), intents(intents), isBot(isBot) {
|
|
||||||
nlohmann::json id = {
|
|
||||||
{"op", GatewayOpcodes::Identify},
|
|
||||||
{"d", {
|
|
||||||
{"token", token},
|
|
||||||
{"intents", intents},
|
|
||||||
{"properties", {
|
|
||||||
{"os", "linux"},
|
|
||||||
{"browser", "firefox"},
|
|
||||||
{"device", "firefox"}
|
|
||||||
}},
|
|
||||||
{"compress", 1},
|
|
||||||
{"presence", {
|
|
||||||
{"activities", nlohmann::json::array({
|
|
||||||
{
|
|
||||||
{"name", "meow"},
|
|
||||||
{"type", 2}
|
|
||||||
}
|
|
||||||
})},
|
|
||||||
{"status", "idle"},
|
|
||||||
{"since", 0},
|
|
||||||
{"afk", false}
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
};
|
|
||||||
ix::initNetSystem();
|
|
||||||
webSocket.setUrl("wss://gateway.discord.gg/?v=10&encoding=json");
|
|
||||||
webSocket.disableAutomaticReconnection();
|
|
||||||
Log::create(INFO, WEBSOCKET, "ixwebsocket init");
|
|
||||||
webSocket.setOnMessageCallback([this, res = nlohmann::json(), heartbeat_interval = 0, connected = false, id](const ix::WebSocketMessagePtr& msg) mutable {
|
|
||||||
switch (msg->type) {
|
|
||||||
case ix::WebSocketMessageType::Message:
|
|
||||||
res = nlohmann::json::parse(msg->str);
|
|
||||||
Log::create(INFO, WEBSOCKET, std::to_string(res["op"].get<int>()) + " " + res["t"].dump());
|
|
||||||
switch (res["op"].get<GatewayOpcodes>()) {
|
|
||||||
case GatewayOpcodes::Hello:
|
|
||||||
heartbeat_interval = res["d"]["heartbeat_interval"].get<int>();
|
|
||||||
if (connected) connected = true; else webSocket.send(id.dump());
|
|
||||||
std::thread([this, &heartbeat_interval, &connected]() {
|
|
||||||
while (connected && heartbeat_interval != -1) {
|
|
||||||
Log::create(INFO, WEBSOCKET, "Heartbeat " + std::to_string(heartbeat_interval));
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(heartbeat_interval));
|
|
||||||
webSocket.send(payload.dump());
|
|
||||||
}
|
|
||||||
}).detach();
|
|
||||||
break;
|
|
||||||
case GatewayOpcodes::Dispatch:
|
|
||||||
Log::create(INFO, WEBSOCKET, res.dump());
|
|
||||||
emit(res["t"].get<std::string>(), res);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ix::WebSocketMessageType::Error:
|
|
||||||
Log::force_create(ERROR, WEBSOCKET, msg->errorInfo.reason);
|
|
||||||
exit(-1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
webSocket.start();
|
|
||||||
}
|
|
||||||
auto WebSocket::getInstance(const std::string& token, int intents, bool bot) -> WebSocket& {
|
|
||||||
Log::create(INFO, WEBSOCKET, "Instance event");
|
|
||||||
static WebSocket instance(token, intents, bot);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
WebSocket::~WebSocket() {
|
|
||||||
webSocket.close();
|
|
||||||
ix::uninitNetSystem();
|
|
||||||
}
|
|
||||||
auto WebSocket::getToken() const -> std::string {
|
|
||||||
return this->isBot ? std::string("Bot " + this->token) : this->token;
|
|
||||||
}
|
|
||||||
auto WebSocket::getIntents() const -> int {
|
|
||||||
return this->intents;
|
|
||||||
}
|
|
||||||
_maybe_unused void WebSocket::sendPresenceUpdate(const char* statusType, const std::string& activityName, const int& activityType) {
|
|
||||||
nlohmann::json prsUpdate = {
|
|
||||||
{"op", 3},
|
|
||||||
{"d", {
|
|
||||||
{"since", 0},
|
|
||||||
{"activities", nlohmann::json::array({{"name", activityName}, {"type", activityType}})},
|
|
||||||
{"status", statusType},
|
|
||||||
{"afk", false}
|
|
||||||
}}
|
|
||||||
};
|
|
||||||
webSocket.send(prsUpdate.dump());
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
#ifndef NETWORK_WEBSOCKET_HPP_
|
|
||||||
#define NETWORK_WEBSOCKET_HPP_
|
|
||||||
#include <pch.hpp>
|
|
||||||
#include <ranges>
|
|
||||||
#include <ixwebsocket/IXNetSystem.h>
|
|
||||||
#include <ixwebsocket/IXWebSocket.h>
|
|
||||||
class EventEmitter {
|
|
||||||
private:
|
|
||||||
using eventHandlers = std::function<void(const nlohmann::json&)>;
|
|
||||||
std::unordered_map<std::string, std::vector<eventHandlers>> handlers;
|
|
||||||
protected:
|
|
||||||
void emit(const std::string& event, const nlohmann::json& data);
|
|
||||||
public:
|
|
||||||
void getEvents() const;
|
|
||||||
void start() const;
|
|
||||||
void on(const std::string& event, eventHandlers handler);
|
|
||||||
void once(const std::string& event, const eventHandlers& handler);
|
|
||||||
void off(const std::string& event, eventHandlers handler);
|
|
||||||
};
|
|
||||||
class WebSocket : public EventEmitter {
|
|
||||||
private:
|
|
||||||
std::string token;
|
|
||||||
int intents;
|
|
||||||
bool isBot;
|
|
||||||
ix::WebSocket webSocket;
|
|
||||||
const nlohmann::json payload = { {"op", GatewayOpcodes::Heartbeat}, {"d", nullptr} };
|
|
||||||
WebSocket(const std::string& token, int intents, bool isBot);
|
|
||||||
public:
|
|
||||||
auto operator=(const WebSocket&)->WebSocket& = delete;
|
|
||||||
auto operator=(WebSocket&&)->WebSocket& = delete;
|
|
||||||
WebSocket(WebSocket&&) = delete;
|
|
||||||
WebSocket(const WebSocket&) = delete;
|
|
||||||
_maybe_unused void sendPresenceUpdate(const char* statusType, const std::string& activityName, const int& activityType);
|
|
||||||
static auto getInstance(const std::string& token = "", int intents = 0, bool bot = true) -> WebSocket&;
|
|
||||||
~WebSocket();
|
|
||||||
auto getToken() const->std::string;
|
|
||||||
auto getIntents() const -> int;
|
|
||||||
};
|
|
||||||
#endif
|
|
59
libs/tls/Network.hpp
Normal file
59
libs/tls/Network.hpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#ifndef TLS_NETWORK_HPP_
|
||||||
|
#define TLS_NETWORK_HPP_
|
||||||
|
#include <includes.h>
|
||||||
|
#include <gateway/Websocket.hpp>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
using std::string, std::cout, std::endl, nlohmann::json;
|
||||||
|
class NetworkManager {
|
||||||
|
private:
|
||||||
|
CURL* curl;
|
||||||
|
CURLcode res;
|
||||||
|
WebSocket& web;
|
||||||
|
NetworkManager& operator=(const NetworkManager&) = delete;
|
||||||
|
NetworkManager(const NetworkManager&) = delete;
|
||||||
|
NetworkManager() : web(WebSocket::getInstance()) {
|
||||||
|
Log::create(INFO, NETWORK, "Network init");
|
||||||
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
|
curl = curl_easy_init();
|
||||||
|
if (!curl) {
|
||||||
|
Log::create(ERROR, NETWORK, "Failed to initialize CURL");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~NetworkManager() {
|
||||||
|
if (curl) {
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
curl_global_cleanup();
|
||||||
|
}
|
||||||
|
static unsigned long WriteCallback(void* contents, unsigned long size, unsigned long nmemb, void* userp) {
|
||||||
|
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||||
|
return size * nmemb;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
static NetworkManager& getInstance() {
|
||||||
|
Log::create(WARNING, NETWORK, "Instance event");
|
||||||
|
static NetworkManager instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
std::string request(const std::string& method, const std::string& path, const std::string& data = "") {
|
||||||
|
std::string response;
|
||||||
|
if (curl) {
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, path.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
|
||||||
|
curl_slist* headers = curl_slist_append(headers, "Accept: application/json");
|
||||||
|
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||||
|
headers = curl_slist_append(headers, ("Authorization: " + web.getToken()).c_str());
|
||||||
|
headers = curl_slist_append(headers, "User-Agent: DiscordBot");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3ONLY);
|
||||||
|
if ((res = curl_easy_perform(curl)) != 0) Log::create(ERROR, NETWORK, "curl_easy_perform() failed: " + std::string(curl_easy_strerror(res)));
|
||||||
|
curl_slist_free_all(headers);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
@ -1,124 +1,108 @@
|
|||||||
#ifndef UTILS_EVENTS_HPP_
|
#ifndef UTILS_EVENTS_HPP_
|
||||||
#define UTILS_EVENTS_HPP_
|
#define UTILS_EVENTS_HPP_
|
||||||
#include <string>
|
|
||||||
struct GatewayEvents {
|
struct GatewayEvents {
|
||||||
static inline constexpr char* APPLICATION_COMMAND_PERMISSIONS_UPDATE = "APPLICATION_COMMAND_PERMISSIONS_UPDATE";
|
static constexpr const char* APPLICATION_COMMAND_PERMISSIONS_UPDATE = "APPLICATION_COMMAND_PERMISSIONS_UPDATE";
|
||||||
static inline constexpr char* AUTO_MODERATION_ACTION_EXECUTION = "AUTO_MODERATION_ACTION_EXECUTION";
|
static constexpr const char* AUTO_MODERATION_ACTION_EXECUTION = "AUTO_MODERATION_ACTION_EXECUTION";
|
||||||
static inline constexpr char* AUTO_MODERATION_RULE_CREATE = "AUTO_MODERATION_RULE_CREATE";
|
static constexpr const char* AUTO_MODERATION_RULE_CREATE = "AUTO_MODERATION_RULE_CREATE";
|
||||||
static inline constexpr char* AUTO_MODERATION_RULE_DELETE = "AUTO_MODERATION_RULE_DELETE";
|
static constexpr const char* AUTO_MODERATION_RULE_DELETE = "AUTO_MODERATION_RULE_DELETE";
|
||||||
static inline constexpr char* AUTO_MODERATION_RULE_UPDATE = "AUTO_MODERATION_RULE_UPDATE";
|
static constexpr const char* AUTO_MODERATION_RULE_UPDATE = "AUTO_MODERATION_RULE_UPDATE";
|
||||||
static inline constexpr char* CHANNEL_CREATE = "CHANNEL_CREATE";
|
static constexpr const char* CHANNEL_CREATE = "CHANNEL_CREATE";
|
||||||
static inline constexpr char* CHANNEL_DELETE = "CHANNEL_DELETE";
|
static constexpr const char* CHANNEL_DELETE = "CHANNEL_DELETE";
|
||||||
static inline constexpr char* CHANNEL_PINS_UPDATE = "CHANNEL_PINS_UPDATE";
|
static constexpr const char* CHANNEL_PINS_UPDATE = "CHANNEL_PINS_UPDATE";
|
||||||
static inline constexpr char* CHANNEL_UPDATE = "CHANNEL_UPDATE";
|
static constexpr const char* CHANNEL_UPDATE = "CHANNEL_UPDATE";
|
||||||
static inline constexpr char* ENTITLEMENT_CREATE = "ENTITLEMENT_CREATE";
|
static constexpr const char* ENTITLEMENT_CREATE = "ENTITLEMENT_CREATE";
|
||||||
static inline constexpr char* ENTITLEMENT_DELETE = "ENTITLEMENT_DELETE";
|
static constexpr const char* ENTITLEMENT_DELETE = "ENTITLEMENT_DELETE";
|
||||||
static inline constexpr char* ENTITLEMENT_UPDATE = "ENTITLEMENT_UPDATE";
|
static constexpr const char* ENTITLEMENT_UPDATE = "ENTITLEMENT_UPDATE";
|
||||||
static inline constexpr char* GUILD_AUDIT_LOG_ENTRY_CREATE = "GUILD_AUDIT_LOG_ENTRY_CREATE";
|
static constexpr const char* GUILD_AUDIT_LOG_ENTRY_CREATE = "GUILD_AUDIT_LOG_ENTRY_CREATE";
|
||||||
static inline constexpr char* GUILD_BAN_ADD = "GUILD_BAN_ADD";
|
static constexpr const char* GUILD_BAN_ADD = "GUILD_BAN_ADD";
|
||||||
static inline constexpr char* GUILD_BAN_REMOVE = "GUILD_BAN_REMOVE";
|
static constexpr const char* GUILD_BAN_REMOVE = "GUILD_BAN_REMOVE";
|
||||||
static inline constexpr char* GUILD_CREATE = "GUILD_CREATE";
|
static constexpr const char* GUILD_CREATE = "GUILD_CREATE";
|
||||||
static inline constexpr char* GUILD_DELETE = "GUILD_DELETE";
|
static constexpr const char* GUILD_DELETE = "GUILD_DELETE";
|
||||||
static inline constexpr char* GUILD_EMOJIS_UPDATE = "GUILD_EMOJIS_UPDATE";
|
static constexpr const char* GUILD_EMOJIS_UPDATE = "GUILD_EMOJIS_UPDATE";
|
||||||
static inline constexpr char* GUILD_INTEGRATIONS_UPDATE = "GUILD_INTEGRATIONS_UPDATE";
|
static constexpr const char* GUILD_INTEGRATIONS_UPDATE = "GUILD_INTEGRATIONS_UPDATE";
|
||||||
static inline constexpr char* GUILD_MEMBER_ADD = "GUILD_MEMBER_ADD";
|
static constexpr const char* GUILD_MEMBER_ADD = "GUILD_MEMBER_ADD";
|
||||||
static inline constexpr char* GUILD_MEMBER_REMOVE = "GUILD_MEMBER_REMOVE";
|
static constexpr const char* GUILD_MEMBER_REMOVE = "GUILD_MEMBER_REMOVE";
|
||||||
static inline constexpr char* GUILD_MEMBERS_CHUNK = "GUILD_MEMBERS_CHUNK";
|
static constexpr const char* GUILD_MEMBERS_CHUNK = "GUILD_MEMBERS_CHUNK";
|
||||||
static inline constexpr char* GUILD_MEMBER_UPDATE = "GUILD_MEMBER_UPDATE";
|
static constexpr const char* GUILD_MEMBER_UPDATE = "GUILD_MEMBER_UPDATE";
|
||||||
static inline constexpr char* GUILD_ROLE_CREATE = "GUILD_ROLE_CREATE";
|
static constexpr const char* GUILD_ROLE_CREATE = "GUILD_ROLE_CREATE";
|
||||||
static inline constexpr char* GUILD_ROLE_DELETE = "GUILD_ROLE_DELETE";
|
static constexpr const char* GUILD_ROLE_DELETE = "GUILD_ROLE_DELETE";
|
||||||
static inline constexpr char* GUILD_ROLE_UPDATE = "GUILD_ROLE_UPDATE";
|
static constexpr const char* GUILD_ROLE_UPDATE = "GUILD_ROLE_UPDATE";
|
||||||
static inline constexpr char* GUILD_SCHEDULED_EVENT_CREATE = "GUILD_SCHEDULED_EVENT_CREATE";
|
static constexpr const char* GUILD_SCHEDULED_EVENT_CREATE = "GUILD_SCHEDULED_EVENT_CREATE";
|
||||||
static inline constexpr char* GUILD_SCHEDULED_EVENT_DELETE = "GUILD_SCHEDULED_EVENT_DELETE";
|
static constexpr const char* GUILD_SCHEDULED_EVENT_DELETE = "GUILD_SCHEDULED_EVENT_DELETE";
|
||||||
static inline constexpr char* GUILD_SCHEDULED_EVENT_UPDATE = "GUILD_SCHEDULED_EVENT_UPDATE";
|
static constexpr const char* GUILD_SCHEDULED_EVENT_UPDATE = "GUILD_SCHEDULED_EVENT_UPDATE";
|
||||||
static inline constexpr char* GUILD_SCHEDULED_EVENT_USER_REMOVE = "GUILD_SCHEDULED_EVENT_USER_REMOVE";
|
static constexpr const char* GUILD_SCHEDULED_EVENT_USER_REMOVE = "GUILD_SCHEDULED_EVENT_USER_REMOVE";
|
||||||
static inline constexpr char* GUILD_SOUNDBOARD_SOUND_CREATE = "GUILD_SOUNDBOARD_SOUND_CREATE";
|
static constexpr const char* GUILD_SOUNDBOARD_SOUND_CREATE = "GUILD_SOUNDBOARD_SOUND_CREATE";
|
||||||
static inline constexpr char* GUILD_SOUNDBOARD_SOUND_DELETE = "GUILD_SOUNDBOARD_SOUND_DELETE";
|
static constexpr const char* GUILD_SOUNDBOARD_SOUND_DELETE = "GUILD_SOUNDBOARD_SOUND_DELETE";
|
||||||
static inline constexpr char* GUILD_SOUNDBOARD_SOUNDS_UPDATE = "GUILD_SOUNDBOARD_SOUNDS_UPDATE";
|
static constexpr const char* GUILD_SOUNDBOARD_SOUNDS_UPDATE = "GUILD_SOUNDBOARD_SOUNDS_UPDATE";
|
||||||
static inline constexpr char* GUILD_SOUNDBOARD_SOUND_UPDATE = "GUILD_SOUNDBOARD_SOUND_UPDATE";
|
static constexpr const char* GUILD_SOUNDBOARD_SOUND_UPDATE = "GUILD_SOUNDBOARD_SOUND_UPDATE";
|
||||||
static inline constexpr char* SOUNDBOARD_SOUNDS = "SOUNDBOARD_SOUNDS";
|
static constexpr const char* SOUNDBOARD_SOUNDS = "SOUNDBOARD_SOUNDS";
|
||||||
static inline constexpr char* GUILD_STICKERS_UPDATE = "GUILD_STICKERS_UPDATE";
|
static constexpr const char* GUILD_STICKERS_UPDATE = "GUILD_STICKERS_UPDATE";
|
||||||
static inline constexpr char* GUILD_UPDATE = "GUILD_UPDATE";
|
static constexpr const char* GUILD_UPDATE = "GUILD_UPDATE";
|
||||||
static inline constexpr char* INTEGRATION_CREATE = "INTEGRATION_CREATE";
|
static constexpr const char* INTEGRATION_CREATE = "INTEGRATION_CREATE";
|
||||||
static inline constexpr char* INTEGRATION_DELETE = "INTEGRATION_DELETE";
|
static constexpr const char* INTEGRATION_DELETE = "INTEGRATION_DELETE";
|
||||||
static inline constexpr char* INTEGRATION_UPDATE = "INTEGRATION_UPDATE";
|
static constexpr const char* INTEGRATION_UPDATE = "INTEGRATION_UPDATE";
|
||||||
static inline constexpr char* INVITE_CREATE = "INVITE_CREATE";
|
static constexpr const char* INVITE_CREATE = "INVITE_CREATE";
|
||||||
static inline constexpr char* INVITE_DELETE = "INVITE_DELETE";
|
static constexpr const char* INVITE_DELETE = "INVITE_DELETE";
|
||||||
static inline constexpr char* MESSAGE_CREATE = "MESSAGE_CREATE";
|
static constexpr const char* MESSAGE_CREATE = "MESSAGE_CREATE";
|
||||||
static inline constexpr char* MESSAGE_DELETE = "MESSAGE_DELETE";
|
static constexpr const char* MESSAGE_DELETE = "MESSAGE_DELETE";
|
||||||
static inline constexpr char* MESSAGE_DELETE_BULK = "MESSAGE_DELETE_BULK";
|
static constexpr const char* MESSAGE_DELETE_BULK = "MESSAGE_DELETE_BULK";
|
||||||
static inline constexpr char* MESSAGE_POLL_VOTE_ADD = "MESSAGE_POLL_VOTE_ADD";
|
static constexpr const char* MESSAGE_POLL_VOTE_ADD = "MESSAGE_POLL_VOTE_ADD";
|
||||||
static inline constexpr char* MESSAGE_POLL_VOTE_REMOVE = "MESSAGE_POLL_VOTE_REMOVE";
|
static constexpr const char* MESSAGE_POLL_VOTE_REMOVE = "MESSAGE_POLL_VOTE_REMOVE";
|
||||||
static inline constexpr char* MESSAGE_REACTION_ADD = "MESSAGE_REACTION_ADD";
|
static constexpr const char* MESSAGE_REACTION_ADD = "MESSAGE_REACTION_ADD";
|
||||||
static inline constexpr char* MESSAGE_REACTION_REMOVE = "MESSAGE_REACTION_REMOVE";
|
static constexpr const char* MESSAGE_REACTION_REMOVE = "MESSAGE_REACTION_REMOVE";
|
||||||
static inline constexpr char* MESSAGE_REACTION_REMOVE_ALL = "MESSAGE_REACTION_REMOVE_ALL";
|
static constexpr const char* MESSAGE_REACTION_REMOVE_ALL = "MESSAGE_REACTION_REMOVE_ALL";
|
||||||
static inline constexpr char* MESSAGE_REACTION_REMOVE_EMOJI = "MESSAGE_REACTION_REMOVE_EMOJI";
|
static constexpr const char* MESSAGE_REACTION_REMOVE_EMOJI = "MESSAGE_REACTION_REMOVE_EMOJI";
|
||||||
static inline constexpr char* MESSAGE_UPDATE = "MESSAGE_UPDATE";
|
static constexpr const char* MESSAGE_UPDATE = "MESSAGE_UPDATE";
|
||||||
static inline constexpr char* PRESENCE_UPDATE = "PRESENCE_UPDATE";
|
static constexpr const char* PRESENCE_UPDATE = "PRESENCE_UPDATE";
|
||||||
static inline constexpr char* READY = "READY";
|
static constexpr const char* READY = "READY";
|
||||||
static inline constexpr char* RESUMED = "RESUMED";
|
static constexpr const char* RESUMED = "RESUMED";
|
||||||
static inline constexpr char* STAGE_INSTANCE_CREATE = "STAGE_INSTANCE_CREATE";
|
static constexpr const char* STAGE_INSTANCE_CREATE = "STAGE_INSTANCE_CREATE";
|
||||||
static inline constexpr char* STAGE_INSTANCE_DELETE = "STAGE_INSTANCE_DELETE";
|
static constexpr const char* STAGE_INSTANCE_DELETE = "STAGE_INSTANCE_DELETE";
|
||||||
static inline constexpr char* STAGE_INSTANCE_UPDATE = "STAGE_INSTANCE_UPDATE";
|
static constexpr const char* STAGE_INSTANCE_UPDATE = "STAGE_INSTANCE_UPDATE";
|
||||||
static inline constexpr char* SUBSCRIPTION_CREATE = "SUBSCRIPTION_CREATE";
|
static constexpr const char* SUBSCRIPTION_CREATE = "SUBSCRIPTION_CREATE";
|
||||||
static inline constexpr char* SUBSCRIPTION_DELETE = "SUBSCRIPTION_DELETE";
|
static constexpr const char* SUBSCRIPTION_DELETE = "SUBSCRIPTION_DELETE";
|
||||||
static inline constexpr char* SUBSCRIPTION_UPDATE = "SUBSCRIPTION_UPDATE";
|
static constexpr const char* SUBSCRIPTION_UPDATE = "SUBSCRIPTION_UPDATE";
|
||||||
static inline constexpr char* THREAD_CREATE = "THREAD_CREATE";
|
static constexpr const char* THREAD_CREATE = "THREAD_CREATE";
|
||||||
static inline constexpr char* THREAD_DELETE = "THREAD_DELETE";
|
static constexpr const char* THREAD_DELETE = "THREAD_DELETE";
|
||||||
static inline constexpr char* THREAD_LIST_SYNC = "THREAD_LIST_SYNC";
|
static constexpr const char* THREAD_LIST_SYNC = "THREAD_LIST_SYNC";
|
||||||
static inline constexpr char* THREAD_MEMBERS_UPDATE = "THREAD_MEMBERS_UPDATE";
|
static constexpr const char* THREAD_MEMBERS_UPDATE = "THREAD_MEMBERS_UPDATE";
|
||||||
static inline constexpr char* THREAD_MEMBER_UPDATE = "THREAD_MEMBER_UPDATE";
|
static constexpr const char* THREAD_MEMBER_UPDATE = "THREAD_MEMBER_UPDATE";
|
||||||
static inline constexpr char* THREAD_UPDATE = "THREAD_UPDATE";
|
static constexpr const char* THREAD_UPDATE = "THREAD_UPDATE";
|
||||||
static inline constexpr char* TYPING_START = "TYPING_START";
|
static constexpr const char* TYPING_START = "TYPING_START";
|
||||||
static inline constexpr char* USER_UPDATE = "USER_UPDATE";
|
static constexpr const char* USER_UPDATE = "USER_UPDATE";
|
||||||
static inline constexpr char* VOICE_CHANNEL_EFFECT_SEND = "VOICE_CHANNEL_EFFECT_SEND";
|
static constexpr const char* VOICE_CHANNEL_EFFECT_SEND = "VOICE_CHANNEL_EFFECT_SEND";
|
||||||
static inline constexpr char* VOICE_SERVER_UPDATE = "VOICE_SERVER_UPDATE";
|
static constexpr const char* VOICE_SERVER_UPDATE = "VOICE_SERVER_UPDATE";
|
||||||
static inline constexpr char* VOICE_STATE_UPDATE = "VOICE_STATE_UPDATE";
|
static constexpr const char* VOICE_STATE_UPDATE = "VOICE_STATE_UPDATE";
|
||||||
static inline constexpr char* WEBHOOKS_UPDATE = "WEBHOOKS_UPDATE";
|
static constexpr const char* WEBHOOKS_UPDATE = "WEBHOOKS_UPDATE";
|
||||||
};
|
};
|
||||||
struct HttpMethods {
|
struct HttpMethods {
|
||||||
static inline constexpr char* POST = "POST";
|
static constexpr const char* POST = "POST";
|
||||||
static inline constexpr char* GET = "GET";
|
static constexpr const char* GET = "GET";
|
||||||
static inline constexpr char* PATCH = "PATCH";
|
static constexpr const char* PATCH = "PATCH";
|
||||||
static inline constexpr char* DELETE = "DELETE";
|
static constexpr const char* DELETE = "DELETE";
|
||||||
static inline constexpr char* PUT = "PUT";
|
static constexpr const char* PUT = "PUT";
|
||||||
static inline constexpr char* OPTIONS = "OPTIONS";
|
static constexpr const char* OPTIONS = "OPTIONS";
|
||||||
};
|
};
|
||||||
struct ApiVersion {
|
struct ApiVersion {
|
||||||
static const inline std::string api = "/api/";
|
static inline std::string api = "/api/";
|
||||||
static const inline std::string v10 = "v10";
|
static inline std::string v10 = "v10";
|
||||||
static const inline std::string v9 = "v9";
|
static inline std::string v9 = "v9";
|
||||||
static const inline std::string v8 = "v8";
|
static inline std::string v8 = "v8";
|
||||||
static const inline std::string v7 = "v7";
|
static inline std::string v7 = "v7";
|
||||||
static const inline std::string v6 = "v6";
|
static inline std::string v6 = "v6";
|
||||||
static const inline std::string current = api + v6;
|
static inline std::string current = api + v6;
|
||||||
static const inline std::string latest = api + v10;
|
static inline std::string latest = api + v10;
|
||||||
};
|
};
|
||||||
struct DiscordEndpoints {
|
struct DiscordEndpoints {
|
||||||
static const inline std::string main_scheme = "https://";
|
static inline std::string main_scheme = "https://";
|
||||||
static const inline std::string discord = main_scheme + "discord.com";
|
static inline std::string discord = main_scheme + "discord.com";
|
||||||
static const inline std::string images = main_scheme + "cdn.discord.com";
|
static inline std::string images = main_scheme + "cdn.discord.com";
|
||||||
static const inline std::string media = main_scheme + "media.discord.com";
|
static inline std::string media = main_scheme + "media.discord.com";
|
||||||
struct details {
|
struct details {
|
||||||
static const inline std::string current = DiscordEndpoints::discord + ApiVersion::current;
|
static inline std::string current = DiscordEndpoints::discord + ApiVersion::current;
|
||||||
static const inline std::string latest = DiscordEndpoints::discord + ApiVersion::latest;
|
static inline std::string latest = DiscordEndpoints::discord + ApiVersion::latest;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
struct StatusType {
|
|
||||||
static inline const char* Offline = "offline";
|
|
||||||
static inline const char* Online = "online";
|
|
||||||
static inline const char* Idle = "idle";
|
|
||||||
static inline const char* DND = "dnd";
|
|
||||||
static inline const char* Invisible = "invisible";
|
|
||||||
};
|
|
||||||
enum ActivityType : unsigned char {
|
|
||||||
Playing,
|
|
||||||
Streaming,
|
|
||||||
Listening,
|
|
||||||
Watching,
|
|
||||||
Custom,
|
|
||||||
Competing
|
|
||||||
};
|
|
||||||
enum GatewayIntents {
|
enum GatewayIntents {
|
||||||
AutoModerationConfiguration = 1048576,
|
AutoModerationConfiguration = 1048576,
|
||||||
AutoModerationExecution = 2097152,
|
AutoModerationExecution = 2097152,
|
||||||
@ -145,21 +129,15 @@ enum GatewayIntents {
|
|||||||
MessageContent = 32768,
|
MessageContent = 32768,
|
||||||
AllIntents = 131071
|
AllIntents = 131071
|
||||||
};
|
};
|
||||||
enum DiscordTime : long {
|
enum UserStatus {
|
||||||
|
Offline,
|
||||||
|
Online,
|
||||||
|
Idle,
|
||||||
|
AFK,
|
||||||
|
DoNotDisturb,
|
||||||
|
Invisible
|
||||||
|
};
|
||||||
|
enum DiscordTime {
|
||||||
Epoch = 1420070400000,
|
Epoch = 1420070400000,
|
||||||
};
|
};
|
||||||
enum GatewayOpcodes : unsigned char {
|
|
||||||
Dispatch,
|
|
||||||
Heartbeat,
|
|
||||||
Identify,
|
|
||||||
PresenceUpdate,
|
|
||||||
VoiceStateUpdate,
|
|
||||||
Resume = 6,
|
|
||||||
Reconnect,
|
|
||||||
RequestGuildMembers,
|
|
||||||
InvalidSession,
|
|
||||||
Hello,
|
|
||||||
HeartbeatACK,
|
|
||||||
RequestSoundboardSounds = 31,
|
|
||||||
};
|
|
||||||
#endif
|
#endif
|
@ -1,40 +0,0 @@
|
|||||||
#ifndef UTILS_FUNCTIONS_HPP_
|
|
||||||
#define UTILS_FUNCTIONS_HPP_
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
struct functions {
|
|
||||||
static inline auto isNull(const nlohmann::json& str) -> std::string {
|
|
||||||
return str.is_null() ? str.dump() : str.get<std::string>();
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
static auto testValue(const nlohmann::json& data, const std::vector<std::string>& keys) -> std::optional<T> {
|
|
||||||
const nlohmann::json* current = &data;
|
|
||||||
for (const auto& key : keys) {
|
|
||||||
if (current->contains(key)) {
|
|
||||||
current = &(*current)[key];
|
|
||||||
} else {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if constexpr (std::is_same_v<T, bool>) {
|
|
||||||
if (current->is_boolean()) {
|
|
||||||
return current->get<bool>();
|
|
||||||
}
|
|
||||||
} else if constexpr (std::is_same_v<T, int>) {
|
|
||||||
if (current->is_number_integer()) {
|
|
||||||
return current->get<int>();
|
|
||||||
}
|
|
||||||
} else if constexpr (std::is_same_v<T, double>) {
|
|
||||||
if (current->is_number_float()) {
|
|
||||||
return current->get<double>();
|
|
||||||
}
|
|
||||||
} else if constexpr (std::is_same_v<T, std::string>) {
|
|
||||||
if (current->is_string()) {
|
|
||||||
return current->get<std::string>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
24765
libs/utils/json.hpp
Normal file
24765
libs/utils/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -5,47 +5,43 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <utils/types.hpp>
|
using std::setfill, std::setw;
|
||||||
enum level : unsigned char { INFO, WARNING, ERROR, CRITICAL };
|
enum level { INFO, WARNING, ERROR, CRITICAL };
|
||||||
enum type : unsigned char { WEBSOCKET, NETWORK, API };
|
enum type { WEBSOCKET, NETWORK, API };
|
||||||
class Log {
|
class Log {
|
||||||
public:
|
public:
|
||||||
_maybe_unused static void create(_maybe_unused const level& lvl, _maybe_unused const type& t, _maybe_unused const std::string& message) {
|
static void create(level lvl, type t, const std::string& message) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
std::string color;
|
std::string color;
|
||||||
switch (lvl) {
|
switch (lvl) {
|
||||||
case INFO: color = "\033[34;1m"; break;
|
case INFO:
|
||||||
case WARNING: color = "\033[33;1m"; break;
|
color = "\033[34;1m";
|
||||||
case ERROR: color = "\033[31;1m"; break;
|
break;
|
||||||
case CRITICAL: color = "\033[31;1;2m"; break;
|
case WARNING:
|
||||||
default: color = "\033[0m"; break;
|
color = "\033[33;1m";
|
||||||
|
break;
|
||||||
|
case ERROR:
|
||||||
|
color = "\033[31;1m";
|
||||||
|
break;
|
||||||
|
case CRITICAL:
|
||||||
|
color = "\033[31;1;2m";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
color = "\033[0m";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
std::cout << color << "[" << getCurrentTime() << "][" << str(t) << "][" << str(lvl) << "] \033[0m" << message << "\033[0m" << std::endl;
|
std::cout << color << "[" << getCurrentTime() << "][" << str(t) << "][" << str(lvl) << "] \033[0m" << message << "\033[0m" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
static void force_create(const level& lvl, const type& t, const std::string& message) {
|
|
||||||
std::string color;
|
|
||||||
switch (lvl) {
|
|
||||||
case INFO: color = "\033[34;1m"; break;
|
|
||||||
case WARNING: color = "\033[33;1m"; break;
|
|
||||||
case ERROR: color = "\033[31;1m"; break;
|
|
||||||
case CRITICAL: color = "\033[31;1;2m"; break;
|
|
||||||
default: color = "\033[0m"; break;
|
|
||||||
}
|
|
||||||
std::cout << color << "[" << getCurrentTime() << "][" << str(t) << "][" << str(lvl) << "] \033[0m" << message << "\033[0m" << '\n';
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
static auto getCurrentTime() -> const std::string {
|
static std::string getCurrentTime() {
|
||||||
std::time_t now_c = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
std::time_t now_c = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||||
std::tm* timer = std::localtime(&now_c);
|
std::tm* timer = std::localtime(&now_c);
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << std::setfill('0') << std::setw(2)
|
oss << setfill('0') << setw(2) << timer->tm_hour << ":" << setfill('0') << setw(2) << timer->tm_min << ":" << setfill('0') << setw(2) << timer->tm_sec;
|
||||||
<< timer->tm_hour << ":" << std::setfill('0') << std::setw(2)
|
|
||||||
<< timer->tm_min << ":" << std::setfill('0') << std::setw(2)
|
|
||||||
<< timer->tm_sec;
|
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
static auto str(const level& lvl) noexcept -> std::string {
|
static std::string str(const level& lvl) {
|
||||||
switch (lvl) {
|
switch (lvl) {
|
||||||
case INFO: return "INFO";
|
case INFO: return "INFO";
|
||||||
case WARNING: return "WARNING";
|
case WARNING: return "WARNING";
|
||||||
@ -54,7 +50,7 @@ private:
|
|||||||
default: return "UNKNOWN";
|
default: return "UNKNOWN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static auto str(const type& t) noexcept -> std::string {
|
static std::string str(const type& t) {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case WEBSOCKET: return "WEBSOCKET";
|
case WEBSOCKET: return "WEBSOCKET";
|
||||||
case NETWORK: return "NETWORK";
|
case NETWORK: return "NETWORK";
|
||||||
@ -63,4 +59,5 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
#endif
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#ifndef UTILS_TYPES_HPP_
|
#ifndef UTILS_TYPES_HPP_
|
||||||
#define UTILS_TYPES_HPP_
|
#define UTILS_TYPES_HPP_
|
||||||
#define _maybe_unused [[maybe_unused]]
|
#define j(...) {{__VA_ARGS__}}
|
||||||
#define _deprecated_t(text) [[deprecated(text)]]
|
#define je(...) {__VA_ARGS__}
|
||||||
#define _deprecated [[deprecated]]
|
#define g(x, y) (std::get<x>(y))
|
||||||
#define _nodiscard [[nodiscard]]
|
#define ALL_INTENTS 131071
|
||||||
|
#define DEBUG
|
||||||
#endif
|
#endif
|
Binary file not shown.
Before Width: | Height: | Size: 189 KiB |
@ -1,46 +1,14 @@
|
|||||||
#include <api.hpp>
|
#include <api.h>
|
||||||
#include <includes.hpp>
|
#include <includes.h>
|
||||||
#include <cxxopts.hpp>
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
cxxopts::Options options("sparkle", "WIP discord bot library in C++");
|
if (argc != 3) return -1;
|
||||||
options.add_options()
|
WebSocket* bot = &WebSocket::getInstance(argv[2], GatewayIntents::AllIntents);
|
||||||
("h,help", "Print help")
|
bot->on(GatewayEvents::READY, [](const Discord<Message, User>a) {
|
||||||
("V,version", "Show version information")
|
cout << DiscordEndpoints::details::latest << endl;
|
||||||
("t,token", "Discord bot token", cxxopts::value<std::string>());
|
|
||||||
|
|
||||||
auto result = options.parse(argc, argv);
|
|
||||||
|
|
||||||
if (result.count("version")) {
|
|
||||||
std::cout << "sparkle version 0.3" << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.count("help")) {
|
|
||||||
std::cout << options.help() << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result.count("token")) {
|
|
||||||
std::cout << "\033[31mError: no token provided.\033[0m" << std::endl;
|
|
||||||
std::cout << options.help() << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebSocket* bot = &WebSocket::getInstance(result["token"].as<std::string>(), GatewayIntents::AllIntents);
|
|
||||||
|
|
||||||
bot->once(GatewayEvents::READY, [](const Discord<User>& ctx) {
|
|
||||||
auto& [user] = ctx.ctx();
|
|
||||||
std::cout << std::boolalpha << user->isBot << std::endl;
|
|
||||||
std::cout << nlohmann::json::parse(user->me())["username"].get<std::string>() << std::endl;
|
|
||||||
});
|
});
|
||||||
|
bot->on(GatewayEvents::MESSAGE_CREATE, [](const Discord<Message, User, Author> msg) {
|
||||||
bot->on(GatewayEvents::MESSAGE_CREATE, [](const Discord<Message, User, Author>& msg) {
|
g(0, msg.net)->send("939957962972229634", j("content", g(2, msg.net)->content()));
|
||||||
auto& [message, user, author] = msg.ctx();
|
|
||||||
if (!author->isBot) {
|
|
||||||
message->send("1334963948767940648", message->pack("content", std::to_string(user->isBot)));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
bot->start();
|
bot->start();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -1,7 +1,12 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <includes.hpp>
|
int add(int a, int b) {
|
||||||
#include <network.hpp>
|
return a + b;
|
||||||
TEST(NetworkManagerTest, RequestReturnsExpectedValue) {
|
}
|
||||||
NetworkManager& networkManager = NetworkManager::getInstance();
|
TEST(AddTest, PositiveNumbers) {
|
||||||
EXPECT_FALSE(networkManager.request(HttpMethods::POST, DiscordEndpoints::details::latest + "/channels/939957962972229634/messages", { "content", "test" }).empty());
|
EXPECT_EQ(add(1, 2), 3);
|
||||||
|
EXPECT_EQ(add(2, 3), 5);
|
||||||
|
}
|
||||||
|
TEST(AddTest, NegativeNumbers) {
|
||||||
|
EXPECT_EQ(add(-1, -1), -2);
|
||||||
|
EXPECT_EQ(add(-1, 1), 0);
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user