#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() == handler.target(); }).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()) + " " + res["t"].dump()); switch (res["op"].get()) { case GatewayOpcodes::Hello: heartbeat_interval = res["d"]["heartbeat_interval"].get(); 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(), 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()); }