fixed deleting QTimer on wrong thread

This commit is contained in:
fourtf 2019-08-20 23:30:39 +02:00
parent 14222f84f2
commit 7643c0d20d
16 changed files with 64 additions and 59 deletions

View file

@ -16,12 +16,17 @@
namespace chatterino { namespace chatterino {
NetworkData::NetworkData() NetworkData::NetworkData()
: timer_(new QTimer())
{ {
timer_->setSingleShot(true);
DebugCount::increase("NetworkData"); DebugCount::increase("NetworkData");
} }
NetworkData::~NetworkData() NetworkData::~NetworkData()
{ {
this->timer_->deleteLater();
DebugCount::decrease("NetworkData"); DebugCount::decrease("NetworkData");
} }
@ -75,8 +80,8 @@ void loadUncached(const std::shared_ptr<NetworkData> &data)
if (data->hasTimeout_) if (data->hasTimeout_)
{ {
data->timer_.setSingleShot(true); data->timer_->setSingleShot(true);
data->timer_.start(); data->timer_->start();
} }
auto onUrlRequested = [data, worker]() mutable { auto onUrlRequested = [data, worker]() mutable {
@ -106,9 +111,9 @@ void loadUncached(const std::shared_ptr<NetworkData> &data)
return; return;
} }
if (data->timer_.isActive()) if (data->timer_->isActive())
{ {
QObject::connect(&data->timer_, &QTimer::timeout, worker, QObject::connect(data->timer_, &QTimer::timeout, worker,
[reply, data]() { [reply, data]() {
log("Aborted!"); log("Aborted!");
reply->abort(); reply->abort();
@ -228,7 +233,7 @@ void loadCached(const std::shared_ptr<NetworkData> &data)
}); });
} }
} }
} // namespace chatterino }
} }
void load(const std::shared_ptr<NetworkData> &data) void load(const std::shared_ptr<NetworkData> &data)

View file

