// // AssetScriptingInterface.h // libraries/script-engine/src // // Created by Stephen Birarda on 2016-03-08. // Copyright 2016 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #pragma once #ifndef hifi_AssetScriptingInterface_h #define hifi_AssetScriptingInterface_h #include #include #include #include #include #include #include #include #include /**jsdoc * The Assets API provides facilities for interacting with the domain's asset server and the client cache. *

Assets are stored in the asset server in files with SHA256 names. These files are mapped to user-friendly URLs of the * format: atp:/path/filename. The assets may optionally be baked, in which case a request for the original * unbaked version of the asset is automatically redirected to the baked version. The asset data may optionally be stored as * compressed.

*

The client cache can be accessed directly, using "atp:" or "cache:" URLs. Interface, avatar, * and assignment client scripts can write to the cache. All script types can read from the cache.

* * @namespace Assets * * @hifi-interface * @hifi-client-entity * @hifi-avatar * @hifi-server-entity * @hifi-assignment-client */ class AssetScriptingInterface : public BaseAssetScriptingInterface, QScriptable { Q_OBJECT public: using Parent = BaseAssetScriptingInterface; AssetScriptingInterface(QObject* parent = nullptr); /**jsdoc * Called when an {@link Assets.uploadData} call is complete. * @callback Assets~uploadDataCallback * @param {string} url - The raw URL of the file that the content is stored in, with atp: as the scheme and * the SHA256 hash as the filename (with no extension). * @param {string} hash - The SHA256 hash of the content. */ /**jsdoc * Uploads content to the asset server, storing it in a SHA256-named file. *

Note: The asset server destroys any unmapped SHA256-named file at server restart. Use {@link Assets.setMapping} to * set a path-to-hash mapping for the new file.

* @function Assets.uploadData * @param {string} data - The content to upload. * @param {Assets~uploadDataCallback} callback - The function to call upon completion. * @example Store a string in the asset server. * Assets.uploadData("Hello world!", function (url, hash) { * print("URL: " + url); // atp:0a1b...9g * Assets.setMapping("/assetsExamples/helloWorld.txt", hash, function (error) { * if (error) { * print("ERROR: Could not set mapping!"); * return; * } * }); * }); */ Q_INVOKABLE void uploadData(QString data, QScriptValue callback); /**jsdoc * Called when an {@link Assets.downloadData} call is complete. * @callback Assets~downloadDataCallback * @param {string} data - The content that was downloaded. * @param {Assets.DownloadDataError} error - The success or failure of the download. */ /**jsdoc * Downloads content from the asset server, from a SHA256-named file. * @function Assets.downloadData * @param {string} url - The raw URL of asset to download: atp: followed by the assets's SHA256 hash. * @param {Assets~downloadDataCallback} callback - The function to call upon completion. * @example Store and retrieve a string from the asset server. * var assetURL; * * // Store the string. * Assets.uploadData("Hello world!", function (url, hash) { * assetURL = url; * print("url: " + assetURL); // atp:a0g89... * Assets.setMapping("/assetsExamples/helloWorld.txt", hash, function (error) { * if (error) { * print("ERROR: Could not set mapping!"); * return; * } * }); * }); * * // Retrieve the string. * Script.setTimeout(function () { * Assets.downloadData(assetURL, function (data, error) { * print("Downloaded data: " + data); * print("Error: " + JSON.stringify(error)); * }); * }, 1000); */ Q_INVOKABLE void downloadData(QString url, QScriptValue callback); /**jsdoc * Called when an {@link Assets.setMapping} call is complete. * @callback Assets~setMappingCallback * @param {string} error - null if the path-to-hash mapping was set, otherwise a description of the error. */ /**jsdoc * Sets a path-to-hash mapping within the asset server. * @function Assets.setMapping * @param {string} path - A user-friendly path for the file in the asset server, without leading "atp:". * @param {string} hash - The hash in the asset server. * @param {Assets~setMappingCallback} callback - The function to call upon completion. */ Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); /**jsdoc * Called when an {@link Assets.getMapping} call is complete. * @callback Assets~getMappingCallback * @param {string} error - null if the path was found, otherwise a description of the error. * @param {string} hash - The hash value if the path was found, "" if it wasn't. */ /**jsdoc * Gets the hash for a path within the asset server. The hash is for the unbaked or baked version of the * asset, according to the asset server setting for the particular path. * @function Assets.getMapping * @param {string} path - The path to a file in the asset server to get the hash of. * @param {Assets~getMappingCallback} callback - The function to call upon completion. * @example Report the hash of an asset server item. * var assetPath = Window.browseAssets(); * if (assetPath) { * var mapping = Assets.getMapping(assetPath, function (error, hash) { * print("Asset: " + assetPath); * print("- hash: " + hash); * print("- error: " + error); * }); * } */ Q_INVOKABLE void getMapping(QString path, QScriptValue callback); /**jsdoc * Called when an {@link Assets.setBakingEnabled} call is complete. * @callback Assets~setBakingEnabledCallback * @param {string} error - null if baking was successfully enabled or disabled, otherwise a description of the * error. */ /**jsdoc * Sets whether or not to bake an asset in the asset server. * @function Assets.setBakingEnabled * @param {string} path - The path to a file in the asset server. * @param {boolean} enabled - true to enable baking of the asset, false to disable. * @param {Assets~setBakingEnabledCallback} callback - The function to call upon completion. */ // Note: Second callback parameter not documented because it's always {}. Q_INVOKABLE void setBakingEnabled(QString path, bool enabled, QScriptValue callback); #if (PR_BUILD || DEV_BUILD) /** * This function is purely for development purposes, and not meant for use in a * production context. It is not a public-facing API, so it should not have JSDoc. */ Q_INVOKABLE void sendFakedHandshake(); #endif /**jsdoc * Details of a callback function. * @typedef {object} Assets.CallbackDetails * @property {object} scope - The scope that the callback function is defined in. This object is bound to * this when the function is called. * @property {Assets~compressDataCallback|Assets~decompressDataCallback|Assets~getAssetCallback * |Assets~getCacheStatusCallback|Assets~loadFromCacheCallback|Assets~putAssetCallback|Assets~queryCacheMetaCallback * |Assets~resolveAssetCallback|Assets~saveToCacheCallback} * callback - The function to call upon completion. May be an inline function or a function identifier. If a function * identifier, it must be a member of scope. */ /**jsdoc * Called when an {@link Assets.getAsset} call is complete. * @callback Assets~getAssetCallback * @param {string} error - null if the content was downloaded, otherwise a description of the error. * @param {Assets.GetResult} result - Information on and the content downloaded. */ /**jsdoc * Downloads content from the asset server. * @function Assets.getAsset * @param {string|Assets.GetOptions} source - What to download and download options. If a string, the mapped path or hash * to download, optionally including a leading "atp:". * @param {object|Assets.CallbackDetails|Assets~getAssetCallback} scopeOrCallback - If an object, then the scope that * the callback function is defined in. This object is bound to this when the function is * called. *

