Page MenuHomePhorge

kazv-io-manager.cpp
No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None

kazv-io-manager.cpp

/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2022-2023 nannanko <nannanko@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <kazv-defs.hpp>
#include "kazv-io-manager.hpp"
#include "kazv-io-job.hpp"
#include "matrix-room.hpp"
#include "upload-job-model.hpp"
#include "qt-rand-adapter.hpp"
#include <api/csapi/content-repo.hpp>
#include <file-desc.hpp>
#include <QObject>
#include <QIODevice>
#include <QFile>
#include <QSaveFile>
#include <QPointer>
#include <QSharedPointer>
#include <QUrl>
#include <QMap>
#include <QMultiMap>
#include <QTemporaryDir>
#include <string>
#include <algorithm>
using namespace Qt::Literals::StringLiterals;
static const QString ROOMLESS = QStringLiteral("not-a-room");
struct KazvIOManagerPrivate
{
/**
* Used to store various temporary files.
* If the user does not specify a cache directory,
* this directory is also used as a cache directory.
*/
QTemporaryDir tmpDir = QTemporaryDir{};
/**
* Stores files that need to be previewed (e.g. in a timeline)
* and are not downloaded by the user, such as images, audio, video covers, and videos.
*/
QDir cacheDir{tmpDir.path()};
Kazv::RandomInterface randomGenerator = QtRandAdapter{};
QMap<QString, QPointer<KazvIODownloadJob>> cacheJobs;
QMap<QString, QSharedPointer<KazvIODownloadJob>> downloadJobs;
QMap<QString, QSharedPointer<UploadJobModel>> uploadJobs;
};
KazvIOManager::KazvIOManager(QObject *parent)
: QObject(parent)
, m_d(new KazvIOManagerPrivate)
{
}
KazvIOManager::~KazvIOManager() = default;
QPointer<KazvIODownloadJob> KazvIOManager::makeDownloadJob(
const QUrl &serverUrl, const QUrl &localFileUrl,
const bool showPrograssBar, const QString &hash,
const QString &key, const QString &iv) const
{
QPointer<KazvIODownloadJob> job{};
if (key.isEmpty()) {
job = new KazvIODownloadJob{localFileUrl.toLocalFile(),
serverUrl, showPrograssBar, hash, std::nullopt};
} else {
auto aes = Kazv::AES256CTRDesc{key.toStdString(), iv.toStdString()};
job = new KazvIODownloadJob{localFileUrl.toLocalFile(),
serverUrl, showPrograssBar, hash, aes};
}
return job;
}
QUrl KazvIOManager::cacheFile(const QUrl &fileUrl, const QString &id, const QString &hash,
const QString &key, const QString &iv)
{
const QString filePath = m_d->cacheDir.filePath(id);
QDir dir(m_d->cacheDir.path());
if (!dir.exists(id) && this->getCacheJob(id) == nullptr) {
auto job = this->makeDownloadJob(fileUrl,
QUrl::fromLocalFile(filePath),
/* showProgressBar = */ false, hash, key, iv);
m_d->cacheJobs[id] = job;
connect(job, &KazvIOBaseJob::result, this, [this, id](auto /* result */) {
m_d->cacheJobs[id]->deleteLater();
m_d->cacheJobs.remove(id);
});
}
return QUrl::fromLocalFile(filePath);
}
KazvIOBaseJob *KazvIOManager::startNewDownloadJob(const QUrl &serverUrl, const QUrl &localFileUrl,
const QString &jobId, const QString &hash, const QString &key, const QString &iv)
{
auto downloadJob = this->makeDownloadJob(serverUrl, localFileUrl,
/* showProgressBar = */ true, hash, key, iv);
m_d->downloadJobs[jobId].reset(downloadJob);
QQmlEngine::setObjectOwnership(downloadJob.data(), QQmlEngine::CppOwnership);
return downloadJob.data();
}
KazvIOBaseJob *KazvIOManager::startNewUploadJob(
const QUrl &serverUrl, const QUrl &localFileUrl, const QString &token,
const QString &roomId, MatrixRoomList *roomList, const bool encrypted,
const QString &relType, const QString &relatedTo)
{
auto uploadJob = QPointer<KazvIOUploadJob>();
if (encrypted) {
auto aes = Kazv::AES256CTRDesc::fromRandom(
m_d->randomGenerator.generateRange<Kazv::RandomData>(Kazv::AES256CTRDesc::randomSize));
uploadJob = new KazvIOUploadJob(localFileUrl.toLocalFile(), serverUrl,
/* showProgressBar = */ true, roomList, roomId, token, aes, relType, relatedTo);
} else {
uploadJob = new KazvIOUploadJob(localFileUrl.toLocalFile(), serverUrl,
/* showProgressBar = */ true, roomList, roomId, token, std::nullopt, relType, relatedTo);
}
if (!m_d->uploadJobs.contains(roomId) || m_d->uploadJobs[roomId].isNull()) {
m_d->uploadJobs[roomId].reset(new UploadJobModel());
}
m_d->uploadJobs[roomId]->addJob(uploadJob);
QQmlEngine::setObjectOwnership(uploadJob.data(), QQmlEngine::CppOwnership);
return uploadJob.data();
}
KazvIOBaseJob *KazvIOManager::startNewRoomlessUploadJob(const QUrl &serverUrl, const QUrl &localFileUrl, const QString &token)
{
return startNewUploadJob(
serverUrl, localFileUrl, token, ROOMLESS, 0, false,
QStringLiteral(""), QStringLiteral(""));
}
KazvIOBaseJob *KazvIOManager::getCacheJob(const QString &jobId) const
{
auto targetJob = m_d->cacheJobs.find(jobId);
if (targetJob == m_d->cacheJobs.end()) {
return nullptr;
}
QQmlEngine::setObjectOwnership(targetJob.value().data(), QQmlEngine::CppOwnership);
return targetJob.value().data();
}
KazvIOBaseJob *KazvIOManager::getDownloadJob(const QString &jobId)
{
auto targetJob = m_d->downloadJobs.find(jobId);
if (targetJob == m_d->downloadJobs.end()) {
return nullptr;
}
QQmlEngine::setObjectOwnership(targetJob.value().data(), QQmlEngine::CppOwnership);
return targetJob.value().data();
}
void KazvIOManager::deleteDownloadJob(const QString &jobId)
{
m_d->downloadJobs.remove(jobId);
}
UploadJobModel *KazvIOManager::getUploadJobs(const QString &roomId)
{
if (!m_d->uploadJobs.contains(roomId) || m_d->uploadJobs[roomId].isNull()) {
m_d->uploadJobs[roomId].reset(new UploadJobModel());
}
QQmlEngine::setObjectOwnership(m_d->uploadJobs[roomId].data(), QQmlEngine::CppOwnership);
return m_d->uploadJobs[roomId].data();
}
void KazvIOManager::deleteUploadJob(const QString &roomId, KazvIOBaseJob *job)
{
m_d->uploadJobs[roomId]->removeJob(QPointer<KazvIOUploadJob>(qobject_cast<KazvIOUploadJob*>(job)));
}
void KazvIOManager::deleteRoomlessUploadJob(KazvIOBaseJob *job)
{
deleteUploadJob(ROOMLESS, job);
}
void KazvIOManager::deleteModelIfEmpty(const QString &roomId)
{
if (!m_d->uploadJobs.contains(roomId)) {
return;
}
if (m_d->uploadJobs[roomId]->rowCount() == 0) {
m_d->uploadJobs.remove(roomId);
}
}
void KazvIOManager::clearJobs()
{
/**
* KazvIOBaseJob::cancel() for cache jobs will remove itself from cacheJobs,
* so iterators and loops for m_d->cacheJobs cannot be used reliably.
*/
for (auto key : m_d->cacheJobs.keys()) {
m_d->cacheJobs[key]->cancel();
}
std::for_each(m_d->downloadJobs.begin(), m_d->downloadJobs.end(), [this](auto job){
job->cancel();
});
std::for_each(m_d->uploadJobs.begin(), m_d->uploadJobs.end(), [this](auto room) {
room->clearJobs();
});
m_d->downloadJobs.clear();
m_d->uploadJobs.clear();
}
QString KazvIOManager::cacheDirectory() const
{
return m_d->cacheDir.path();
}
void KazvIOManager::setCacheDirectory(QString cacheDirectory)
{
if (cacheDirectory.isEmpty()) {
m_d->cacheDir = QDir{m_d->tmpDir.path()};
} else {
auto cacheDir = QDir{QUrl{cacheDirectory}.toLocalFile()};
if (!cacheDir.mkpath(u"."_s)) {
return;
}
m_d->cacheDir = cacheDir;
}
m_d->downloadJobs.clear();
Q_EMIT cacheDirectoryChanged();
}

File Metadata

Mime Type
text/x-c
Expires
Tue, Nov 26, 2:03 PM (1 d, 12 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40354
Default Alt Text
kazv-io-manager.cpp (7 KB)

Event Timeline