added code to handle a single connection

This commit is contained in:
fourtf
2018-07-16 17:23:41 +02:00
parent e51c5c692a
commit 3b3c5d8d75
18 changed files with 114 additions and 84 deletions
+2 -2
View File
@@ -46,8 +46,8 @@ public:
friend void test(); friend void test();
[[deprecated("use getSettings() instead")]] Settings *settings = nullptr; Settings *settings = nullptr;
[[deprecated("use getPaths() instead")]] Paths *paths = nullptr; Paths *paths = nullptr;
Theme *themes = nullptr; Theme *themes = nullptr;
WindowManager *windows = nullptr; WindowManager *windows = nullptr;
+11
View File
@@ -2,12 +2,23 @@
#include "Application.hpp" #include "Application.hpp"
#include "singletons/Paths.hpp" #include "singletons/Paths.hpp"
#include "util/DebugCount.hpp"
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QFile> #include <QFile>
namespace chatterino { namespace chatterino {
NetworkData::NetworkData()
{
DebugCount::increase("NetworkData");
}
NetworkData::~NetworkData()
{
DebugCount::decrease("NetworkData");
}
QString NetworkData::getHash() QString NetworkData::getHash()
{ {
if (this->hash_.isEmpty()) { if (this->hash_.isEmpty()) {
+3
View File
@@ -13,6 +13,9 @@ namespace chatterino {
class NetworkResult; class NetworkResult;
struct NetworkData { struct NetworkData {
NetworkData();
~NetworkData();
QNetworkRequest request_; QNetworkRequest request_;
const QObject *caller_ = nullptr; const QObject *caller_ = nullptr;
bool useQuickLoadCache_{}; bool useQuickLoadCache_{};
+15 -17
View File
@@ -167,20 +167,21 @@ void NetworkRequest::doRequest()
this->timer->start(); this->timer->start();
auto onUrlRequested = [data = this->data, timer = this->timer, worker]() mutable { auto onUrlRequested = [data = this->data, timer = this->timer, worker]() mutable {
QNetworkReply *reply = nullptr; auto reply = [&]() -> QNetworkReply * {
switch (data->requestType_) { switch (data->requestType_) {
case NetworkRequestType::Get: { case NetworkRequestType::Get:
reply = NetworkManager::NaM.get(data->request_); return NetworkManager::NaM.get(data->request_);
} break;
case NetworkRequestType::Put: { case NetworkRequestType::Put:
reply = NetworkManager::NaM.put(data->request_, data->payload_); return NetworkManager::NaM.put(data->request_, data->payload_);
} break;
case NetworkRequestType::Delete: { case NetworkRequestType::Delete:
reply = NetworkManager::NaM.deleteResource(data->request_); return NetworkManager::NaM.deleteResource(data->request_);
} break;
} default:
return nullptr;
}
}();
if (reply == nullptr) { if (reply == nullptr) {
Log("Unhandled request type"); Log("Unhandled request type");
@@ -201,8 +202,6 @@ void NetworkRequest::doRequest()
data->onReplyCreated_(reply); data->onReplyCreated_(reply);
} }
bool directAction = (data->caller_ == nullptr);
auto handleReply = [data, timer, reply]() mutable { auto handleReply = [data, timer, reply]() mutable {
// TODO(pajlada): A reply was received, kill the timeout timer // TODO(pajlada): A reply was received, kill the timeout timer
if (reply->error() != QNetworkReply::NetworkError::NoError) { if (reply->error() != QNetworkReply::NetworkError::NoError) {
@@ -222,8 +221,7 @@ void NetworkRequest::doRequest()
}; };
if (data->caller_ != nullptr) { if (data->caller_ != nullptr) {
QObject::connect(worker, &NetworkWorker::doneUrl, data->caller_, QObject::connect(worker, &NetworkWorker::doneUrl, data->caller_, handleReply);
std::move(handleReply));
QObject::connect(reply, &QNetworkReply::finished, worker, [worker]() mutable { QObject::connect(reply, &QNetworkReply::finished, worker, [worker]() mutable {
emit worker->doneUrl(); emit worker->doneUrl();
@@ -231,7 +229,7 @@ void NetworkRequest::doRequest()
}); });
} else { } else {
QObject::connect(reply, &QNetworkReply::finished, worker, QObject::connect(reply, &QNetworkReply::finished, worker,
[handleReply = std::move(handleReply), worker]() mutable { [handleReply, worker]() mutable {
handleReply(); handleReply();
delete worker; delete worker;
@@ -140,7 +140,7 @@ QString CommandController::execCommand(const QString &text, ChannelPtr channel,
app->twitch.server->whispersChannel->addMessage(b.getMessage()); app->twitch.server->whispersChannel->addMessage(b.getMessage());
app->twitch.server->getWriteConnection()->sendRaw("PRIVMSG #jtv :" + text + "\r\n"); app->twitch.server->sendMessage("jtv", text);
if (getSettings()->inlineWhispers) { if (getSettings()->inlineWhispers) {
app->twitch.server->forEachChannel( app->twitch.server->forEachChannel(
+17 -21
View File
@@ -35,26 +35,18 @@ AbstractIrcServer::AbstractIrcServer()
// this->writeConnection->reconnectRequested.connect([this] { this->connect(); }); // this->writeConnection->reconnectRequested.connect([this] { this->connect(); });
} }
IrcConnection *AbstractIrcServer::getReadConnection() const
{
return this->readConnection_.get();
}
IrcConnection *AbstractIrcServer::getWriteConnection() const
{
return this->writeConnection_.get();
}
void AbstractIrcServer::connect() void AbstractIrcServer::connect()
{ {
this->disconnect(); this->disconnect();
// if (this->hasSeparateWriteConnection()) { bool separateWriteConnection = this->hasSeparateWriteConnection();
this->initializeConnection(this->writeConnection_.get(), false, true);
this->initializeConnection(this->readConnection_.get(), true, false); if (separateWriteConnection) {
// } else { this->initializeConnection(this->writeConnection_.get(), false, true);
// this->initializeConnection(this->readConnection.get(), true, true); this->initializeConnection(this->readConnection_.get(), true, false);
// } } else {
this->initializeConnection(this->readConnection_.get(), true, true);
}
// fourtf: this should be asynchronous // fourtf: this should be asynchronous
{ {
@@ -67,7 +59,6 @@ void AbstractIrcServer::connect()
continue; continue;
} }
this->writeConnection_->sendRaw("JOIN #" + chan->name);
this->readConnection_->sendRaw("JOIN #" + chan->name); this->readConnection_->sendRaw("JOIN #" + chan->name);
} }
@@ -88,13 +79,18 @@ void AbstractIrcServer::disconnect()
} }
void AbstractIrcServer::sendMessage(const QString &channelName, const QString &message) void AbstractIrcServer::sendMessage(const QString &channelName, const QString &message)
{
this->sendRawMessage("PRIVMSG #" + channelName + " :" + message);
}
void AbstractIrcServer::sendRawMessage(const QString &rawMessage)
{ {
std::lock_guard<std::mutex> locker(this->connectionMutex_); std::lock_guard<std::mutex> locker(this->connectionMutex_);
// fourtf: trim the message if it's sent from twitch chat if (this->hasSeparateWriteConnection()) {
this->writeConnection_->sendRaw(rawMessage);
if (this->writeConnection_) { } else {
this->writeConnection_->sendRaw("PRIVMSG #" + channelName + " :" + message); this->readConnection_->sendRaw(rawMessage);
} }
} }
+2 -3
View File
@@ -17,13 +17,11 @@ public:
virtual ~AbstractIrcServer() = default; virtual ~AbstractIrcServer() = default;
// connection // connection
IrcConnection *getReadConnection() const;
IrcConnection *getWriteConnection() const;
void connect(); void connect();
void disconnect(); void disconnect();
void sendMessage(const QString &channelName, const QString &message); void sendMessage(const QString &channelName, const QString &message);
void sendRawMessage(const QString &rawMessage);
// channels // channels
std::shared_ptr<Channel> getOrAddChannel(const QString &dirtyChannelName); std::shared_ptr<Channel> getOrAddChannel(const QString &dirtyChannelName);
@@ -54,6 +52,7 @@ protected:
virtual std::shared_ptr<Channel> getCustomChannel(const QString &channelName); virtual std::shared_ptr<Channel> getCustomChannel(const QString &channelName);
virtual bool hasSeparateWriteConnection() const = 0;
virtual QString cleanChannelName(const QString &dirtyChannelName); virtual QString cleanChannelName(const QString &dirtyChannelName);
QMap<QString, std::weak_ptr<Channel>> channels; QMap<QString, std::weak_ptr<Channel>> channels;
+11 -6
View File
@@ -9,18 +9,23 @@ IrcConnection::IrcConnection(QObject *parent)
this->pingTimer_.setInterval(5000); this->pingTimer_.setInterval(5000);
this->pingTimer_.start(); this->pingTimer_.start();
QObject::connect(&this->pingTimer_, &QTimer::timeout, [this] { QObject::connect(&this->pingTimer_, &QTimer::timeout, [this] {
if (!this->recentlyReceivedMessage_.load()) { if (this->isConnected()) {
this->sendRaw("PING"); if (!this->recentlyReceivedMessage_.load()) {
this->reconnectTimer_.start(); this->sendRaw("PING");
this->reconnectTimer_.start();
}
this->recentlyReceivedMessage_ = false;
} }
this->recentlyReceivedMessage_ = false;
}); });
// reconnect after x seconds without receiving a message // reconnect after x seconds without receiving a message
this->reconnectTimer_.setInterval(5000); this->reconnectTimer_.setInterval(5000);
this->reconnectTimer_.setSingleShot(true); this->reconnectTimer_.setSingleShot(true);
QObject::connect(&this->reconnectTimer_, &QTimer::timeout, QObject::connect(&this->reconnectTimer_, &QTimer::timeout, [this] {
[this] { reconnectRequested.invoke(); }); if (this->isConnected()) {
reconnectRequested.invoke();
}
});
QObject::connect(this, &Communi::IrcConnection::messageReceived, [this](Communi::IrcMessage *) { QObject::connect(this, &Communi::IrcConnection::messageReceived, [this](Communi::IrcMessage *) {
this->recentlyReceivedMessage_ = true; this->recentlyReceivedMessage_ = true;
+4 -3
View File
@@ -19,7 +19,7 @@
namespace chatterino { namespace chatterino {
TwitchChannel::TwitchChannel(const QString &channelName, Communi::IrcConnection *readConnection) TwitchChannel::TwitchChannel(const QString &channelName)
: Channel(channelName, Channel::Type::Twitch) : Channel(channelName, Channel::Type::Twitch)
, bttvEmotes_(new EmoteMap) , bttvEmotes_(new EmoteMap)
, ffzEmotes_(new EmoteMap) , ffzEmotes_(new EmoteMap)
@@ -27,7 +27,6 @@ TwitchChannel::TwitchChannel(const QString &channelName, Communi::IrcConnection
, channelUrl_("https://twitch.tv/" + name) , channelUrl_("https://twitch.tv/" + name)
, popoutPlayerUrl_("https://player.twitch.tv/?channel=" + name) , popoutPlayerUrl_("https://player.twitch.tv/?channel=" + name)
, mod_(false) , mod_(false)
, readConnection_(readConnection)
{ {
Log("[TwitchChannel:{}] Opened", this->name); Log("[TwitchChannel:{}] Opened", this->name);
@@ -420,7 +419,9 @@ bool TwitchChannel::parseRecentMessages(const QJsonObject &jsonRoot)
for (const auto jsonMessage : jsonMessages) { for (const auto jsonMessage : jsonMessages) {
auto content = jsonMessage.toString().toUtf8(); auto content = jsonMessage.toString().toUtf8();
auto message = Communi::IrcMessage::fromData(content, this->readConnection_); // passing nullptr as the channel makes the message invalid but we don't check for that
// anyways
auto message = Communi::IrcMessage::fromData(content, nullptr);
auto privMsg = dynamic_cast<Communi::IrcPrivateMessage *>(message); auto privMsg = dynamic_cast<Communi::IrcPrivateMessage *>(message);
assert(privMsg); assert(privMsg);
+1 -2
View File
@@ -86,7 +86,7 @@ private:
QString localizedName; QString localizedName;
}; };
explicit TwitchChannel(const QString &channelName, Communi::IrcConnection *readConnection); explicit TwitchChannel(const QString &channelName);
// Methods // Methods
void refreshLiveStatus(); void refreshLiveStatus();
@@ -124,7 +124,6 @@ private:
QObject lifetimeGuard_; QObject lifetimeGuard_;
QTimer liveStatusTimer_; QTimer liveStatusTimer_;
QTimer chattersListTimer_; QTimer chattersListTimer_;
Communi::IrcConnection *readConnection_ = nullptr;
friend class TwitchServer; friend class TwitchServer;
}; };
+14 -5
View File
@@ -28,6 +28,9 @@ TwitchServer::TwitchServer()
qDebug() << "init TwitchServer"; qDebug() << "init TwitchServer";
this->pubsub = new PubSub; this->pubsub = new PubSub;
getSettings()->twitchSeperateWriteConnection.connect([this](auto, auto) { this->connect(); },
this->signalHolder_, false);
} }
void TwitchServer::initialize(Application &app) void TwitchServer::initialize(Application &app)
@@ -42,12 +45,13 @@ void TwitchServer::initializeConnection(IrcConnection *connection, bool isRead,
{ {
assert(this->app); assert(this->app);
this->singleConnection_ = isRead == isWrite;
std::shared_ptr<TwitchAccount> account = getApp()->accounts->twitch.getCurrent(); std::shared_ptr<TwitchAccount> account = getApp()->accounts->twitch.getCurrent();
qDebug() << "logging in as" << account->getUserName(); qDebug() << "logging in as" << account->getUserName();
QString username = account->getUserName(); QString username = account->getUserName();
// QString oauthClient = account->getOAuthClient();
QString oauthToken = account->getOAuthToken(); QString oauthToken = account->getOAuthToken();
if (!oauthToken.startsWith("oauth:")) { if (!oauthToken.startsWith("oauth:")) {
@@ -60,9 +64,6 @@ void TwitchServer::initializeConnection(IrcConnection *connection, bool isRead,
if (!account->isAnon()) { if (!account->isAnon()) {
connection->setPassword(oauthToken); connection->setPassword(oauthToken);
// fourtf: ignored users
// this->refreshIgnoredUsers(username, oauthClient, oauthToken);
} }
connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/membership")); connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/membership"));
@@ -75,7 +76,7 @@ void TwitchServer::initializeConnection(IrcConnection *connection, bool isRead,
std::shared_ptr<Channel> TwitchServer::createChannel(const QString &channelName) std::shared_ptr<Channel> TwitchServer::createChannel(const QString &channelName)
{ {
TwitchChannel *channel = new TwitchChannel(channelName, this->getReadConnection()); TwitchChannel *channel = new TwitchChannel(channelName);
channel->sendMessageSignal.connect([this, channel](auto &chan, auto &msg, bool &sent) { channel->sendMessageSignal.connect([this, channel](auto &chan, auto &msg, bool &sent) {
this->onMessageSendRequested(channel, msg, sent); this->onMessageSendRequested(channel, msg, sent);
@@ -91,6 +92,8 @@ void TwitchServer::privateMessageReceived(Communi::IrcPrivateMessage *message)
void TwitchServer::messageReceived(Communi::IrcMessage *message) void TwitchServer::messageReceived(Communi::IrcMessage *message)
{ {
qDebug() << message->toData();
// this->readConnection // this->readConnection
if (message->type() == Communi::IrcMessage::Type::Private) { if (message->type() == Communi::IrcMessage::Type::Private) {
// We already have a handler for private messages // We already have a handler for private messages
@@ -179,6 +182,12 @@ QString TwitchServer::cleanChannelName(const QString &dirtyChannelName)
return dirtyChannelName.toLower(); return dirtyChannelName.toLower();
} }
bool TwitchServer::hasSeparateWriteConnection() const
{
return true;
// return getSettings()->twitchSeperateWriteConnection;
}
void TwitchServer::onMessageSendRequested(TwitchChannel *channel, const QString &message, void TwitchServer::onMessageSendRequested(TwitchChannel *channel, const QString &message,
bool &sent) bool &sent)
{ {
+13 -8
View File
@@ -22,7 +22,6 @@ public:
virtual void initialize(Application &app) override; virtual void initialize(Application &app) override;
// fourtf: ugh
void forEachChannelAndSpecialChannels(std::function<void(ChannelPtr)> func); void forEachChannelAndSpecialChannels(std::function<void(ChannelPtr)> func);
std::shared_ptr<Channel> getChannelOrEmptyByID(const QString &channelID); std::shared_ptr<Channel> getChannelOrEmptyByID(const QString &channelID);
@@ -36,16 +35,18 @@ public:
PubSub *pubsub; PubSub *pubsub;
protected: protected:
void initializeConnection(IrcConnection *connection, bool isRead, bool isWrite) override; virtual void initializeConnection(IrcConnection *connection, bool isRead,
std::shared_ptr<Channel> createChannel(const QString &channelName) override; bool isWrite) override;
virtual std::shared_ptr<Channel> createChannel(const QString &channelName) override;
void privateMessageReceived(Communi::IrcPrivateMessage *message) override; virtual void privateMessageReceived(Communi::IrcPrivateMessage *message) override;
void messageReceived(Communi::IrcMessage *message) override; virtual void messageReceived(Communi::IrcMessage *message) override;
void writeConnectionMessageReceived(Communi::IrcMessage *message) override; virtual void writeConnectionMessageReceived(Communi::IrcMessage *message) override;
std::shared_ptr<Channel> getCustomChannel(const QString &channelname) override; virtual std::shared_ptr<Channel> getCustomChannel(const QString &channelname) override;
QString cleanChannelName(const QString &dirtyChannelName) override; virtual QString cleanChannelName(const QString &dirtyChannelName) override;
virtual bool hasSeparateWriteConnection() const override;
private: private:
void onMessageSendRequested(TwitchChannel *channel, const QString &message, bool &sent); void onMessageSendRequested(TwitchChannel *channel, const QString &message, bool &sent);
@@ -57,6 +58,10 @@ private:
std::queue<std::chrono::steady_clock::time_point> lastMessageMod_; std::queue<std::chrono::steady_clock::time_point> lastMessageMod_;
std::chrono::steady_clock::time_point lastErrorTimeSpeed_; std::chrono::steady_clock::time_point lastErrorTimeSpeed_;
std::chrono::steady_clock::time_point lastErrorTimeAmount_; std::chrono::steady_clock::time_point lastErrorTimeAmount_;
bool singleConnection_ = false;
pajlada::Signals::SignalHolder signalHolder_;
}; };
} // namespace chatterino } // namespace chatterino
+2
View File
@@ -52,6 +52,8 @@ public:
BoolSetting showJoins = {"/behaviour/showJoins", false}; BoolSetting showJoins = {"/behaviour/showJoins", false};
BoolSetting showParts = {"/behaviour/showParts", false}; BoolSetting showParts = {"/behaviour/showParts", false};
FloatSetting mouseScrollMultiplier = {"/behaviour/mouseScrollMultiplier", 1.0}; FloatSetting mouseScrollMultiplier = {"/behaviour/mouseScrollMultiplier", 1.0};
// BoolSetting twitchSeperateWriteConnection = {"/behaviour/twitchSeperateWriteConnection",
// false};
// Auto-completion // Auto-completion
BoolSetting onlyFetchChattersForSmallerStreamers = { BoolSetting onlyFetchChattersForSmallerStreamers = {
+1 -2
View File
@@ -2,7 +2,6 @@
namespace chatterino { namespace chatterino {
QMap<QString, int64_t> DebugCount::counts_; UniqueAccess<QMap<QString, int64_t>> DebugCount::counts_;
std::mutex DebugCount::mut_;
} // namespace chatterino } // namespace chatterino
+13 -12
View File
@@ -1,5 +1,7 @@
#pragma once #pragma once
#include <common/UniqueAccess.hpp>
#include <mutex> #include <mutex>
#include <typeinfo> #include <typeinfo>
@@ -13,11 +15,11 @@ class DebugCount
public: public:
static void increase(const QString &name) static void increase(const QString &name)
{ {
std::lock_guard<std::mutex> lock(mut_); auto counts = counts_.access();
auto it = counts_.find(name); auto it = counts->find(name);
if (it == counts_.end()) { if (it == counts->end()) {
counts_.insert(name, 1); counts->insert(name, 1);
} else { } else {
reinterpret_cast<int64_t &>(it.value())++; reinterpret_cast<int64_t &>(it.value())++;
} }
@@ -25,11 +27,11 @@ public:
static void decrease(const QString &name) static void decrease(const QString &name)
{ {
std::lock_guard<std::mutex> lock(mut_); auto counts = counts_.access();
auto it = counts_.find(name); auto it = counts->find(name);
if (it == counts_.end()) { if (it == counts->end()) {
counts_.insert(name, -1); counts->insert(name, -1);
} else { } else {
reinterpret_cast<int64_t &>(it.value())--; reinterpret_cast<int64_t &>(it.value())--;
} }
@@ -37,10 +39,10 @@ public:
static QString getDebugText() static QString getDebugText()
{ {
std::lock_guard<std::mutex> lock(mut_); auto counts = counts_.access();
QString text; QString text;
for (auto it = counts_.begin(); it != counts_.end(); it++) { for (auto it = counts->begin(); it != counts->end(); it++) {
text += it.key() + ": " + QString::number(it.value()) + "\n"; text += it.key() + ": " + QString::number(it.value()) + "\n";
} }
return text; return text;
@@ -52,8 +54,7 @@ public:
} }
private: private:
static QMap<QString, int64_t> counts_; static UniqueAccess<QMap<QString, int64_t>> counts_;
static std::mutex mut_;
}; };
} // namespace chatterino } // namespace chatterino
+1 -1
View File
@@ -15,7 +15,7 @@ DebugPopup::DebugPopup()
auto *text = new QLabel(this); auto *text = new QLabel(this);
auto *timer = new QTimer(this); auto *timer = new QTimer(this);
timer->setInterval(1000); timer->setInterval(300);
QObject::connect(timer, &QTimer::timeout, QObject::connect(timer, &QTimer::timeout,
[text] { text->setText(DebugCount::getDebugText()); }); [text] { text->setText(DebugCount::getDebugText()); });
timer->start(); timer->start();
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once #pragma once
#include <QWindow> #include <QWidget>
namespace chatterino { namespace chatterino {
+2
View File
@@ -24,6 +24,8 @@ FeelPage::FeelPage()
auto layout = layoutCreator.setLayoutType<QVBoxLayout>(); auto layout = layoutCreator.setLayoutType<QVBoxLayout>();
// layout.append(this->createCheckBox("Use a seperate write connection.",
// getSettings()->twitchSeperateWriteConnection));
layout.append(this->createCheckBox(SCROLL_SMOOTH, getSettings()->enableSmoothScrolling)); layout.append(this->createCheckBox(SCROLL_SMOOTH, getSettings()->enableSmoothScrolling));
layout.append( layout.append(
this->createCheckBox(SCROLL_NEWMSG, getSettings()->enableSmoothScrollingNewMessages)); this->createCheckBox(SCROLL_NEWMSG, getSettings()->enableSmoothScrollingNewMessages));