Assets API cache methods

This commit is contained in:
David Rowe 2019-09-04 13:48:06 +12:00
parent 2ad1d7a2a2
commit 8820d1d76b
4 changed files with 216 additions and 30 deletions

View file

@ -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. <em>Not used.</em>
* @property {Date} [expirationDate] - The date and time when the meta data expires. An invalid date means "never expires".
* @property {boolean} isValid - <code>true</code> if the item specified in the URL is in the cache, <code>false</code> 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. <em>Not used.</em>
* @property {boolean} [saveToDisk] - <code>true</code> if the cache item is allowed to be store on disk,
* <code>false</code> 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} [last-modified] - The date and time the cache value was last modified, in the format:
* <code>"ddd, dd MMM yyyy HH:mm:ss"</code>. The default value is the current date and time.
* @property {string} [expires] - The date and time the cache value expires, in the format:
* <code>"ddd, dd MMM yyyy HH:mm:ss"</code>. The default value is an invalid date, representing "never expires".
*/
/**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] - <code>true</code> 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

View file

@ -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 <code>response</code>.
* @property {string} url - The URL of the cache item.
*/
Promise BaseAssetScriptingInterface::loadFromCache(const QUrl& url, bool decompress, const QString& responseType) {
QVariantMap metaData = {
{ "_type", "cache" },

View file

@ -362,6 +362,15 @@ void AssetScriptingInterface::queryCacheMeta(QScriptValue options, QScriptValue
jsPromiseReady(Parent::queryCacheMeta(url), scope, callback);
}
/**jsdoc
* Source and retrieval options for {@link Assets.loadFromCache}.
* @typedef {object} Assets.LoadFromCacheOptions
* @property {string} url - The URL of the asset to load from cache. Must start with <code>"atp:"</code> or
* <code>"cache:"</code>.
* @property {Assets.ResponseType} [responseType=text] - The desired result type.
* @property {boolean} [decompress=false] - <code>true</code> to gunzip decompress the cached data. Synonym:
* <code>compressed</code>.
*/
void AssetScriptingInterface::loadFromCache(QScriptValue options, QScriptValue scope, QScriptValue callback) {
QString url, responseType;
bool decompress = false;
@ -396,6 +405,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 <code>"atp:"</code> or
* <code>"cache:"</code>. If not specified, the URL is <code>"atp:"</code> 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()));

View file

@ -468,66 +468,185 @@ public:
Q_INVOKABLE void compressData(QScriptValue options, QScriptValue scope, QScriptValue callback = QScriptValue());
/**jsdoc
* Initializes the local cache if it isn't already initialized.
* @function Assets.initializeCache
* @returns {boolean}
* @returns {boolean} <code>true</code> if the local cache is initialized, <code>false</code> if it isn't.
*/
Q_INVOKABLE bool initializeCache() { return Parent::initializeCache(); }
/**jsdoc
* Checks whether the script can write to the local cache.
* @function Assets.canWriteCacheValue
* @param {string} url
* @returns {boolean}
* @param {string} url - <em>Not used.</em>
* @returns {boolean} <code>true</code> if the script is an Interface, avatar, or assignment client script,
* <code>false</code> if the script is a client entity or server entity script.
* @example <caption>Report whether the script can write to the cache.</caption>
* 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 - <code>null</code> if the cache status was retrieved without error, otherwise a description of
* the error.
* @param {Assets.GetCacheStatusResult} status - 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 <code>callback</code> function is defined in. This object is bound to <code>this</code> when the function is
* called.
* <p>Otherwise, the function to call upon completion. This may be an inline function or a function identifier.</p>
* @param {Assets~getCacheStatusCallback} [callback] - Used if <code>scopeOrCallback</code> specifies the scope.
* <p>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
* <code>scopeOrCallback</code>.</p>
* @example <caption>Report the cache status.</caption>
* 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 - <code>null</code> if the URL has a valid cache entry, otherwise a description of the error.
* @param {Assets.CacheItemMetaData} queryResult - Information on an asset in the cache.
*/
/**jsdoc
* Gets information about the status of an asset in the cache.
* @function Assets.queryCacheMeta
* @param {string|object} path - The URL of the cached asset to get information on. If an object then <code>path.url</code>
* is used. Must start with <code>"atp:"</code> or <code>"cache:"</code>.
* @param {object|Assets.CallbackDetails|Assets~queryCacheMetaCallback} scopeOrCallback - If an object, then the scope that
* the <code>callback</code> function is defined in. This object is bound to <code>this</code> when the function is
* called.
* <p>Otherwise, the function to call upon completion. This may be an inline function or a function identifier.</p>
* @param {Assets~queryCacheMetaCallback} [callback] - Used if <code>scopeOrCallback</code> specifies the scope.
* <p>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
* <code>scopeOrCallback</code>.</p>
* @example <caption>Report details of a string store in the cache.</caption>
* 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 - <code>null</code> 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 <code>"atp:"</code>
* or <code>"cache:"</code>.
* @param {object|Assets.CallbackDetails|Assets~loadFromCacheCallback} scopeOrCallback - If an object, then the scope that
* the <code>callback</code> function is defined in. This object is bound to <code>this</code> when the function is
* called.
* <p>Otherwise, the function to call upon completion. This may be an inline function or a function identifier.</p>
* @param {Assets~loadFromCacheCallback} [callback] - Used if <code>scopeOrCallback</code> specifies the scope.
* <p>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
* <code>scopeOrCallback</code>.</p>
* @example <caption>Retrieve a string from the cache.</caption>
* 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 - <code>null</code> 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.
* <p>Note: Can only be used in Interface, avatar, and assignment client scripts.</p>
* @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 <code>callback</code> function is defined in. This object is bound to <code>this</code> when the function is
* called.
* <p>Otherwise, the function to call upon completion. This may be an inline function or a function identifier.</p>
* @param {Assets~saveToCacheCallback} [callback] - Used if <code>scopeOrCallback</code> specifies the scope.
* <p>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
* <code>scopeOrCallback</code>.</p>
* @example <caption>Save a string in the cache.</caption>
* 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.
* <p>Note: Can only be used in Interface, avatar, and assignment client scripts.</p>
* @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 <code>"atp:"</code> or
* <code>"cache:"</code>.
* @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 <code>callback</code> function is defined in. This object is bound to <code>this</code> when the function is
* called.
* <p>Otherwise, the function to call upon completion. This may be an inline function or a function identifier.</p>
* @param {Assets~saveToCacheCallback} [callback] - Used if <code>scopeOrCallback</code> specifies the scope.
* <p>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
* <code>scopeOrCallback</code>.</p>
*/
Q_INVOKABLE void saveToCache(const QUrl& url, const QByteArray& data, const QVariantMap& metadata,
QScriptValue scope, QScriptValue callback = QScriptValue());
protected: