From 929ebf1a6008d861473e3ceffd11cd4eca90d620 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Tue, 15 Nov 2022 02:14:49 -0500 Subject: mess with some websocket stuff to try and fix things to be honest, im not sure what ive done here. whatever memory i have of the issue i was trying to fix has long disappeared by the time im committing this. theres still some issues with being force disconnected and i really dont understand it ill figure it out eventually... maybe :/ --- src/discord/discord.cpp | 13 ++++-- src/discord/discord.hpp | 2 +- src/discord/voiceclient.cpp | 103 +++++++++++++++++++++++++++++++++++--------- src/discord/voiceclient.hpp | 24 ++++++++++- src/discord/websocket.cpp | 20 ++++++--- src/discord/websocket.hpp | 9 ++-- 6 files changed, 137 insertions(+), 34 deletions(-) diff --git a/src/discord/discord.cpp b/src/discord/discord.cpp index 2a08574..cd16aa8 100644 --- a/src/discord/discord.cpp +++ b/src/discord/discord.cpp @@ -9,7 +9,8 @@ using namespace std::string_literals; DiscordClient::DiscordClient(bool mem_store) : m_decompress_buf(InflateChunkSize) - , m_store(mem_store) { + , m_store(mem_store) + , m_websocket("gateway-ws") { m_msg_dispatch.connect(sigc::mem_fun(*this, &DiscordClient::MessageDispatch)); auto dispatch_cb = [this]() { m_generic_mutex.lock(); @@ -2171,6 +2172,11 @@ void DiscordClient::HandleGatewayVoiceStateUpdate(const GatewayMessage &msg) { if (data.UserID == m_user_data.ID) { spdlog::get("discord")->debug("Voice session ID: {}", data.SessionID); m_voice.SetSessionID(data.SessionID); + + // channel_id = null means disconnect. stop cuz out of order maybe + if (!data.ChannelID.has_value()) { + m_voice.Stop(); + } } else { if (data.GuildID.has_value() && data.Member.has_value()) { if (data.Member->User.has_value()) { @@ -2504,9 +2510,8 @@ void DiscordClient::SetSuperPropertiesFromIdentity(const IdentifyMessage &identi void DiscordClient::HandleSocketOpen() { } -void DiscordClient::HandleSocketClose(uint16_t code) { - printf("got socket close code: %d\n", code); - auto close_code = static_cast(code); +void DiscordClient::HandleSocketClose(const ix::WebSocketCloseInfo &info) { + auto close_code = static_cast(info.code); auto cb = [this, close_code]() { m_heartbeat_waiter.kill(); if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join(); diff --git a/src/discord/discord.hpp b/src/discord/discord.hpp index fc714e6..2d8db91 100644 --- a/src/discord/discord.hpp +++ b/src/discord/discord.hpp @@ -289,7 +289,7 @@ private: void SetSuperPropertiesFromIdentity(const IdentifyMessage &identity); void HandleSocketOpen(); - void HandleSocketClose(uint16_t code); + void HandleSocketClose(const ix::WebSocketCloseInfo &info); static bool CheckCode(const http::response_type &r); static bool CheckCode(const http::response_type &r, int expected); diff --git a/src/discord/voiceclient.cpp b/src/discord/voiceclient.cpp index 291b975..3118cec 100644 --- a/src/discord/voiceclient.cpp +++ b/src/discord/voiceclient.cpp @@ -126,18 +126,26 @@ UDPSocket::type_signal_data UDPSocket::signal_data() { } DiscordVoiceClient::DiscordVoiceClient() { - sodium_init(); + if (sodium_init() == -1) { + spdlog::get("voice")->critical("sodium_init() failed"); + } + + m_ws = std::make_unique("voice-ws"); - m_ws.signal_open().connect([this]() { + m_ws->signal_open().connect([this]() { spdlog::get("voice")->info("Websocket open"); + SetState(State::Opened); }); - m_ws.signal_close().connect([this](uint16_t code) { - spdlog::get("voice")->info("Websocket closed with code {}", code); + m_ws->signal_close().connect([this](const ix::WebSocketCloseInfo &info) { + if (info.remote) { + SetState(State::ClosingByServer); + } Stop(); }); - m_ws.signal_message().connect([this](const std::string &str) { + m_ws->signal_message().connect([this](const std::string &str) { + spdlog::get("voice-ws")->trace("Recv: {}", str); std::lock_guard _(m_dispatch_mutex); m_message_queue.push(str); m_dispatcher.emit(); @@ -175,7 +183,8 @@ DiscordVoiceClient::~DiscordVoiceClient() { } void DiscordVoiceClient::Start() { - m_ws.StartConnection("wss://" + m_endpoint + "/?v=7"); + SetState(State::Opening); + m_ws->StartConnection("wss://" + m_endpoint + "/?v=7"); m_heartbeat_waiter.revive(); m_keepalive_waiter.revive(); m_connected = true; @@ -183,15 +192,29 @@ void DiscordVoiceClient::Start() { } void DiscordVoiceClient::Stop() { - m_ws.Stop(); - m_udp.Stop(); - m_heartbeat_waiter.kill(); - if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join(); - m_keepalive_waiter.kill(); - if (m_keepalive_thread.joinable()) m_keepalive_thread.join(); - if (m_connected) { - m_connected = false; - m_signal_disconnected.emit(); + if (IsOpening() || IsOpened()) { + spdlog::get("voice")->debug("Requested voice client stop"); + SetState(State::ClosingByClient); + m_ws->Stop(); + } else if (IsClosing()) { + spdlog::get("voice")->debug("Completing stop in closing"); + if (m_state == State::ClosingByClient) { + SetState(State::ClosedByClient); + } else if (m_state == State::ClosingByServer) { + SetState(State::ClosedByServer); + } + m_ws->Stop(); + m_udp.Stop(); + m_heartbeat_waiter.kill(); + if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join(); + m_keepalive_waiter.kill(); + if (m_keepalive_thread.joinable()) m_keepalive_thread.join(); + if (m_connected) { + m_connected = false; + m_signal_disconnected.emit(); + } + } else { + spdlog::get("voice")->debug("Stop called, but already stopped"); } } @@ -228,7 +251,6 @@ bool DiscordVoiceClient::IsConnected() const noexcept { void DiscordVoiceClient::OnGatewayMessage(const std::string &str) { VoiceGatewayMessage msg = nlohmann::json::parse(str); - puts(msg.Data.dump(4).c_str()); switch (msg.Opcode) { case VoiceGatewayOp::Hello: { HandleGatewayHello(msg); @@ -278,7 +300,7 @@ void DiscordVoiceClient::HandleGatewaySessionDescription(const VoiceGatewayMessa msg.Delay = 0; msg.SSRC = m_ssrc; msg.Speaking = VoiceSpeakingType::Microphone; - m_ws.Send(msg); + m_ws->Send(msg); m_secret_key = d.SecretKey; m_udp.SetSSRC(m_ssrc); @@ -304,7 +326,7 @@ void DiscordVoiceClient::Identify() { msg.SessionID = m_session_id; msg.Token = m_token; msg.Video = true; - m_ws.Send(msg); + m_ws->Send(msg); } void DiscordVoiceClient::Discovery() { @@ -341,7 +363,7 @@ void DiscordVoiceClient::SelectProtocol(std::string_view ip, uint16_t port) { msg.Address = ip; msg.Port = port; msg.Protocol = "udp"; - m_ws.Send(msg); + m_ws->Send(msg); } void DiscordVoiceClient::OnUDPData(std::vector data) { @@ -370,7 +392,7 @@ void DiscordVoiceClient::HeartbeatThread() { VoiceHeartbeatMessage msg; msg.Nonce = static_cast(ms); - m_ws.Send(msg); + m_ws->Send(msg); } } @@ -386,6 +408,47 @@ void DiscordVoiceClient::KeepaliveThread() { } } +void DiscordVoiceClient::SetState(State state) { + m_state = state; + + switch (state) { + case State::Opening: + spdlog::get("voice")->debug("WS state: Opening"); + break; + case State::Opened: + spdlog::get("voice")->debug("WS state: Opened"); + break; + case State::ClosingByClient: + spdlog::get("voice")->debug("WS state: Closing (Client)"); + break; + case State::ClosingByServer: + spdlog::get("voice")->debug("WS state: Closing (Server)"); + break; + case State::ClosedByClient: + spdlog::get("voice")->debug("WS state: Closed (Client)"); + break; + case State::ClosedByServer: + spdlog::get("voice")->debug("WS state: Closed (Server)"); + break; + } +} + +bool DiscordVoiceClient::IsOpening() const noexcept { + return m_state == State::Opening; +} + +bool DiscordVoiceClient::IsOpened() const noexcept { + return m_state == State::Opened; +} + +bool DiscordVoiceClient::IsClosing() const noexcept { + return m_state == State::ClosingByClient || m_state == State::ClosingByServer; +} + +bool DiscordVoiceClient::IsClosed() const noexcept { + return m_state == State::ClosedByClient || m_state == State::ClosedByServer; +} + DiscordVoiceClient::type_signal_disconnected DiscordVoiceClient::signal_connected() { return m_signal_connected; } diff --git a/src/discord/voiceclient.hpp b/src/discord/voiceclient.hpp index 1d8b952..61b329c 100644 --- a/src/discord/voiceclient.hpp +++ b/src/discord/voiceclient.hpp @@ -15,6 +15,7 @@ // clang-format on enum class VoiceGatewayCloseCode : uint16_t { + Normal = 4000, UnknownOpcode = 4001, InvalidPayload = 4002, NotAuthenticated = 4003, @@ -228,7 +229,10 @@ private: std::array m_secret_key; - Websocket m_ws; + // this is a unique_ptr because Websocket/ixwebsocket seems to have some strange behavior + // and quite frankly i do not feel like figuring out what is wrong + // so using a unique_ptr will just let me nuke the whole thing and make a new one + std::unique_ptr m_ws; UDPSocket m_udp; Glib::Dispatcher m_dispatcher; @@ -246,6 +250,24 @@ private: std::atomic m_connected = false; + enum class State { + Opening, + Opened, + ClosingByClient, + ClosedByClient, + ClosingByServer, + ClosedByServer, + }; + + void SetState(State state); + + [[nodiscard]] bool IsOpening() const noexcept; + [[nodiscard]] bool IsOpened() const noexcept; + [[nodiscard]] bool IsClosing() const noexcept; + [[nodiscard]] bool IsClosed() const noexcept; + + std::atomic m_state; + using type_signal_connected = sigc::signal; using type_signal_disconnected = sigc::signal; using type_signal_speaking = sigc::signal; diff --git a/src/discord/websocket.cpp b/src/discord/websocket.cpp index cf0111c..349913a 100644 --- a/src/discord/websocket.cpp +++ b/src/discord/websocket.cpp @@ -1,19 +1,25 @@ #include "websocket.hpp" +#include #include -Websocket::Websocket() - : m_close_code(ix::WebSocketCloseConstants::kNormalClosureCode) { +Websocket::Websocket(const std::string &id) + : m_close_info { 1000, "Normal", false } { + if (m_log = spdlog::get(id); !m_log) { + m_log = spdlog::stdout_color_mt(id); + } + m_open_dispatcher.connect([this]() { m_signal_open.emit(); }); m_close_dispatcher.connect([this]() { Stop(); - m_signal_close.emit(m_close_code); + m_signal_close.emit(m_close_info); }); } void Websocket::StartConnection(const std::string &url) { + m_log->debug("Starting connection to {}", url); m_websocket.disableAutomaticReconnection(); m_websocket.setUrl(url); m_websocket.setOnMessageCallback([this](auto &&msg) { OnMessage(std::forward(msg)); }); @@ -34,16 +40,18 @@ void Websocket::SetPrintMessages(bool show) noexcept { } void Websocket::Stop() { + m_log->debug("Stopping with default close code"); Stop(ix::WebSocketCloseConstants::kNormalClosureCode); } void Websocket::Stop(uint16_t code) { + m_log->debug("Stopping with close code {}", code); m_websocket.stop(code); } void Websocket::Send(const std::string &str) { if (m_print_messages) - printf("sending %s\n", str.c_str()); + m_log->trace("Send: {}", str); m_websocket.sendText(str); } @@ -54,10 +62,12 @@ void Websocket::Send(const nlohmann::json &j) { void Websocket::OnMessage(const ix::WebSocketMessagePtr &msg) { switch (msg->type) { case ix::WebSocketMessageType::Open: { + m_log->debug("Received open frame, dispatching"); m_open_dispatcher.emit(); } break; case ix::WebSocketMessageType::Close: { - m_close_code = msg->closeInfo.code; + m_log->debug("Received close frame, dispatching. {} ({}){}", msg->closeInfo.code, msg->closeInfo.reason, msg->closeInfo.remote ? " Remote" : ""); + m_close_info = msg->closeInfo; m_close_dispatcher.emit(); } break; case ix::WebSocketMessageType::Message: { diff --git a/src/discord/websocket.hpp b/src/discord/websocket.hpp index ba55254..768121e 100644 --- a/src/discord/websocket.hpp +++ b/src/discord/websocket.hpp @@ -6,10 +6,11 @@ #include #include #include +#include class Websocket { public: - Websocket(); + Websocket(const std::string &id); void StartConnection(const std::string &url); void SetUserAgent(std::string agent); @@ -30,7 +31,7 @@ private: public: using type_signal_open = sigc::signal; - using type_signal_close = sigc::signal; + using type_signal_close = sigc::signal; using type_signal_message = sigc::signal; type_signal_open signal_open(); @@ -46,5 +47,7 @@ private: Glib::Dispatcher m_open_dispatcher; Glib::Dispatcher m_close_dispatcher; - std::atomic m_close_code; + ix::WebSocketCloseInfo m_close_info; + + std::shared_ptr m_log; }; -- cgit v1.2.3