From 52696a58c6596781aebad8c498d2c5016c66a613 Mon Sep 17 00:00:00 2001 From: fluttershy <a@a.a> Date: Mon, 13 Jan 2025 14:40:21 +0500 Subject: [PATCH] code cleanup --- libs/api/Channel.hpp | 6 +- libs/api/Message.hpp | 18 ++++- libs/api/User.hpp | 27 +++++-- libs/gateway/{websocket.hpp => Websocket.hpp} | 50 +++++------- libs/tls/{network.hpp => Network.hpp} | 76 +++++++++++++------ sources/main.cpp | 28 +++---- 6 files changed, 120 insertions(+), 85 deletions(-) rename libs/gateway/{websocket.hpp => Websocket.hpp} (87%) rename libs/tls/{network.hpp => Network.hpp} (50%) diff --git a/libs/api/Channel.hpp b/libs/api/Channel.hpp index 7ab16ed..c98258c 100644 --- a/libs/api/Channel.hpp +++ b/libs/api/Channel.hpp @@ -3,8 +3,8 @@ #include <string> #include <exception> #include <iostream> -#include <tls/network.hpp> -#include <gateway/websocket.hpp> +#include <tls/Network.hpp> +#include <gateway/Websocket.hpp> #include <utils/types.hpp> using std::string; using std::cout; @@ -15,7 +15,7 @@ private: WebSocket& web; NetworkManager& req; public: - Channel(const json& data) : data(data), web(*WebSocket::getInstance()), req(*NetworkManager::getInstance()) {} + Channel(const json& data) : data(data), web(WebSocket::getInstance()), req(NetworkManager::getInstance()) {} string send(const json& msg) const { return req.request("POST", dapi + "/channels/" + data["d"]["channel_id"].get<string>() + "/messages", msg.dump()); } diff --git a/libs/api/Message.hpp b/libs/api/Message.hpp index 30ca120..cb45af3 100644 --- a/libs/api/Message.hpp +++ b/libs/api/Message.hpp @@ -4,8 +4,8 @@ #include <string> #include <exception> #include <iostream> -#include <tls/network.hpp> -#include <gateway/websocket.hpp> +#include <tls/Network.hpp> +#include <gateway/Websocket.hpp> using std::string; using std::cout; using std::endl; @@ -15,9 +15,21 @@ private: WebSocket& web; NetworkManager& req; public: - Message(const json& data) : data(data), web(*WebSocket::getInstance()), req(*NetworkManager::getInstance()) {}; + Message(const json& data) : data(data), web(WebSocket::getInstance()), req(NetworkManager::getInstance()) {}; string send(const string& id, const json& msg) { return req.request("POST", dapi + "/channels/" + id + "/messages", msg.dump()); } + string getMessages(const string& id, const string& count, const string& before = "") { + if (before.empty()) { + return req.request("GET", dapi + "/channels/" + id + "/messages?limit=" + count); + } + else { + return req.request("GET", dapi + "/channels/" + id + "/messages?before=" + before + "&limit=" + count); + } + return "pizda"; + } + string deleteMessage(const string& channel_id, const string& message_id) { + return req.request("DELETE", dapi + "/channels/" + channel_id + "/messages/" + message_id); + } }; #endif \ No newline at end of file diff --git a/libs/api/User.hpp b/libs/api/User.hpp index c6e0365..c6e26b4 100644 --- a/libs/api/User.hpp +++ b/libs/api/User.hpp @@ -2,10 +2,10 @@ #define API_USER_HPP_ #include <utils/types.hpp> #include <string> -#include <exception> #include <iostream> -#include <tls/network.hpp> -#include <gateway/websocket.hpp> +#include <tls/Network.hpp> +#include <gateway/Websocket.hpp> +#include <vector> using std::string; using std::cout; using std::endl; @@ -15,12 +15,23 @@ private: WebSocket& web; NetworkManager& req; public: - User(const json& data) : data(data), web(*WebSocket::getInstance()), req(*NetworkManager::getInstance()) {} - string id() { - return data["d"]["author"]["id"]; + 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; } - string me() const { - return req.request("GET", dapi + "/users/@me", ""); + virtual string me() { + return req.request("GET", dapi + "/users/@me"); } bool isBot() { try { diff --git a/libs/gateway/websocket.hpp b/libs/gateway/Websocket.hpp similarity index 87% rename from libs/gateway/websocket.hpp rename to libs/gateway/Websocket.hpp index b3e8776..ae1eb2f 100644 --- a/libs/gateway/websocket.hpp +++ b/libs/gateway/Websocket.hpp @@ -91,18 +91,18 @@ private: {VOICE_STATE_UPDATE, "VOICE_STATE_UPDATE"}, {WEBHOOKS_UPDATE, "WEBHOOKS_UPDATE"} }}; - bool connected = false; - static bool initialized, isBot; - static WebSocket* instance; - static int i; - static std::string t; + bool connected = false, isBot; + int intents; + std::string token; ix::WebSocket webSocket; int heartbeat_interval, lastS; json payload = { {"op", 1},{"d", nullptr} }, id, res; std::unordered_map<std::string_view, 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) : lastS(0), heartbeat_interval(-1) { - WebSocket::t = token; - WebSocket::i = intents; + WebSocket::token = token; + WebSocket::intents = intents; WebSocket::isBot = isBot; id = { {"op", 2}, @@ -139,7 +139,12 @@ private: case 10: heartbeat_interval = res["d"]["heartbeat_interval"].get<int>(); !connected ? connected = true, webSocket.send(id.dump()) : false; - start_heartbeat(); + std::thread([this]() { + while (connected && heartbeat_interval != -1) { + 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()) { @@ -152,6 +157,7 @@ private: webSocket.start(); } public: + /* void sendPresenceUpdate(int statusType, const std::string& activityName) { json prsUpdate = { {"op", 3}, @@ -164,14 +170,9 @@ public: }; webSocket.send(prsUpdate.dump()); } - static WebSocket* getInstance(const std::string& token = "", const int intents = 0, bool bot = true) { - if (!instance) { - if (token.empty() || intents == 0) { - throw std::invalid_argument("Token or intents is empty."); - } - instance = new WebSocket(token, intents, bot); - initialized = true; - } + */ + static WebSocket& getInstance(const std::string& token = "", const int intents = 0, bool bot = true) { + static WebSocket instance(token, intents, bot); return instance; } ~WebSocket() { @@ -179,10 +180,10 @@ public: ix::uninitNetSystem(); } std::string getToken() const { - return isBot ? std::string("Bot " + WebSocket::t) : WebSocket::t; + return isBot ? std::string("Bot " + WebSocket::token) : WebSocket::token; } int getIntents() const { - return WebSocket::i; + return WebSocket::intents; } void on(const int event, std::function<void(const json&)> handler) { eventHandlers[events[event].second] = [handler](const json& message) { @@ -199,21 +200,8 @@ public: } }; } - void start_heartbeat() { - std::thread([this]() { - while (connected && heartbeat_interval != -1) { - std::this_thread::sleep_for(milliseconds(heartbeat_interval)); - webSocket.send(payload.dump()); - } - }).detach(); - } void start() { while (1) std::this_thread::sleep_for(1ms); } }; -WebSocket* WebSocket::instance = nullptr; -std::string WebSocket::t = ""; -int WebSocket::i = 0; -bool WebSocket::initialized = false; -bool WebSocket::isBot = true; #endif \ No newline at end of file diff --git a/libs/tls/network.hpp b/libs/tls/Network.hpp similarity index 50% rename from libs/tls/network.hpp rename to libs/tls/Network.hpp index 1984a4e..49ace82 100644 --- a/libs/tls/network.hpp +++ b/libs/tls/Network.hpp @@ -7,27 +7,23 @@ #include <string> #include <net/if.h> #include <netdb.h> -#include <unistd.h> #include <utils/types.hpp> -#include <gateway/websocket.hpp> +#include <gateway/Websocket.hpp> using std::cout; using std::cerr; using std::endl; class NetworkManager { private: WebSocket& web; - static NetworkManager* instance; SSL_CTX* ctx; int sock = -1; - std::string result; std::unique_ptr<SSL, decltype(&SSL_free)> ssl = { nullptr, &SSL_free }; void handleSSLInitErrors() { ERR_print_errors_fp(stderr); abort(); } void createSSLConnection(const std::string& hostname, const std::string& port) { - addrinfo hints = { 0 }, * res = { 0 }; - hints.ai_family = AF_UNSPEC; + addrinfo hints = { 0 }, *res = { 0 }; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(hostname.c_str(), port.c_str(), &hints, &res) != 0) { cerr << "Failed to get address info for " << hostname << ":" << port << endl; @@ -57,7 +53,9 @@ private: } freeaddrinfo(res); } - NetworkManager() : ctx(nullptr), result(""), web(*WebSocket::getInstance()) { + NetworkManager& operator=(const NetworkManager&) = delete; + NetworkManager(const NetworkManager&) = delete; + NetworkManager() : ctx(nullptr), web(WebSocket::getInstance()) { if (!ctx) { ctx = SSL_CTX_new(TLS_client_method()); if (!ctx) { @@ -71,22 +69,49 @@ private: createSSLConnection("discord.com", "443"); } } -public: - static NetworkManager* getInstance() { - if (!instance) { - instance = new NetworkManager(); + std::string parseJson(const std::string& response) { + unsigned long jsonStart = response.find("\r\n\r\n"); + if (jsonStart == std::string::npos) { + return ""; } + jsonStart += 4; + std::string jsonString = response.substr(jsonStart); + unsigned long jsonBegin = jsonString.find('['), jsonEnd = jsonString.rfind(']'); + if (jsonBegin == std::string::npos || jsonEnd == std::string::npos || jsonEnd < jsonBegin) { + return ""; + } + jsonString = jsonString.substr(jsonBegin, jsonEnd - jsonBegin + 1); + jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), '\r'), jsonString.end()); + jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), '\t'), jsonString.end()); + jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), '\n'), jsonString.end()); + jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), '\\'), jsonString.end()); + jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), '\''), jsonString.end()); + jsonString.erase(std::remove(jsonString.begin(), jsonString.end(), ' '), jsonString.end()); + try { + nlohmann::json jsonData = nlohmann::json::parse(jsonString); + return jsonData.dump(); + } + catch (const nlohmann::json::parse_error& e) { + return ""; + } + } +public: + static NetworkManager& getInstance() { + static NetworkManager instance; return instance; } ~NetworkManager() { if (ctx) SSL_CTX_free(ctx); close(sock); } - const std::string& request(const std::string& method, const std::string& path, const std::string& data) { - auto net = [this, method, path, data, bytesRead = 0, request = std::string("")]() mutable -> void { - request = method + " " + path + " HTTP/1.1\r\nHost: discord.com\r\nAccept: application/json\r\nContent-Type: application/json\r\n"; - request += "Authorization: " + web.getToken() + "\r\n"; - request += "Content-Length: " + std::to_string(data.length()) + "\r\n"; + std::string request(const std::string& method, const std::string& path, const std::string& data = "") { + #ifdef DEBUG + createSSLConnection("discord.com", "443"); + #endif + std::string result; + auto net = [this, method, path, data, &result]() mutable { + std::string request = method + " " + path + " HTTP/1.1\r\nHost: discord.com\r\nAccept: application/json\r\nContent-Type: application/json\r\n"; + request += "Authorization: " + web.getToken() + "\r\nContent-Length: " + std::to_string(data.length()) + "\r\n"; #ifdef DEBUG request += "Connection: close\r\n\r\n"; #elif defined(RELEASE) @@ -94,21 +119,26 @@ public: #endif request += data; if (SSL_write(ssl.get(), request.c_str(), request.length()) <= 0) { - cerr << "Failed to send request" << endl; + std::cerr << "Failed to send request" << std::endl; handleSSLInitErrors(); } - chngcol("REQUEST: " + path, 192, 255, 0); #ifdef DEBUG - cout << request << endl; - char buffer[4096]; - while ((bytesRead = SSL_read(ssl.get(), buffer, sizeof(buffer))) > 0) { - result.append(buffer); + std::vector<char> buffer(1024); + int bytesRead; + while ((bytesRead = SSL_read(ssl.get(), buffer.data(), buffer.size())) > 0) { + result.append(buffer.data(), bytesRead); + if (bytesRead == buffer.size()) { + buffer.resize(buffer.size() * 2); + } } #endif }; net(); + #ifdef DEBUG + return parseJson(result); + #elif defined(RELEASE) return result; + #endif } }; -NetworkManager* NetworkManager::instance = nullptr; #endif \ No newline at end of file diff --git a/sources/main.cpp b/sources/main.cpp index a05ef23..f6c1e70 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -1,34 +1,28 @@ #define RELEASE #include <utils/json.hpp> #include <utils/enums.hpp> -#include <tls/network.hpp> -#include <gateway/websocket.hpp> +#include <tls/Network.hpp> +#include <gateway/Websocket.hpp> #include <utils/types.hpp> #include <api/Bot.hpp> #include <api/Channel.hpp> #include <api/Message.hpp> #include <api/Embed.hpp> #include <api/Author.hpp> +#include <api/User.hpp> #include <utils/types.hpp> -using namespace std; int main(int argc, char* argv[]) { - if (argc != 5) return -1; - WebSocket* bot = WebSocket::getInstance(argv[2], stoi(argv[4]), true); - bot->on(GatewayEvents::READY, [](const Bot<Message>& b) { - cout << "started" << endl; + if (argc != 3) return -1; + WebSocket* bot = &WebSocket::getInstance(argv[2], 131071); + bot->on(GatewayEvents::READY, [](const Bot<Message, User, Author>& b) { + g(0, b.net)->send("939957962972229634", j("content", "started")); }); - bot->on(GatewayEvents::MESSAGE_CREATE, [](const Bot<Message, Author, EmbedBuilder>& msg) { - if (g(1, msg.net)->isBot() == false) { - g(0, msg.net)->send("939957962972229634", j("content", g(1, msg.net)->content())); + bot->on(GatewayEvents::MESSAGE_CREATE, [](const Bot<Message, User, Author>& b) { + if (!g(2, b.net)->isBot()) { + g(0, b.net)->send("939957962972229634", j("content", g(2, b.net)->content())); + cout << g(1, b.net)->extract({ "content" }).get<string>() << endl; } }); - bot->on(GatewayEvents::MESSAGE_REACTION_REMOVE, [](const Bot<Message>& msg) { - g(0, msg.net)->send("939957962972229634", - j("content", "bye")); - }); - bot->on(GatewayEvents::MESSAGE_REACTION_ADD, [](const Bot<Message>& msg) { - g(0, msg.net)->send("939957962972229634", j("content", "hello")); - }); bot->start(); return 0; } \ No newline at end of file