Showing the changes to libraries/networking/src/BaseAssetScriptingInterface.cpp (1 of 14 files). Show all
Unified · Split
| @@ -28,14 +28,18 @@ · 27 unmodified lines | ||
| 28 | 28 | using Promise = MiniPromise::Promise; |
| 29 | 29 | |
| 30 | 30 | QSharedPointer<AssetClient> BaseAssetScriptingInterface::assetClient() { |
| 31 | − return DependencyManager::get<AssetClient>(); | |
| 31 | + auto client = DependencyManager::get<AssetClient>(); | |
| 32 | + Q_ASSERT(client); | |
| 33 | + if (!client) { | |
| 34 | + qDebug() << "BaseAssetScriptingInterface::assetClient unavailable"; | |
| 35 | + } | |
| 36 | + return client; | |
| 32 | 37 | } |
| 33 | 38 | |
| 34 | 39 | BaseAssetScriptingInterface::BaseAssetScriptingInterface(QObject* parent) : QObject(parent) {} |
| 35 | 40 | |
| 36 | 41 | bool BaseAssetScriptingInterface::initializeCache() { |
| 37 | − auto assets = assetClient(); | |
| 38 | − if (!assets) { | |
| 42 | + if (!assetClient()) { | |
| 39 | 43 | return false; // not yet possible to initialize the cache |
| 40 | 44 | } |
| 41 | 45 | if (!_cacheDirectory.isEmpty()) { |
| @@ -43,41 +47,64 @@ bool BaseAssetScriptingInterface::initializeCache() { · 1 unmodified line | ||
| 43 | 47 | } |
| 44 | 48 | |
| 45 | 49 | // attempt to initialize the cache |
| 46 | − QMetaObject::invokeMethod(assets.data(), "init"); | |
| 50 | + QMetaObject::invokeMethod(assetClient().data(), "init"); | |
| 47 | 51 | |
| 48 | 52 | Promise deferred = makePromise("BaseAssetScriptingInterface--queryCacheStatus"); |
| 49 | − deferred->then([&](QVariantMap result) { | |
| 53 | + deferred->then([this](QVariantMap result) { | |
| 50 | 54 | _cacheDirectory = result.value("cacheDirectory").toString(); |
| 51 | 55 | }); |
| 52 | − deferred->fail([&](QString error) { | |
| 56 | + deferred->fail([](QString error) { | |
| 53 | 57 | qDebug() << "BaseAssetScriptingInterface::queryCacheStatus ERROR" << QThread::currentThread() << error; |
| 54 | 58 | }); |
| 55 | − assets->cacheInfoRequest(deferred); | |
| 59 | + assetClient()->cacheInfoRequestAsync(deferred); | |
| 56 | 60 | return false; // cache is not ready yet |
| 57 | 61 | } |
| 58 | 62 | |
| 59 | 63 | Promise BaseAssetScriptingInterface::getCacheStatus() { |
| 60 | − Promise deferred = makePromise(__FUNCTION__); | |
| 61 | − DependencyManager::get<AssetClient>()->cacheInfoRequest(deferred); | |
| 62 | − return deferred; | |
| 64 | + return assetClient()->cacheInfoRequestAsync(makePromise(__FUNCTION__)); | |
| 63 | 65 | } |
| 64 | 66 | |
| 65 | 67 | Promise BaseAssetScriptingInterface::queryCacheMeta(const QUrl& url) { |
| 66 | − Promise deferred = makePromise(__FUNCTION__); | |
| 67 | − DependencyManager::get<AssetClient>()->queryCacheMeta(deferred, url); | |
| 68 | − return deferred; | |
| 68 | + return assetClient()->queryCacheMetaAsync(url, makePromise(__FUNCTION__)); | |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | −Promise BaseAssetScriptingInterface::loadFromCache(const QUrl& url) { | |
| 72 | − Promise deferred = makePromise(__FUNCTION__); | |
| 73 | − DependencyManager::get<AssetClient>()->loadFromCache(deferred, url); | |
| 74 | − return deferred; | |
| 71 | +Promise BaseAssetScriptingInterface::loadFromCache(const QUrl& url, bool decompress, const QString& responseType) { | |
| 72 | + QVariantMap metaData = { | |
| 73 | + { "_type", "cache" }, | |
| 74 | + { "url", url }, | |
| 75 | + { "responseType", responseType }, | |
| 76 | + }; | |
| 77 | + | |
| 78 | + Promise completed = makePromise("loadFromCache::completed"); | |
| 79 | + Promise fetched = makePromise("loadFromCache::fetched"); | |
| 80 | + | |
| 81 | + Promise downloaded = assetClient()->loadFromCacheAsync(url, makePromise("loadFromCache-retrieval")); | |
| 82 | + downloaded->mixin(metaData); | |
| 83 | + downloaded->fail(fetched); | |
| 84 | + | |
| 85 | + if (decompress) { | |
| 86 | + downloaded->then([=](QVariantMap result) { | |
| 87 | + fetched->mixin(result); | |
| 88 | + Promise decompressed = decompressBytes(result.value("data").toByteArray()); | |
| 89 | + decompressed->mixin(result); | |
| 90 | + decompressed->ready(fetched); | |
| 91 | + }); | |
| 92 | + } else { | |
| 93 | + downloaded->then(fetched); | |
| 94 | + } | |
| 95 | + | |
| 96 | + fetched->fail(completed); | |
| 97 | + fetched->then([=](QVariantMap result) { | |
| 98 | + Promise converted = convertBytes(result.value("data").toByteArray(), responseType); | |
| 99 | + converted->mixin(result); | |
| 100 | + converted->ready(completed); | |
| 101 | + }); | |
| 102 | + | |
| 103 | + return completed; | |
| 75 | 104 | } |
| 76 | 105 | |
| 77 | 106 | Promise BaseAssetScriptingInterface::saveToCache(const QUrl& url, const QByteArray& data, const QVariantMap& headers) { |
| 78 | − Promise deferred = makePromise(__FUNCTION__); | |
| 79 | − DependencyManager::get<AssetClient>()->saveToCache(deferred, url, data, headers); | |
| 80 | − return deferred; | |
| 107 | + return assetClient()->saveToCacheAsync(url, data, headers, makePromise(__FUNCTION__)); | |
| 81 | 108 | } |
| 82 | 109 | |
| 83 | 110 | Promise BaseAssetScriptingInterface::loadAsset(QString asset, bool decompress, QString responseType) { |
| @@ -92,73 +119,81 @@ Promise BaseAssetScriptingInterface::loadAsset(QString asset, bool decompress, Q · 8 unmodified lines | ||
| 92 | 119 | { "responseType", responseType }, |
| 93 | 120 | }; |
| 94 | 121 | |
| 95 | − Promise fetched = makePromise("loadAsset::fetched"), | |
| 96 | − loaded = makePromise("loadAsset::loaded"); | |
| 97 | − | |
| 98 | − downloadBytes(hash) | |
| 99 | − ->mixin(metaData) | |
| 100 | − ->ready([=](QString error, QVariantMap result) { | |
| 101 | − Q_ASSERT(thread() == QThread::currentThread()); | |
| 102 | − fetched->mixin(result); | |
| 103 | − if (decompress) { | |
| 104 | − decompressBytes(result.value("data").toByteArray()) | |
| 105 | − ->mixin(result) | |
| 106 | − ->ready([=](QString error, QVariantMap result) { | |
| 107 | − fetched->handle(error, result); | |
| 108 | − }); | |
| 109 | − } else { | |
| 110 | − fetched->handle(error, result); | |
| 111 | − } | |
| 112 | − }); | |
| 122 | + Promise completed = makePromise("loadAsset::completed"); | |
| 123 | + Promise fetched = makePromise("loadAsset::fetched"); | |
| 113 | 124 | |
| 114 | − fetched->ready([=](QString error, QVariantMap result) { | |
| 115 | − if (responseType == "arraybuffer") { | |
| 116 | − loaded->resolve(NoError, result); | |
| 117 | − } else { | |
| 118 | − convertBytes(result.value("data").toByteArray(), responseType) | |
| 119 | − ->mixin(result) | |
| 120 | − ->ready([=](QString error, QVariantMap result) { | |
| 121 | − loaded->resolve(NoError, result); | |
| 122 | − }); | |
| 123 | − } | |
| 125 | + Promise downloaded = downloadBytes(hash); | |
| 126 | + downloaded->mixin(metaData); | |
| 127 | + downloaded->fail(fetched); | |
| 128 | + | |
| 129 | + if (decompress) { | |
| 130 | + downloaded->then([=](QVariantMap result) { | |
| 131 | + Q_ASSERT(thread() == QThread::currentThread()); | |
| 132 | + fetched->mixin(result); | |
| 133 | + Promise decompressed = decompressBytes(result.value("data").toByteArray()); | |
| 134 | + decompressed->mixin(result); | |
| 135 | + decompressed->ready(fetched); | |
| 136 | + }); | |
| 137 | + } else { | |
| 138 | + downloaded->then(fetched); | |
| 139 | + } | |
| 140 | + | |
| 141 | + fetched->fail(completed); | |
| 142 | + fetched->then([=](QVariantMap result) { | |
| 143 | + Promise converted = convertBytes(result.value("data").toByteArray(), responseType); | |
| 144 | + converted->mixin(result); | |
| 145 | + converted->ready(completed); | |
| 124 | 146 | }); |
| 125 | 147 | |
| 126 | − return loaded; | |
| 148 | + return completed; | |
| 127 | 149 | } |
| 128 | 150 | |
| 129 | 151 | Promise BaseAssetScriptingInterface::convertBytes(const QByteArray& dataByteArray, const QString& responseType) { |
| 130 | − QVariantMap result; | |
| 152 | + QVariantMap result = { | |
| 153 | + { "_contentType", QMimeDatabase().mimeTypeForData(dataByteArray).name() }, | |
| 154 | + { "_byteLength", dataByteArray.size() }, | |
| 155 | + { "_responseType", responseType }, | |
| 156 | + }; | |
| 157 | + QString error; | |
| 131 | 158 | Promise conversion = makePromise(__FUNCTION__); |
| 132 | − if (dataByteArray.size() == 0) { | |
| 133 | − result["response"] = QString(); | |
| 159 | + if (!RESPONSE_TYPES.contains(responseType)) { | |
| 160 | + error = QString("convertBytes: invalid responseType: '%1' (expected: %2)").arg(responseType).arg(RESPONSE_TYPES.join(" | ")); | |
| 161 | + } else if (responseType == "arraybuffer") { | |
| 162 | + // interpret as bytes | |
| 163 | + result["response"] = dataByteArray; | |
| 134 | 164 | } else if (responseType == "text") { |
| 165 | + // interpret as utf-8 text | |
| 135 | 166 | result["response"] = QString::fromUtf8(dataByteArray); |
| 136 | 167 | } else if (responseType == "json") { |
| 168 | + // interpret as JSON | |
| 137 | 169 | QJsonParseError status; |
| 138 | 170 | auto parsed = QJsonDocument::fromJson(dataByteArray, &status); |
| 139 | 171 | if (status.error == QJsonParseError::NoError) { |
| 140 | − result["response"] = parsed.isArray() ? | |
| 141 | − QVariant(parsed.array().toVariantList()) : | |
| 142 | − QVariant(parsed.object().toVariantMap()); | |
| 172 | + result["response"] = parsed.isArray() ? QVariant(parsed.array().toVariantList()) : QVariant(parsed.object().toVariantMap()); | |
| 143 | 173 | } else { |
| 144 | − QVariantMap errorResult = { | |
| 174 | + result = { | |
| 145 | 175 | { "error", status.error }, |
| 146 | 176 | { "offset", status.offset }, |
| 147 | 177 | }; |
| 148 | − return conversion->reject("JSON Parse Error: " + status.errorString(), errorResult); | |
| 178 | + error = "JSON Parse Error: " + status.errorString(); | |
| 149 | 179 | } |
| 150 | − } else if (responseType == "arraybuffer") { | |
| 151 | − result["response"] = dataByteArray; | |
| 152 | 180 | } |
| 153 | − return conversion->resolve(NoError, result); | |
| 181 | + if (result.value("response").canConvert<QByteArray>()) { | |
| 182 | + auto data = result.value("response").toByteArray(); | |
| 183 | + result["contentType"] = QMimeDatabase().mimeTypeForData(data).name(); | |
| 184 | + result["byteLength"] = data.size(); | |
| 185 | + result["responseType"] = responseType; | |
| 186 | + } | |
| 187 | + return conversion->handle(error, result); | |
| 154 | 188 | } |
| 155 | 189 | |
| 156 | 190 | Promise BaseAssetScriptingInterface::decompressBytes(const QByteArray& dataByteArray) { |
| 157 | 191 | QByteArray inflated; |
| 192 | + Promise decompressed = makePromise(__FUNCTION__); | |
| 158 | 193 | auto start = usecTimestampNow(); |
| 159 | 194 | if (gunzip(dataByteArray, inflated)) { |
| 160 | 195 | auto end = usecTimestampNow(); |
| 161 | − return makePromise(__FUNCTION__)->resolve(NoError, { | |
| 196 | + decompressed->resolve({ | |
| 162 | 197 | { "_compressedByteLength", dataByteArray.size() }, |
| 163 | 198 | { "_compressedContentType", QMimeDatabase().mimeTypeForData(dataByteArray).name() }, |
| 164 | 199 | { "_compressMS", (double)(end - start) / 1000.0 }, |
| @@ -168,16 +203,18 @@ Promise BaseAssetScriptingInterface::decompressBytes(const QByteArray& dataByteA · 3 unmodified lines | ||
| 168 | 203 | { "data", inflated }, |
| 169 | 204 | }); |
| 170 | 205 | } else { |
| 171 | − return makePromise(__FUNCTION__)->reject("gunzip error", {}); | |
| 206 | + decompressed->reject("gunzip error"); | |
| 172 | 207 | } |
| 208 | + return decompressed; | |
| 173 | 209 | } |
| 174 | 210 | |
| 175 | 211 | Promise BaseAssetScriptingInterface::compressBytes(const QByteArray& dataByteArray, int level) { |
| 176 | 212 | QByteArray deflated; |
| 177 | 213 | auto start = usecTimestampNow(); |
| 214 | + Promise compressed = makePromise(__FUNCTION__); | |
| 178 | 215 | if (gzip(dataByteArray, deflated, level)) { |
| 179 | 216 | auto end = usecTimestampNow(); |
| 180 | − return makePromise(__FUNCTION__)->resolve(NoError, { | |
| 217 | + compressed->resolve({ | |
| 181 | 218 | { "_uncompressedByteLength", dataByteArray.size() }, |
| 182 | 219 | { "_uncompressedContentType", QMimeDatabase().mimeTypeForData(dataByteArray).name() }, |
| 183 | 220 | { "_compressMS", (double)(end - start) / 1000.0 }, |
| @@ -187,13 +224,13 @@ Promise BaseAssetScriptingInterface::compressBytes(const QByteArray& dataByteArr · 3 unmodified lines | ||
| 187 | 224 | { "data", deflated }, |
| 188 | 225 | }); |
| 189 | 226 | } else { |
| 190 | − return makePromise(__FUNCTION__)->reject("gzip error", {}); | |
| 227 | + compressed->reject("gzip error", {}); | |
| 191 | 228 | } |
| 229 | + return compressed; | |
| 192 | 230 | } |
| 193 | 231 | |
| 194 | 232 | Promise BaseAssetScriptingInterface::downloadBytes(QString hash) { |
| 195 | − auto assetClient = DependencyManager::get<AssetClient>(); | |
| 196 | − QPointer<AssetRequest> assetRequest = assetClient->createRequest(hash); | |
| 233 | + QPointer<AssetRequest> assetRequest = assetClient()->createRequest(hash); | |
| 197 | 234 | Promise deferred = makePromise(__FUNCTION__); |
| 198 | 235 | |
| 199 | 236 | QObject::connect(assetRequest, &AssetRequest::finished, assetRequest, [this, deferred](AssetRequest* request) { |
| @@ -208,7 +245,7 @@ Promise BaseAssetScriptingInterface::downloadBytes(QString hash) { · 8 unmodified lines | ||
| 208 | 245 | { "url", request->getUrl() }, |
| 209 | 246 | { "hash", request->getHash() }, |
| 210 | 247 | { "cached", request->loadedFromCache() }, |
| 211 | − { "content-type", QMimeDatabase().mimeTypeForData(data).name() }, | |
| 248 | + { "contentType", QMimeDatabase().mimeTypeForData(data).name() }, | |
| 212 | 249 | { "data", data }, |
| 213 | 250 | }; |
| 214 | 251 | } else { |
| @@ -225,8 +262,9 @@ Promise BaseAssetScriptingInterface::downloadBytes(QString hash) { · 10 unmodified lines | ||
| 225 | 262 | |
| 226 | 263 | Promise BaseAssetScriptingInterface::uploadBytes(const QByteArray& bytes) { |
| 227 | 264 | Promise deferred = makePromise(__FUNCTION__); |
| 228 | − QPointer<AssetUpload> upload = DependencyManager::get<AssetClient>()->createUpload(bytes); | |
| 265 | + QPointer<AssetUpload> upload = assetClient()->createUpload(bytes); | |
| 229 | 266 | |
| 267 | + const auto byteLength = bytes.size(); | |
| 230 | 268 | QObject::connect(upload, &AssetUpload::finished, upload, [=](AssetUpload* upload, const QString& hash) { |
| 231 | 269 | Q_ASSERT(QThread::currentThread() == upload->thread()); |
| 232 | 270 | // note: we are now on the "Resource Manager" thread |
| @@ -237,6 +275,7 @@ Promise BaseAssetScriptingInterface::uploadBytes(const QByteArray& bytes) { · 4 unmodified lines | ||
| 237 | 275 | { "hash", hash }, |
| 238 | 276 | { "url", AssetUtils::getATPUrl(hash).toString() }, |
| 239 | 277 | { "filename", upload->getFilename() }, |
| 278 | + { "byteLength", byteLength }, | |
| 240 | 279 | }; |
| 241 | 280 | } else { |
| 242 | 281 | error = upload->getErrorString(); |
| @@ -251,20 +290,19 @@ Promise BaseAssetScriptingInterface::uploadBytes(const QByteArray& bytes) { · 8 unmodified lines | ||
| 251 | 290 | } |
| 252 | 291 | |
| 253 | 292 | Promise BaseAssetScriptingInterface::getAssetInfo(QString asset) { |
| 254 | − auto deferred = makePromise(__FUNCTION__); | |
| 293 | + Promise deferred = makePromise(__FUNCTION__); | |
| 255 | 294 | auto url = AssetUtils::getATPUrl(asset); |
| 256 | 295 | auto path = url.path(); |
| 257 | 296 | auto hash = AssetUtils::extractAssetHash(asset); |
| 258 | 297 | if (AssetUtils::isValidHash(hash)) { |
| 259 | 298 | // already a valid ATP hash -- nothing to do |
| 260 | − deferred->resolve(NoError, { | |
| 299 | + deferred->resolve({ | |
| 261 | 300 | { "hash", hash }, |
| 262 | 301 | { "path", path }, |
| 263 | 302 | { "url", url }, |
| 264 | 303 | }); |
| 265 | 304 | } else if (AssetUtils::isValidFilePath(path)) { |
| 266 | − auto assetClient = DependencyManager::get<AssetClient>(); | |
| 267 | − QPointer<GetMappingRequest> request = assetClient->createGetMappingRequest(path); | |
| 305 | + QPointer<GetMappingRequest> request = assetClient()->createGetMappingRequest(path); | |
| 268 | 306 | |
| 269 | 307 | QObject::connect(request, &GetMappingRequest::finished, request, [=]() { |
| 270 | 308 | Q_ASSERT(QThread::currentThread() == request->thread()); |
| @@ -276,7 +314,9 @@ Promise BaseAssetScriptingInterface::getAssetInfo(QString asset) { · 5 unmodified lines | ||
| 276 | 314 | { "_hash", hash }, |
| 277 | 315 | { "_path", path }, |
| 278 | 316 | { "_url", url }, |
| 317 | + { "url", url }, | |
| 279 | 318 | { "hash", request->getHash() }, |
| 319 | + { "hashURL", AssetUtils::getATPUrl(request->getHash()).toString() }, | |
| 280 | 320 | { "wasRedirected", request->wasRedirected() }, |
| 281 | 321 | { "path", request->wasRedirected() ? request->getRedirectedPath() : path }, |
| 282 | 322 | }; |
| @@ -297,8 +337,7 @@ Promise BaseAssetScriptingInterface::getAssetInfo(QString asset) { · 14 unmodified lines | ||
| 297 | 337 | |
| 298 | 338 | Promise BaseAssetScriptingInterface::symlinkAsset(QString hash, QString path) { |
| 299 | 339 | auto deferred = makePromise(__FUNCTION__); |
| 300 | − auto assetClient = DependencyManager::get<AssetClient>(); | |
| 301 | − QPointer<SetMappingRequest> setMappingRequest = assetClient->createSetMappingRequest(path, hash); | |
| 340 | + QPointer<SetMappingRequest> setMappingRequest = assetClient()->createSetMappingRequest(path, hash); | |
| 302 | 341 | |
| 303 | 342 | connect(setMappingRequest, &SetMappingRequest::finished, setMappingRequest, [=](SetMappingRequest* request) { |
| 304 | 343 | Q_ASSERT(QThread::currentThread() == request->thread()); |