refactor: more net cleanup

This runs clang-tidy on some other files in launcher/net/.

This also makes use of some JSON wrappers in HttpMetaCache, instead of
using the Qt stuff directly.

Lastly, this removes useless null checks (crashes don't occur because of
this, but because of concurrent usage / free of the QByteArray pointer),
and fix a fixme in Download.h
This commit is contained in:
flow 2022-04-27 18:36:11 -03:00
parent efa3fbff39
commit 040ee919e5
No known key found for this signature in database
GPG Key ID: 8D0F221F0A59F469
9 changed files with 228 additions and 300 deletions

View File

@ -6,6 +6,8 @@ namespace Net {
/*
* Sink object for downloads that uses an external QByteArray it doesn't own as a target.
* FIXME: It is possible that the QByteArray is freed while we're doing some operation on it,
* causing a segmentation fault.
*/
class ByteArraySink : public Sink {
public:
@ -16,9 +18,6 @@ class ByteArraySink : public Sink {
public:
auto init(QNetworkRequest& request) -> Task::State override
{
if(!m_output)
return Task::State::Failed;
m_output->clear();
if (initAllValidators(request))
return Task::State::Running;
@ -27,9 +26,6 @@ class ByteArraySink : public Sink {
auto write(QByteArray& data) -> Task::State override
{
if(!m_output)
return Task::State::Failed;
m_output->append(data);
if (writeAllValidators(data))
return Task::State::Running;
@ -38,9 +34,6 @@ class ByteArraySink : public Sink {
auto abort() -> Task::State override
{
if(!m_output)
return Task::State::Failed;
m_output->clear();
failAllValidators();
return Task::State::Failed;

View File

@ -1,55 +1,47 @@
#pragma once
#include "Validator.h"
#include <QCryptographicHash>
#include <memory>
#include <QFile>
namespace Net {
class ChecksumValidator: public Validator
{
public: /* con/des */
class ChecksumValidator : public Validator {
public:
ChecksumValidator(QCryptographicHash::Algorithm algorithm, QByteArray expected = QByteArray())
:m_checksum(algorithm), m_expected(expected)
{
};
virtual ~ChecksumValidator() {};
: m_checksum(algorithm), m_expected(expected){};
virtual ~ChecksumValidator() = default;
public: /* methods */
bool init(QNetworkRequest &) override
public:
auto init(QNetworkRequest&) -> bool override
{
m_checksum.reset();
return true;
}
bool write(QByteArray & data) override
auto write(QByteArray& data) -> bool override
{
m_checksum.addData(data);
return true;
}
bool abort() override
auto abort() -> bool override { return true; }
auto validate(QNetworkReply&) -> bool override
{
return true;
}
bool validate(QNetworkReply &) override
{
if(m_expected.size() && m_expected != hash())
{
if (m_expected.size() && m_expected != hash()) {
qWarning() << "Checksum mismatch, download is bad.";
return false;
}
return true;
}
QByteArray hash()
{
return m_checksum.result();
}
void setExpected(QByteArray expected)
{
m_expected = expected;
}
private: /* data */
auto hash() -> QByteArray { return m_checksum.result(); }
void setExpected(QByteArray expected) { m_expected = expected; }
private:
QCryptographicHash m_checksum;
QByteArray m_expected;
};
}
} // namespace Net

View File

@ -33,30 +33,29 @@ Download::Download() : NetAction()
m_state = State::Inactive;
}
Download::Ptr Download::makeCached(QUrl url, MetaEntryPtr entry, Options options)
auto Download::makeCached(QUrl url, MetaEntryPtr entry, Options options) -> Download::Ptr
{
Download* dl = new Download();
auto* dl = new Download();
dl->m_url = url;
dl->m_options = options;
auto md5Node = new ChecksumValidator(QCryptographicHash::Md5);
auto cachedNode = new MetaCacheSink(entry, md5Node);
dl->m_sink.reset(cachedNode);
dl->m_target_path = entry->getFullPath();
return dl;
}
Download::Ptr Download::makeByteArray(QUrl url, QByteArray* output, Options options)
auto Download::makeByteArray(QUrl url, QByteArray* output, Options options) -> Download::Ptr
{
Download* dl = new Download();
auto* dl = new Download();
dl->m_url = url;
dl->m_options = options;
dl->m_sink.reset(new ByteArraySink(output));
return dl;
}
Download::Ptr Download::makeFile(QUrl url, QString path, Options options)
auto Download::makeFile(QUrl url, QString path, Options options) -> Download::Ptr
{
Download* dl = new Download();
auto* dl = new Download();
dl->m_url = url;
dl->m_options = options;
dl->m_sink.reset(new FileSink(path));
@ -143,7 +142,7 @@ void Download::sslErrors(const QList<QSslError>& errors)
}
}
bool Download::handleRedirect()
auto Download::handleRedirect() -> bool
{
QUrl redirect = m_reply->header(QNetworkRequest::LocationHeader).toUrl();
if (!redirect.isValid()) {
@ -230,7 +229,7 @@ void Download::downloadFinished()
// make sure we got all the remaining data, if any
auto data = m_reply->readAll();
if (data.size()) {
qDebug() << "Writing extra" << data.size() << "bytes to" << m_target_path;
qDebug() << "Writing extra" << data.size() << "bytes";
m_state = m_sink->write(data);
}
@ -243,6 +242,7 @@ void Download::downloadFinished()
emitFailed();
return;
}
m_reply.reset();
qDebug() << "Download succeeded:" << m_url.toString();
emit succeeded();
@ -254,17 +254,17 @@ void Download::downloadReadyRead()
auto data = m_reply->readAll();
m_state = m_sink->write(data);
if (m_state == State::Failed) {
qCritical() << "Failed to process response chunk for " << m_target_path;
qCritical() << "Failed to process response chunk";
}
// qDebug() << "Download" << m_url.toString() << "gained" << data.size() << "bytes";
} else {
qCritical() << "Cannot write to " << m_target_path << ", illegal status" << m_status;
qCritical() << "Cannot write download data! illegal status " << m_status;
}
}
} // namespace Net
bool Net::Download::abort()
auto Net::Download::abort() -> bool
{
if (m_reply) {
m_reply->abort();

View File

@ -15,63 +15,54 @@
#pragma once
#include "NetAction.h"
#include "HttpMetaCache.h"
#include "Validator.h"
#include "NetAction.h"
#include "Sink.h"
#include "Validator.h"
#include "QObjectPtr.h"
namespace Net {
class Download : public NetAction
{
class Download : public NetAction {
Q_OBJECT
public:
typedef shared_qobject_ptr<class Download> Ptr;
enum class Option
{
NoOptions = 0,
AcceptLocalFiles = 1
};
public:
using Ptr = shared_qobject_ptr<class Download>;
enum class Option { NoOptions = 0, AcceptLocalFiles = 1 };
Q_DECLARE_FLAGS(Options, Option)
protected:
protected:
explicit Download();
public:
virtual ~Download(){};
static Download::Ptr makeCached(QUrl url, MetaEntryPtr entry, Options options = Option::NoOptions);
static Download::Ptr makeByteArray(QUrl url, QByteArray *output, Options options = Option::NoOptions);
static Download::Ptr makeFile(QUrl url, QString path, Options options = Option::NoOptions);
public:
QString getTargetFilepath()
{
return m_target_path;
}
void addValidator(Validator * v);
bool abort() override;
bool canAbort() const override { return true; };
public:
~Download() override = default;
private:
bool handleRedirect();
static auto makeCached(QUrl url, MetaEntryPtr entry, Options options = Option::NoOptions) -> Download::Ptr;
static auto makeByteArray(QUrl url, QByteArray* output, Options options = Option::NoOptions) -> Download::Ptr;
static auto makeFile(QUrl url, QString path, Options options = Option::NoOptions) -> Download::Ptr;
protected slots:
public:
void addValidator(Validator* v);
auto abort() -> bool override;
auto canAbort() const -> bool override { return true; };
private:
auto handleRedirect() -> bool;
protected slots:
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override;
void downloadError(QNetworkReply::NetworkError error) override;
void sslErrors(const QList<QSslError> & errors);
void sslErrors(const QList<QSslError>& errors);
void downloadFinished() override;
void downloadReadyRead() override;
public slots:
public slots:
void executeTask() override;
private:
// FIXME: remove this, it has no business being here.
QString m_target_path;
private:
std::unique_ptr<Sink> m_sink;
Options m_options;
};
}
} // namespace Net
Q_DECLARE_OPERATORS_FOR_FLAGS(Net::Download::Options)

View File

@ -1,7 +1,5 @@
#include "FileSink.h"
#include <QFile>
#include "FileSystem.h"
namespace Net {
@ -9,44 +7,38 @@ namespace Net {
Task::State FileSink::init(QNetworkRequest& request)
{
auto result = initCache(request);
if(result != Task::State::Running)
{
if (result != Task::State::Running) {
return result;
}
// create a new save file and open it for writing
if (!FS::ensureFilePathExists(m_filename))
{
if (!FS::ensureFilePathExists(m_filename)) {
qCritical() << "Could not create folder for " + m_filename;
return Task::State::Failed;
}
wroteAnyData = false;
m_output_file.reset(new QSaveFile(m_filename));
if (!m_output_file->open(QIODevice::WriteOnly))
{
if (!m_output_file->open(QIODevice::WriteOnly)) {
qCritical() << "Could not open " + m_filename + " for writing";
return Task::State::Failed;
}
if(initAllValidators(request))
if (initAllValidators(request))
return Task::State::Running;
return Task::State::Failed;
}
Task::State FileSink::initCache(QNetworkRequest &)
{
return Task::State::Running;
}
Task::State FileSink::write(QByteArray& data)
{
if (!writeAllValidators(data) || m_output_file->write(data) != data.size())
{
if (!writeAllValidators(data) || m_output_file->write(data) != data.size()) {
qCritical() << "Failed writing into " + m_filename;
m_output_file->cancelWriting();
m_output_file.reset();
wroteAnyData = false;
return Task::State::Failed;
}
wroteAnyData = true;
return Task::State::Running;
}
@ -64,34 +56,39 @@ Task::State FileSink::finalize(QNetworkReply& reply)
QVariant statusCodeV = reply.attribute(QNetworkRequest::HttpStatusCodeAttribute);
bool validStatus = false;
int statusCode = statusCodeV.toInt(&validStatus);
if(validStatus)
{
if (validStatus) {
// this leaves out 304 Not Modified
gotFile = statusCode == 200 || statusCode == 203;
}
// if we wrote any data to the save file, we try to commit the data to the real file.
// if it actually got a proper file, we write it even if it was empty
if (gotFile || wroteAnyData)
{
if (gotFile || wroteAnyData) {
// ask validators for data consistency
// we only do this for actual downloads, not 'your data is still the same' cache hits
if(!finalizeAllValidators(reply))
if (!finalizeAllValidators(reply))
return Task::State::Failed;
// nothing went wrong...
if (!m_output_file->commit())
{
if (!m_output_file->commit()) {
qCritical() << "Failed to commit changes to " << m_filename;
m_output_file->cancelWriting();
return Task::State::Failed;
}
}
// then get rid of the save file
m_output_file.reset();
return finalizeCache(reply);
}
Task::State FileSink::finalizeCache(QNetworkReply &)
Task::State FileSink::initCache(QNetworkRequest&)
{
return Task::State::Running;
}
Task::State FileSink::finalizeCache(QNetworkReply&)
{
return Task::State::Succeeded;
}
@ -101,4 +98,4 @@ bool FileSink::hasLocalData()
QFileInfo info(m_filename);
return info.exists() && info.size() != 0;
}
}
} // namespace Net

View File

@ -15,29 +15,26 @@
#include "HttpMetaCache.h"
#include "FileSystem.h"
#include "Json.h"
#include <QFileInfo>
#include <QFile>
#include <QDateTime>
#include <QCryptographicHash>
#include <QDateTime>
#include <QFile>
#include <QFileInfo>
#include <QDebug>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
QString MetaEntry::getFullPath()
auto MetaEntry::getFullPath() -> QString
{
// FIXME: make local?
return FS::PathCombine(basePath, relativePath);
}
HttpMetaCache::HttpMetaCache(QString path) : QObject()
HttpMetaCache::HttpMetaCache(QString path) : QObject(), m_index_file(path)
{
m_index_file = path;
saveBatchingTimer.setSingleShot(true);
saveBatchingTimer.setTimerType(Qt::VeryCoarseTimer);
connect(&saveBatchingTimer, SIGNAL(timeout()), SLOT(SaveNow()));
}
@ -47,45 +44,42 @@ HttpMetaCache::~HttpMetaCache()
SaveNow();
}
MetaEntryPtr HttpMetaCache::getEntry(QString base, QString resource_path)
auto HttpMetaCache::getEntry(QString base, QString resource_path) -> MetaEntryPtr
{
// no base. no base path. can't store
if (!m_entries.contains(base))
{
if (!m_entries.contains(base)) {
// TODO: log problem
return MetaEntryPtr();
return {};
}
EntryMap &map = m_entries[base];
if (map.entry_list.contains(resource_path))
{
EntryMap& map = m_entries[base];
if (map.entry_list.contains(resource_path)) {
return map.entry_list[resource_path];
}
return MetaEntryPtr();
return {};
}
MetaEntryPtr HttpMetaCache::resolveEntry(QString base, QString resource_path, QString expected_etag)
auto HttpMetaCache::resolveEntry(QString base, QString resource_path, QString expected_etag) -> MetaEntryPtr
{
auto entry = getEntry(base, resource_path);
// it's not present? generate a default stale entry
if (!entry)
{
if (!entry) {
return staleEntry(base, resource_path);
}
auto &selected_base = m_entries[base];
auto& selected_base = m_entries[base];
QString real_path = FS::PathCombine(selected_base.base_path, resource_path);
QFileInfo finfo(real_path);
// is the file really there? if not -> stale
if (!finfo.isFile() || !finfo.isReadable())
{
if (!finfo.isFile() || !finfo.isReadable()) {
// if the file doesn't exist, we disown the entry
selected_base.entry_list.remove(resource_path);
return staleEntry(base, resource_path);
}
if (!expected_etag.isEmpty() && expected_etag != entry->etag)
{
if (!expected_etag.isEmpty() && expected_etag != entry->etag) {
// if the etag doesn't match expected, we disown the entry
selected_base.entry_list.remove(resource_path);
return staleEntry(base, resource_path);
@ -93,18 +87,15 @@ MetaEntryPtr HttpMetaCache::resolveEntry(QString base, QString resource_path, QS
// if the file changed, check md5sum
qint64 file_last_changed = finfo.lastModified().toUTC().toMSecsSinceEpoch();
if (file_last_changed != entry->local_changed_timestamp)
{
if (file_last_changed != entry->local_changed_timestamp) {
QFile input(real_path);
input.open(QIODevice::ReadOnly);
QString md5sum = QCryptographicHash::hash(input.readAll(), QCryptographicHash::Md5)
.toHex()
.constData();
if (entry->md5sum != md5sum)
{
QString md5sum = QCryptographicHash::hash(input.readAll(), QCryptographicHash::Md5).toHex().constData();
if (entry->md5sum != md5sum) {
selected_base.entry_list.remove(resource_path);
return staleEntry(base, resource_path);
}
// md5sums matched... keep entry and save the new state to file
entry->local_changed_timestamp = file_last_changed;
SaveEventually();
@ -115,42 +106,42 @@ MetaEntryPtr HttpMetaCache::resolveEntry(QString base, QString resource_path, QS
return entry;
}
bool HttpMetaCache::updateEntry(MetaEntryPtr stale_entry)
auto HttpMetaCache::updateEntry(MetaEntryPtr stale_entry) -> bool
{
if (!m_entries.contains(stale_entry->baseId))
{
qCritical() << "Cannot add entry with unknown base: "
<< stale_entry->baseId.toLocal8Bit();
if (!m_entries.contains(stale_entry->baseId)) {
qCritical() << "Cannot add entry with unknown base: " << stale_entry->baseId.toLocal8Bit();
return false;
}
if (stale_entry->stale)
{
if (stale_entry->stale) {
qCritical() << "Cannot add stale entry: " << stale_entry->getFullPath().toLocal8Bit();
return false;
}
m_entries[stale_entry->baseId].entry_list[stale_entry->relativePath] = stale_entry;
SaveEventually();
return true;
}
auto HttpMetaCache::evictEntry(MetaEntryPtr entry) -> bool
{
if (!entry)
return false;
entry->stale = true;
SaveEventually();
return true;
}
bool HttpMetaCache::evictEntry(MetaEntryPtr entry)
{
if(entry)
{
entry->stale = true;
SaveEventually();
return true;
}
return false;
}
MetaEntryPtr HttpMetaCache::staleEntry(QString base, QString resource_path)
auto HttpMetaCache::staleEntry(QString base, QString resource_path) -> MetaEntryPtr
{
auto foo = new MetaEntry();
foo->baseId = base;
foo->basePath = getBasePath(base);
foo->relativePath = resource_path;
foo->stale = true;
return MetaEntryPtr(foo);
}
@ -159,24 +150,25 @@ void HttpMetaCache::addBase(QString base, QString base_root)
// TODO: report error
if (m_entries.contains(base))
return;
// TODO: check if the base path is valid
EntryMap foo;
foo.base_path = base_root;
m_entries[base] = foo;
}
QString HttpMetaCache::getBasePath(QString base)
auto HttpMetaCache::getBasePath(QString base) -> QString
{
if (m_entries.contains(base))
{
if (m_entries.contains(base)) {
return m_entries[base].base_path;
}
return QString();
return {};
}
void HttpMetaCache::Load()
{
if(m_index_file.isNull())
if (m_index_file.isNull())
return;
QFile index(m_index_file);
@ -184,41 +176,35 @@ void HttpMetaCache::Load()
return;
QJsonDocument json = QJsonDocument::fromJson(index.readAll());
if (!json.isObject())
return;
auto root = json.object();
auto root = Json::requireObject(json, "HttpMetaCache root");
// check file version first
auto version_val = root.value("version");
if (!version_val.isString())
return;
if (version_val.toString() != "1")
auto version_val = Json::ensureString(root, "version");
if (version_val != "1")
return;
// read the entry array
auto entries_val = root.value("entries");
if (!entries_val.isArray())
return;
QJsonArray array = entries_val.toArray();
for (auto element : array)
{
if (!element.isObject())
return;
auto element_obj = element.toObject();
QString base = element_obj.value("base").toString();
auto array = Json::ensureArray(root, "entries");
for (auto element : array) {
auto element_obj = Json::ensureObject(element);
auto base = Json::ensureString(element_obj, "base");
if (!m_entries.contains(base))
continue;
auto &entrymap = m_entries[base];
auto& entrymap = m_entries[base];
auto foo = new MetaEntry();
foo->baseId = base;
QString path = foo->relativePath = element_obj.value("path").toString();
foo->md5sum = element_obj.value("md5sum").toString();
foo->etag = element_obj.value("etag").toString();
foo->local_changed_timestamp = element_obj.value("last_changed_timestamp").toDouble();
foo->remote_changed_timestamp =
element_obj.value("remote_changed_timestamp").toString();
foo->relativePath = Json::ensureString(element_obj, "path");
foo->md5sum = Json::ensureString(element_obj, "md5sum");
foo->etag = Json::ensureString(element_obj, "etag");
foo->local_changed_timestamp = Json::ensureDouble(element_obj, "last_changed_timestamp");
foo->remote_changed_timestamp = Json::ensureString(element_obj, "remote_changed_timestamp");
// presumed innocent until closer examination
foo->stale = false;
entrymap.entry_list[path] = MetaEntryPtr(foo);
entrymap.entry_list[foo->relativePath] = MetaEntryPtr(foo);
}
}
@ -231,42 +217,36 @@ void HttpMetaCache::SaveEventually()
void HttpMetaCache::SaveNow()
{
if(m_index_file.isNull())
if (m_index_file.isNull())
return;
QJsonObject toplevel;
toplevel.insert("version", QJsonValue(QString("1")));
Json::writeString(toplevel, "version", "1");
QJsonArray entriesArr;
for (auto group : m_entries)
{
for (auto entry : group.entry_list)
{
for (auto group : m_entries) {
for (auto entry : group.entry_list) {
// do not save stale entries. they are dead.
if(entry->stale)
{
if (entry->stale) {
continue;
}
QJsonObject entryObj;
entryObj.insert("base", QJsonValue(entry->baseId));
entryObj.insert("path", QJsonValue(entry->relativePath));
entryObj.insert("md5sum", QJsonValue(entry->md5sum));
entryObj.insert("etag", QJsonValue(entry->etag));
entryObj.insert("last_changed_timestamp",
QJsonValue(double(entry->local_changed_timestamp)));
Json::writeString(entryObj, "base", entry->baseId);
Json::writeString(entryObj, "path", entry->relativePath);
Json::writeString(entryObj, "md5sum", entry->md5sum);
Json::writeString(entryObj, "etag", entry->etag);
entryObj.insert("last_changed_timestamp", QJsonValue(double(entry->local_changed_timestamp)));
if (!entry->remote_changed_timestamp.isEmpty())
entryObj.insert("remote_changed_timestamp",
QJsonValue(entry->remote_changed_timestamp));
entryObj.insert("remote_changed_timestamp", QJsonValue(entry->remote_changed_timestamp));
entriesArr.append(entryObj);
}
}
toplevel.insert("entries", entriesArr);
QJsonDocument doc(toplevel);
try
{
FS::write(m_index_file, doc.toJson());
}
catch (const Exception &e)
{
try {
Json::write(toplevel, m_index_file);
} catch (const Exception& e) {
qWarning() << e.what();
}
}

View File

@ -14,109 +14,88 @@
*/
#pragma once
#include <QString>
#include <QMap>
#include <qtimer.h>
#include <QMap>
#include <QString>
#include <memory>
class HttpMetaCache;
class MetaEntry
{
friend class HttpMetaCache;
protected:
MetaEntry() {}
public:
bool isStale()
{
return stale;
}
void setStale(bool stale)
{
this->stale = stale;
}
QString getFullPath();
QString getRemoteChangedTimestamp()
{
return remote_changed_timestamp;
}
void setRemoteChangedTimestamp(QString remote_changed_timestamp)
{
this->remote_changed_timestamp = remote_changed_timestamp;
}
void setLocalChangedTimestamp(qint64 timestamp)
{
local_changed_timestamp = timestamp;
}
QString getETag()
{
return etag;
}
void setETag(QString etag)
{
this->etag = etag;
}
QString getMD5Sum()
{
return md5sum;
}
void setMD5Sum(QString md5sum)
{
this->md5sum = md5sum;
}
protected:
class MetaEntry {
friend class HttpMetaCache;
protected:
MetaEntry() = default;
public:
auto isStale() -> bool { return stale; }
void setStale(bool stale) { this->stale = stale; }
auto getFullPath() -> QString;
auto getRemoteChangedTimestamp() -> QString { return remote_changed_timestamp; }
void setRemoteChangedTimestamp(QString remote_changed_timestamp) { this->remote_changed_timestamp = remote_changed_timestamp; }
void setLocalChangedTimestamp(qint64 timestamp) { local_changed_timestamp = timestamp; }
auto getETag() -> QString { return etag; }
void setETag(QString etag) { this->etag = etag; }
auto getMD5Sum() -> QString { return md5sum; }
void setMD5Sum(QString md5sum) { this->md5sum = md5sum; }
protected:
QString baseId;
QString basePath;
QString relativePath;
QString md5sum;
QString etag;
qint64 local_changed_timestamp = 0;
QString remote_changed_timestamp; // QString for now, RFC 2822 encoded time
QString remote_changed_timestamp; // QString for now, RFC 2822 encoded time
bool stale = true;
};
typedef std::shared_ptr<MetaEntry> MetaEntryPtr;
using MetaEntryPtr = std::shared_ptr<MetaEntry>;
class HttpMetaCache : public QObject
{
class HttpMetaCache : public QObject {
Q_OBJECT
public:
public:
// supply path to the cache index file
HttpMetaCache(QString path = QString());
~HttpMetaCache();
~HttpMetaCache() override;
// get the entry solely from the cache
// you probably don't want this, unless you have some specific caching needs.
MetaEntryPtr getEntry(QString base, QString resource_path);
auto getEntry(QString base, QString resource_path) -> MetaEntryPtr;
// get the entry from cache and verify that it isn't stale (within reason)
MetaEntryPtr resolveEntry(QString base, QString resource_path,
QString expected_etag = QString());
auto resolveEntry(QString base, QString resource_path, QString expected_etag = QString()) -> MetaEntryPtr;
// add a previously resolved stale entry
bool updateEntry(MetaEntryPtr stale_entry);
auto updateEntry(MetaEntryPtr stale_entry) -> bool;
// evict selected entry from cache
bool evictEntry(MetaEntryPtr entry);
auto evictEntry(MetaEntryPtr entry) -> bool;
void addBase(QString base, QString base_root);
// (re)start a timer that calls SaveNow later.
void SaveEventually();
void Load();
QString getBasePath(QString base);
public
slots:
auto getBasePath(QString base) -> QString;
public slots:
void SaveNow();
private:
private:
// create a new stale entry, given the parameters
MetaEntryPtr staleEntry(QString base, QString resource_path);
struct EntryMap
{
auto staleEntry(QString base, QString resource_path) -> MetaEntryPtr;
struct EntryMap {
QString base_path;
QMap<QString, MetaEntryPtr> entry_list;
};
QMap<QString, EntryMap> m_entries;
QString m_index_file;
QTimer saveBatchingTimer;

View File

@ -1,10 +1,5 @@
#pragma once
namespace Net
{
enum class Mode
{
Offline,
Online
};
namespace Net {
enum class Mode { Offline, Online };
}

View File

@ -8,14 +8,15 @@ namespace Net {
class Sink {
public:
Sink() = default;
virtual ~Sink(){};
virtual ~Sink() = default;
public:
virtual Task::State init(QNetworkRequest& request) = 0;
virtual Task::State write(QByteArray& data) = 0;
virtual Task::State abort() = 0;
virtual Task::State finalize(QNetworkReply& reply) = 0;
virtual bool hasLocalData() = 0;
virtual auto init(QNetworkRequest& request) -> Task::State = 0;
virtual auto write(QByteArray& data) -> Task::State = 0;
virtual auto abort() -> Task::State = 0;
virtual auto finalize(QNetworkReply& reply) -> Task::State = 0;
virtual auto hasLocalData() -> bool = 0;
void addValidator(Validator* validator)
{
@ -24,7 +25,15 @@ class Sink {
}
}
protected: /* methods */
protected:
bool initAllValidators(QNetworkRequest& request)
{
for (auto& validator : validators) {
if (!validator->init(request))
return false;
}
return true;
}
bool finalizeAllValidators(QNetworkReply& reply)
{
for (auto& validator : validators) {
@ -41,14 +50,6 @@ class Sink {
}
return success;
}
bool initAllValidators(QNetworkRequest& request)
{
for (auto& validator : validators) {
if (!validator->init(request))
return false;
}
return true;
}
bool writeAllValidators(QByteArray& data)
{
for (auto& validator : validators) {
@ -58,7 +59,7 @@ class Sink {
return true;
}
protected: /* data */
protected:
std::vector<std::shared_ptr<Validator>> validators;
};
} // namespace Net