mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Do not do any of the migration crap
This diff is horrendous I am sorry.
This commit is contained in:
parent
847a300e36
commit
fb8584a51d
4 changed files with 127 additions and 204 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
Loading…
Reference in a new issue