Showing the changes to libraries/networking/src/BaseAssetScriptingInterface.cpp (1 of 5 files). Show all
Unified · Split
| @@ -31,31 +31,23 @@ QSharedPointer<AssetClient> BaseAssetScriptingInterface::assetClient() { · 30 unmodified lines | |||
| 31 | return DependencyManager::get<AssetClient>(); | 31 | return DependencyManager::get<AssetClient>(); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | BaseAssetScriptingInterface::BaseAssetScriptingInterface(QObject* parent) : QObject(parent), _cache(this) { | 34 | BaseAssetScriptingInterface::BaseAssetScriptingInterface(QObject* parent) : QObject(parent) {} |
| 35 | } | ||
| 36 | |||
| 37 | 35 | ||
| 38 | bool BaseAssetScriptingInterface::initializeCache() { | 36 | bool BaseAssetScriptingInterface::initializeCache() { |
| 39 | // NOTE: *instances* of QNetworkDiskCache are not thread-safe -- however, different threads can effectively | ||
| 40 | // use the same underlying cache if configured with identical settings. Once AssetClient's disk cache settings | ||
| 41 | // become available we configure our instance to match. | ||
| 42 | auto assets = assetClient(); | 37 | auto assets = assetClient(); |
| 43 | if (!assets) { | 38 | if (!assets) { |
| 44 | return false; // not yet possible to initialize the cache | 39 | return false; // not yet possible to initialize the cache |
| 45 | } | 40 | } |
| 46 | if (_cache.cacheDirectory().size()) { | 41 | if (!_cacheDirectory.isEmpty()) { |
| 47 | return true; // cache is ready | 42 | return true; // cache is ready |
| 48 | } | 43 | } |
| 49 | 44 | ||
| 50 | // attempt to initialize the cache | 45 | // attempt to initialize the cache |
| 51 | QMetaObject::invokeMethod(assetClient().data(), "init"); | 46 | QMetaObject::invokeMethod(assets.data(), "init"); |
| 52 | 47 | ||
| 53 | Promise deferred = makePromise("BaseAssetScriptingInterface--queryCacheStatus"); | 48 | Promise deferred = makePromise("BaseAssetScriptingInterface--queryCacheStatus"); |
| 54 | deferred->then([&](QVariantMap result) { | 49 | deferred->then([&](QVariantMap result) { |
| 55 | auto cacheDirectory = result.value("cacheDirectory").toString(); | 50 | _cacheDirectory = result.value("cacheDirectory").toString(); |
| 56 | auto maximumCacheSize = result.value("maximumCacheSize").toLongLong(); | ||
| 57 | _cache.setCacheDirectory(cacheDirectory); | ||
| 58 | _cache.setMaximumCacheSize(maximumCacheSize); | ||
| 59 | }); | 51 | }); |
| 60 | deferred->fail([&](QString error) { | 52 | deferred->fail([&](QString error) { |
| 61 | qDebug() << "BaseAssetScriptingInterface::queryCacheStatus ERROR" << QThread::currentThread() << error; | 53 | qDebug() << "BaseAssetScriptingInterface::queryCacheStatus ERROR" << QThread::currentThread() << error; |
| @@ -64,79 +56,28 @@ bool BaseAssetScriptingInterface::initializeCache() { · 2 unmodified lines | |||
| 64 | return false; // cache is not ready yet | 56 | return false; // cache is not ready yet |
| 65 | } | 57 | } |
| 66 | 58 | ||
| 67 | QVariantMap BaseAssetScriptingInterface::getCacheStatus() { | 59 | Promise BaseAssetScriptingInterface::getCacheStatus() { |
| 68 | return { | 60 | Promise deferred = makePromise(__FUNCTION__); |
| 69 | { "cacheDirectory", _cache.cacheDirectory() }, | 61 | DependencyManager::get<AssetClient>()->cacheInfoRequest(deferred); |
| 70 | { "cacheSize", _cache.cacheSize() }, | 62 | return deferred; |
| 71 | { "maximumCacheSize", _cache.maximumCacheSize() }, | ||
| 72 | }; | ||
| 73 | } | ||
| 74 | |||
| 75 | QVariantMap BaseAssetScriptingInterface::queryCacheMeta(const QUrl& url) { | ||
| 76 | QNetworkCacheMetaData metaData = _cache.metaData(url); | ||
| 77 | QVariantMap attributes, rawHeaders; | ||
| 78 | |||
| 79 | QHashIterator<QNetworkRequest::Attribute, QVariant> i(metaData.attributes()); | ||
| 80 | while (i.hasNext()) { | ||
| 81 | i.next(); | ||
| 82 | attributes[QString::number(i.key())] = i.value(); | ||
| 83 | } | ||
| 84 | for (const auto& i : metaData.rawHeaders()) { | ||
| 85 | rawHeaders[i.first] = i.second; | ||
| 86 | } | ||
| 87 | return { | ||
| 88 | { "isValid", metaData.isValid() }, | ||
| 89 | { "url", metaData.url() }, | ||
| 90 | { "expirationDate", metaData.expirationDate() }, | ||
| 91 | { "lastModified", metaData.lastModified().toString().isEmpty() ? QDateTime() : metaData.lastModified() }, | ||
| 92 | { "saveToDisk", metaData.saveToDisk() }, | ||
| 93 | { "attributes", attributes }, | ||
| 94 | { "rawHeaders", rawHeaders }, | ||
| 95 | }; | ||
| 96 | } | 63 | } |
| 97 | 64 | ||
| 98 | QVariantMap BaseAssetScriptingInterface::loadFromCache(const QUrl& url) { | 65 | Promise BaseAssetScriptingInterface::queryCacheMeta(const QUrl& url) { |
| 99 | QVariantMap result = { | 66 | Promise deferred = makePromise(__FUNCTION__); |
| 100 | { "metadata", queryCacheMeta(url) }, | 67 | DependencyManager::get<AssetClient>()->queryCacheMeta(deferred, url); |
| 101 | { "data", QByteArray() }, | 68 | return deferred; |
| 102 | }; | ||
| 103 | // caller is responsible for the deletion of the ioDevice, hence the unique_ptr | ||
| 104 | if (auto ioDevice = std::unique_ptr<QIODevice>(_cache.data(url))) { | ||
| 105 | QByteArray data = ioDevice->readAll(); | ||
| 106 | result["data"] = data; | ||
| 107 | } | ||
| 108 | return result; | ||
| 109 | } | 69 | } |
| 110 | 70 | ||
| 111 | namespace { | 71 | Promise BaseAssetScriptingInterface::loadFromCache(const QUrl& url) { |
| 112 | // parse RFC 1123 HTTP date format | 72 | Promise deferred = makePromise(__FUNCTION__); |
| 113 | QDateTime parseHttpDate(const QString& dateString) { | 73 | DependencyManager::get<AssetClient>()->loadFromCache(deferred, url); |
| 114 | QDateTime dt = QDateTime::fromString(dateString.left(25), "ddd, dd MMM yyyy HH:mm:ss"); | 74 | return deferred; |
| 115 | dt.setTimeSpec(Qt::UTC); | ||
| 116 | return dt; | ||
| 117 | } | ||
| 118 | } | 75 | } |
| 119 | 76 | ||
| 120 | bool BaseAssetScriptingInterface::saveToCache(const QUrl& url, const QByteArray& data, const QVariantMap& headers) { | 77 | Promise BaseAssetScriptingInterface::saveToCache(const QUrl& url, const QByteArray& data, const QVariantMap& headers) { |
| 121 | QDateTime lastModified = headers.contains("last-modified") ? | 78 | Promise deferred = makePromise(__FUNCTION__); |
| 122 | parseHttpDate(headers["last-modified"].toString()) : | 79 | DependencyManager::get<AssetClient>()->saveToCache(deferred, url, data, headers); |
| 123 | QDateTime::currentDateTimeUtc(); | 80 | return deferred; |
| 124 | QDateTime expirationDate = headers.contains("expires") ? | ||
| 125 | parseHttpDate(headers["expires"].toString()) : | ||
| 126 | QDateTime(); // never expires | ||
| 127 | QNetworkCacheMetaData metaData; | ||
| 128 | metaData.setUrl(url); | ||
| 129 | metaData.setSaveToDisk(true); | ||
| 130 | metaData.setLastModified(lastModified); | ||
| 131 | metaData.setExpirationDate(expirationDate); | ||
| 132 | if (auto ioDevice = _cache.prepare(metaData)) { | ||
| 133 | ioDevice->write(data); | ||
| 134 | _cache.insert(ioDevice); | ||
| 135 | qCDebug(asset_client) << url.toDisplayString() << "saved to disk cache ("<< data.size()<<" bytes)"; | ||
| 136 | return true; | ||
| 137 | } | ||
| 138 | qCWarning(asset_client) << "Could not save" << url.toDisplayString() << "to disk cache."; | ||
| 139 | return false; | ||
| 140 | } | 81 | } |
| 141 | 82 | ||
| 142 | Promise BaseAssetScriptingInterface::loadAsset(QString asset, bool decompress, QString responseType) { | 83 | Promise BaseAssetScriptingInterface::loadAsset(QString asset, bool decompress, QString responseType) { |