diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bb73c30..50b425d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ - Dev: Save settings in `aboutToQuit`. (#6159) - Dev: Bumped deprecation cutoff to Qt 6.4.3. (#6169) - Dev: Added a `run-and-kill.sh` script to help debug crash-on-exit bugs. (#6188) +- Dev: Refactored event API initialization away from Application and into TwitchIrcServer. (#6198) - Dev: Updated GoogleTest to v1.17.0. (#6180) - Dev: Mini refactor of `TwitchAccount`. (#6182) - Dev: Refactored away some `getApp` usages in `WindowManager`. (#6194) diff --git a/mocks/include/mocks/TwitchIrcServer.hpp b/mocks/include/mocks/TwitchIrcServer.hpp index a27029e5..bc8bcb3c 100644 --- a/mocks/include/mocks/TwitchIrcServer.hpp +++ b/mocks/include/mocks/TwitchIrcServer.hpp @@ -134,6 +134,12 @@ public: this->lastUserThatWhisperedMe = user; } + void initEventAPIs(BttvLiveUpdates *bttvLiveUpdates, + SeventvEventAPI *seventvEventAPI) override + { + // + } + ChannelPtr getWhispersChannel() const override { return this->whispersChannel; diff --git a/src/Application.cpp b/src/Application.cpp index 1e50664c..508443fc 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -289,8 +289,8 @@ void Application::initialize(Settings &settings, const Paths &paths) } this->twitchPubSub->initialize(); - this->initBttvLiveUpdates(); - this->initSeventvEventAPI(); + this->twitch->initEventAPIs(this->bttvLiveUpdates.get(), + this->seventvEventAPI.get()); this->streamerMode->start(); @@ -613,102 +613,6 @@ void Application::initNm(const Paths &paths) #endif } -void Application::initBttvLiveUpdates() -{ - if (!this->bttvLiveUpdates) - { - qCDebug(chatterinoBttv) - << "Skipping initialization of Live Updates as it's disabled"; - return; - } - - // We can safely ignore these signal connections since the twitch object will always - // be destroyed before the Application - std::ignore = this->bttvLiveUpdates->signals_.emoteAdded.connect( - [&](const auto &data) { - auto chan = this->twitch->getChannelOrEmptyByID(data.channelID); - - postToThread([chan, data] { - if (auto *channel = dynamic_cast(chan.get())) - { - channel->addBttvEmote(data); - } - }); - }); - std::ignore = this->bttvLiveUpdates->signals_.emoteUpdated.connect( - [&](const auto &data) { - auto chan = this->twitch->getChannelOrEmptyByID(data.channelID); - - postToThread([chan, data] { - if (auto *channel = dynamic_cast(chan.get())) - { - channel->updateBttvEmote(data); - } - }); - }); - std::ignore = this->bttvLiveUpdates->signals_.emoteRemoved.connect( - [&](const auto &data) { - auto chan = this->twitch->getChannelOrEmptyByID(data.channelID); - - postToThread([chan, data] { - if (auto *channel = dynamic_cast(chan.get())) - { - channel->removeBttvEmote(data); - } - }); - }); - this->bttvLiveUpdates->start(); -} - -void Application::initSeventvEventAPI() -{ - if (!this->seventvEventAPI) - { - qCDebug(chatterinoSeventvEventAPI) - << "Skipping initialization as the EventAPI is disabled"; - return; - } - - // We can safely ignore these signal connections since the twitch object will always - // be destroyed before the Application - std::ignore = this->seventvEventAPI->signals_.emoteAdded.connect( - [&](const auto &data) { - postToThread([this, data] { - this->twitch->forEachSeventvEmoteSet( - data.emoteSetID, [data](TwitchChannel &chan) { - chan.addSeventvEmote(data); - }); - }); - }); - std::ignore = this->seventvEventAPI->signals_.emoteUpdated.connect( - [&](const auto &data) { - postToThread([this, data] { - this->twitch->forEachSeventvEmoteSet( - data.emoteSetID, [data](TwitchChannel &chan) { - chan.updateSeventvEmote(data); - }); - }); - }); - std::ignore = this->seventvEventAPI->signals_.emoteRemoved.connect( - [&](const auto &data) { - postToThread([this, data] { - this->twitch->forEachSeventvEmoteSet( - data.emoteSetID, [data](TwitchChannel &chan) { - chan.removeSeventvEmote(data); - }); - }); - }); - std::ignore = this->seventvEventAPI->signals_.userUpdated.connect( - [&](const auto &data) { - this->twitch->forEachSeventvUser(data.userID, - [data](TwitchChannel &chan) { - chan.updateSeventvUser(data); - }); - }); - - this->seventvEventAPI->start(); -} - IApplication *getApp() { assert(INSTANCE != nullptr); diff --git a/src/Application.hpp b/src/Application.hpp index 66aa03c4..c6f7147f 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -233,8 +233,6 @@ public: ITwitchUsers *getTwitchUsers() override; private: - void initBttvLiveUpdates(); - void initSeventvEventAPI(); void initNm(const Paths &paths); NativeMessagingServer nmServer; diff --git a/src/providers/twitch/TwitchIrcServer.cpp b/src/providers/twitch/TwitchIrcServer.cpp index ad86ae0f..ac6ddfb5 100644 --- a/src/providers/twitch/TwitchIrcServer.cpp +++ b/src/providers/twitch/TwitchIrcServer.cpp @@ -11,8 +11,10 @@ #include "messages/Message.hpp" #include "messages/MessageBuilder.hpp" #include "providers/bttv/BttvEmotes.hpp" +#include "providers/bttv/BttvLiveUpdates.hpp" #include "providers/ffz/FfzEmotes.hpp" #include "providers/irc/IrcConnection2.hpp" +#include "providers/seventv/eventapi/Dispatch.hpp" // IWYU pragma: keep #include "providers/seventv/SeventvEmotes.hpp" #include "providers/seventv/SeventvEventAPI.hpp" #include "providers/twitch/api/Helix.hpp" @@ -182,7 +184,7 @@ TwitchIrcServer::TwitchIrcServer() &Communi::IrcConnection::connected, this, [this] { this->onWriteConnected(this->writeConnection_.get()); }); - this->connections_.managedConnect( + this->signalHolder.managedConnect( this->writeConnection_->connectionLost, [this](bool timeout) { qCDebug(chatterinoIrc) << "Write connection reconnect requested. Timeout:" << timeout; @@ -211,7 +213,7 @@ TwitchIrcServer::TwitchIrcServer() &Communi::IrcConnection::disconnected, this, [this] { this->onDisconnected(); }); - this->connections_.managedConnect( + this->signalHolder.managedConnect( this->readConnection_->connectionLost, [this](bool timeout) { qCDebug(chatterinoIrc) << "Read connection reconnect requested. Timeout:" << timeout; @@ -224,7 +226,7 @@ TwitchIrcServer::TwitchIrcServer() } this->readConnection_->smartReconnect(); }); - this->connections_.managedConnect(this->readConnection_->heartbeat, [this] { + this->signalHolder.managedConnect(this->readConnection_->heartbeat, [this] { this->markChannelsConnected(); }); } @@ -237,7 +239,7 @@ void TwitchIrcServer::initialize() }); }); - this->connections_.managedConnect( + this->signalHolder.managedConnect( getApp()->getTwitchPubSub()->pointReward.redeemed, [this](auto &data) { QString channelId = data.value("channel_id").toString(); if (channelId.isEmpty()) @@ -828,6 +830,109 @@ void TwitchIrcServer::setLastUserThatWhisperedMe(const QString &user) this->lastUserThatWhisperedMe.set(user); } +void TwitchIrcServer::initEventAPIs(BttvLiveUpdates *bttvLiveUpdates, + SeventvEventAPI *seventvEventAPI) +{ + assertInGuiThread(); + + if (bttvLiveUpdates != nullptr) + { + // We can safely ignore these signal connections since the twitch object will always + // be destroyed before the Application + this->signalHolder.managedConnect( + bttvLiveUpdates->signals_.emoteAdded, [&](const auto &data) { + auto chan = this->getChannelOrEmptyByID(data.channelID); + + postToThread([chan, data] { + if (auto *channel = + dynamic_cast(chan.get())) + { + channel->addBttvEmote(data); + } + }); + }); + this->signalHolder.managedConnect( + bttvLiveUpdates->signals_.emoteUpdated, [&](const auto &data) { + auto chan = this->getChannelOrEmptyByID(data.channelID); + + postToThread([chan, data] { + if (auto *channel = + dynamic_cast(chan.get())) + { + channel->updateBttvEmote(data); + } + }); + }); + this->signalHolder.managedConnect( + bttvLiveUpdates->signals_.emoteRemoved, [&](const auto &data) { + auto chan = this->getChannelOrEmptyByID(data.channelID); + + postToThread([chan, data] { + if (auto *channel = + dynamic_cast(chan.get())) + { + channel->removeBttvEmote(data); + } + }); + }); + + bttvLiveUpdates->start(); + } + else + { + qCDebug(chatterinoBttv) + << "Skipping initialization of Live Updates as it's disabled"; + } + + if (seventvEventAPI != nullptr) + { + // We can safely ignore these signal connections since the twitch object will always + // be destroyed before the Application + this->signalHolder.managedConnect( + seventvEventAPI->signals_.emoteAdded, [this](const auto &data) { + postToThread([this, data] { + this->forEachSeventvEmoteSet(data.emoteSetID, + [data](TwitchChannel &chan) { + chan.addSeventvEmote(data); + }); + }); + }); + this->signalHolder.managedConnect( + seventvEventAPI->signals_.emoteUpdated, [this](const auto &data) { + postToThread([this, data] { + this->forEachSeventvEmoteSet( + data.emoteSetID, [data](TwitchChannel &chan) { + chan.updateSeventvEmote(data); + }); + }); + }); + this->signalHolder.managedConnect( + seventvEventAPI->signals_.emoteRemoved, [this](const auto &data) { + postToThread([this, data] { + this->forEachSeventvEmoteSet( + data.emoteSetID, [data](TwitchChannel &chan) { + chan.removeSeventvEmote(data); + }); + }); + }); + this->signalHolder.managedConnect( + seventvEventAPI->signals_.userUpdated, [this](const auto &data) { + // TODO: is it fine if this is called in non-gui-thread? + this->forEachSeventvUser(data.userID, + [data](TwitchChannel &chan) { + chan.updateSeventvUser(data); + }); + }); + + seventvEventAPI->start(); + } + else + { + qCDebug(chatterinoSeventvEventAPI) + << "Skipping initialization as the EventAPI is disabled"; + } +} + void TwitchIrcServer::reloadAllBTTVChannelEmotes() { this->forEachChannel([](const auto &chan) { @@ -1048,7 +1153,7 @@ ChannelPtr TwitchIrcServer::getOrAddChannel(const QString &dirtyChannelName) } this->channels.insert(channelName, chan); - this->connections_.managedConnect(chan->destroyed, [this, channelName] { + this->signalHolder.managedConnect(chan->destroyed, [this, channelName] { // fourtf: issues when the server itself is destroyed qCDebug(chatterinoIrc) << "[TwitchIrcServer::addChannel]" << channelName diff --git a/src/providers/twitch/TwitchIrcServer.hpp b/src/providers/twitch/TwitchIrcServer.hpp index 86a2afd6..e155fb13 100644 --- a/src/providers/twitch/TwitchIrcServer.hpp +++ b/src/providers/twitch/TwitchIrcServer.hpp @@ -25,6 +25,8 @@ class BttvEmotes; class FfzEmotes; class SeventvEmotes; class RatelimitBucket; +class BttvLiveUpdates; +class SeventvEventAPI; class ITwitchIrcServer { @@ -68,6 +70,9 @@ public: virtual QString getLastUserThatWhisperedMe() const = 0; virtual void setLastUserThatWhisperedMe(const QString &user) = 0; + virtual void initEventAPIs(BttvLiveUpdates *bttvLiveUpdates, + SeventvEventAPI *seventvEventAPI) = 0; + // Update this interface with TwitchIrcServer methods as needed }; @@ -154,6 +159,9 @@ public: QString getLastUserThatWhisperedMe() const override; void setLastUserThatWhisperedMe(const QString &user) override; + void initEventAPIs(BttvLiveUpdates *bttvLiveUpdates, + SeventvEventAPI *seventvEventAPI) override; + protected: void initializeConnection(IrcConnection *connection, ConnectionType type); std::shared_ptr createChannel(const QString &channelName); @@ -193,7 +201,7 @@ private: std::mutex connectionMutex_; - pajlada::Signals::SignalHolder connections_; + pajlada::Signals::SignalHolder signalHolder; std::mutex lastMessageMutex_; std::queue lastMessagePleb_;