@ -51,7 +51,7 @@ struct NetworkData {
// to enable the timer, the "setTimeout" function needs to be called before // to enable the timer, the "setTimeout" function needs to be called before
// execute is called // execute is called
bool hasTimeout_{}; bool hasTimeout_{};
QTimer timer_; QTimer *timer_;
QString getHash(); QString getHash();

View file

@ -49,12 +49,15 @@ NetworkRequest NetworkRequest::type(NetworkRequestType newRequestType) &&
} }
NetworkRequest NetworkRequest::caller(const QObject *caller) && NetworkRequest NetworkRequest::caller(const QObject *caller) &&
{
if (caller)
{ {
// Caller must be in gui thread // Caller must be in gui thread
assert(caller->thread() == qApp->thread()); assert(caller->thread() == qApp->thread());
this->data->caller_ = const_cast<QObject *>(caller); this->data->caller_ = const_cast<QObject *>(caller);
this->data->hasCaller_ = true; this->data->hasCaller_ = true;
}
return std::move(*this); return std::move(*this);
} }
@ -100,7 +103,7 @@ NetworkRequest NetworkRequest::header(const char *headerName,
NetworkRequest NetworkRequest::timeout(int ms) && NetworkRequest NetworkRequest::timeout(int ms) &&
{ {
this->data->hasTimeout_ = true; this->data->hasTimeout_ = true;
this->data->timer_.setInterval(ms); this->data->timer_->setInterval(ms);
return std::move(*this); return std::move(*this);
} }

View file

@ -156,7 +156,6 @@ void NotificationController::getFakeTwitchChannelLiveStatus(
QString url("https://api.twitch.tv/kraken/streams/" + roomID); QString url("https://api.twitch.tv/kraken/streams/" + roomID);
NetworkRequest::twitchRequest(url) NetworkRequest::twitchRequest(url)
.caller(QThread::currentThread())
.onSuccess([this, channelName](auto result) -> Outcome { .onSuccess([this, channelName](auto result) -> Outcome {
rapidjson::Document document = result.parseRapidJson(); rapidjson::Document document = result.parseRapidJson();
if (!document.IsObject()) if (!document.IsObject())

View file

@ -387,10 +387,10 @@ void MessageBuilder::addLink(const QString &origLink,
textColor) textColor)
->setLink(linkElement); ->setLink(linkElement);
LinkResolver::getLinkInfo(matchedLink, [weakMessage = this->weakOf(), LinkResolver::getLinkInfo(
linkMELowercase, linkMEOriginal, matchedLink, nullptr,
matchedLink](QString tooltipText, [weakMessage = this->weakOf(), linkMELowercase, linkMEOriginal,
Link originalLink) { matchedLink](QString tooltipText, Link originalLink) {
auto shared = weakMessage.lock(); auto shared = weakMessage.lock();
if (!shared) if (!shared)
{ {
@ -401,7 +401,8 @@ void MessageBuilder::addLink(const QString &origLink,
linkMELowercase->setTooltip(tooltipText); linkMELowercase->setTooltip(tooltipText);
linkMEOriginal->setTooltip(tooltipText); linkMEOriginal->setTooltip(tooltipText);
} }
if (originalLink.value != matchedLink && !originalLink.value.isEmpty()) if (originalLink.value != matchedLink &&
!originalLink.value.isEmpty())
{ {
linkMELowercase->setLink(originalLink)->updateLink(); linkMELowercase->setLink(originalLink)->updateLink();
linkMEOriginal->setLink(originalLink)->updateLink(); linkMEOriginal->setLink(originalLink)->updateLink();

View file

@ -11,7 +11,8 @@
namespace chatterino { namespace chatterino {
void LinkResolver::getLinkInfo( void LinkResolver::getLinkInfo(
const QString url, std::function<void(QString, Link)> successCallback) const QString url, QObject *caller,
std::function<void(QString, Link)> successCallback)
{ {
if (!getSettings()->linkInfoTooltip) if (!getSettings()->linkInfoTooltip)
{ {
@ -22,7 +23,7 @@ void LinkResolver::getLinkInfo(
// QTimer::singleShot(3000, [=]() { // QTimer::singleShot(3000, [=]() {
NetworkRequest(Env::get().linkResolverUrl.arg(QString::fromUtf8( NetworkRequest(Env::get().linkResolverUrl.arg(QString::fromUtf8(
QUrl::toPercentEncoding(url, "", "/:")))) QUrl::toPercentEncoding(url, "", "/:"))))
.caller(QThread::currentThread()) .caller(caller)
.timeout(30000) .timeout(30000)
.onSuccess([successCallback, url](auto result) mutable -> Outcome { .onSuccess([successCallback, url](auto result) mutable -> Outcome {
auto root = result.parseJson(); auto root = result.parseJson();

View file

@ -10,10 +10,8 @@ namespace chatterino {
class LinkResolver class LinkResolver
{ {
public: public:
static void getLinkInfo(const QString url, static void getLinkInfo(const QString url, QObject *caller,
std::function<void(QString, Link)> callback); std::function<void(QString, Link)> callback);
private:
}; };
} // namespace chatterino } // namespace chatterino

View file

@ -113,7 +113,6 @@ boost::optional<EmotePtr> BttvEmotes::emote(const EmoteName &name) const
void BttvEmotes::loadEmotes() void BttvEmotes::loadEmotes()
{ {
NetworkRequest(QString(globalEmoteApiUrl)) NetworkRequest(QString(globalEmoteApiUrl))
.caller(QThread::currentThread())
.timeout(30000) .timeout(30000)
.onSuccess([this](auto result) -> Outcome { .onSuccess([this](auto result) -> Outcome {
auto emotes = this->global_.get(); auto emotes = this->global_.get();
@ -130,7 +129,6 @@ void BttvEmotes::loadChannel(const QString &channelName,
std::function<void(EmoteMap &&)> callback) std::function<void(EmoteMap &&)> callback)
{ {
NetworkRequest(QString(bttvChannelEmoteApiUrl) + channelName) NetworkRequest(QString(bttvChannelEmoteApiUrl) + channelName)
.caller(QThread::currentThread())
.timeout(3000) .timeout(3000)
.onSuccess([callback = std::move(callback)](auto result) -> Outcome { .onSuccess([callback = std::move(callback)](auto result) -> Outcome {
auto pair = parseChannelEmotes(result.parseJson()); auto pair = parseChannelEmotes(result.parseJson());

View file

@ -37,7 +37,7 @@ void ChatterinoBadges::loadChatterinoBadges()
static QUrl url("https://fourtf.com/chatterino/badges.json"); static QUrl url("https://fourtf.com/chatterino/badges.json");
NetworkRequest(url) NetworkRequest(url)
.caller(QThread::currentThread())
.onSuccess([this](auto result) -> Outcome { .onSuccess([this](auto result) -> Outcome {
auto jsonRoot = result.parseJson(); auto jsonRoot = result.parseJson();
int index = 0; int index = 0;

View file

@ -138,7 +138,7 @@ void FfzEmotes::loadEmotes()
QString url("https://api.frankerfacez.com/v1/set/global"); QString url("https://api.frankerfacez.com/v1/set/global");
NetworkRequest(url) NetworkRequest(url)
.caller(QThread::currentThread())
.timeout(30000) .timeout(30000)
.onSuccess([this](auto result) -> Outcome { .onSuccess([this](auto result) -> Outcome {
auto emotes = this->emotes(); auto emotes = this->emotes();
@ -157,7 +157,7 @@ void FfzEmotes::loadChannel(const QString &channelName,
log("[FFZEmotes] Reload FFZ Channel Emotes for channel {}\n", channelName); log("[FFZEmotes] Reload FFZ Channel Emotes for channel {}\n", channelName);
NetworkRequest("https://api.frankerfacez.com/v1/room/" + channelName) NetworkRequest("https://api.frankerfacez.com/v1/room/" + channelName)
.caller(QThread::currentThread())
.timeout(20000) .timeout(20000)
.onSuccess([callback = std::move(callback)](auto result) -> Outcome { .onSuccess([callback = std::move(callback)](auto result) -> Outcome {
auto pair = parseChannelEmotes(result.parseJson()); auto pair = parseChannelEmotes(result.parseJson());

View file

@ -23,7 +23,7 @@ void FfzModBadge::loadCustomModBadge()
QString url = partialUrl + channelName_ + "/1"; QString url = partialUrl + channelName_ + "/1";
NetworkRequest(url) NetworkRequest(url)
.caller(QThread::currentThread())
.onSuccess([this, url](auto result) -> Outcome { .onSuccess([this, url](auto result) -> Outcome {
auto data = result.getData(); auto data = result.getData();

View file

@ -95,7 +95,7 @@ void TwitchAccount::loadIgnores()
"/blocks"); "/blocks");
NetworkRequest(url) NetworkRequest(url)
.caller(QThread::currentThread())
.authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken()) .authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken())
.onSuccess([=](auto result) -> Outcome { .onSuccess([=](auto result) -> Outcome {
auto document = result.parseRapidJson(); auto document = result.parseRapidJson();
@ -168,7 +168,7 @@ void TwitchAccount::ignoreByID(
"/blocks/" + targetUserID); "/blocks/" + targetUserID);
NetworkRequest(url, NetworkRequestType::Put) NetworkRequest(url, NetworkRequestType::Put)
.caller(QThread::currentThread())
.authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken()) .authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken())
.onError([=](int errorCode) { .onError([=](int errorCode) {
onFinished(IgnoreResult_Failed, onFinished(IgnoreResult_Failed,
@ -245,7 +245,7 @@ void TwitchAccount::unignoreByID(
"/blocks/" + targetUserID); "/blocks/" + targetUserID);
NetworkRequest(url, NetworkRequestType::Delete) NetworkRequest(url, NetworkRequestType::Delete)
.caller(QThread::currentThread())
.authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken()) .authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken())
.onError([=](int errorCode) { .onError([=](int errorCode) {
onFinished( onFinished(
@ -279,7 +279,7 @@ void TwitchAccount::checkFollow(const QString targetUserID,
"/follows/channels/" + targetUserID); "/follows/channels/" + targetUserID);
NetworkRequest(url) NetworkRequest(url)
.caller(QThread::currentThread())
.authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken()) .authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken())
.onError([=](int errorCode) { .onError([=](int errorCode) {
if (errorCode == 203) if (errorCode == 203)
@ -308,7 +308,7 @@ void TwitchAccount::followUser(const QString userID,
"/follows/channels/" + userID); "/follows/channels/" + userID);
NetworkRequest(requestUrl, NetworkRequestType::Put) NetworkRequest(requestUrl, NetworkRequestType::Put)
.caller(QThread::currentThread())
.authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken()) .authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken())
.onSuccess([successCallback](auto result) -> Outcome { .onSuccess([successCallback](auto result) -> Outcome {
// TODO: Properly check result of follow request // TODO: Properly check result of follow request
@ -326,7 +326,7 @@ void TwitchAccount::unfollowUser(const QString userID,
"/follows/channels/" + userID); "/follows/channels/" + userID);
NetworkRequest(requestUrl, NetworkRequestType::Delete) NetworkRequest(requestUrl, NetworkRequestType::Delete)
.caller(QThread::currentThread())
.authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken()) .authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken())
.onError([successCallback](int code) { .onError([successCallback](int code) {
if (code >= 200 && code <= 299) if (code >= 200 && code <= 299)
@ -368,7 +368,7 @@ void TwitchAccount::loadEmotes()
"/emotes"); "/emotes");
NetworkRequest(url) NetworkRequest(url)
.caller(QThread::currentThread())
.authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken()) .authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken())
.onError([=](int errorCode) { .onError([=](int errorCode) {
log("[TwitchAccount::loadEmotes] Error {}", errorCode); log("[TwitchAccount::loadEmotes] Error {}", errorCode);
@ -409,7 +409,7 @@ void TwitchAccount::autoModAllow(const QString msgID)
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.header("Content-Length", QByteArray::number(qba.size())) .header("Content-Length", QByteArray::number(qba.size()))
.payload(qba) .payload(qba)
.caller(QThread::currentThread())
.authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken()) .authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken())
.onError([=](int errorCode) { .onError([=](int errorCode) {
log("[TwitchAccounts::autoModAllow] Error {}", errorCode); log("[TwitchAccounts::autoModAllow] Error {}", errorCode);
@ -429,7 +429,7 @@ void TwitchAccount::autoModDeny(const QString msgID)
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.header("Content-Length", QByteArray::number(qba.size())) .header("Content-Length", QByteArray::number(qba.size()))
.payload(qba) .payload(qba)
.caller(QThread::currentThread())
.authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken()) .authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken())
.onError([=](int errorCode) { .onError([=](int errorCode) {
log("[TwitchAccounts::autoModDeny] Error {}", errorCode); log("[TwitchAccounts::autoModDeny] Error {}", errorCode);

View file

@ -16,7 +16,7 @@ void TwitchApi::findUserId(const QString user,
QString requestUrl("https://api.twitch.tv/kraken/users?login=" + user); QString requestUrl("https://api.twitch.tv/kraken/users?login=" + user);
NetworkRequest(requestUrl) NetworkRequest(requestUrl)
.caller(QThread::currentThread())
.authorizeTwitchV5(getDefaultClientID()) .authorizeTwitchV5(getDefaultClientID())
.timeout(30000) .timeout(30000)
.onSuccess([successCallback](auto result) mutable -> Outcome { .onSuccess([successCallback](auto result) mutable -> Outcome {
@ -65,7 +65,7 @@ void TwitchApi::findUserName(const QString userid,
QString requestUrl("https://api.twitch.tv/kraken/users/" + userid); QString requestUrl("https://api.twitch.tv/kraken/users/" + userid);
NetworkRequest(requestUrl) NetworkRequest(requestUrl)
.caller(QThread::currentThread())
.authorizeTwitchV5(getDefaultClientID()) .authorizeTwitchV5(getDefaultClientID())
.timeout(30000) .timeout(30000)
.onSuccess([successCallback](auto result) mutable -> Outcome { .onSuccess([successCallback](auto result) mutable -> Outcome {

View file

@ -18,7 +18,7 @@ void TwitchBadges::loadTwitchBadges()
"https://badges.twitch.tv/v1/badges/global/display?language=en"); "https://badges.twitch.tv/v1/badges/global/display?language=en");
NetworkRequest(url) NetworkRequest(url)
.caller(QThread::currentThread())
.onSuccess([this](auto result) -> Outcome { .onSuccess([this](auto result) -> Outcome {
auto root = result.parseJson(); auto root = result.parseJson();
auto badgeSets = this->badgeSets_.access(); auto badgeSets = this->badgeSets_.access();

View file

@ -502,7 +502,7 @@ void TwitchChannel::refreshLiveStatus()
// auto request = makeGetStreamRequest(roomID, QThread::currentThread()); // auto request = makeGetStreamRequest(roomID, QThread::currentThread());
NetworkRequest::twitchRequest(url) NetworkRequest::twitchRequest(url)
.caller(QThread::currentThread())
.onSuccess( .onSuccess(
[this, weak = weakOf<Channel>(this)](auto result) -> Outcome { [this, weak = weakOf<Channel>(this)](auto result) -> Outcome {
ChannelPtr shared = weak.lock(); ChannelPtr shared = weak.lock();
@ -670,7 +670,7 @@ void TwitchChannel::refreshChatters()
// get viewer list // get viewer list
NetworkRequest("https://tmi.twitch.tv/group/user/" + this->getName() + NetworkRequest("https://tmi.twitch.tv/group/user/" + this->getName() +
"/chatters") "/chatters")
.caller(QThread::currentThread())
.onSuccess( .onSuccess(
[this, weak = weakOf<Channel>(this)](auto result) -> Outcome { [this, weak = weakOf<Channel>(this)](auto result) -> Outcome {
// channel still exists? // channel still exists?
@ -694,7 +694,7 @@ void TwitchChannel::refreshBadges()
auto url = Url{"https://badges.twitch.tv/v1/badges/channels/" + auto url = Url{"https://badges.twitch.tv/v1/badges/channels/" +
this->roomId() + "/display?language=en"}; this->roomId() + "/display?language=en"};
NetworkRequest(url.string) NetworkRequest(url.string)
.caller(QThread::currentThread())
.onSuccess([this, .onSuccess([this,
weak = weakOf<Channel>(this)](auto result) -> Outcome { weak = weakOf<Channel>(this)](auto result) -> Outcome {
auto shared = weak.lock(); auto shared = weak.lock();

View file

@ -214,7 +214,7 @@ void Toasts::fetchChannelAvatar(const QString channelName,
channelName); channelName);
NetworkRequest(requestUrl) NetworkRequest(requestUrl)
.caller(QThread::currentThread())
.authorizeTwitchV5(getDefaultClientID()) .authorizeTwitchV5(getDefaultClientID())
.timeout(30000) .timeout(30000)
.onSuccess([successCallback](auto result) mutable -> Outcome { .onSuccess([successCallback](auto result) mutable -> Outcome {