Do not do any of the migration crap

This diff is horrendous I am sorry.
This commit is contained in:
Mm2PL 2024-05-14 14:45:40 +02:00
parent 847a300e36
commit fb8584a51d
No known key found for this signature in database
GPG key ID: 94AC9B80EFA15ED9
4 changed files with 127 additions and 204 deletions

View file

@ -446,7 +446,6 @@ set(SOURCE_FILES
singletons/Fonts.hpp singletons/Fonts.hpp
singletons/imageuploader/ImageUploader.cpp singletons/imageuploader/ImageUploader.cpp
singletons/imageuploader/ImageUploader.hpp singletons/imageuploader/ImageUploader.hpp
singletons/imageuploader/UploadedImage.hpp
singletons/imageuploader/UploadedImageModel.cpp singletons/imageuploader/UploadedImageModel.cpp
singletons/imageuploader/UploadedImageModel.hpp singletons/imageuploader/UploadedImageModel.hpp
singletons/Logging.cpp singletons/Logging.cpp

View file

@ -13,6 +13,7 @@
#include "singletons/Settings.hpp" #include "singletons/Settings.hpp"
#include "util/CombinePath.hpp" #include "util/CombinePath.hpp"
#include "util/RapidjsonHelpers.hpp" #include "util/RapidjsonHelpers.hpp"
#include "util/Result.hpp"
#include "widgets/helper/ResizingTextEdit.hpp" #include "widgets/helper/ResizingTextEdit.hpp"
#include <QBuffer> #include <QBuffer>
@ -28,6 +29,7 @@
#include <rapidjson/document.h> #include <rapidjson/document.h>
#include <memory> #include <memory>
#include <vector>
#include <utility> #include <utility>
@ -50,6 +52,48 @@ std::optional<QByteArray> convertToPng(const QImage &image)
return std::nullopt; return std::nullopt;
} }
using namespace chatterino;
Result<std::vector<UploadedImage>, QString> loadLogFile(
const QString &logFileName)
{
//reading existing logs
QFile logReadFile(logFileName);
bool isLogFileOkay =
logReadFile.open(QIODevice::ReadWrite | QIODevice::Text);
if (!isLogFileOkay)
{
return QString("Failed to open log file with links at ") + logFileName;
}
auto logs = logReadFile.readAll();
if (logs.isEmpty())
{
logs = QJsonDocument(QJsonArray()).toJson();
}
logReadFile.close();
QJsonArray entries = QJsonDocument::fromJson(logs).array();
std::vector<UploadedImage> images;
for (const auto &entry : entries)
{
if (!entry.isObject())
{
qCWarning(chatterinoImageuploader)
<< "History file contains non-Object JSON data!";
continue;
}
auto obj = entry.toObject();
images.emplace_back(obj);
}
return images;
}
QString getLogFilePath()
{
return combinePath((getSettings()->logPath.getValue().isEmpty()
? getIApp()->getPaths().messageLogDirectory
: getSettings()->logPath),
"ImageUploader.json");
}
} // namespace } // namespace
namespace chatterino { namespace chatterino {
@ -59,51 +103,36 @@ void ImageUploader::logToFile(const QString &originalFilePath,
const QString &imageLink, const QString &imageLink,
const QString &deletionLink, ChannelPtr channel) const QString &deletionLink, ChannelPtr channel)
{ {
const QString logFileName = const QString logFileName = getLogFilePath();
combinePath((getSettings()->logPath.getValue().isEmpty() auto res = loadLogFile(logFileName);
? getIApp()->getPaths().messageLogDirectory if (!res.isOk())
: getSettings()->logPath),
"ImageUploader.json");
//reading existing logs
QFile logReadFile(logFileName);
bool isLogFileOkay =
logReadFile.open(QIODevice::ReadWrite | QIODevice::Text);
if (!isLogFileOkay)
{ {
channel->addMessage(makeSystemMessage( channel->addMessage(makeSystemMessage(res.error()));
QString("Failed to open log file with links at ") + logFileName));
return; return;
} }
auto logs = logReadFile.readAll(); auto entries = res.value();
if (logs.isEmpty())
{
logs = QJsonDocument(QJsonArray()).toJson();
}
logReadFile.close();
//writing new data to logs //writing new data to logs
QJsonObject newLogEntry; UploadedImage img;
newLogEntry["channelName"] = channel->getName(); img.channelName = channel->getName();
newLogEntry["deletionLink"] = img.deletionLink = deletionLink;
deletionLink.isEmpty() ? QJsonValue(QJsonValue::Null) : deletionLink; img.imageLink = imageLink;
newLogEntry["imageLink"] = imageLink; img.localPath = originalFilePath;
newLogEntry["localPath"] = originalFilePath.isEmpty() img.timestamp = QDateTime::currentSecsSinceEpoch();
? QJsonValue(QJsonValue::Null) entries.push_back(img);
: originalFilePath;
newLogEntry["timestamp"] = QDateTime::currentSecsSinceEpoch();
// channel name // channel name
// deletion link (can be empty) // deletion link (can be empty)
// image link // image link
// local path to an image (can be empty) // local path to an image (can be empty)
// timestamp // timestamp
QJsonArray arr;
for (auto &entry : entries)
{
arr.append(entry.toJson());
}
QSaveFile logSaveFile(logFileName); QSaveFile logSaveFile(logFileName);
logSaveFile.open(QIODevice::WriteOnly | QIODevice::Text); logSaveFile.open(QIODevice::WriteOnly | QIODevice::Text);
QJsonArray entries = QJsonDocument::fromJson(logs).array(); logSaveFile.write(QJsonDocument(arr).toJson());
entries.push_back(newLogEntry);
logSaveFile.write(QJsonDocument(entries).toJson());
logSaveFile.commit(); logSaveFile.commit();
//>>>>>>> e7508332ff1399a89424bfdc0997f979fd0c9acc:src/singletons/ImageUploader.cpp
} }
// extracting link to either image or its deletion from response body // extracting link to either image or its deletion from response body
@ -133,86 +162,30 @@ QString getLinkFromResponse(NetworkResult response, QString pattern)
void ImageUploader::save() void ImageUploader::save()
{ {
this->sm_->save();
} }
UploadedImageModel *ImageUploader::createModel(QObject *parent) UploadedImageModel *ImageUploader::createModel(QObject *parent)
{ {
auto *model = new UploadedImageModel(parent); auto *model = new UploadedImageModel(parent);
auto res = loadLogFile(getLogFilePath());
// Replace content of images_
auto len = this->images_.raw().size();
for (int i = 0; i < len; i++)
{
this->images_.removeAt(0);
}
std::vector<UploadedImage> vec = res.valueOr({});
for (const auto &img : vec)
{
this->images_.append(img);
}
model->initialize(&this->images_); model->initialize(&this->images_);
return model; return model;
} }
void ImageUploader::initialize(Settings &settings, const Paths &paths)
{
auto logPath = (getSettings()->logPath.getValue().isEmpty()
? paths.messageLogDirectory
: getSettings()->logPath);
const QString oldLogName = combinePath(logPath, "ImageUploader.json");
// read/write new one
const QString path = combinePath(logPath, "ImageUploader2.json");
this->sm_ = std::make_shared<pajlada::Settings::SettingManager>();
this->sm_->setPath(qPrintable(path));
this->sm_->setBackupEnabled(true);
this->sm_->setBackupSlots(9);
this->uploadedImagesSetting_ = std::make_unique<
pajlada::Settings::Setting<std::vector<UploadedImage>>>(
"/uploadedImages", this->sm_);
this->sm_->load();
// try to read old log
QFile oldLogFile(oldLogName);
bool isOldLogFileOkay =
oldLogFile.open(QIODevice::ReadOnly | QIODevice::Text);
if (isOldLogFileOkay)
{
auto data = oldLogFile.readAll();
rapidjson::Document doc;
doc.Parse(data.data(), data.size());
if (doc.HasParseError())
{
qCWarning(chatterinoCommon) << "Unable to read ImageUploader.json";
return;
}
std::vector<UploadedImage> temporary;
if (!doc.IsArray())
{
qCWarning(chatterinoCommon)
<< "Unable to parse ImageUploader.json: not an array";
return;
}
if (!rj::getSafe(doc, temporary))
{
qCWarning(chatterinoCommon)
<< "Unable to parse ImageUploader.json: getSafe failed";
return;
}
for (const auto &t : temporary)
{
this->images_.append(t);
}
oldLogFile.close();
oldLogFile.rename(combinePath(logPath, "ImageUploader.old.json"));
}
for (const auto &item : this->uploadedImagesSetting_->getValue())
{
this->images_.append(item);
}
this->signals_.addConnection(
this->images_.delayedItemsChanged.connect([this]() {
this->uploadedImagesSetting_->setValue(this->images_.raw());
}));
if (isOldLogFileOkay)
{
this->uploadedImagesSetting_->setValue(this->images_.raw());
this->sm_->save();
}
}
void ImageUploader::sendImageUploadRequest(RawImageData imageData, void ImageUploader::sendImageUploadRequest(RawImageData imageData,
ChannelPtr channel, ChannelPtr channel,
QPointer<ResizingTextEdit> textEdit) QPointer<ResizingTextEdit> textEdit)

View file

@ -2,19 +2,17 @@
#include "common/SignalVector.hpp" #include "common/SignalVector.hpp"
#include "common/Singleton.hpp" #include "common/Singleton.hpp"
#include "pajlada/settings/setting.hpp" #include "singletons/imageuploader/UploadedImageModel.hpp"
#include "pajlada/settings/settingmanager.hpp"
#include "singletons/imageuploader/UploadedImage.hpp"
#include <pajlada/signals/signalholder.hpp> #include <pajlada/signals/signalholder.hpp>
#include <QJsonObject>
#include <QMimeData> #include <QMimeData>
#include <QMutex> #include <QMutex>
#include <qobject.h> #include <QObject>
#include <QString> #include <QString>
#include <memory> #include <memory>
#include <queue> #include <queue>
#include <vector>
namespace chatterino { namespace chatterino {
@ -23,12 +21,58 @@ class Channel;
class NetworkResult; class NetworkResult;
using ChannelPtr = std::shared_ptr<Channel>; using ChannelPtr = std::shared_ptr<Channel>;
struct UploadedImage {
QString channelName;
QString deletionLink;
QString imageLink;
QString localPath;
int64_t timestamp{};
UploadedImage() = default;
UploadedImage(QJsonObject obj)
: channelName(obj["channelName"].toString())
, imageLink(obj["imageLink"].toString())
, timestamp(obj["timestamp"].toInt())
{
auto del = obj["deletionLink"];
if (!del.isNull())
{
this->deletionLink = del.toString();
}
auto path = obj["localPath"];
if (!path.isNull())
{
this->localPath = path.toString();
}
}
QJsonObject toJson() const
{
QJsonObject out;
out["channelName"] = this->channelName;
out["deletionLink"] = this->deletionLink.isEmpty()
? QJsonValue(QJsonValue::Null)
: this->deletionLink;
out["imageLink"] = this->imageLink;
out["localPath"] = this->localPath.isEmpty()
? QJsonValue(QJsonValue::Null)
: this->localPath;
// without cast, this is ambiguous
out["timestamp"] = (qint64)this->timestamp;
return out;
}
};
class UploadedImageModel;
struct RawImageData { struct RawImageData {
QByteArray data; QByteArray data;
QString format; QString format;
QString filePath; QString filePath;
}; };
class UploadedImageModel;
class ImageUploader final : public Singleton class ImageUploader final : public Singleton
{ {
public: public:
@ -43,7 +87,6 @@ public:
void save() override; void save() override;
void upload(std::queue<RawImageData> images, ChannelPtr channel, void upload(std::queue<RawImageData> images, ChannelPtr channel,
QPointer<ResizingTextEdit> outputTextEdit); QPointer<ResizingTextEdit> outputTextEdit);
void initialize(Settings &settings, const Paths &paths) override;
UploadedImageModel *createModel(QObject *parent); UploadedImageModel *createModel(QObject *parent);
private: private:
@ -58,15 +101,11 @@ private:
void logToFile(const QString &originalFilePath, const QString &imageLink, void logToFile(const QString &originalFilePath, const QString &imageLink,
const QString &deletionLink, ChannelPtr channel); const QString &deletionLink, ChannelPtr channel);
// These variables are only used from the main thread. // These variables are only used from the main thread.
QMutex uploadMutex_; QMutex uploadMutex_;
std::queue<RawImageData> uploadQueue_; std::queue<RawImageData> uploadQueue_;
std::shared_ptr<pajlada::Settings::SettingManager> sm_;
SignalVector<UploadedImage> images_; SignalVector<UploadedImage> images_;
std::unique_ptr<pajlada::Settings::Setting<std::vector<UploadedImage>>>
uploadedImagesSetting_;
pajlada::Signals::SignalHolder signals_; pajlada::Signals::SignalHolder signals_;
}; };
} // namespace chatterino } // namespace chatterino

View file

@ -1,88 +0,0 @@
#pragma once
#include "util/RapidjsonHelpers.hpp"
#include <QString>
#include <Qt>
#include <cstdint>
namespace chatterino {
struct UploadedImage {
QString channelName;
QString deletionLink;
QString imageLink;
QString localPath;
int64_t timestamp{};
};
} // namespace chatterino
namespace pajlada {
template <>
struct Serialize<chatterino::UploadedImage> {
static rapidjson::Value get(const chatterino::UploadedImage &value,
rapidjson::Document::AllocatorType &a)
{
rapidjson::Value ret(rapidjson::kObjectType);
chatterino::rj::set(ret, "channelName", value.channelName, a);
chatterino::rj::set(ret, "imageLink", value.imageLink, a);
chatterino::rj::set(ret, "timestamp", value.timestamp, a);
chatterino::rj::set(ret, "localPath", value.localPath, a);
chatterino::rj::set(ret, "deletionLink", value.deletionLink, a);
return ret;
}
};
template <>
struct Deserialize<chatterino::UploadedImage> {
static chatterino::UploadedImage get(const rapidjson::Value &value,
bool *error = nullptr)
{
chatterino::UploadedImage img;
if (!value.IsObject())
{
PAJLADA_REPORT_ERROR(error);
return img;
}
if (value["localPath"].IsNull())
{
img.localPath = QString();
}
else if (!chatterino::rj::getSafe(value, "localPath", img.localPath))
{
PAJLADA_REPORT_ERROR(error);
return img;
}
if (!chatterino::rj::getSafe(value, "imageLink", img.imageLink))
{
PAJLADA_REPORT_ERROR(error);
return img;
}
if (value["deletionLink"].IsNull())
{
img.deletionLink = QString();
}
else if (!chatterino::rj::getSafe(value, "deletionLink",
img.deletionLink))
{
PAJLADA_REPORT_ERROR(error);
return img;
}
if (!chatterino::rj::getSafe(value, "channelName", img.channelName))
{
PAJLADA_REPORT_ERROR(error);
return img;
}
if (!chatterino::rj::getSafe(value, "timestamp", img.timestamp))
{
PAJLADA_REPORT_ERROR(error);
return img;
}
return img;
}
};
} // namespace pajlada