From 13d1fab30391cb0e6b813643e8a484d0577f9e84 Mon Sep 17 00:00:00 2001 From: fourtf Date: Sat, 14 Sep 2019 20:45:01 +0200 Subject: [PATCH] credentials are now loaded when needed --- src/Application.cpp | 3 +- src/common/Credentials.cpp | 3 +- src/common/Credentials.hpp | 2 +- src/providers/irc/AbstractIrcServer.cpp | 36 ++++++++++++------- src/providers/irc/AbstractIrcServer.hpp | 8 +++-- src/providers/irc/Irc2.cpp | 32 +++++++++-------- src/providers/irc/Irc2.hpp | 5 ++- src/providers/irc/IrcChannel2.cpp | 1 + src/providers/irc/IrcServer.cpp | 38 ++++++++++++--------- src/providers/irc/IrcServer.hpp | 4 +-- src/providers/twitch/TwitchServer.cpp | 8 ++--- src/providers/twitch/TwitchServer.hpp | 5 ++- src/util/QObjectRef.hpp | 5 +-- src/widgets/dialogs/IrcConnectionEditor.cpp | 7 ++-- src/widgets/dialogs/IrcConnectionEditor.ui | 6 +++- 15 files changed, 100 insertions(+), 63 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index bfa03bfe2..4b17def9e 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -79,6 +79,8 @@ void Application::initialize(Settings &settings, Paths &paths) assert(isAppInitialized == false); isAppInitialized = true; + Irc::getInstance().load(); + for (auto &singleton : this->singletons_) { singleton->initialize(settings, paths); @@ -98,7 +100,6 @@ int Application::run(QApplication &qtApp) assert(isAppInitialized); this->twitch.server->connect(); - Irc::getInstance().load(); this->windows->getMainWindow().show(); diff --git a/src/common/Credentials.cpp b/src/common/Credentials.cpp index fb5e5f983..37727de6d 100644 --- a/src/common/Credentials.cpp +++ b/src/common/Credentials.cpp @@ -86,6 +86,7 @@ Credentials::Credentials() } void Credentials::get(const QString &provider, const QString &name_, + QObject *receiver, std::function &&onLoaded) { assertInGuiThread(); @@ -97,7 +98,7 @@ void Credentials::get(const QString &provider, const QString &name_, auto job = new QKeychain::ReadPasswordJob("chatterino"); job->setAutoDelete(true); job->setKey(name); - QObject::connect(job, &QKeychain::Job::finished, qApp, + QObject::connect(job, &QKeychain::Job::finished, receiver, [job, onLoaded = std::move(onLoaded)](auto) mutable { onLoaded(job->textData()); }, diff --git a/src/common/Credentials.hpp b/src/common/Credentials.hpp index d8dd9098b..b71ed6cd2 100644 --- a/src/common/Credentials.hpp +++ b/src/common/Credentials.hpp @@ -10,7 +10,7 @@ class Credentials public: static Credentials &getInstance(); - void get(const QString &provider, const QString &name, + void get(const QString &provider, const QString &name, QObject *receiver, std::function &&onLoaded); void set(const QString &provider, const QString &name, const QString &credential); diff --git a/src/providers/irc/AbstractIrcServer.cpp b/src/providers/irc/AbstractIrcServer.cpp index fa8de283b..31a7688f4 100644 --- a/src/providers/irc/AbstractIrcServer.cpp +++ b/src/providers/irc/AbstractIrcServer.cpp @@ -78,19 +78,26 @@ void AbstractIrcServer::connect() if (this->hasSeparateWriteConnection()) { - this->initializeConnection(this->writeConnection_.get(), false, true); - this->initializeConnection(this->readConnection_.get(), true, false); + this->initializeConnection(this->writeConnection_.get(), Write); + this->initializeConnection(this->readConnection_.get(), Read); } else { - this->initializeConnection(this->readConnection_.get(), true, true); + this->initializeConnection(this->readConnection_.get(), Both); } +} - // fourtf: this should be asynchronous +void AbstractIrcServer::open(ConnectionType type) +{ + std::lock_guard lock1(this->connectionMutex_); + std::lock_guard lock2(this->channelMutex); + + if (type == Write) + { + this->writeConnection_->open(); + } + if (type & Read) { - std::lock_guard lock1(this->connectionMutex_); - std::lock_guard lock2(this->channelMutex); - for (std::weak_ptr &weak : this->channels.values()) { if (auto channel = weak.lock()) @@ -98,11 +105,6 @@ void AbstractIrcServer::connect() this->readConnection_->sendRaw("JOIN #" + channel->getName()); } } - - if (this->hasSeparateWriteConnection()) - { - this->writeConnection_->open(); - } this->readConnection_->open(); } } @@ -254,6 +256,16 @@ void AbstractIrcServer::onReadConnected(IrcConnection *connection) std::lock_guard lock(this->channelMutex); + // join channels + for (auto &&weak : this->channels) + { + if (auto channel = weak.lock()) + { + connection->sendRaw("JOIN #" + channel->getName()); + } + } + + // connected/disconnected message auto connectedMsg = makeSystemMessage("connected"); connectedMsg->flags.set(MessageFlag::ConnectedMessage); auto reconnected = makeSystemMessage("reconnected"); diff --git a/src/providers/irc/AbstractIrcServer.hpp b/src/providers/irc/AbstractIrcServer.hpp index 23f22a407..5f1145519 100644 --- a/src/providers/irc/AbstractIrcServer.hpp +++ b/src/providers/irc/AbstractIrcServer.hpp @@ -17,6 +17,8 @@ using ChannelPtr = std::shared_ptr; class AbstractIrcServer : public QObject { public: + enum ConnectionType { Read = 1, Write = 2, Both = 3 }; + virtual ~AbstractIrcServer() = default; // connection @@ -43,8 +45,8 @@ public: protected: AbstractIrcServer(); - virtual void initializeConnection(IrcConnection *connection, bool isRead, - bool isWrite) = 0; + virtual void initializeConnection(IrcConnection *connection, + ConnectionType type) = 0; virtual std::shared_ptr createChannel( const QString &channelName) = 0; @@ -63,6 +65,8 @@ protected: virtual bool hasSeparateWriteConnection() const = 0; virtual QString cleanChannelName(const QString &dirtyChannelName); + void open(ConnectionType type); + QMap> channels; std::mutex channelMutex; diff --git a/src/providers/irc/Irc2.cpp b/src/providers/irc/Irc2.cpp index 39e1bb9cc..9f0a746e9 100644 --- a/src/providers/irc/Irc2.cpp +++ b/src/providers/irc/Irc2.cpp @@ -38,7 +38,6 @@ namespace { row[3]->data(Qt::EditRole).toString(), // user row[4]->data(Qt::EditRole).toString(), // nick row[5]->data(Qt::EditRole).toString(), // real - original.password, // password original.connectCommands, // connectCommands original.id, // id }; @@ -70,6 +69,18 @@ inline QString getCredentialName(const IrcServerData &data) escape(data.host); } +void IrcServerData::getPassword( + QObject *receiver, std::function &&onLoaded) const +{ + Credentials::getInstance().get("irc", getCredentialName(*this), receiver, + std::move(onLoaded)); +} + +void IrcServerData::setPassword(const QString &password) +{ + Credentials::getInstance().set("irc", getCredentialName(*this), password); +} + Irc::Irc() { this->connections.itemInserted.connect([this](auto &&args) { @@ -99,10 +110,6 @@ Irc::Irc() this->servers_.emplace(args.item.id, std::make_unique(args.item)); } - - // store password - Credentials::getInstance().set("irc", getCredentialName(args.item), - args.item.password); }); this->connections.itemRemoved.connect([this](auto &&args) { @@ -217,6 +224,8 @@ void Irc::load() file.open(QIODevice::ReadOnly); auto object = QJsonDocument::fromJson(file.readAll()).object(); + std::unordered_set ids; + // load servers for (auto server : object.value("servers").toArray()) { @@ -233,18 +242,11 @@ void Irc::load() data.id = obj.value("id").toInt(data.id); // duplicate id's are not allowed :( - if (this->abandonedChannels_.find(data.id) == - this->abandonedChannels_.end()) + if (ids.find(data.id) == ids.end()) { - // insert element - this->abandonedChannels_[data.id]; + ids.insert(data.id); - Credentials::getInstance().get( - "irc", getCredentialName(data), - [=](const QString &password) mutable { - data.password = password; - this->connections.appendItem(data); - }); + this->connections.appendItem(data); } } } diff --git a/src/providers/irc/Irc2.hpp b/src/providers/irc/Irc2.hpp index a256f47d8..639c1bd2f 100644 --- a/src/providers/irc/Irc2.hpp +++ b/src/providers/irc/Irc2.hpp @@ -22,7 +22,10 @@ struct IrcServerData { QString real; // IrcAuthType authType = Anonymous; - QString password; + void getPassword(QObject *receiver, + std::function &&onLoaded) const; + void setPassword(const QString &password); + QStringList connectCommands; int id; diff --git a/src/providers/irc/IrcChannel2.cpp b/src/providers/irc/IrcChannel2.cpp index 6ccf681e1..d19af8b50 100644 --- a/src/providers/irc/IrcChannel2.cpp +++ b/src/providers/irc/IrcChannel2.cpp @@ -20,6 +20,7 @@ void IrcChannel::sendMessage(const QString &message) this->server()->sendMessage(this->getName(), message); MessageBuilder builder; + builder.emplace(); builder.emplace(this->server()->nick() + ":", MessageElementFlag::Username); builder.emplace(message, MessageElementFlag::Text); diff --git a/src/providers/irc/IrcServer.cpp b/src/providers/irc/IrcServer.cpp index ac8e0f88f..9692698c1 100644 --- a/src/providers/irc/IrcServer.cpp +++ b/src/providers/irc/IrcServer.cpp @@ -5,6 +5,7 @@ #include "messages/MessageBuilder.hpp" #include "providers/irc/Irc2.hpp" #include "providers/irc/IrcChannel2.hpp" +#include "util/QObjectRef.hpp" namespace chatterino { @@ -44,13 +45,13 @@ const QString &IrcServer::user() const QString &IrcServer::nick() { - return this->data_->nick; + return this->data_->nick.isEmpty() ? this->data_->user : this->data_->nick; } -void IrcServer::initializeConnection(IrcConnection *connection, bool isRead, - bool isWrite) +void IrcServer::initializeConnection(IrcConnection *connection, + ConnectionType type) { - assert(isRead && isWrite); + assert(type == Both); connection->setSecure(this->data_->ssl); connection->setHost(this->data_->host); @@ -61,7 +62,18 @@ void IrcServer::initializeConnection(IrcConnection *connection, bool isRead, : this->data_->nick); connection->setRealName(this->data_->real.isEmpty() ? this->data_->user : this->data_->nick); - connection->setPassword(this->data_->password); + + this->data_->getPassword( + this, [conn = new QObjectRef(connection) /* can't copy */, + this](const QString &password) mutable { + if (*conn) + { + (*conn)->setPassword(password); + this->open(Both); + } + + delete conn; + }); } std::shared_ptr IrcServer::createChannel(const QString &channelName) @@ -76,22 +88,16 @@ bool IrcServer::hasSeparateWriteConnection() const void IrcServer::onReadConnected(IrcConnection *connection) { - AbstractIrcServer::onReadConnected(connection); - - std::lock_guard lock(this->channelMutex); - - for (auto &&command : this->data_->connectCommands) { - connection->sendRaw(command + "\r\n"); - } + std::lock_guard lock(this->channelMutex); - for (auto &&weak : this->channels) - { - if (auto channel = weak.lock()) + for (auto &&command : this->data_->connectCommands) { - connection->sendRaw("JOIN #" + channel->getName()); + connection->sendRaw(command + "\r\n"); } } + + AbstractIrcServer::onReadConnected(connection); } void IrcServer::privateMessageReceived(Communi::IrcPrivateMessage *message) diff --git a/src/providers/irc/IrcServer.hpp b/src/providers/irc/IrcServer.hpp index 71deb9081..94419f622 100644 --- a/src/providers/irc/IrcServer.hpp +++ b/src/providers/irc/IrcServer.hpp @@ -21,8 +21,8 @@ public: // AbstractIrcServer interface protected: - void initializeConnection(IrcConnection *connection, bool isRead, - bool isWrite) override; + void initializeConnection(IrcConnection *connection, + ConnectionType type) override; std::shared_ptr createChannel(const QString &channelName) override; bool hasSeparateWriteConnection() const override; diff --git a/src/providers/twitch/TwitchServer.cpp b/src/providers/twitch/TwitchServer.cpp index fa1b158ac..ff6c1c9bb 100644 --- a/src/providers/twitch/TwitchServer.cpp +++ b/src/providers/twitch/TwitchServer.cpp @@ -63,11 +63,9 @@ void TwitchServer::initialize(Settings &settings, Paths &paths) this->ffz.loadEmotes(); } -void TwitchServer::initializeConnection(IrcConnection *connection, bool isRead, - bool isWrite) +void TwitchServer::initializeConnection(IrcConnection *connection, + ConnectionType type) { - this->singleConnection_ = isRead == isWrite; - std::shared_ptr account = getApp()->accounts->twitch.getCurrent(); @@ -97,6 +95,8 @@ void TwitchServer::initializeConnection(IrcConnection *connection, bool isRead, // SSL enabled: irc://irc.chat.twitch.tv:6697 connection->setHost("irc.chat.twitch.tv"); connection->setPort(6697); + + this->open(type); } std::shared_ptr TwitchServer::createChannel(const QString &channelName) diff --git a/src/providers/twitch/TwitchServer.hpp b/src/providers/twitch/TwitchServer.hpp index e0adcf6ef..c14347f4a 100644 --- a/src/providers/twitch/TwitchServer.hpp +++ b/src/providers/twitch/TwitchServer.hpp @@ -44,8 +44,8 @@ public: const FfzEmotes &getFfzEmotes() const; protected: - virtual void initializeConnection(IrcConnection *connection, bool isRead, - bool isWrite) override; + virtual void initializeConnection(IrcConnection *connection, + ConnectionType type) override; virtual std::shared_ptr createChannel( const QString &channelName) override; @@ -75,7 +75,6 @@ private: std::chrono::steady_clock::time_point lastErrorTimeSpeed_; std::chrono::steady_clock::time_point lastErrorTimeAmount_; - bool singleConnection_ = false; TwitchBadges twitchBadges; BttvEmotes bttv; FfzEmotes ffz; diff --git a/src/util/QObjectRef.hpp b/src/util/QObjectRef.hpp index cf8ad69ee..4a15545d1 100644 --- a/src/util/QObjectRef.hpp +++ b/src/util/QObjectRef.hpp @@ -62,8 +62,9 @@ private: if (other) { this->conn_ = - QObject::connect(other, &QObject::destroyed, - [this](QObject *) { this->set(nullptr); }); + QObject::connect(other, &QObject::destroyed, qApp, + [this](QObject *) { this->set(nullptr); }, + Qt::DirectConnection); } this->t_ = other; diff --git a/src/widgets/dialogs/IrcConnectionEditor.cpp b/src/widgets/dialogs/IrcConnectionEditor.cpp index dfa13dad8..53f2cd19f 100644 --- a/src/widgets/dialogs/IrcConnectionEditor.cpp +++ b/src/widgets/dialogs/IrcConnectionEditor.cpp @@ -28,7 +28,10 @@ IrcConnectionEditor::IrcConnectionEditor(const IrcServerData &data, bool isAdd, this->ui_->realNameLineEdit->setText(data.real); this->ui_->connectCommandsEditor->setPlainText( data.connectCommands.join('\n')); - this->ui_->passwordLineEdit->setText(data.password); + + data.getPassword(this, [this](const QString &password) { + this->ui_->passwordLineEdit->setText(password); + }); QFont font("Monospace"); font.setStyleHint(QFont::TypeWriter); @@ -51,7 +54,7 @@ IrcServerData IrcConnectionEditor::data() data.real = this->ui_->realNameLineEdit->text(); data.connectCommands = this->ui_->connectCommandsEditor->toPlainText().split('\n'); - data.password = this->ui_->passwordLineEdit->text(); + data.setPassword(this->ui_->passwordLineEdit->text()); return data; } diff --git a/src/widgets/dialogs/IrcConnectionEditor.ui b/src/widgets/dialogs/IrcConnectionEditor.ui index df79f6d31..db1c6124f 100644 --- a/src/widgets/dialogs/IrcConnectionEditor.ui +++ b/src/widgets/dialogs/IrcConnectionEditor.ui @@ -158,7 +158,11 @@ - <html><head/><body><p>Send IRC commands</p><p>on connect:</p></body></html> + Send IRC commands +on connect: + + + Qt::PlainText