Index: chrome/browser/resources/file_manager/js/metadata/metadata_provider.js |
diff --git a/chrome/browser/resources/file_manager/js/metadata/metadata_provider.js b/chrome/browser/resources/file_manager/js/metadata/metadata_provider.js |
index bad35636d83a3b451e3125a60a2d9f27b1655e39..311cb94fd921ccdc694af1be9ae9c75172c348fb 100644 |
--- a/chrome/browser/resources/file_manager/js/metadata/metadata_provider.js |
+++ b/chrome/browser/resources/file_manager/js/metadata/metadata_provider.js |
@@ -3,16 +3,12 @@ |
// found in the LICENSE file. |
/** |
- * A base class for metadata providers. Implementing in-memory caching. |
+ * A base class for metadata provider. Implementing in-memory caching. |
*/ |
function MetadataCache() { |
this.cache_ = {}; |
} |
-MetadataCache.prototype.isSupported = function(url) { |
- return true; |
-}; |
- |
MetadataCache.prototype.doFetch = function(url) { |
throw new Error('MetadataCache.doFetch not implemented'); |
}; |
@@ -21,12 +17,11 @@ MetadataCache.prototype.fetch = function(url, callback) { |
var cacheValue = this.cache_[url]; |
if (!cacheValue) { |
- // This is the first time anyone's asked, go get it. |
- if (this.isSupported(url)) { |
- this.cache_[url] = [callback]; |
- this.doFetch(url); |
- } else { |
+ // This is the first time anyone has asked, go get it. |
+ this.cache_[url] = [callback]; |
+ if (!this.doFetch(url)) { |
// Fetch failed, return an empty map, no caching needed. |
+ delete this.cache_[url]; |
setTimeout(callback, 0, {}); |
} |
return; |
@@ -40,7 +35,7 @@ MetadataCache.prototype.fetch = function(url, callback) { |
if (cacheValue instanceof Object) { |
// We already know the answer, let the caller know in a fresh call stack. |
- setTimeout(function() { callback(cacheValue) }, 0); |
+ setTimeout(callback, 0, cacheValue); |
return; |
} |
@@ -75,10 +70,37 @@ MetadataCache.prototype.reset = function(url) { |
}; |
/** |
- * Create metadata provider for local files. |
+ * Base class for metadata fetchers. |
+ * |
+ * @param {function(string, Object)} resultCallback |
+ * @param {string} urlPrefix. |
*/ |
-function MetadataProvider() { |
- MetadataCache.call(this); |
+function MetadataFetcher(resultCallback, urlPrefix) { |
+ this.resultCallback_ = resultCallback; |
+ this.urlPrefix_ = urlPrefix; |
+} |
+ |
+MetadataFetcher.prototype.processResult = function(url, metadata) { |
+ this.resultCallback_(url, metadata); |
+}; |
+ |
+MetadataFetcher.prototype.isInitialized = function() { |
+ return true; |
+}; |
+ |
+MetadataFetcher.prototype.supports = function(url) { |
+ return url.indexOf(this.urlPrefix_) == 0; |
+}; |
+ |
+MetadataFetcher.prototype.doFetch = function(url) { |
+ console.error('MetadataFetcher.doFetch not implemented'); |
+}; |
+ |
+/** |
+ * Create metadata cache for local files. |
+ */ |
+function LocalMetadataFetcher(resultCallback, rootUrl) { |
+ MetadataFetcher.apply(this, arguments); |
// Pass all URLs to the metadata reader until we have a correct filter. |
this.urlFilter = /.*/; |
@@ -93,22 +115,28 @@ function MetadataProvider() { |
this.dispatcher_.postMessage({verb: 'init'}); |
// Initialization is not complete until the Worker sends back the |
// 'initialized' message. See below. |
+ this.initialized_ = false; |
} |
-MetadataProvider.prototype = { __proto__: MetadataCache.prototype }; |
+LocalMetadataFetcher.prototype = { __proto__: MetadataFetcher.prototype }; |
-MetadataProvider.prototype.isSupported = function(url) { |
- return url.match(this.urlFilter); |
+LocalMetadataFetcher.prototype.supports = function(url) { |
+ return MetadataFetcher.prototype.supports.apply(this, arguments) && |
+ url.match(this.urlFilter); |
}; |
-MetadataProvider.prototype.doFetch = function(url) { |
+LocalMetadataFetcher.prototype.doFetch = function(url) { |
this.dispatcher_.postMessage({verb: 'request', arguments: [url]}); |
}; |
+LocalMetadataFetcher.prototype.isInitialized = function() { |
+ return this.initialized_; |
+}; |
+ |
/** |
* Dispatch a message from a metadata reader to the appropriate on* method. |
*/ |
-MetadataProvider.prototype.onMessage_ = function(event) { |
+LocalMetadataFetcher.prototype.onMessage_ = function(event) { |
var data = event.data; |
var methodName = |
@@ -125,39 +153,48 @@ MetadataProvider.prototype.onMessage_ = function(event) { |
/** |
* Handles the 'initialized' message from the metadata reader Worker. |
*/ |
-MetadataProvider.prototype.onInitialized_ = function(regexp) { |
+LocalMetadataFetcher.prototype.onInitialized_ = function(regexp) { |
this.urlFilter = regexp; |
+ |
+ // Tests can monitor for this state with |
+ // ExtensionTestMessageListener listener("worker-initialized"); |
+ // ASSERT_TRUE(listener.WaitUntilSatisfied()); |
+ // Automated tests need to wait for this, otherwise we crash in |
+ // browser_test cleanup because the worker process still has |
+ // URL requests in-flight. |
+ chrome.test.sendMessage('worker-initialized'); |
+ this.initialized_ = true; |
}; |
-MetadataProvider.prototype.onResult_ = function(url, metadata) { |
+LocalMetadataFetcher.prototype.onResult_ = function(url, metadata) { |
this.processResult(url, metadata); |
}; |
-MetadataProvider.prototype.onError_ = function(url, step, error, metadata) { |
+LocalMetadataFetcher.prototype.onError_ = function(url, step, error, metadata) { |
console.warn('metadata: ' + url + ': ' + step + ': ' + error); |
this.processResult(url, metadata || {}); |
}; |
-MetadataProvider.prototype.onLog_ = function(arglist) { |
+LocalMetadataFetcher.prototype.onLog_ = function(arglist) { |
console.log.apply(console, ['metadata:'].concat(arglist)); |
}; |
/** |
- * Create a metadata provider for GData files. |
+ * Create a metadata fetcher for GData files. |
* |
* Instead of reading the file contents it gets the metadata from GData API. |
*/ |
-function GDataMetadataProvider() { |
- MetadataCache.call(this); |
+function GDataMetadataFetcher(resultCallback, rootUrl) { |
+ MetadataFetcher.apply(this, arguments); |
} |
-GDataMetadataProvider.prototype = { __proto__: MetadataCache.prototype }; |
+GDataMetadataFetcher.prototype = { __proto__: MetadataFetcher.prototype }; |
-GDataMetadataProvider.prototype.doFetch = function(url) { |
+GDataMetadataFetcher.prototype.doFetch = function(url) { |
function convertMetadata(result) { |
return { |
thumbnailURL: result.thumbnailUrl, |
- thumbnailOnly: true, // Temporary, unless we learn to fetch the content. |
+ contentURL: (result.contentUrl || '').replace(/\?.*$/gi, ''), |
fileSize: 0 // TODO(kaznacheev) Get the correct size from File API. |
} |
} |
@@ -167,3 +204,44 @@ GDataMetadataProvider.prototype.doFetch = function(url) { |
this.processResult(url, convertMetadata(results[0])); |
}.bind(this)); |
}; |
+ |
+/** |
+ * Create universal metadata provider. |
+ * |
+ * @param {string} rootUrl The file system root url. |
+ * @constructor |
+ */ |
+function MetadataProvider(rootUrl) { |
+ MetadataCache.call(this); |
+ |
+ var resultCallback = this.processResult.bind(this); |
+ |
+ // TODO(kaznacheev): We use 'gdata' literal here because |
+ // DirectoryModel.GDATA_DIRECTORY definition might be not available. |
+ // Consider extracting this definition into some common js file. |
+ this.fetchers_ = [ |
+ new GDataMetadataFetcher(resultCallback, rootUrl + 'gdata' + '/'), |
+ new LocalMetadataFetcher(resultCallback, rootUrl) |
+ ]; |
+} |
+ |
+MetadataProvider.prototype = { __proto__: MetadataCache.prototype }; |
+ |
+MetadataProvider.prototype.isInitialized = function() { |
+ for (var i = 0; i != this.fetchers_.length; i++) { |
+ if (!this.fetchers_[i].isInitialized()) |
+ return false; |
+ } |
+ return true; |
+}; |
+ |
+MetadataProvider.prototype.doFetch = function(url) { |
+ for (var i = 0; i != this.fetchers_.length; i++) { |
+ var fetcher = this.fetchers_[i]; |
+ if (fetcher.supports(url)) { |
+ fetcher.doFetch(url); |
+ return true; |
+ } |
+ } |
+ return false; |
+}; |