Sync channels with browser (#4741)

* feat: keep channels from browser tabs alive

* chore: add changelog entry

* fix: add comment

* fix: rename key

---------

Co-authored-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
nerix 2023-08-05 14:23:26 +02:00 committed by GitHub
parent 9e2eb0dd29
commit 1438529e98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 0 deletions

View file

@ -18,6 +18,7 @@
- Minor: 7TV badges now automatically update upon changing. (#4512) - Minor: 7TV badges now automatically update upon changing. (#4512)
- Minor: Stream status requests are now batched. (#4713) - Minor: Stream status requests are now batched. (#4713)
- Minor: Added `/c2-theme-autoreload` command to automatically reload a custom theme. This is useful for when you're developing your own theme. (#4718) - Minor: Added `/c2-theme-autoreload` command to automatically reload a custom theme. This is useful for when you're developing your own theme. (#4718)
- Minor: All channels opened in browser tabs are synced when using the extension for quicker switching between tabs. (#4741)
- Minor: Show channel point redemptions without messages in usercard. (#4557) - Minor: Show channel point redemptions without messages in usercard. (#4557)
- Minor: Allow for customizing the behavior of `Right Click`ing of usernames. (#4622, #4751) - Minor: Allow for customizing the behavior of `Right Click`ing of usernames. (#4622, #4751)
- Bugfix: Increased amount of blocked users loaded from 100 to 1,000. (#4721) - Bugfix: Increased amount of blocked users loaded from 100 to 1,000. (#4721)

View file

@ -3,6 +3,7 @@
#include "Application.hpp" #include "Application.hpp"
#include "common/Literals.hpp" #include "common/Literals.hpp"
#include "common/QLogging.hpp" #include "common/QLogging.hpp"
#include "debug/AssertInGuiThread.hpp"
#include "providers/twitch/TwitchIrcServer.hpp" #include "providers/twitch/TwitchIrcServer.hpp"
#include "singletons/Paths.hpp" #include "singletons/Paths.hpp"
#include "util/IpcQueue.hpp" #include "util/IpcQueue.hpp"
@ -129,12 +130,22 @@ namespace nm::client {
} // namespace nm::client } // namespace nm::client
// SERVER // SERVER
NativeMessagingServer::NativeMessagingServer()
: thread(*this)
{
}
void NativeMessagingServer::start() void NativeMessagingServer::start()
{ {
this->thread.start(); this->thread.start();
} }
NativeMessagingServer::ReceiverThread::ReceiverThread(
NativeMessagingServer &parent)
: parent_(parent)
{
}
void NativeMessagingServer::ReceiverThread::run() void NativeMessagingServer::ReceiverThread::run()
{ {
auto [messageQueue, error] = auto [messageQueue, error] =
@ -177,6 +188,11 @@ void NativeMessagingServer::ReceiverThread::handleMessage(
this->handleDetach(root); this->handleDetach(root);
return; return;
} }
if (action == "sync")
{
this->handleSync(root);
return;
}
qCDebug(chatterinoNativeMessage) << "NM unknown action" << action; qCDebug(chatterinoNativeMessage) << "NM unknown action" << action;
} }
@ -263,6 +279,39 @@ void NativeMessagingServer::ReceiverThread::handleDetach(
} }
// NOLINTEND(readability-convert-member-functions-to-static) // NOLINTEND(readability-convert-member-functions-to-static)
void NativeMessagingServer::ReceiverThread::handleSync(const QJsonObject &root)
{
// Structure:
// { action: 'sync', twitchChannels?: string[] }
postToThread([&parent = this->parent_,
twitch = root["twitchChannels"_L1].toArray()] {
parent.syncChannels(twitch);
});
}
void NativeMessagingServer::syncChannels(const QJsonArray &twitchChannels)
{
assertInGuiThread();
auto *app = getApp();
std::vector<ChannelPtr> updated;
updated.reserve(twitchChannels.size());
for (const auto &value : twitchChannels)
{
auto name = value.toString();
if (name.isEmpty())
{
continue;
}
// the deduping is done on the extension side
updated.emplace_back(app->twitch->getOrAddChannel(name));
}
// This will destroy channels that aren't used anymore.
this->channelWarmer_ = std::move(updated);
}
Atomic<boost::optional<QString>> &nmIpcError() Atomic<boost::optional<QString>> &nmIpcError()
{ {
static Atomic<boost::optional<QString>> x; static Atomic<boost::optional<QString>> x;

View file

@ -6,10 +6,15 @@
#include <QString> #include <QString>
#include <QThread> #include <QThread>
#include <vector>
namespace chatterino { namespace chatterino {
class Application; class Application;
class Paths; class Paths;
class Channel;
using ChannelPtr = std::shared_ptr<Channel>;
void registerNmHost(Paths &paths); void registerNmHost(Paths &paths);
std::string &getNmQueueName(Paths &paths); std::string &getNmQueueName(Paths &paths);
@ -26,21 +31,40 @@ namespace nm::client {
class NativeMessagingServer final class NativeMessagingServer final
{ {
public: public:
NativeMessagingServer();
NativeMessagingServer(const NativeMessagingServer &) = delete;
NativeMessagingServer(NativeMessagingServer &&) = delete;
NativeMessagingServer &operator=(const NativeMessagingServer &) = delete;
NativeMessagingServer &operator=(NativeMessagingServer &&) = delete;
void start(); void start();
private: private:
class ReceiverThread : public QThread class ReceiverThread : public QThread
{ {
public: public:
ReceiverThread(NativeMessagingServer &parent);
void run() override; void run() override;
private: private:
void handleMessage(const QJsonObject &root); void handleMessage(const QJsonObject &root);
void handleSelect(const QJsonObject &root); void handleSelect(const QJsonObject &root);
void handleDetach(const QJsonObject &root); void handleDetach(const QJsonObject &root);
void handleSync(const QJsonObject &root);
NativeMessagingServer &parent_;
}; };
void syncChannels(const QJsonArray &twitchChannels);
ReceiverThread thread; ReceiverThread thread;
/// This vector contains all channels that are open the user's browser.
/// These channels are joined to be able to switch channels more quickly.
std::vector<ChannelPtr> channelWarmer_;
friend ReceiverThread;
}; };
} // namespace chatterino } // namespace chatterino