diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index b9a3e6f61e..44f42caec2 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -85,6 +85,13 @@ namespace { const QString& CACHE_ERROR_MESSAGE{ "AssetClient::Error: %1 %2" }; } +/**jsdoc + * Cache status value returned by {@link Assets.getCacheStatus}. + * @typedef {object} Assets.GetCacheStatusResult + * @property {string} cacheDirectory - The path of the cache directory. + * @property {number} cacheSize - The current cache size, in bytes. + * @property {number} maximumCacheSize - The maximum cache size, in bytes. + */ MiniPromise::Promise AssetClient::cacheInfoRequestAsync(MiniPromise::Promise deferred) { if (!deferred) { deferred = makePromise(__FUNCTION__); // create on caller's thread @@ -106,6 +113,20 @@ MiniPromise::Promise AssetClient::cacheInfoRequestAsync(MiniPromise::Promise def return deferred; } +/**jsdoc + * Information on an asset in the cache. Value returned by {@link Assets.queryCacheMeta} and included in the data returned by + * {@link Assets.loadFromCache}. + * @typedef {object} Assets.CacheItemMetaData + * @property {object} [attributes] - The attributes that are stored with this cache item. Not used. + * @property {Date} [expirationDate] - The date and time when the meta data expires. An invalid date means "never expires". + * @property {boolean} isValid - true if the item specified in the URL is in the cache, false if + * it isn't. + * @property {Date} [lastModified] - The date and time when the meta data was last modified. + * @property {object} [rawHeaders] - The raw headers that are set in the meta data. Not used. + * @property {boolean} [saveToDisk] - true if the cache item is allowed to be store on disk, + * false if it isn't. + * @property {string} [url|metaDataURL] - The ATP URL of the cached item. + */ MiniPromise::Promise AssetClient::queryCacheMetaAsync(const QUrl& url, MiniPromise::Promise deferred) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "queryCacheMetaAsync", Q_ARG(const QUrl&, url), Q_ARG(MiniPromise::Promise, deferred)); @@ -202,6 +223,24 @@ namespace { } } +/**jsdoc + * Last-modified and expiry times for a cache item. + * @typedef {object} Assets.SaveToCacheHeaders + * @property {string} [expires] - The date and time the cache value expires, in the format: + * "ddd, dd MMM yyyy HH:mm:ss". The default value is an invalid date, representing "never expires". + * @property {string} [last-modified] - The date and time the cache value was last modified, in the format: + * "ddd, dd MMM yyyy HH:mm:ss". The default value is the current date and time. + */ +/**jsdoc + * Information on saving asset data to the cache with {@link Assets.saveToCache}. + * @typedef {object} Assets.SaveToCacheResult + * @property {number} [byteLength] - The size of the cached data, in bytes. + * @property {Date} [expirationDate] - The date and time that the cache item expires. An invalid date means "never expires". + * @property {Date} [lastModified] - The date and time that the cache item was last modified. + * @property {string} [metaDataURL] - The URL associated with the cache item. + * @property {boolean} [success] - true if the save to cache request was successful. + * @property {string} [url] - The URL associated with the cache item. + */ MiniPromise::Promise AssetClient::saveToCacheAsync(const QUrl& url, const QByteArray& data, const QVariantMap& headers, MiniPromise::Promise deferred) { if (!deferred) { deferred = makePromise(__FUNCTION__); // create on caller's thread diff --git a/libraries/networking/src/BaseAssetScriptingInterface.cpp b/libraries/networking/src/BaseAssetScriptingInterface.cpp index b231339e51..2a98dbf3c3 100644 --- a/libraries/networking/src/BaseAssetScriptingInterface.cpp +++ b/libraries/networking/src/BaseAssetScriptingInterface.cpp @@ -68,6 +68,17 @@ Promise BaseAssetScriptingInterface::queryCacheMeta(const QUrl& url) { return assetClient()->queryCacheMetaAsync(url, makePromise(__FUNCTION__)); } +/**jsdoc + * Data and information returned by {@link Assets.loadFromCache}. + * @typedef {object} Assets.LoadFromCacheResult + * @property {number} [byteLength] - The number of bytes in the retrieved data. + * @property {string} [contentType] - The automatically detected MIME type of the content. + * @property {ArrayBuffer} data - The data bytes. + * @property {Assets.CacheItemMetaData} metadata - Information on the cache item. + * @property {string|object|ArrayBuffer} [response] - The content of the response. + * @property {Assets.ResponseType} responseType - The type of the content in response. + * @property {string} url - The URL of the cache item. + */ Promise BaseAssetScriptingInterface::loadFromCache(const QUrl& url, bool decompress, const QString& responseType) { QVariantMap metaData = { { "_type", "cache" }, diff --git a/libraries/networking/src/BaseAssetScriptingInterface.h b/libraries/networking/src/BaseAssetScriptingInterface.h index 497f627421..7d118e1979 100644 --- a/libraries/networking/src/BaseAssetScriptingInterface.h +++ b/libraries/networking/src/BaseAssetScriptingInterface.h @@ -24,6 +24,22 @@ class BaseAssetScriptingInterface : public QObject { Q_OBJECT public: + + /**jsdoc + *

Types of response that {@link Assets.decompressData}, {@link Assets.getAsset}, or {@link Assets.loadFromCache} may + * provide.

+ * + * + * + * + * + * + * + * + * + *
ValueDescription
"arraybuffer"A binary ArrayBuffer object.
"json"A parsed JSON object.
"text"UTF-8 decoded string value.
+ * @typedef {string} Assets.ResponseType + */ const QStringList RESPONSE_TYPES{ "text", "arraybuffer", "json" }; using Promise = MiniPromise::Promise; QSharedPointer assetClient(); @@ -33,51 +49,62 @@ public: public slots: /**jsdoc + * Checks whether a string is a valid path. Note: A valid path must start with a "/". * @function Assets.isValidPath - * @param {string} input - * @returns {boolean} + * @param {string} path - The path to check. + * @returns {boolean} true if the path is a valid path, false if it isn't. */ bool isValidPath(QString input) { return AssetUtils::isValidPath(input); } /**jsdoc + * Checks whether a string is a valid path and filename. Note: A valid path and filename must start with a "/" + * but must not end with a "/". * @function Assets.isValidFilePath - * @param {string} input - * @returns {boolean} + * @param {string} path - The path to check. + * @returns {boolean} true if the path is a valid file path, false if it isn't. */ bool isValidFilePath(QString input) { return AssetUtils::isValidFilePath(input); } /**jsdoc + * Gets the normalized ATP URL for a path or hash: ensures that it has "atp:" at the start. * @function Assets.getATPUrl - * @param {string} input - * @returns {string} + * @param {string} url - The URL to normalize. + * @returns {string} The normalized ATP URL. */ QUrl getATPUrl(QString input) { return AssetUtils::getATPUrl(input); } /**jsdoc + * Gets the SHA256 hexadecimal hash portion of an asset server URL. * @function Assets.extractAssetHash - * @param {string} input - * @returns {string} + * @param {string} url - The URL to get the SHA256 hexadecimal hash from. + * @returns {string} The SHA256 hexadecimal hash portion of the URL if present and valid, "" otherwise. */ QString extractAssetHash(QString input) { return AssetUtils::extractAssetHash(input); } /**jsdoc + * Checks whether a string is a valid SHA256 hexadecimal hash, i.e., 64 hexadecimal characters. * @function Assets.isValidHash - * @param {string} input - * @returns {boolean} + * @param {string} hash - The hash to check. + * @returns {boolean} true if the hash is a valid SHA256 hexadecimal string, false if it isn't. */ bool isValidHash(QString input) { return AssetUtils::isValidHash(input); } /**jsdoc + * Calculates the SHA256 hash of given data. * @function Assets.hashData - * @param {} data - * @returns {object} + * @param {string|ArrayBuffer} data - The data to calculate the hash of. + * @returns {ArrayBuffer} The SHA256 hash of the data. */ QByteArray hashData(const QByteArray& data) { return AssetUtils::hashData(data); } /**jsdoc + * Calculates the SHA256 hash of given data, in hexadecimal format. * @function Assets.hashDataHex - * @param {} data - * @returns {string} + * @param {string|ArrayBuffer} data - The data to calculate the hash of. + * @returns {string} The SHA256 hash of the data, in hexadecimal format. + * @example Calculate the hash of some text. + * var text = "Hello world!"; + * print("Hash: " + Assets.hashDataHex(text)); */ QString hashDataHex(const QByteArray& data) { return hashData(data).toHex(); } diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index 689b4b89ea..54b570e256 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -81,6 +81,11 @@ void AssetScriptingInterface::setMapping(QString path, QString hash, QScriptValu setMappingRequest->start(); } +/**jsdoc + * The success or failure of an {@link Assets.downloadData} call. + * @typedef {object} Assets.DownloadDataError + * @property {string} errorMessage - "" if the download was successful, otherwise a description of the error. + */ void AssetScriptingInterface::downloadData(QString urlString, QScriptValue callback) { // FIXME: historically this API method failed silently when given a non-atp prefixed // urlString (or if the AssetRequest failed). @@ -219,20 +224,31 @@ void AssetScriptingInterface::deleteAsset(QScriptValue options, QScriptValue sco } /**jsdoc - * @typedef {string} Assets.GetOptions.ResponseType - *

Available responseType values for use with @{link Assets.getAsset} and @{link Assets.loadFromCache} configuration option.

- * - * - * - * - * - * - * - * - * - *
responseTypetypeof response value
"text"contents returned as utf-8 decoded String value
"arraybuffer"contents as a binary ArrayBuffer object
"json"contents as a parsed JSON object
+ * Source and download options for {@link Assets.getAsset}. + * @typedef {object} Assets.GetOptions + * @property {boolean} [decompress=false] - true to gunzip decompress the downloaded data. Synonym: + * compressed. + * @property {Assets.ResponseType} [responseType="text"] - The desired result type. + * @property {string} url - The mapped path or hash to download. May have a leading "atp:". + */ +/**jsdoc + * Result value returned by {@link Assets.getAsset}. + * @typedef {object} Assets.GetResult + * @property {number} [byteLength] - The number of bytes in the downloaded content in response. + * @property {boolean} cached - true if the item was retrieved from the cache, false if it was + * downloaded. + * @property {string} [contentType] - The automatically detected MIME type of the content. + * @property {boolean} [decompressed] - true if the content was decompressed, false if it wasn't. + * @property {string} [hash] - The hash for the downloaded asset. + * @property {string} [hashURL] - The ATP URL of the hash file. + * @property {string} [path] - The path for the asset, if a path was requested. Otherwise, undefined. + * @property {string|object|ArrayBuffer} [response] - The downloaded content. + * @property {Assets.ResponseType} [responseType] - The type of the downloaded content in response. + * @property {string} [url] - The URL of the asset requested: the path with leading "atp:" if a path was + * requested, otherwise the requested URL. + * @property {boolean} [wasRedirected] - true if the downloaded data is the baked version of the asset, + * false if it isn't baked. */ - void AssetScriptingInterface::getAsset(QScriptValue options, QScriptValue scope, QScriptValue callback) { JS_VERIFY(options.isObject() || options.isString(), "expected request options Object or URL as first parameter"); @@ -283,6 +299,22 @@ void AssetScriptingInterface::getAsset(QScriptValue options, QScriptValue scope, } } +/**jsdoc + * Source options for {@link Assets.resolveAsset}. + * @typedef {object} Assets.ResolveOptions + * @property {string} url - The hash or path to resolve. May have a leading "atp:". + */ +/**jsdoc + * Result value returned by {@link Assets.resolveAsset}. + *

Note: If resolving a hash, a file of that hash need not be present on the asset server for the hash to resolve.

+ * @typedef {object} Assets.ResolveResult + * @property {string} [hash] - The hash of the asset. + * @property {string} [hashURL] - The url of the asset's hash file, with leading atp:. + * @property {string} [path] - The path to the asset. + * @property {string} [url] - The URL of the asset. + * @property {boolean} [wasRedirected] - true if the resolved data is for the baked version of the asset, + * false if it isn't. + */ void AssetScriptingInterface::resolveAsset(QScriptValue options, QScriptValue scope, QScriptValue callback) { const QString& URL{ "url" }; @@ -295,6 +327,21 @@ void AssetScriptingInterface::resolveAsset(QScriptValue options, QScriptValue sc jsPromiseReady(getAssetInfo(asset), scope, callback); } +/**jsdoc + * Content and decompression options for {@link Assets.decompressData}. + * @typedef {object} Assets.DecompressOptions + * @property {ArrayBuffer} data - The data to decompress. + * @property {Assets.ResponseType} [responseType=text] - The type of decompressed data to return. + */ +/**jsdoc + * Result value returned by {@link Assets.decompressData}. + * @typedef {object} Assets.DecompressResult + * @property {number} [byteLength] - The number of bytes in the decompressed data. + * @property {string} [contentType] - The MIME type of the decompressed data. + * @property {boolean} [decompressed] - true if the data is decompressed. + * @property {string|object|ArrayBuffer} [response] - The decompressed data. + * @property {Assets.ResponseType} [responseType] - The type of the decompressed data in response. + */ void AssetScriptingInterface::decompressData(QScriptValue options, QScriptValue scope, QScriptValue callback) { auto data = options.property("data"); QByteArray dataByteArray = qscriptvalue_cast(data); @@ -319,6 +366,23 @@ namespace { const int32_t DEFAULT_GZIP_COMPRESSION_LEVEL = -1; const int32_t MAX_GZIP_COMPRESSION_LEVEL = 9; } + +/**jsdoc + * Content and compression options for {@link Assets.compressData}. + * @typedef {object} Assets.CompressOptions + * @property {string|ArrayBuffer} data - The data to compress. + * @property {number} level - The compression level, range -19. -1 means + * use the default gzip compression level, 0 means no compression, and 9 means maximum + * compression. + */ +/**jsdoc + * Result value returned by {@link Assets.compressData}. + * @typedef {object} Assets.CompressResult + * @property {number} [byteLength] - The number of bytes in the compressed data. + * @property {boolean} [compressed] - true if the data is compressed. + * @property {string} [contentType] - The MIME type of the compressed data, i.e., "application/gzip". + * @property {ArrayBuffer} [data] - The compressed data. + */ void AssetScriptingInterface::compressData(QScriptValue options, QScriptValue scope, QScriptValue callback) { auto data = options.property("data").isValid() ? options.property("data") : options; QByteArray dataByteArray = data.isString() ? data.toString().toUtf8() : qscriptvalue_cast(data); @@ -327,6 +391,27 @@ void AssetScriptingInterface::compressData(QScriptValue options, QScriptValue sc jsPromiseReady(compressBytes(dataByteArray, level), scope, callback); } +/**jsdoc + * Content and upload options for {@link Assets.putAsset}. + * @typedef {object} Assets.PutOptions + * @property {boolean} [compress=false] - true to gzip compress the content for upload and storage, + * false to upload and store the data without gzip compression. Synonym: compressed. + * @property {string|ArrayBuffer} data - The content to upload. + * @property {string} [path] - A user-friendly path for the file in the asset server. May have a leading + * "atp:". IF not specified, no path-to-hash mapping is set. + *

Note: The asset server destroys any unmapped SHA256-named file at server restart. Either set the mapping path + * with this property or use {@link Assets.setMapping} to set a path-to-hash mapping for the uploaded file.

+ */ +/**jsdoc + * Result value returned by {@link Assets.putAsset}. + * @typedef {object} Assets.PutResult + * @property {number} [byteLength] - The number of bytes in the hash file stored on the asset server. + * @property {boolean} [compressed] - true if the content stored is gzip compressed. + * @property {string} [contentType] - "application/gzip" if the content stored is gzip compressed. + * @property {string} [hash] - The SHA256 hash of the content. + * @property {string} [url] - The atp: URL of the content: using the path if specified, otherwise the hash. + * @property {string} [path] - The uploaded content's mapped path, if specified. + */ void AssetScriptingInterface::putAsset(QScriptValue options, QScriptValue scope, QScriptValue callback) { auto compress = options.property("compress").toBool() || options.property("compressed").toBool(); auto data = options.isObject() ? options.property("data") : options; @@ -377,12 +462,27 @@ void AssetScriptingInterface::putAsset(QScriptValue options, QScriptValue scope, } } +/**jsdoc + * Source for {@link Assets.queryCacheMeta}. + * @typedef {object} Assets.QueryCacheMetaOptions + * @property {string} url - The URL of the cached asset to get information on. Must start with "atp:" or + * "cache:". + */ void AssetScriptingInterface::queryCacheMeta(QScriptValue options, QScriptValue scope, QScriptValue callback) { QString url = options.isString() ? options.toString() : options.property("url").toString(); JS_VERIFY(QUrl(url).isValid(), QString("Invalid URL '%1'").arg(url)); jsPromiseReady(Parent::queryCacheMeta(url), scope, callback); } +/**jsdoc + * Source and retrieval options for {@link Assets.loadFromCache}. + * @typedef {object} Assets.LoadFromCacheOptions + * @property {boolean} [decompress=false] - true to gunzip decompress the cached data. Synonym: + * compressed. + * @property {Assets.ResponseType} [responseType=text] - The desired result type. + * @property {string} url - The URL of the asset to load from cache. Must start with "atp:" or + * "cache:". + */ void AssetScriptingInterface::loadFromCache(QScriptValue options, QScriptValue scope, QScriptValue callback) { QString url, responseType; bool decompress = false; @@ -417,6 +517,14 @@ bool AssetScriptingInterface::canWriteCacheValue(const QUrl& url) { return true; } +/**jsdoc + * The data to save to the cache and cache options for {@link Assets.saveToCache}. + * @typedef {object} Assets.SaveToCacheOptions + * @property {string|ArrayBuffer} data - The data to save to the cache. + * @property {Assets.SaveToCacheHeaders} [headers] - The last-modified and expiry times for the cache item. + * @property {string} [url] - The URL to associate with the cache item. Must start with "atp:" or + * "cache:". If not specified, the URL is "atp:" followed by the SHA256 hash of the content. + */ void AssetScriptingInterface::saveToCache(QScriptValue options, QScriptValue scope, QScriptValue callback) { JS_VERIFY(options.isObject(), QString("expected options object as first parameter not: %1").arg(options.toVariant().typeName())); diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h index 07d681ca88..5da3c51a08 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -25,7 +25,14 @@ #include /**jsdoc - * The Assets API allows you to communicate with the Asset Browser. + * 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 access 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 @@ -41,251 +48,490 @@ public: AssetScriptingInterface(QObject* parent = nullptr); /**jsdoc - * Upload content to the connected domain's asset server. - * @function Assets.uploadData - * @static - * @param data {string} content to upload - * @param callback {Assets~uploadDataCallback} called when upload is complete + * 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 - * Called when uploadData is complete - * @callback Assets~uploadDataCallback - * @param {string} url - * @param {string} hash + * 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 - * Download data from the connected domain's asset server. - * @function Assets.downloadData - * @param url {string} URL of asset to download, must be ATP scheme URL. - * @param callback {Assets~downloadDataCallback} + * 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 - * Called when downloadData is complete - * @callback Assets~downloadDataCallback - * @param data {string} content that was downloaded + * 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 downloadComplete); + Q_INVOKABLE void downloadData(QString url, QScriptValue callback); /**jsdoc - * Sets up a path to hash mapping within the connected domain's asset server - * @function Assets.setMapping - * @param path {string} - * @param hash {string} - * @param callback {Assets~setMappingCallback} + * 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 - * Called when setMapping is complete - * @callback Assets~setMappingCallback - * @param {string} error + * 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 - * Look up a path to hash mapping within the connected domain's asset server - * @function Assets.getMapping - * @param path {string} - * @param callback {Assets~getMappingCallback} + * 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 - * Called when getMapping is complete. - * @callback Assets~getMappingCallback - * @param assetID {string} hash value if found, else an empty string - * @param error {string} error description if the path could not be resolved; otherwise a null value. + * 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 - * @function Assets.setBakingEnabled - * @param path {string} - * @param enabled {boolean} - * @param callback {} + * 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 - * Called when setBakingEnabled is complete. - * @callback Assets~setBakingEnabledCallback + * 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 contain jsdoc. + * production context. It is not a public-facing API, so it should not have JSDoc. */ Q_INVOKABLE void sendFakedHandshake(); #endif /**jsdoc - * Request Asset data from the ATP Server - * @function Assets.getAsset - * @param {URL|Assets.GetOptions} options An atp: style URL, hash, or relative mapped path; or an {@link Assets.GetOptions} object with request parameters - * @param {Assets~getAssetCallback} scope A scope callback function to receive (error, results) values - * @param {function} [callback=undefined] + * 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 - * A set of properties that can be passed to {@link Assets.getAsset}. - * @typedef {object} Assets.GetOptions - * @property {string} [url] an "atp:" style URL, hash, or relative mapped path to fetch - * @property {string} [responseType=text] the desired reponse type (text | arraybuffer | json) - * @property {boolean} [decompress=false] whether to attempt gunzip decompression on the fetched data - * See: {@link Assets.putAsset} and its .compress=true option - */ - - /**jsdoc - * Called when Assets.getAsset is complete. + * Called when an {@link Assets.getAsset} call is complete. * @callback Assets~getAssetCallback - * @param {string} error - contains error message or null value if no error occured fetching the asset - * @param {Asset~getAssetResult} result - result object containing, on success containing asset metadata and contents + * @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 - * Result value returned by {@link Assets.getAsset}. - * @typedef {object} Assets~getAssetResult - * @property {string} [url] the resolved "atp:" style URL for the fetched asset - * @property {string} [hash] the resolved hash for the fetched asset - * @property {string|ArrayBuffer|Object} [response] response data (possibly converted per .responseType value) - * @property {string} [responseType] response type (text | arraybuffer | json) - * @property {string} [contentType] detected asset mime-type (autodetected) - * @property {number} [byteLength] response data size in bytes - * @property {number} [decompressed] flag indicating whether data was decompressed + * 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 - * Upload Asset data to the ATP Server + * 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 {Assets.PutOptions} options A PutOptions object with upload parameters - * @param {Assets~putAssetCallback} scope[callback] A scoped callback function invoked with (error, results) - * @param {function} [callback=undefined] + * @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 + * } + * } + * ); */ - - /**jsdoc - * A set of properties that can be passed to {@link Assets.putAsset}. - * @typedef {object} Assets.PutOptions - * @property {ArrayBuffer|string} [data] byte buffer or string value representing the new asset's content - * @property {string} [path=null] ATP path mapping to automatically create (upon successful upload to hash) - * @property {boolean} [compress=false] whether to gzip compress data before uploading - */ - - /**jsdoc - * Called when Assets.putAsset is complete. - * @callback Assets~puttAssetCallback - * @param {string} error - contains error message (or null value if no error occured while uploading/mapping the new asset) - * @param {Asset~putAssetResult} result - result object containing error or result status of asset upload - */ - - /**jsdoc - * Result value returned by {@link Assets.putAsset}. - * @typedef {object} Assets~putAssetResult - * @property {string} [url] the resolved "atp:" style URL for the uploaded asset (based on .path if specified, otherwise on the resulting ATP hash) - * @property {string} [path] the uploaded asset's resulting ATP path (or undefined if no path mapping was assigned) - * @property {string} [hash] the uploaded asset's resulting ATP hash - * @property {boolean} [compressed] flag indicating whether the data was compressed before upload - * @property {number} [byteLength] flag indicating final byte size of the data uploaded to the ATP server - */ - Q_INVOKABLE void putAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); /**jsdoc - * @function Assets.deleteAsset - * @param {} options - * @param {} scope - * @param {} [callback = ""] + * 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. */ - - Q_INVOKABLE void deleteAsset(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue()); - /**jsdoc - * @function Assets.resolveAsset - * @param {} options - * @param {} scope - * @param {} [callback = ""] + * 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 - * @function Assets.decompressData - * @param {} options - * @param {} scope - * @param {} [callback = ""] + * 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 - * @function Assets.compressData - * @param {} options - * @param {} scope - * @param {} [callback = ""] + * 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} + * @returns {boolean} true if the cache is initialized, false if it isn't. */ - Q_INVOKABLE bool initializeCache() { return Parent::initializeCache(); } /**jsdoc + * Checks whether the script can write to the cache. * @function Assets.canWriteCacheValue - * @param {string} url - * @returns {boolean} + * @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 - * @function Assets.getCacheStatus - * @param {} scope - * @param {} [callback=undefined] + * 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 - * @function Assets.queryCacheMeta - * @param {} options - * @param {} scope - * @param {} [callback=undefined] + * 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 - * @function Assets.loadFromCache - * @param {} options - * @param {} scope - * @param {} [callback=undefined] + * 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 - * @function Assets.saveToCache - * @param {} options - * @param {} scope - * @param {} [callback=undefined] + * 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 {} url - * @param {} data - * @param {} metadata - * @param {} scope - * @param {} [callback=undefined] + * @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: