Use pajlada::Settings for uploaded images (includes migration)

This commit is contained in:
Mm2PL 2023-12-01 16:54:23 +01:00
parent 6d02bb7304
commit d7a888d651
No known key found for this signature in database
GPG key ID: 94AC9B80EFA15ED9
2 changed files with 156 additions and 44 deletions

View file

@ -9,16 +9,21 @@
#include "singletons/Paths.hpp" #include "singletons/Paths.hpp"
#include "singletons/Settings.hpp" #include "singletons/Settings.hpp"
#include "util/CombinePath.hpp" #include "util/CombinePath.hpp"
#include "util/RapidjsonHelpers.hpp"
#include "widgets/helper/ResizingTextEdit.hpp" #include "widgets/helper/ResizingTextEdit.hpp"
#include <QBuffer> #include <QBuffer>
#include <QHttpMultiPart> #include <QHttpMultiPart>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <qloggingcategory.h>
#include <QMimeDatabase> #include <QMimeDatabase>
#include <QMutex> #include <QMutex>
#include <QPointer> #include <QPointer>
#include <QSaveFile> #include <QSaveFile>
#include <rapidjson/document.h>
#include <memory>
#define UPLOAD_DELAY 2000 #define UPLOAD_DELAY 2000
// Delay between uploads in milliseconds // Delay between uploads in milliseconds
@ -48,50 +53,15 @@ 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 = this->imageLogSetting_->push_back(UploadedImage{
combinePath((getSettings()->logPath.getValue().isEmpty() .channelName = channel->getName(),
? getPaths()->messageLogDirectory .deletionLink = deletionLink,
: getSettings()->logPath), .imageLink = imageLink,
"ImageUploader.json"); .localPath = originalFilePath,
.timestamp = QDateTime::currentSecsSinceEpoch(),
//reading existing logs });
QFile logReadFile(logFileName); qCDebug(chatterinoCommon) << "Saving ImageUploader.json";
bool isLogFileOkay = this->sm_->save();
logReadFile.open(QIODevice::ReadWrite | QIODevice::Text);
if (!isLogFileOkay)
{
channel->addMessage(makeSystemMessage(
QString("Failed to open log file with links at ") + logFileName));
return;
}
auto logs = logReadFile.readAll();
if (logs.isEmpty())
{
logs = QJsonDocument(QJsonArray()).toJson();
}
logReadFile.close();
//writing new data to logs
QJsonObject newLogEntry;
newLogEntry["channelName"] = channel->getName();
newLogEntry["deletionLink"] =
deletionLink.isEmpty() ? QJsonValue(QJsonValue::Null) : deletionLink;
newLogEntry["imageLink"] = imageLink;
newLogEntry["localPath"] = originalFilePath.isEmpty()
? QJsonValue(QJsonValue::Null)
: originalFilePath;
newLogEntry["timestamp"] = QDateTime::currentSecsSinceEpoch();
// channel name
// deletion link (can be empty)
// image link
// local path to an image (can be empty)
// timestamp
QSaveFile logSaveFile(logFileName);
logSaveFile.open(QIODevice::WriteOnly | QIODevice::Text);
QJsonArray entries = QJsonDocument::fromJson(logs).array();
entries.push_back(newLogEntry);
logSaveFile.write(QJsonDocument(entries).toJson());
logSaveFile.commit();
} }
// extracting link to either image or its deletion from response body // extracting link to either image or its deletion from response body
@ -121,6 +91,59 @@ QString getLinkFromResponse(NetworkResult response, QString pattern)
void ImageUploader::save() void ImageUploader::save()
{ {
this->sm_->save();
}
void ImageUploader::initialize(Settings &settings, Paths &paths)
{
auto logPath = (getSettings()->logPath.getValue().isEmpty()
? getPaths()->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->imageLogSetting_ = std::make_unique<
pajlada::Settings::Setting<std::vector<UploadedImage>>>(
"/uploadedImages", this->sm_);
// 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;
}
this->imageLogSetting_->setValue(temporary);
oldLogFile.close();
oldLogFile.rename(combinePath(logPath, "ImageUploader.old.json"));
this->sm_->save();
}
} }
void ImageUploader::sendImageUploadRequest(RawImageData imageData, void ImageUploader::sendImageUploadRequest(RawImageData imageData,

View file

@ -1,11 +1,16 @@
#pragma once #pragma once
#include "common/Singleton.hpp" #include "common/Singleton.hpp"
#include "pajlada/settings/setting.hpp"
#include "pajlada/settings/settingmanager.hpp"
#include "util/RapidjsonHelpers.hpp"
#include <QMimeData> #include <QMimeData>
#include <QMutex> #include <QMutex>
#include <QString> #include <QString>
#include <Qt>
#include <cstdint>
#include <memory> #include <memory>
#include <queue> #include <queue>
@ -22,12 +27,21 @@ struct RawImageData {
QString filePath; QString filePath;
}; };
struct UploadedImage {
QString channelName;
QString deletionLink;
QString imageLink;
QString localPath;
int64_t timestamp{};
};
class ImageUploader final : public Singleton class ImageUploader final : public Singleton
{ {
public: public:
void save() override; void save() override;
void upload(const QMimeData *source, ChannelPtr channel, void upload(const QMimeData *source, ChannelPtr channel,
QPointer<ResizingTextEdit> outputTextEdit); QPointer<ResizingTextEdit> outputTextEdit);
void initialize(Settings &settings, Paths &paths) override;
private: private:
void sendImageUploadRequest(RawImageData imageData, ChannelPtr channel, void sendImageUploadRequest(RawImageData imageData, ChannelPtr channel,
@ -45,5 +59,80 @@ private:
// 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_;
std::unique_ptr<pajlada::Settings::Setting<std::vector<UploadedImage>>>
imageLogSetting_;
}; };
} // namespace chatterino } // 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