Initial QSfera import
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
#include "libsync/networkjobs/resources.h"
|
||||
|
||||
#include "libsync/account.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QIcon>
|
||||
#include <QMimeDatabase>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcResources, "sync.networkjob.resource")
|
||||
|
||||
namespace {
|
||||
QString hashMd5(const QString &data)
|
||||
{
|
||||
QCryptographicHash hash(QCryptographicHash::Algorithm::Md5);
|
||||
hash.addData(data.toLatin1());
|
||||
return QString::fromLatin1(hash.result().toHex());
|
||||
}
|
||||
|
||||
QString cacheKey(QNetworkReply *reply)
|
||||
{
|
||||
const QString urlHash = hashMd5(reply->url().toString());
|
||||
const QString eTagHash = hashMd5(reply->header(QNetworkRequest::ETagHeader).toString());
|
||||
|
||||
const auto db = QMimeDatabase();
|
||||
|
||||
QString extension = db.mimeTypeForName(reply->header(QNetworkRequest::ContentTypeHeader).toString()).preferredSuffix();
|
||||
if (extension.isEmpty()) {
|
||||
extension = db.mimeTypeForData(reply).preferredSuffix();
|
||||
}
|
||||
if (extension.isEmpty()) {
|
||||
extension = QStringLiteral("unknown");
|
||||
}
|
||||
|
||||
return QStringLiteral("%1-%2.%3").arg(urlHash, eTagHash, extension);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceJob::finished()
|
||||
{
|
||||
if (reply()->error() != QNetworkReply::NoError) {
|
||||
qCWarning(lcResources) << u"Network error: " << this << errorString();
|
||||
} else {
|
||||
_cacheKey = cacheKey(reply());
|
||||
}
|
||||
|
||||
// storing the file on disk enables Qt to apply some optimizations, e.g., in QIcon
|
||||
// also, specifically for icons, loading from disk allows easy management of scalable and non-scalable entities
|
||||
if (httpStatusCode() == 200 && reply()->size() > 0) {
|
||||
const QString path = _cache->path(_cacheKey);
|
||||
|
||||
qCDebug(lcResources) << u"cache file path:" << path;
|
||||
|
||||
// furthermore, we can skip writing the file if the cache key has not changed (i.e., a file exists) and the file has come from the network cache
|
||||
if (QFileInfo::exists(path) && reply()->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool()) {
|
||||
qCDebug(lcResources) << u"file has come from network cache, skipping writing";
|
||||
} else {
|
||||
QFile cacheFile(path);
|
||||
|
||||
// note: we want to truncate the file if it exists
|
||||
if (!cacheFile.open(QIODevice::WriteOnly)) {
|
||||
qCCritical(lcResources) << u"failed to open cache file for writing:" << cacheFile.fileName();
|
||||
} else {
|
||||
if (!cacheFile.write(reply()->readAll())) {
|
||||
qCCritical(lcResources) << u"failed to write to cache file:" << cacheFile.fileName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleNetworkJob::finished();
|
||||
}
|
||||
|
||||
QIcon ResourceJob::asIcon() const
|
||||
{
|
||||
// storing the file on disk enables Qt to apply some optimizations (e.g., caching of rendered pixmaps)
|
||||
Q_ASSERT(!_cacheKey.isEmpty());
|
||||
return QIcon(_cache->path(_cacheKey));
|
||||
}
|
||||
|
||||
ResourceJob::ResourceJob(const ResourcesCache *cache, const QUrl &rootUrl, const QString &path, QObject *parent)
|
||||
: SimpleNetworkJob(cache->account()->sharedFromThis(), rootUrl, path, "GET", {}, parent)
|
||||
, _cache(cache)
|
||||
{
|
||||
setStoreInCache(true);
|
||||
}
|
||||
|
||||
ResourcesCache::ResourcesCache(const QString &cacheDirectory, Account *account)
|
||||
: QObject(account)
|
||||
, _account(account)
|
||||
, _cacheDirectory(QStringLiteral("%1/tmp.XXXXXX").arg(cacheDirectory))
|
||||
{
|
||||
Q_ASSERT(_cacheDirectory.isValid());
|
||||
}
|
||||
|
||||
ResourceJob *ResourcesCache::makeGetJob(const QUrl &rootUrl, const QString &path, QObject *parent) const
|
||||
{
|
||||
return new ResourceJob(this, rootUrl, path, parent);
|
||||
}
|
||||
|
||||
ResourceJob *ResourcesCache::makeGetJob(const QString &path, QObject *parent) const
|
||||
{
|
||||
return makeGetJob(_account->url(), path, parent);
|
||||
}
|
||||
|
||||
Account *ResourcesCache::account() const
|
||||
{
|
||||
return _account;
|
||||
}
|
||||
|
||||
QString ResourcesCache::path(const QString &cacheKey) const
|
||||
{
|
||||
Q_ASSERT(!cacheKey.isEmpty());
|
||||
Q_ASSERT(_cacheDirectory.isValid());
|
||||
return _cacheDirectory.filePath(cacheKey);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user