mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
test code
This commit is contained in:
parent
66e99fd36f
commit
03ff2205fa
17 changed files with 397 additions and 221 deletions
|
@ -162,7 +162,8 @@ SOURCES += \
|
|||
src/widgets/settingspages/logspage.cpp \
|
||||
src/widgets/basewindow.cpp \
|
||||
src/singletons/helper/moderationaction.cpp \
|
||||
src/widgets/streamview.cpp
|
||||
src/widgets/streamview.cpp \
|
||||
src/util/networkrequest.cpp
|
||||
|
||||
HEADERS += \
|
||||
src/precompiled_header.hpp \
|
||||
|
@ -262,7 +263,10 @@ HEADERS += \
|
|||
src/widgets/settingspages/logspage.hpp \
|
||||
src/widgets/basewindow.hpp \
|
||||
src/singletons/helper/moderationaction.hpp \
|
||||
src/widgets/streamview.hpp
|
||||
src/widgets/streamview.hpp \
|
||||
src/util/networkrequest.hpp \
|
||||
src/util/networkworker.hpp \
|
||||
src/util/networkrequester.hpp
|
||||
|
||||
RESOURCES += \
|
||||
resources/resources.qrc
|
||||
|
|
|
@ -47,9 +47,10 @@ void Image::loadImage()
|
|||
{
|
||||
util::NetworkRequest req(this->getUrl());
|
||||
req.setCaller(this);
|
||||
req.get([lli = this](QNetworkReply * reply) {
|
||||
QByteArray array = reply->readAll();
|
||||
QBuffer buffer(&array);
|
||||
req.setUseQuickLoadCache(true);
|
||||
req.get([lli = this](QByteArray bytes) {
|
||||
QByteArray copy = QByteArray::fromRawData(bytes.constData(), bytes.length());
|
||||
QBuffer buffer(©);
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
|
||||
QImage image;
|
||||
|
@ -63,7 +64,7 @@ void Image::loadImage()
|
|||
|
||||
if (first) {
|
||||
first = false;
|
||||
lli->currentPixmap = pixmap;
|
||||
lli->loadedPixmap = pixmap;
|
||||
}
|
||||
|
||||
chatterino::messages::Image::FrameData data;
|
||||
|
@ -78,6 +79,10 @@ void Image::loadImage()
|
|||
lli->animated = true;
|
||||
}
|
||||
|
||||
lli->currentPixmap = lli->loadedPixmap;
|
||||
|
||||
lli->isLoaded = true;
|
||||
|
||||
singletons::EmoteManager::getInstance().incGeneration();
|
||||
|
||||
singletons::WindowManager::getInstance().layoutVisibleChatWidgets();
|
||||
|
@ -91,7 +96,7 @@ void Image::loadImage()
|
|||
|
||||
void Image::gifUpdateTimout()
|
||||
{
|
||||
if (animated) {
|
||||
if (this->animated) {
|
||||
this->currentFrameOffset += GIF_FRAME_LENGTH;
|
||||
|
||||
while (true) {
|
||||
|
@ -112,9 +117,16 @@ const QPixmap *Image::getPixmap()
|
|||
if (!this->isLoading) {
|
||||
this->isLoading = true;
|
||||
|
||||
loadImage();
|
||||
this->loadImage();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (this->isLoaded) {
|
||||
return this->currentPixmap;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
return this->currentPixmap;
|
||||
}
|
||||
|
||||
qreal Image::getScale() const
|
||||
|
@ -157,6 +169,7 @@ int Image::getWidth() const
|
|||
if (this->currentPixmap == nullptr) {
|
||||
return 16;
|
||||
}
|
||||
|
||||
return this->currentPixmap->width();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
namespace chatterino {
|
||||
namespace messages {
|
||||
|
||||
|
@ -41,6 +43,7 @@ private:
|
|||
};
|
||||
|
||||
QPixmap *currentPixmap;
|
||||
QPixmap *loadedPixmap;
|
||||
std::vector<FrameData> allFrames;
|
||||
int currentFrame = 0;
|
||||
int currentFrameOffset = 0;
|
||||
|
@ -53,7 +56,8 @@ private:
|
|||
bool ishat;
|
||||
qreal scale;
|
||||
|
||||
bool isLoading;
|
||||
bool isLoading = false;
|
||||
std::atomic<bool> isLoaded{false};
|
||||
|
||||
void loadImage();
|
||||
void gifUpdateTimout();
|
||||
|
|
|
@ -79,6 +79,10 @@ int ImageLayoutElement::getSelectionIndexCount()
|
|||
|
||||
void ImageLayoutElement::paint(QPainter &painter)
|
||||
{
|
||||
if (this->image == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QPixmap *pixmap = this->image->getPixmap();
|
||||
|
||||
if (pixmap != nullptr && !this->image->isAnimated()) {
|
||||
|
@ -89,12 +93,18 @@ void ImageLayoutElement::paint(QPainter &painter)
|
|||
|
||||
void ImageLayoutElement::paintAnimated(QPainter &painter, int yOffset)
|
||||
{
|
||||
if (this->image == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->image->isAnimated()) {
|
||||
if (this->image->getPixmap() != nullptr) {
|
||||
auto pixmap = this->image->getPixmap();
|
||||
|
||||
if (pixmap != nullptr) {
|
||||
// fourtf: make it use qreal values
|
||||
QRect rect = this->getRect();
|
||||
rect.moveTop(rect.y() + yOffset);
|
||||
painter.drawPixmap(QRectF(rect), *this->image->getPixmap(), QRectF());
|
||||
painter.drawPixmap(QRectF(rect), *pixmap, QRectF());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,8 +121,8 @@ public:
|
|||
newChunks->at(0) = newFirstChunk;
|
||||
|
||||
this->chunks = newChunks;
|
||||
qDebug() << acceptedItems.size();
|
||||
qDebug() << this->chunks->at(0)->size();
|
||||
// qDebug() << acceptedItems.size();
|
||||
// qDebug() << this->chunks->at(0)->size();
|
||||
|
||||
if (this->chunks->size() == 1) {
|
||||
this->lastChunkEnd += offset;
|
||||
|
|
|
@ -237,7 +237,7 @@ TwitchModerationElement::TwitchModerationElement()
|
|||
void TwitchModerationElement::addToContainer(MessageLayoutContainer &container,
|
||||
MessageElement::Flags _flags)
|
||||
{
|
||||
qDebug() << _flags;
|
||||
// qDebug() << _flags;
|
||||
|
||||
if (_flags & MessageElement::ModeratorTools) {
|
||||
QSize size((int)(container.scale * 16), (int)(container.scale * 16));
|
||||
|
|
|
@ -142,8 +142,7 @@ void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName,
|
|||
link = link.replace("{{id}}", id).replace("{{image}}", "1x");
|
||||
|
||||
auto emote = this->getBTTVChannelEmoteFromCaches().getOrAdd(id, [this, &code, &link] {
|
||||
return util::EmoteData(
|
||||
new Image(link, 1, code, code + "<br/>Channel BTTV Emote"));
|
||||
return util::EmoteData(new Image(link, 1, code, code + "<br/>Channel BTTV Emote"));
|
||||
});
|
||||
|
||||
this->bttvChannelEmotes.insert(code, emote);
|
||||
|
@ -293,9 +292,8 @@ void EmoteManager::loadEmojis()
|
|||
"emojione/2.2.6/assets/png/" +
|
||||
code + ".png";
|
||||
|
||||
this->emojis.insert(code,
|
||||
util::EmoteData(new Image(url, 0.35, ":" + shortCode + ":",
|
||||
":" + shortCode + ":<br/>Emoji")));
|
||||
this->emojis.insert(code, util::EmoteData(new Image(url, 0.35, ":" + shortCode + ":",
|
||||
":" + shortCode + ":<br/>Emoji")));
|
||||
|
||||
// TODO(pajlada): The vectors in emojiFirstByte need to be sorted by
|
||||
// emojiData.code.length()
|
||||
|
@ -374,8 +372,7 @@ void EmoteManager::parseEmojis(std::vector<std::tuple<util::EmoteData, QString>>
|
|||
|
||||
// Create or fetch cached emoji image
|
||||
auto emojiImage = this->emojis.getOrAdd(matchedEmoji.code, [this, &url] {
|
||||
return util::EmoteData(
|
||||
new Image(url, 0.35, "?????????", "???????????????")); //
|
||||
return util::EmoteData(new Image(url, 0.35, "?????????", "???????????????")); //
|
||||
});
|
||||
|
||||
// Push the emoji as a word to parsedWords
|
||||
|
@ -447,7 +444,7 @@ void EmoteManager::refreshTwitchEmotes(const std::shared_ptr<twitch::TwitchUser>
|
|||
|
||||
util::twitch::getAuthorized(
|
||||
url, clientID, oauthToken, QThread::currentThread(),
|
||||
[=, &emoteData](QJsonObject &root) {
|
||||
[=, &emoteData](const QJsonObject &root) {
|
||||
emoteData.emoteSets.clear();
|
||||
emoteData.emoteCodes.clear();
|
||||
auto emoticonSets = root.value("emoticon_sets").toObject();
|
||||
|
@ -477,6 +474,7 @@ void EmoteManager::loadBTTVEmotes()
|
|||
util::NetworkRequest req(url);
|
||||
req.setCaller(QThread::currentThread());
|
||||
req.setTimeout(30000);
|
||||
req.setUseQuickLoadCache(true);
|
||||
req.getJSON([this](QJsonObject &root) {
|
||||
debug::Log("Got global bttv emotes");
|
||||
auto emotes = root.value("emotes").toArray();
|
||||
|
@ -489,12 +487,12 @@ void EmoteManager::loadBTTVEmotes()
|
|||
QString code = emote.toObject().value("code").toString();
|
||||
|
||||
util::EmoteData emoteData;
|
||||
emoteData.image1x = new Image(GetBTTVEmoteLink(urlTemplate, id, "1x"), 1,
|
||||
code, code + "<br />Global BTTV Emote");
|
||||
emoteData.image2x = new Image(GetBTTVEmoteLink(urlTemplate, id, "2x"), 0.5,
|
||||
code, code + "<br />Global BTTV Emote");
|
||||
emoteData.image3x = new Image(GetBTTVEmoteLink(urlTemplate, id, "3x"), 0.25,
|
||||
code, code + "<br />Global BTTV Emote");
|
||||
emoteData.image1x = new Image(GetBTTVEmoteLink(urlTemplate, id, "1x"), 1, code,
|
||||
code + "<br />Global BTTV Emote");
|
||||
emoteData.image2x = new Image(GetBTTVEmoteLink(urlTemplate, id, "2x"), 0.5, code,
|
||||
code + "<br />Global BTTV Emote");
|
||||
emoteData.image3x = new Image(GetBTTVEmoteLink(urlTemplate, id, "3x"), 0.25, code,
|
||||
code + "<br />Global BTTV Emote");
|
||||
|
||||
this->bttvGlobalEmotes.insert(code, emoteData);
|
||||
codes.push_back(code.toStdString());
|
||||
|
@ -548,11 +546,11 @@ util::EmoteData EmoteManager::getTwitchEmoteById(long id, const QString &emoteNa
|
|||
return _twitchEmoteFromCache.getOrAdd(id, [this, &emoteName, &_emoteName, &id] {
|
||||
util::EmoteData newEmoteData;
|
||||
newEmoteData.image1x = new Image(GetTwitchEmoteLink(id, "1.0"), 1, emoteName,
|
||||
_emoteName + "<br/>Twitch Emote 1x");
|
||||
_emoteName + "<br/>Twitch Emote 1x");
|
||||
newEmoteData.image2x = new Image(GetTwitchEmoteLink(id, "2.0"), .5, emoteName,
|
||||
_emoteName + "<br/>Twitch Emote 2x");
|
||||
_emoteName + "<br/>Twitch Emote 2x");
|
||||
newEmoteData.image3x = new Image(GetTwitchEmoteLink(id, "3.0"), .25, emoteName,
|
||||
_emoteName + "<br/>Twitch Emote 3x");
|
||||
_emoteName + "<br/>Twitch Emote 3x");
|
||||
|
||||
return newEmoteData;
|
||||
});
|
||||
|
|
|
@ -253,6 +253,11 @@ void IrcManager::privateMessageReceived(Communi::IrcPrivateMessage *message)
|
|||
return;
|
||||
}
|
||||
|
||||
auto xd = message->content();
|
||||
auto xd2 = message->toData();
|
||||
|
||||
debug::Log("HEHE: {}", xd2.toStdString());
|
||||
|
||||
messages::MessageParseArgs args;
|
||||
|
||||
twitch::TwitchMessageBuilder builder(c.get(), message, args);
|
||||
|
|
|
@ -50,6 +50,13 @@ bool PathManager::init(int argc, char **argv)
|
|||
return false;
|
||||
}
|
||||
|
||||
this->cacheFolderPath = rootPath + "/Cache";
|
||||
|
||||
if (!QDir().mkpath(this->cacheFolderPath)) {
|
||||
printf("Error creating cache directory: %s\n", qPrintable(this->cacheFolderPath));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ public:
|
|||
|
||||
QString settingsFolderPath;
|
||||
QString customFolderPath;
|
||||
QString cacheFolderPath;
|
||||
};
|
||||
|
||||
} // namespace singletons
|
||||
|
|
|
@ -106,11 +106,6 @@ void TwitchChannel::setMod(bool value)
|
|||
|
||||
bool TwitchChannel::isBroadcaster()
|
||||
{
|
||||
QString xD = this->name;
|
||||
QString xD2 = singletons::AccountManager::getInstance().Twitch.getCurrent()->getUserName();
|
||||
|
||||
qDebug() << xD << xD2;
|
||||
|
||||
return this->name ==
|
||||
singletons::AccountManager::getInstance().Twitch.getCurrent()->getUserName();
|
||||
}
|
||||
|
@ -144,7 +139,7 @@ void TwitchChannel::refreshLiveStatus()
|
|||
|
||||
std::weak_ptr<Channel> weak = this->shared_from_this();
|
||||
|
||||
util::twitch::get2(url, QThread::currentThread(), [weak](rapidjson::Document &d) {
|
||||
util::twitch::get2(url, QThread::currentThread(), [weak](const rapidjson::Document &d) {
|
||||
SharedChannel shared = weak.lock();
|
||||
|
||||
if (!shared) {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "debug/log.hpp"
|
||||
#include "util/networkrequester.hpp"
|
||||
#include "util/networkworker.hpp"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
@ -29,22 +31,6 @@ static QJsonObject parseJSONFromReplyxD(QNetworkReply *reply)
|
|||
return jsonDoc.object();
|
||||
}
|
||||
|
||||
class NetworkWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void doneUrl(QNetworkReply *);
|
||||
};
|
||||
|
||||
class NetworkRequester : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void requestUrl();
|
||||
};
|
||||
|
||||
class NetworkManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -183,122 +169,5 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class NetworkRequest
|
||||
{
|
||||
struct Data {
|
||||
QNetworkRequest request;
|
||||
const QObject *caller = nullptr;
|
||||
std::function<void(QNetworkReply *)> onReplyCreated;
|
||||
int timeoutMS = -1;
|
||||
} data;
|
||||
|
||||
public:
|
||||
NetworkRequest() = delete;
|
||||
|
||||
explicit NetworkRequest(const char *url)
|
||||
{
|
||||
this->data.request.setUrl(QUrl(url));
|
||||
}
|
||||
|
||||
explicit NetworkRequest(const std::string &url)
|
||||
{
|
||||
this->data.request.setUrl(QUrl(QString::fromStdString(url)));
|
||||
}
|
||||
|
||||
explicit NetworkRequest(const QString &url)
|
||||
{
|
||||
this->data.request.setUrl(QUrl(url));
|
||||
}
|
||||
|
||||
void setCaller(const QObject *_caller)
|
||||
{
|
||||
this->data.caller = _caller;
|
||||
}
|
||||
|
||||
void setOnReplyCreated(std::function<void(QNetworkReply *)> f)
|
||||
{
|
||||
this->data.onReplyCreated = f;
|
||||
}
|
||||
|
||||
void setRawHeader(const QByteArray &headerName, const QByteArray &value)
|
||||
{
|
||||
this->data.request.setRawHeader(headerName, value);
|
||||
}
|
||||
|
||||
void setTimeout(int ms)
|
||||
{
|
||||
this->data.timeoutMS = ms;
|
||||
}
|
||||
|
||||
template <typename FinishedCallback>
|
||||
void get(FinishedCallback onFinished)
|
||||
{
|
||||
QTimer *timer = nullptr;
|
||||
if (this->data.timeoutMS > 0) {
|
||||
timer = new QTimer;
|
||||
}
|
||||
|
||||
NetworkRequester requester;
|
||||
NetworkWorker *worker = new NetworkWorker;
|
||||
|
||||
worker->moveToThread(&NetworkManager::workerThread);
|
||||
|
||||
if (this->data.caller != nullptr) {
|
||||
QObject::connect(worker, &NetworkWorker::doneUrl, this->data.caller,
|
||||
[onFinished](auto reply) {
|
||||
onFinished(reply);
|
||||
reply->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
if (timer != nullptr) {
|
||||
timer->start(this->data.timeoutMS);
|
||||
}
|
||||
|
||||
QObject::connect(
|
||||
&requester, &NetworkRequester::requestUrl, worker,
|
||||
[ timer, data = std::move(this->data), worker, onFinished{std::move(onFinished)} ]() {
|
||||
QNetworkReply *reply = NetworkManager::NaM.get(data.request);
|
||||
|
||||
if (timer != nullptr) {
|
||||
QObject::connect(timer, &QTimer::timeout, worker, [reply, timer]() {
|
||||
debug::Log("Aborted!");
|
||||
reply->abort();
|
||||
timer->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
if (data.onReplyCreated) {
|
||||
data.onReplyCreated(reply);
|
||||
}
|
||||
|
||||
QObject::connect(reply, &QNetworkReply::finished, worker, [
|
||||
data = std::move(data), worker, reply, onFinished = std::move(onFinished)
|
||||
]() {
|
||||
if (data.caller == nullptr) {
|
||||
onFinished(reply);
|
||||
|
||||
reply->deleteLater();
|
||||
} else {
|
||||
emit worker->doneUrl(reply);
|
||||
}
|
||||
|
||||
delete worker;
|
||||
});
|
||||
});
|
||||
|
||||
emit requester.requestUrl();
|
||||
}
|
||||
|
||||
template <typename FinishedCallback>
|
||||
void getJSON(FinishedCallback onFinished)
|
||||
{
|
||||
this->get([onFinished{std::move(onFinished)}](auto reply) {
|
||||
auto object = parseJSONFromReplyxD(reply);
|
||||
onFinished(object);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
} // namespace chatterino
|
||||
|
|
42
src/util/networkrequest.cpp
Normal file
42
src/util/networkrequest.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "util/networkrequest.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
namespace util {
|
||||
|
||||
NetworkRequest::NetworkRequest(const char *url)
|
||||
{
|
||||
this->data.request.setUrl(QUrl(url));
|
||||
}
|
||||
|
||||
NetworkRequest::NetworkRequest(const std::string &url)
|
||||
{
|
||||
this->data.request.setUrl(QUrl(QString::fromStdString(url)));
|
||||
}
|
||||
|
||||
NetworkRequest::NetworkRequest(const QString &url)
|
||||
{
|
||||
this->data.request.setUrl(QUrl(url));
|
||||
}
|
||||
|
||||
void NetworkRequest::setUseQuickLoadCache(bool value)
|
||||
{
|
||||
this->data.useQuickLoadCache = value;
|
||||
}
|
||||
|
||||
void NetworkRequest::Data::writeToCache(const QByteArray &bytes)
|
||||
{
|
||||
if (this->useQuickLoadCache) {
|
||||
auto &pathManager = singletons::PathManager::getInstance();
|
||||
|
||||
QFile cachedFile(pathManager.cacheFolderPath + "/" + this->getHash());
|
||||
|
||||
if (cachedFile.open(QIODevice::WriteOnly)) {
|
||||
cachedFile.write(bytes);
|
||||
|
||||
cachedFile.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace chatterino
|
228
src/util/networkrequest.hpp
Normal file
228
src/util/networkrequest.hpp
Normal file
|
@ -0,0 +1,228 @@
|
|||
#pragma once
|
||||
|
||||
#include "singletons/pathmanager.hpp"
|
||||
#include "util/networkmanager.hpp"
|
||||
#include "util/networkrequester.hpp"
|
||||
#include "util/networkworker.hpp"
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QFile>
|
||||
|
||||
namespace chatterino {
|
||||
namespace util {
|
||||
|
||||
static QJsonObject parseJSONFromData(const QByteArray &data)
|
||||
{
|
||||
QJsonDocument jsonDoc(QJsonDocument::fromJson(data));
|
||||
|
||||
if (jsonDoc.isNull()) {
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
return jsonDoc.object();
|
||||
}
|
||||
|
||||
static rapidjson::Document parseJSONFromData2(const QByteArray &data)
|
||||
{
|
||||
rapidjson::Document ret(rapidjson::kNullType);
|
||||
|
||||
rapidjson::ParseResult result = ret.Parse(data.data(), data.length());
|
||||
|
||||
if (result.Code() != rapidjson::kParseErrorNone) {
|
||||
debug::Log("JSON parse error: {} ({})", rapidjson::GetParseError_En(result.Code()),
|
||||
result.Offset());
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static rapidjson::Document parseJSONFromReply2(QNetworkReply *reply)
|
||||
{
|
||||
rapidjson::Document ret(rapidjson::kNullType);
|
||||
|
||||
if (reply->error() != QNetworkReply::NetworkError::NoError) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
rapidjson::ParseResult result = ret.Parse(data.data(), data.length());
|
||||
|
||||
if (result.Code() != rapidjson::kParseErrorNone) {
|
||||
debug::Log("JSON parse error: {} ({})", rapidjson::GetParseError_En(result.Code()),
|
||||
result.Offset());
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
class NetworkRequest
|
||||
{
|
||||
struct Data {
|
||||
QNetworkRequest request;
|
||||
const QObject *caller = nullptr;
|
||||
std::function<void(QNetworkReply *)> onReplyCreated;
|
||||
int timeoutMS = -1;
|
||||
bool useQuickLoadCache = false;
|
||||
|
||||
QString getHash()
|
||||
{
|
||||
if (this->hash.isEmpty()) {
|
||||
QByteArray bytes;
|
||||
|
||||
bytes.append(this->request.url().toString());
|
||||
|
||||
for (const auto &header : this->request.rawHeaderList()) {
|
||||
bytes.append(header);
|
||||
}
|
||||
|
||||
QByteArray hashBytes(QCryptographicHash::hash(bytes, QCryptographicHash::Sha256));
|
||||
|
||||
this->hash = hashBytes.toHex();
|
||||
}
|
||||
|
||||
return this->hash;
|
||||
}
|
||||
|
||||
void writeToCache(const QByteArray &bytes);
|
||||
|
||||
private:
|
||||
QString hash;
|
||||
} data;
|
||||
|
||||
public:
|
||||
NetworkRequest() = delete;
|
||||
explicit NetworkRequest(const char *url);
|
||||
explicit NetworkRequest(const std::string &url);
|
||||
explicit NetworkRequest(const QString &url);
|
||||
|
||||
void setUseQuickLoadCache(bool value);
|
||||
|
||||
void setCaller(const QObject *_caller)
|
||||
{
|
||||
this->data.caller = _caller;
|
||||
}
|
||||
|
||||
void setOnReplyCreated(std::function<void(QNetworkReply *)> f)
|
||||
{
|
||||
this->data.onReplyCreated = f;
|
||||
}
|
||||
|
||||
void setRawHeader(const QByteArray &headerName, const QByteArray &value)
|
||||
{
|
||||
this->data.request.setRawHeader(headerName, value);
|
||||
}
|
||||
|
||||
void setTimeout(int ms)
|
||||
{
|
||||
this->data.timeoutMS = ms;
|
||||
}
|
||||
|
||||
template <typename FinishedCallback>
|
||||
void get(FinishedCallback onFinished)
|
||||
{
|
||||
if (this->data.useQuickLoadCache) {
|
||||
auto &pathManager = singletons::PathManager::getInstance();
|
||||
|
||||
QFile cachedFile(pathManager.cacheFolderPath + "/" + this->data.getHash());
|
||||
|
||||
if (cachedFile.exists()) {
|
||||
if (cachedFile.open(QIODevice::ReadOnly)) {
|
||||
QByteArray bytes = cachedFile.readAll();
|
||||
|
||||
onFinished(bytes);
|
||||
|
||||
cachedFile.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QTimer *timer = nullptr;
|
||||
if (this->data.timeoutMS > 0) {
|
||||
timer = new QTimer;
|
||||
}
|
||||
|
||||
NetworkRequester requester;
|
||||
NetworkWorker *worker = new NetworkWorker;
|
||||
|
||||
worker->moveToThread(&NetworkManager::workerThread);
|
||||
|
||||
if (this->data.caller != nullptr) {
|
||||
QObject::connect(worker, &NetworkWorker::doneUrl, this->data.caller,
|
||||
[ onFinished, data = this->data ](auto reply) mutable {
|
||||
if (reply->error() != QNetworkReply::NetworkError::NoError) {
|
||||
// TODO: We might want to call an onError callback here
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray bytes = reply->readAll();
|
||||
data.writeToCache(bytes);
|
||||
// onFinished(bytes);
|
||||
|
||||
reply->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
if (timer != nullptr) {
|
||||
timer->start(this->data.timeoutMS);
|
||||
}
|
||||
|
||||
QObject::connect(
|
||||
&requester, &NetworkRequester::requestUrl, worker,
|
||||
[ timer, data = std::move(this->data), worker, onFinished{std::move(onFinished)} ]() {
|
||||
QNetworkReply *reply = NetworkManager::NaM.get(data.request);
|
||||
|
||||
if (timer != nullptr) {
|
||||
QObject::connect(timer, &QTimer::timeout, worker, [reply, timer]() {
|
||||
debug::Log("Aborted!");
|
||||
reply->abort();
|
||||
timer->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
if (data.onReplyCreated) {
|
||||
data.onReplyCreated(reply);
|
||||
}
|
||||
|
||||
QObject::connect(reply, &QNetworkReply::finished, worker, [
|
||||
data = std::move(data), worker, reply, onFinished = std::move(onFinished)
|
||||
]() mutable {
|
||||
if (data.caller == nullptr) {
|
||||
QByteArray bytes = reply->readAll();
|
||||
data.writeToCache(bytes);
|
||||
// onFinished(bytes);
|
||||
|
||||
reply->deleteLater();
|
||||
} else {
|
||||
emit worker->doneUrl(reply);
|
||||
}
|
||||
|
||||
delete worker;
|
||||
});
|
||||
});
|
||||
|
||||
emit requester.requestUrl();
|
||||
}
|
||||
|
||||
template <typename FinishedCallback>
|
||||
void getJSON(FinishedCallback onFinished)
|
||||
{
|
||||
this->get([onFinished{std::move(onFinished)}](const QByteArray &bytes) {
|
||||
auto object = parseJSONFromData(bytes);
|
||||
onFinished(object);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename FinishedCallback>
|
||||
void getJSON2(FinishedCallback onFinished)
|
||||
{
|
||||
this->get([onFinished{std::move(onFinished)}](const QByteArray &bytes) {
|
||||
auto object = parseJSONFromData2(bytes);
|
||||
onFinished(object);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
} // namespace chatterino
|
17
src/util/networkrequester.hpp
Normal file
17
src/util/networkrequester.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace chatterino {
|
||||
namespace util {
|
||||
|
||||
class NetworkRequester : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void requestUrl();
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
} // namespace chatterino
|
17
src/util/networkworker.hpp
Normal file
17
src/util/networkworker.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace chatterino {
|
||||
namespace util {
|
||||
|
||||
class NetworkWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void doneUrl(QNetworkReply *);
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
} // namespace chatterino
|
|
@ -4,6 +4,7 @@
|
|||
#include "debug/log.hpp"
|
||||
#include "singletons/accountmanager.hpp"
|
||||
#include "util/networkmanager.hpp"
|
||||
#include "util/networkrequest.hpp"
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
|
@ -21,82 +22,47 @@
|
|||
|
||||
namespace chatterino {
|
||||
namespace util {
|
||||
|
||||
static QJsonObject parseJSONFromReply(QNetworkReply *reply)
|
||||
{
|
||||
if (reply->error() != QNetworkReply::NetworkError::NoError) {
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
QJsonDocument jsonDoc(QJsonDocument::fromJson(data));
|
||||
|
||||
if (jsonDoc.isNull()) {
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
return jsonDoc.object();
|
||||
}
|
||||
|
||||
static rapidjson::Document parseJSONFromReply2(QNetworkReply *reply)
|
||||
{
|
||||
rapidjson::Document ret(rapidjson::kNullType);
|
||||
|
||||
if (reply->error() != QNetworkReply::NetworkError::NoError) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
rapidjson::ParseResult result = ret.Parse(data.data(), data.length());
|
||||
|
||||
if (result.Code() != rapidjson::kParseErrorNone) {
|
||||
debug::Log("JSON parse error: {} ({})", rapidjson::GetParseError_En(result.Code()),
|
||||
result.Offset());
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
namespace twitch {
|
||||
|
||||
static void get(QString url, const QObject *caller,
|
||||
std::function<void(QJsonObject &)> successCallback)
|
||||
std::function<void(const QJsonObject &)> successCallback)
|
||||
{
|
||||
util::NetworkRequest req(url);
|
||||
req.setCaller(caller);
|
||||
req.setRawHeader("Client-ID", getDefaultClientID());
|
||||
req.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
|
||||
req.get([=](QNetworkReply *reply) {
|
||||
auto node = parseJSONFromReply(reply);
|
||||
successCallback(node);
|
||||
|
||||
req.getJSON([=](const QJsonObject &node) {
|
||||
successCallback(node); //
|
||||
});
|
||||
}
|
||||
|
||||
static void get2(QString url, const QObject *caller,
|
||||
std::function<void(rapidjson::Document &)> successCallback)
|
||||
std::function<void(const rapidjson::Document &)> successCallback)
|
||||
{
|
||||
util::NetworkRequest req(url);
|
||||
req.setCaller(caller);
|
||||
req.setRawHeader("Client-ID", getDefaultClientID());
|
||||
req.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
|
||||
req.get([=](QNetworkReply *reply) {
|
||||
auto document = parseJSONFromReply2(reply);
|
||||
successCallback(document);
|
||||
req.setUseQuickLoadCache(true);
|
||||
|
||||
req.getJSON2([=](const rapidjson::Document &document) {
|
||||
successCallback(document); //
|
||||
});
|
||||
}
|
||||
|
||||
static void getAuthorized(QString url, const QString &clientID, const QString &oauthToken,
|
||||
const QObject *caller, std::function<void(QJsonObject &)> successCallback)
|
||||
const QObject *caller,
|
||||
std::function<void(const QJsonObject &)> successCallback)
|
||||
{
|
||||
util::NetworkRequest req(url);
|
||||
req.setCaller(caller);
|
||||
req.setRawHeader("Client-ID", clientID.toUtf8());
|
||||
req.setRawHeader("Authorization", "OAuth " + oauthToken.toUtf8());
|
||||
req.setRawHeader("Accept", "application/vnd.twitchtv.v5+json");
|
||||
req.get([=](QNetworkReply *reply) {
|
||||
auto node = parseJSONFromReply(reply);
|
||||
successCallback(node);
|
||||
|
||||
req.getJSON([=](const QJsonObject &node) {
|
||||
successCallback(node); //
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue