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