Otherwise, the function to call upon completion. This may be an inline function or a function identifier.

* @param {Assets~getAssetCallback} [callback] - Used if scopeOrCallback specifies the scope. *

The function to call upon completion. May be an inline function, a function identifier, or the name of a function * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

* @example Retrieve a string from the asset server. * Assets.getAsset( * { * url: "/assetsExamples/helloWorld.txt", * responseType: "text" * }, * function (error, result) { * if (error) { * print("ERROR: Data not downloaded"); * } else { * print("Data: " + result.response); * } * } * ); */ Q_INVOKABLE void getAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); /**jsdoc * Called when an {@link Assets.putAsset} call is complete. * @callback Assets~putAssetCallback * @param {string} error - null if the content was uploaded and any path-to-hash mapping set, otherwise a * description of the error. * @param {Assets.PutResult} result - Information on the content uploaded. */ /**jsdoc * Uploads content to the asset server and sets a path-to-hash mapping. * @function Assets.putAsset * @param {string|Assets.PutOptions} options - The content to upload and upload options. If a string, the value of the * string is uploaded but a path-to-hash mapping is not set. * @param {object|Assets.CallbackDetails|Assets~putAssetCallback} scopeOrCallback - If an object, then the scope that * the callback function is defined in. This object is bound to this when the function is * called. *

Otherwise, the function to call upon completion. This may be an inline function or a function identifier.

* @param {Assets~putAssetCallback} [callback] - Used if scopeOrCallback specifies the scope. *

The function to call upon completion. May be an inline function, a function identifier, or the name of a function * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

* @example Store a string in the asset server. * Assets.putAsset( * { * data: "Hello world!", * path: "/assetsExamples/helloWorld.txt" * }, * function (error, result) { * if (error) { * print("ERROR: Data not uploaded or mapping not set"); * } else { * print("URL: " + result.url); // atp:/assetsExamples/helloWorld.txt * } * } * ); */ Q_INVOKABLE void putAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); /**jsdoc * Called when an {@link Assets.deleteAsset} call is complete. *

Not implemented: This type is not implemented yet.

* @callback Assets~deleteAssetCallback * @param {string} error - null if the content was deleted, otherwise a description of the error. * @param {Assets.DeleteResult} result - Information on the content deleted. */ /**jsdoc * Deletes content from the asset server. *

Not implemented: This method is not implemented yet.

* @function Assets.deleteAsset * @param {Assets.DeleteOptions} options - The content to delete and delete options. * @param {object} scope - The scope that the callback function is defined in. * @param {Assets~deleteAssetCallback} callback - The function to call upon completion. */ Q_INVOKABLE void deleteAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); /**jsdoc * Called when an {@link Assets.resolveAsset} call is complete. * @callback Assets~resolveAssetCallback * @param {string} error - null if the asset hash or path was resolved, otherwise a description of the error. * @param {Assets.ResolveResult} result - Information on the hash or path resolved. */ /**jsdoc * Resolves and returns information on a hash or a path in the asset server. * @function Assets.resolveAsset * @param {string|Assets.ResolveOptions} source - The hash or path to resolve if a string, otherwise an object specifying * what to resolve. If a string, it may have a leading "atp:". * @param {object|Assets.CallbackDetails|Assets~resolveAssetCallback} scopeOrCallback - If an object, then the scope that * the callback function is defined in. This object is bound to this when the function is * called. *

Otherwise, the function to call upon completion. This may be an inline function or a function identifier.

* @param {Assets~resolveAssetCallback} [callback] - Used if scopeOrCallback specifies the scope. *

The function to call upon completion. May be an inline function, a function identifier, or the name of a function * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

* @example Get the hash and URL for a path. * Assets.resolveAsset( * "/assetsExamples/helloWorld.txt", * function (error, result) { * if (error) { * print("ERROR: " + error); * } else { * print("Hash: " + result.hash); * print("URL: " + result.url); * } * } * ); */ Q_INVOKABLE void resolveAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); /**jsdoc * Called when an {@link Assets.decompressData} call is complete. * @callback Assets~decompressDataCallback * @param {string} error - null if the data was successfully compressed, otherwise a description of the error. * @param {Assets.DecompressResult} result - Information on and the decompressed data. */ /**jsdoc * Decompresses data in memory using gunzip. * @function Assets.decompressData * @param {Assets.DecompressOptions} source - What to decompress and decompression options. * @param {object|Assets.CallbackDetails|Assets~decompressDataCallback} scopeOrCallback - If an object, then the scope that * the callback function is defined in. This object is bound to this when the function is * called. *

Otherwise, the function to call upon completion. This may be an inline function or a function identifier.

* @param {Assets~decompressDataCallback} [callback] - Used if scopeOrCallback specifies the scope. *

The function to call upon completion. May be an inline function, a function identifier, or the name of a function * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

*/ Q_INVOKABLE void decompressData(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); /**jsdoc * Called when an {@link Assets.compressData} call is complete. * @callback Assets~compressDataCallback * @param {string} error - null if the data was successfully compressed, otherwise a description of the error. * @param {Assets.CompressResult} result - Information on and the compressed data. */ /**jsdoc * Compresses data in memory using gzip. * @function Assets.compressData * @param {string|ArrayBuffer|Assets.CompressOptions} source - What to compress and compression options. If a string or * ArrayBuffer, the data to compress. * @param {object|Assets.CallbackDetails|Assets~compressDataCallback} scopeOrCallback - If an object, then the scope that * the callback function is defined in. This object is bound to this when the function is * called. *

Otherwise, the function to call upon completion. This may be an inline function or a function identifier.

* @param {Assets~compressDataCallback} [callback] - Used if scopeOrCallback specifies the scope. *

The function to call upon completion. May be an inline function, a function identifier, or the name of a function * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

*/ Q_INVOKABLE void compressData(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); /**jsdoc * Initializes the cache if it isn't already initialized. * @function Assets.initializeCache * @returns {boolean} true if the cache is initialized, false if it isn't. */ Q_INVOKABLE bool initializeCache(); /**jsdoc * Checks whether the script can write to the cache. * @function Assets.canWriteCacheValue * @param {string} url - Not used. * @returns {boolean} true if the script is an Interface, avatar, or assignment client script, * false if the script is a client entity or server entity script. * @example Report whether the script can write to the cache. * print("Can write to cache: " + Assets.canWriteCacheValue(null)); */ Q_INVOKABLE bool canWriteCacheValue(const QUrl& url); /**jsdoc * Called when a {@link Assets.getCacheStatus} call is complete. * @callback Assets~getCacheStatusCallback * @param {string} error - null if the cache status was retrieved without error, otherwise a description of * the error. * @param {Assets.GetCacheStatusResult} result - Details of the current cache status. */ /**jsdoc * Gets the current cache status. * @function Assets.getCacheStatus * @param {object|Assets.CallbackDetails|Assets~getCacheStatusCallback} scopeOrCallback - If an object, then the scope that * the callback function is defined in. This object is bound to this when the function is * called. *

Otherwise, the function to call upon completion. This may be an inline function or a function identifier.

* @param {Assets~getCacheStatusCallback} [callback] - Used if scopeOrCallback specifies the scope. *

The function to call upon completion. May be an inline function, a function identifier, or the name of a function * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

* @example Report the cache status. * Assets.getCacheStatus(function (error, status) { * print("Cache status"); * print("- Error: " + error); * print("- Status: " + JSON.stringify(status)); * }); */ Q_INVOKABLE void getCacheStatus(QScriptValue scope, QScriptValue callback = QScriptValue()) { jsPromiseReady(Parent::getCacheStatus(), scope, callback); } /**jsdoc * Called when {@link Assets.queryCacheMeta} is complete. * @callback Assets~queryCacheMetaCallback * @param {string} error - null if the URL has a valid cache entry, otherwise a description of the error. * @param {Assets.CacheItemMetaData} result - Information on an asset in the cache. */ /**jsdoc * Gets information about the status of an asset in the cache. * @function Assets.queryCacheMeta * @param {string|Assets.QueryCacheMetaOptions} path - The URL of the cached asset to get information on if a string, * otherwise an object specifying the cached asset to get information on. The URL must start with "atp:" * or "cache:". * @param {object|Assets.CallbackDetails|Assets~queryCacheMetaCallback} scopeOrCallback - If an object, then the scope that * the callback function is defined in. This object is bound to this when the function is * called. *

Otherwise, the function to call upon completion. This may be an inline function or a function identifier.

* @param {Assets~queryCacheMetaCallback} [callback] - Used if scopeOrCallback specifies the scope. *

The function to call upon completion. May be an inline function, a function identifier, or the name of a function * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

* @example Report details of a string store in the cache. * Assets.queryCacheMeta( * "cache:/cacheExample/helloCache.txt", * function (error, result) { * if (error) { * print("Error: " + error); * } else { * print("Success:"); * print("- URL: " + result.url); * print("- isValid: " + result.isValid); * print("- saveToDisk: " + result.saveToDisk); * print("- expirationDate: " + result.expirationDate); * } * } * ); */ Q_INVOKABLE void queryCacheMeta(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); /**jsdoc * Called when an {@link Assets.loadFromCache} call is complete. * @callback Assets~loadFromCacheCallback * @param {string} error - null if the cache item was successfully retrieved, otherwise a description of the * error. * @param {Assets.LoadFromCacheResult} result - Information on and the retrieved data. */ /**jsdoc * Retrieves data from the cache directly, without downloading it. * @function Assets.loadFromCache * @param {string|Assets.LoadFromCacheOptions} options - The URL of the asset to load from the cache if a string, otherwise * an object specifying the asset to load from the cache and load options. The URL must start with "atp:" * or "cache:". * @param {object|Assets.CallbackDetails|Assets~loadFromCacheCallback} scopeOrCallback - If an object, then the scope that * the callback function is defined in. This object is bound to this when the function is * called. *

Otherwise, the function to call upon completion. This may be an inline function or a function identifier.

* @param {Assets~loadFromCacheCallback} [callback] - Used if scopeOrCallback specifies the scope. *

The function to call upon completion. May be an inline function, a function identifier, or the name of a function * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

* @example Retrieve a string from the cache. * Assets.loadFromCache( * "cache:/cacheExample/helloCache.txt", * function (error, result) { * if (error) { * print("Error: " + error); * } else { * print("Success:"); * print("- Response: " + result.response); * print("- Content type: " + result.contentType); * print("- Number of bytes: " + result.byteLength); * print("- Bytes: " + [].slice.call(new Uint8Array(result.data), 0, result.byteLength)); * print("- URL: " + result.url); * } * } * ); */ Q_INVOKABLE void loadFromCache(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); /**jsdoc * Called when an {@link Assets.saveToCache} call is complete. * @callback Assets~saveToCacheCallback * @param {string} error - null if the asset data was successfully saved to the cache, otherwise a description * of the error. * @param {Assets.SaveToCacheResult} result - Information on the cached data. */ /**jsdoc * Saves asset data to the cache directly, without downloading it from a URL. *

Note: Can only be used in Interface, avatar, and assignment client scripts.

* @function Assets.saveToCache * @param {Assets.SaveToCacheOptions} options - The data to save to the cache and cache options. * @param {object|Assets.CallbackDetails|Assets~saveToCacheCallback} scopeOrCallback - If an object, then the scope that * the callback function is defined in. This object is bound to this when the function is * called. *

Otherwise, the function to call upon completion. This may be an inline function or a function identifier.

* @param {Assets~saveToCacheCallback} [callback] - Used if scopeOrCallback specifies the scope. *

The function to call upon completion. May be an inline function, a function identifier, or the name of a function * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

* @example Save a string in the cache. * Assets.saveToCache( * { * url: "cache:/cacheExample/helloCache.txt", * data: "Hello cache" * }, * function (error, result) { * if (error) { * print("Error: " + error); * } else { * print("Success:"); * print("- Bytes: " + result.byteLength); * print("- URL: " + result.url); * } * } * ); */ Q_INVOKABLE void saveToCache(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); /**jsdoc * Saves asset data to the cache directly, without downloading it from a URL. *

Note: Can only be used in Interface, avatar, and assignment client scripts.

* @function Assets.saveToCache * @param {string} url - The URL to associate with the cache item. Must start with "atp:" or * "cache:". * @param {string|ArrayBuffer} data - The data to save to the cache. * @param {Assets.SaveToCacheHeaders} headers - The last-modified and expiry times for the cache item. * @param {object|Assets.CallbackDetails|Assets~saveToCacheCallback} scopeOrCallback - If an object, then the scope that * the callback function is defined in. This object is bound to this when the function is * called. *

Otherwise, the function to call upon completion. This may be an inline function or a function identifier.

* @param {Assets~saveToCacheCallback} [callback] - Used if scopeOrCallback specifies the scope. *

The function to call upon completion. May be an inline function, a function identifier, or the name of a function * in a string. If the name of a function or a function identifier, it must be a member of the scope specified by * scopeOrCallback.

*/ Q_INVOKABLE void saveToCache(const QUrl& url, const QByteArray& data, const QVariantMap& metadata, QScriptValue scope, QScriptValue callback = QScriptValue()); protected: QScriptValue jsBindCallback(QScriptValue scope, QScriptValue callback = QScriptValue()); Promise jsPromiseReady(Promise promise, QScriptValue scope, QScriptValue callback = QScriptValue()); void jsCallback(const QScriptValue& handler, const QScriptValue& error, const QVariantMap& result); void jsCallback(const QScriptValue& handler, const QScriptValue& error, const QScriptValue& result); bool jsVerify(bool condition, const QString& error); }; #endif // hifi_AssetScriptingInterface_h