History

rework ScriptValue to act like a stack variable rather than a pointer

Heather Anderson committed 5 years ago

Commit 85810221 parent f209c51170 files · +2837 −2594Browse files

Showing the changes to libraries/script-engine/src/AssetScriptingInterface.cpp (1 of 170 files). Show all

Unified · Split

libraries/script-engine/src/AssetScriptingInterface.cpp+65−61
@@ -63,7 +63,7 @@ bool AssetScriptingInterface::initializeCache() { · 62 unmodified lines
63 }63 }
64}64}
65 65
66void AssetScriptingInterface::uploadData(QString data, ScriptValuePointer callback) {66void AssetScriptingInterface::uploadData(QString data, const ScriptValue& callback) {
67 auto handler = jsBindCallback(thisObject(), callback);67 auto handler = jsBindCallback(thisObject(), callback);
68 QByteArray dataByteArray = data.toUtf8();68 QByteArray dataByteArray = data.toUtf8();
69 auto upload = DependencyManager::get<AssetClient>()->createUpload(dataByteArray);69 auto upload = DependencyManager::get<AssetClient>()->createUpload(dataByteArray);
@@ -88,7 +88,7 @@ void AssetScriptingInterface::uploadData(QString data, ScriptValuePointer callba · 18 unmodified lines
88 upload->start();88 upload->start();
89}89}
90 90
91void AssetScriptingInterface::setMapping(QString path, QString hash, ScriptValuePointer callback) {91void AssetScriptingInterface::setMapping(QString path, QString hash, const ScriptValue& callback) {
92 auto handler = jsBindCallback(thisObject(), callback);92 auto handler = jsBindCallback(thisObject(), callback);
93 auto setMappingRequest = assetClient()->createSetMappingRequest(path, hash);93 auto setMappingRequest = assetClient()->createSetMappingRequest(path, hash);
94 Promise deferred = makePromise(__FUNCTION__);94 Promise deferred = makePromise(__FUNCTION__);
@@ -113,7 +113,7 @@ void AssetScriptingInterface::setMapping(QString path, QString hash, ScriptValue · 18 unmodified lines
113 * @typedef {object} Assets.DownloadDataError113 * @typedef {object} Assets.DownloadDataError
114 * @property {string} errorMessage - <code>""</code> if the download was successful, otherwise a description of the error.114 * @property {string} errorMessage - <code>""</code> if the download was successful, otherwise a description of the error.
115 */115 */
116void AssetScriptingInterface::downloadData(QString urlString, ScriptValuePointer callback) {116void AssetScriptingInterface::downloadData(QString urlString, const ScriptValue& callback) {
117 // FIXME: historically this API method failed silently when given a non-atp prefixed117 // FIXME: historically this API method failed silently when given a non-atp prefixed
118 // urlString (or if the AssetRequest failed).118 // urlString (or if the AssetRequest failed).
119 // .. is that by design or could we update without breaking things to provide better feedback to scripts?119 // .. is that by design or could we update without breaking things to provide better feedback to scripts?
@@ -156,7 +156,7 @@ void AssetScriptingInterface::downloadData(QString urlString, ScriptValuePointer · 36 unmodified lines
156 assetRequest->start();156 assetRequest->start();
157}157}
158 158
159void AssetScriptingInterface::setBakingEnabled(QString path, bool enabled, ScriptValuePointer callback) {159void AssetScriptingInterface::setBakingEnabled(QString path, bool enabled, const ScriptValue& callback) {
160 auto setBakingEnabledRequest = DependencyManager::get<AssetClient>()->createSetBakingEnabledRequest({ path }, enabled);160 auto setBakingEnabledRequest = DependencyManager::get<AssetClient>()->createSetBakingEnabledRequest({ path }, enabled);
161 161
162 Promise deferred = jsPromiseReady(makePromise(__FUNCTION__), thisObject(), callback);162 Promise deferred = jsPromiseReady(makePromise(__FUNCTION__), thisObject(), callback);
@@ -186,11 +186,11 @@ void AssetScriptingInterface::sendFakedHandshake() { · 23 unmodified lines
186 186
187#endif187#endif
188 188
189void AssetScriptingInterface::getMapping(QString asset, ScriptValuePointer callback) {189void AssetScriptingInterface::getMapping(QString asset, const ScriptValue& callback) {
190 auto path = AssetUtils::getATPUrl(asset).path();190 auto path = AssetUtils::getATPUrl(asset).path();
191 auto handler = jsBindCallback(thisObject(), callback);191 auto handler = jsBindCallback(thisObject(), callback);
192 JS_VERIFY(AssetUtils::isValidFilePath(path), "invalid ATP file path: " + asset + "(path:"+path+")");192 JS_VERIFY(AssetUtils::isValidFilePath(path), "invalid ATP file path: " + asset + "(path:"+path+")");
193 JS_VERIFY(callback->isFunction(), "expected second parameter to be a callback function");193 JS_VERIFY(callback.isFunction(), "expected second parameter to be a callback function");
194 Promise promise = getAssetInfo(path);194 Promise promise = getAssetInfo(path);
195 auto scriptEngine = engine();195 auto scriptEngine = engine();
196 promise->ready([=](QString error, QVariantMap result) {196 promise->ready([=](QString error, QVariantMap result) {
@@ -210,19 +210,19 @@ bool AssetScriptingInterface::jsVerify(bool condition, const QString& error) { · 13 unmodified lines
210 return false;210 return false;
211}211}
212 212
213ScriptValuePointer AssetScriptingInterface::jsBindCallback(ScriptValuePointer scope, ScriptValuePointer callback) {213ScriptValue AssetScriptingInterface::jsBindCallback(const ScriptValue& scope, const ScriptValue& callback) {
214 ScriptValuePointer handler = ::makeScopedHandlerObject(scope, callback);214 ScriptValue handler = ::makeScopedHandlerObject(scope, callback);
215 ScriptValuePointer value = handler->property("callback");215 ScriptValue value = handler.property("callback");
216 if (!jsVerify(handler->isObject() && value->isFunction(),216 if (!jsVerify(handler.isObject() && value.isFunction(),
217 QString("jsBindCallback -- .callback is not a function (%1)").arg(value->toVariant().typeName()))) {217 QString("jsBindCallback -- .callback is not a function (%1)").arg(value.toVariant().typeName()))) {
218 return ScriptValuePointer();218 return ScriptValue();
219 }219 }
220 return handler;220 return handler;
221}221}
222 222
223Promise AssetScriptingInterface::jsPromiseReady(Promise promise, ScriptValuePointer scope, ScriptValuePointer callback) {223Promise AssetScriptingInterface::jsPromiseReady(Promise promise, const ScriptValue& scope, const ScriptValue& callback) {
224 auto handler = jsBindCallback(scope, callback);224 auto handler = jsBindCallback(scope, callback);
225 if (!jsVerify(handler->isValid(), "jsPromiseReady -- invalid callback handler")) {225 if (!jsVerify(handler.isValid(), "jsPromiseReady -- invalid callback handler")) {
226 return nullptr;226 return nullptr;
227 }227 }
228 auto scriptEngine = engine();228 auto scriptEngine = engine();
@@ -231,25 +231,25 @@ Promise AssetScriptingInterface::jsPromiseReady(Promise promise, ScriptValuePoin · 2 unmodified lines
231 });231 });
232}232}
233 233
234void AssetScriptingInterface::jsCallback(const ScriptValuePointer& handler,234void AssetScriptingInterface::jsCallback(const ScriptValue& handler,
235 const ScriptValuePointer& error, const ScriptValuePointer& result) {235 const ScriptValue& error, const ScriptValue& result) {
236 Q_ASSERT(thread() == QThread::currentThread());236 Q_ASSERT(thread() == QThread::currentThread());
237 auto errorValue = !error->toBool() ? engine()->nullValue() : error;237 auto errorValue = !error.toBool() ? engine()->nullValue() : error;
238 JS_VERIFY(handler->isObject() && handler->property("callback")->isFunction(),238 JS_VERIFY(handler.isObject() && handler.property("callback").isFunction(),
239 QString("jsCallback -- .callback is not a function (%1)")239 QString("jsCallback -- .callback is not a function (%1)")
240 .arg(handler->property("callback")->toVariant().typeName()));240 .arg(handler.property("callback").toVariant().typeName()));
241 ::callScopedHandlerObject(handler, errorValue, result);241 ::callScopedHandlerObject(handler, errorValue, result);
242}242}
243 243
244void AssetScriptingInterface::jsCallback(const ScriptValuePointer& handler,244void AssetScriptingInterface::jsCallback(const ScriptValue& handler,
245 const ScriptValuePointer& error, const QVariantMap& result) {245 const ScriptValue& error, const QVariantMap& result) {
246 Q_ASSERT(thread() == QThread::currentThread());246 Q_ASSERT(thread() == QThread::currentThread());
247 Q_ASSERT(handler->engine());247 Q_ASSERT(handler.engine());
248 auto engine = handler->engine();248 auto engine = handler.engine();
249 jsCallback(handler, error, engine->toScriptValue(result));249 jsCallback(handler, error, engine->toScriptValue(result));
250}250}
251 251
252void AssetScriptingInterface::deleteAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) {252void AssetScriptingInterface::deleteAsset(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) {
253 jsVerify(false, "TODO: deleteAsset API");253 jsVerify(false, "TODO: deleteAsset API");
254}254}
255 255
@@ -279,14 +279,14 @@ void AssetScriptingInterface::deleteAsset(ScriptValuePointer options, ScriptValu · 23 unmodified lines
279 * @property {boolean} [wasRedirected] - <code>true</code> if the downloaded data is the baked version of the asset, 279 * @property {boolean} [wasRedirected] - <code>true</code> if the downloaded data is the baked version of the asset,
280 * <code>false</code> if it isn't baked.280 * <code>false</code> if it isn't baked.
281 */281 */
282void AssetScriptingInterface::getAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) {282void AssetScriptingInterface::getAsset(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) {
283 JS_VERIFY(options->isObject() || options->isString(), "expected request options Object or URL as first parameter");283 JS_VERIFY(options.isObject() || options.isString(), "expected request options Object or URL as first parameter");
284 284
285 auto decompress = options->property("decompress")->toBool() || options->property("compressed")->toBool();285 auto decompress = options.property("decompress").toBool() || options.property("compressed").toBool();
286 auto responseType = options->property("responseType")->toString().toLower();286 auto responseType = options.property("responseType").toString().toLower();
287 auto url = options->property("url")->toString();287 auto url = options.property("url").toString();
288 if (options->isString()) {288 if (options.isString()) {
289 url = options->toString();289 url = options.toString();
290 }290 }
291 if (responseType.isEmpty()) {291 if (responseType.isEmpty()) {
292 responseType = "text";292 responseType = "text";
@@ -345,10 +345,10 @@ void AssetScriptingInterface::getAsset(ScriptValuePointer options, ScriptValuePo · 52 unmodified lines
345 * @property {boolean} [wasRedirected] - <code>true</code> if the resolved data is for the baked version of the asset,345 * @property {boolean} [wasRedirected] - <code>true</code> if the resolved data is for the baked version of the asset,
346 * <code>false</code> if it isn't.346 * <code>false</code> if it isn't.
347 */347 */
348void AssetScriptingInterface::resolveAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) {348void AssetScriptingInterface::resolveAsset(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) {
349 const QString& URL{ "url" };349 const QString& URL{ "url" };
350 350
351 auto url = (options->isString() ? options : options->property(URL))->toString();351 auto url = (options.isString() ? options : options.property(URL)).toString();
352 auto asset = AssetUtils::getATPUrl(url).path();352 auto asset = AssetUtils::getATPUrl(url).path();
353 353
354 JS_VERIFY(AssetUtils::isValidFilePath(asset) || AssetUtils::isValidHash(asset),354 JS_VERIFY(AssetUtils::isValidFilePath(asset) || AssetUtils::isValidHash(asset),
@@ -372,10 +372,10 @@ void AssetScriptingInterface::resolveAsset(ScriptValuePointer options, ScriptVal · 17 unmodified lines
372 * @property {string|object|ArrayBuffer} [response] - The decompressed data.372 * @property {string|object|ArrayBuffer} [response] - The decompressed data.
373 * @property {Assets.ResponseType} [responseType] - The type of the decompressed data in <code>response</code>.373 * @property {Assets.ResponseType} [responseType] - The type of the decompressed data in <code>response</code>.
374 */374 */
375void AssetScriptingInterface::decompressData(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) {375void AssetScriptingInterface::decompressData(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) {
376 auto data = options->property("data");376 auto data = options.property("data");
377 QByteArray dataByteArray = scriptvalue_cast<QByteArray>(data);377 QByteArray dataByteArray = scriptvalue_cast<QByteArray>(data);
378 auto responseType = options->property("responseType")->toString().toLower();378 auto responseType = options.property("responseType").toString().toLower();
379 if (responseType.isEmpty()) {379 if (responseType.isEmpty()) {
380 responseType = "text";380 responseType = "text";
381 }381 }
@@ -413,10 +413,10 @@ namespace { · 31 unmodified lines
413 * @property {string} [contentType] - The MIME type of the compressed data, i.e., <code>"application/gzip"</code>.413 * @property {string} [contentType] - The MIME type of the compressed data, i.e., <code>"application/gzip"</code>.
414 * @property {ArrayBuffer} [data] - The compressed data.414 * @property {ArrayBuffer} [data] - The compressed data.
415 */415 */
416void AssetScriptingInterface::compressData(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) {416void AssetScriptingInterface::compressData(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) {
417 auto data = options->property("data")->isValid() ? options->property("data") : options;417 auto data = options.property("data").isValid() ? options.property("data") : options;
418 QByteArray dataByteArray = data->isString() ? data->toString().toUtf8() : scriptvalue_cast<QByteArray>(data);418 QByteArray dataByteArray = data.isString() ? data.toString().toUtf8() : scriptvalue_cast<QByteArray>(data);
419 int level = options->property("level")->isNumber() ? options->property("level")->toInt32() : DEFAULT_GZIP_COMPRESSION_LEVEL;419 int level = options.property("level").isNumber() ? options.property("level").toInt32() : DEFAULT_GZIP_COMPRESSION_LEVEL;
420 JS_VERIFY(level >= DEFAULT_GZIP_COMPRESSION_LEVEL || level <= MAX_GZIP_COMPRESSION_LEVEL, QString("invalid .level %1").arg(level));420 JS_VERIFY(level >= DEFAULT_GZIP_COMPRESSION_LEVEL || level <= MAX_GZIP_COMPRESSION_LEVEL, QString("invalid .level %1").arg(level));
421 jsPromiseReady(compressBytes(dataByteArray, level), scope, callback);421 jsPromiseReady(compressBytes(dataByteArray, level), scope, callback);
422}422}
@@ -442,18 +442,18 @@ void AssetScriptingInterface::compressData(ScriptValuePointer options, ScriptVal · 19 unmodified lines
442 * @property {string} [url] - The <code>atp:</code> URL of the content: using the path if specified, otherwise the hash.442 * @property {string} [url] - The <code>atp:</code> URL of the content: using the path if specified, otherwise the hash.
443 * @property {string} [path] - The uploaded content's mapped path, if specified.443 * @property {string} [path] - The uploaded content's mapped path, if specified.
444 */444 */
445void AssetScriptingInterface::putAsset(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) {445void AssetScriptingInterface::putAsset(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) {
446 auto compress = options->property("compress")->toBool() || options->property("compressed")->toBool();446 auto compress = options.property("compress").toBool() || options.property("compressed").toBool();
447 auto data = options->isObject() ? options->property("data") : options;447 auto data = options.isObject() ? options.property("data") : options;
448 auto rawPath = options->property("path")->toString();448 auto rawPath = options.property("path").toString();
449 auto path = AssetUtils::getATPUrl(rawPath).path();449 auto path = AssetUtils::getATPUrl(rawPath).path();
450 450
451 QByteArray dataByteArray = data->isString() ? data->toString().toUtf8() : scriptvalue_cast<QByteArray>(data);451 QByteArray dataByteArray = data.isString() ? data.toString().toUtf8() : scriptvalue_cast<QByteArray>(data);
452 452
453 JS_VERIFY(path.isEmpty() || AssetUtils::isValidFilePath(path),453 JS_VERIFY(path.isEmpty() || AssetUtils::isValidFilePath(path),
454 QString("expected valid ATP file path '%1' ('%2')").arg(rawPath).arg(path));454 QString("expected valid ATP file path '%1' ('%2')").arg(rawPath).arg(path));
455 JS_VERIFY(dataByteArray.size() > 0,455 JS_VERIFY(dataByteArray.size() > 0,
456 QString("expected non-zero .data (got %1 / #%2 bytes)").arg(data->toVariant().typeName()).arg(dataByteArray.size()));456 QString("expected non-zero .data (got %1 / #%2 bytes)").arg(data.toVariant().typeName()).arg(dataByteArray.size()));
457 457
458 // [compressed] => uploaded to server => [mapped to path]458 // [compressed] => uploaded to server => [mapped to path]
459 Promise prepared = makePromise("putAsset::prepared");459 Promise prepared = makePromise("putAsset::prepared");
@@ -498,8 +498,8 @@ void AssetScriptingInterface::putAsset(ScriptValuePointer options, ScriptValuePo · 38 unmodified lines
498 * @property {string} url - The URL of the cached asset to get information on. Must start with <code>"atp:"</code> or 498 * @property {string} url - The URL of the cached asset to get information on. Must start with <code>"atp:"</code> or
499 * <code>"cache:"</code>.499 * <code>"cache:"</code>.
500 */500 */
501void AssetScriptingInterface::queryCacheMeta(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) {501void AssetScriptingInterface::queryCacheMeta(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) {
502 QString url = options->isString() ? options->toString() : options->property("url")->toString();502 QString url = options.isString() ? options.toString() : options.property("url").toString();
503 JS_VERIFY(QUrl(url).isValid(), QString("Invalid URL '%1'").arg(url));503 JS_VERIFY(QUrl(url).isValid(), QString("Invalid URL '%1'").arg(url));
504 jsPromiseReady(Parent::queryCacheMeta(url), scope, callback);504 jsPromiseReady(Parent::queryCacheMeta(url), scope, callback);
505}505}
@@ -513,16 +513,16 @@ void AssetScriptingInterface::queryCacheMeta(ScriptValuePointer options, ScriptV · 7 unmodified lines
513 * @property {string} url - The URL of the asset to load from cache. Must start with <code>"atp:"</code> or513 * @property {string} url - The URL of the asset to load from cache. Must start with <code>"atp:"</code> or
514 * <code>"cache:"</code>.514 * <code>"cache:"</code>.
515 */515 */
516void AssetScriptingInterface::loadFromCache(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) {516void AssetScriptingInterface::loadFromCache(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) {
517 QString url, responseType;517 QString url, responseType;
518 bool decompress = false;518 bool decompress = false;
519 if (options->isString()) {519 if (options.isString()) {
520 url = options->toString();520 url = options.toString();
521 responseType = "text";521 responseType = "text";
522 } else {522 } else {
523 url = options->property("url")->toString();523 url = options.property("url").toString();
524 responseType = options->property("responseType")->isValid() ? options->property("responseType")->toString() : "text";524 responseType = options.property("responseType").isValid() ? options.property("responseType").toString() : "text";
525 decompress = options->property("decompress")->toBool() || options->property("compressed")->toBool();525 decompress = options.property("decompress").toBool() || options.property("compressed").toBool();
526 }526 }
527 JS_VERIFY(QUrl(url).isValid(), QString("Invalid URL '%1'").arg(url));527 JS_VERIFY(QUrl(url).isValid(), QString("Invalid URL '%1'").arg(url));
528 JS_VERIFY(RESPONSE_TYPES.contains(responseType),528 JS_VERIFY(RESPONSE_TYPES.contains(responseType),
@@ -555,17 +555,21 @@ bool AssetScriptingInterface::canWriteCacheValue(const QUrl& url) { · 26 unmodified lines
555 * @property {string} [url] - The URL to associate with the cache item. Must start with <code>"atp:"</code> or555 * @property {string} [url] - The URL to associate with the cache item. Must start with <code>"atp:"</code> or
556 * <code>"cache:"</code>. If not specified, the URL is <code>"atp:"</code> followed by the SHA256 hash of the content.556 * <code>"cache:"</code>. If not specified, the URL is <code>"atp:"</code> followed by the SHA256 hash of the content.
557 */557 */
558void AssetScriptingInterface::saveToCache(ScriptValuePointer options, ScriptValuePointer scope, ScriptValuePointer callback) {558void AssetScriptingInterface::saveToCache(const ScriptValue& options, const ScriptValue& scope, const ScriptValue& callback) {
559 JS_VERIFY(options->isObject(), QString("expected options object as first parameter not: %1").arg(options->toVariant().typeName()));559 JS_VERIFY(options.isObject(), QString("expected options object as first parameter not: %1").arg(options.toVariant().typeName()));
560 560
561 QString url = options->property("url")->toString();561 QString url = options.property("url").toString();
562 QByteArray data = scriptvalue_cast<QByteArray>(options->property("data"));562 QByteArray data = scriptvalue_cast<QByteArray>(options.property("data"));
563 QVariantMap headers = scriptvalue_cast<QVariantMap>(options->property("headers"));563 QVariantMap headers = scriptvalue_cast<QVariantMap>(options.property("headers"));
564 564
565 saveToCache(url, data, headers, scope, callback);565 saveToCache(url, data, headers, scope, callback);
566}566}
567 567
568void AssetScriptingInterface::saveToCache(const QUrl& rawURL, const QByteArray& data, const QVariantMap& metadata, ScriptValuePointer scope, ScriptValuePointer callback) {568void AssetScriptingInterface::saveToCache(const QUrl& rawURL,
569 const QByteArray& data,
570 const QVariantMap& metadata,
571 const ScriptValue& scope,
572 const ScriptValue& callback) {
569 QUrl url = rawURL;573 QUrl url = rawURL;
570 if (url.path().isEmpty() && !data.isEmpty()) {574 if (url.path().isEmpty() && !data.isEmpty()) {
571 // generate a valid ATP URL from the data -- appending any existing fragment or querystring values575 // generate a valid ATP URL from the data -- appending any existing fragment or querystring values