Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(375)

Unified Diff: ui/file_manager/file_manager/background/js/media_scanner.js

Issue 865343002: Files.app: Invalidate ScanResult when the scanned directory is changed. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/file_manager/file_manager/background/js/media_scanner.js
diff --git a/ui/file_manager/file_manager/background/js/media_scanner.js b/ui/file_manager/file_manager/background/js/media_scanner.js
index 2d4ce96d91439929c58de6dd8d948de9297d2c36..895c7fa03e32de81d2f64365d061bd047c1e8f78 100644
--- a/ui/file_manager/file_manager/background/js/media_scanner.js
+++ b/ui/file_manager/file_manager/background/js/media_scanner.js
@@ -45,6 +45,11 @@ importer.ScanResult = function() {};
importer.ScanResult.prototype.isFinal;
/**
+ * @return {boolean} true if scanning is invalidated.
+ */
+importer.ScanResult.prototype.isInvalidated;
+
+/**
* Returns all files entries discovered so far. The list will be
* complete only after scanning has completed and {@code isFinal}
* returns {@code true}.
@@ -85,12 +90,14 @@ importer.ScanResult.prototype.whenFinal;
*
* @param {function(!FileEntry): !Promise.<string>} hashGenerator
* @param {!importer.HistoryLoader} historyLoader
+ * @param {!importer.DirectoryWatcherFactory} watcherFactory
*/
-importer.DefaultMediaScanner = function(hashGenerator, historyLoader) {
+importer.DefaultMediaScanner = function(
+ hashGenerator, historyLoader, watcherFactory) {
/**
* A little factory for DefaultScanResults which allows us to forgo
* the saving it's dependencies in our fields.
- * @private {function(): !importer.DefaultScanResult}
+ * @return {!importer.DefaultScanResult}
*/
this.createScanResult_ = function() {
return new importer.DefaultScanResult(hashGenerator, historyLoader);
@@ -98,6 +105,12 @@ importer.DefaultMediaScanner = function(hashGenerator, historyLoader) {
/** @private {!Array.<!importer.ScanObserver>} */
this.observers_ = [];
+
+ /**
+ * @private {!importer.DirectoryWatcherFactory}
+ * @const
+ */
+ this.watcherFactory_ = watcherFactory;
};
/** @override */
@@ -122,7 +135,16 @@ importer.DefaultMediaScanner.prototype.scan = function(entries) {
}
var scanResult = this.createScanResult_();
- var scanPromises = entries.map(this.scanEntry_.bind(this, scanResult));
+ var watcher = this.watcherFactory_(function() {
+ scanResult.invalidateScan();
+ this.observers_.forEach(
+ /** @param {!importer.ScanObserver} observer */
+ function(observer) {
+ observer(importer.ScanEvent.INVALIDATED, scanResult);
+ });
+ }.bind(this));
+ var scanPromises = entries.map(
+ this.scanEntry_.bind(this, scanResult, watcher));
Promise.all(scanPromises)
.then(scanResult.resolveScan.bind(scanResult))
@@ -155,45 +177,50 @@ importer.DefaultMediaScanner.prototype.onScanFinished_ = function(result) {
* Resolves the entry to a list of {@code FileEntry}.
*
* @param {!importer.DefaultScanResult} result
+ * @param {!importer.DirectoryWatcher} watcher
* @param {!Entry} entry
* @return {!Promise}
* @private
*/
importer.DefaultMediaScanner.prototype.scanEntry_ =
- function(result, entry) {
+ function(result, watcher, entry) {
return entry.isFile ?
result.onFileEntryFound(/** @type {!FileEntry} */ (entry)) :
- this.scanDirectory_(result, /** @type {!DirectoryEntry} */ (entry));
+ this.scanDirectory_(
+ result, watcher, /** @type {!DirectoryEntry} */ (entry));
};
/**
* Finds all files beneath directory.
*
* @param {!importer.DefaultScanResult} result
+ * @param {!importer.DirectoryWatcher} watcher
* @param {!DirectoryEntry} entry
* @return {!Promise}
* @private
*/
importer.DefaultMediaScanner.prototype.scanDirectory_ =
- function(result, entry) {
- return new Promise(
- function(resolve, reject) {
- // Collect promises for all files being added to results.
- // The directory scan promise can't resolve until all
- // file entries are completely promised.
- var promises = [];
- fileOperationUtil.findFilesRecursively(
- entry,
- /** @param {!FileEntry} fileEntry */
- function(fileEntry) {
- promises.push(result.onFileEntryFound(fileEntry));
- })
- .then(
- /** @this {importer.DefaultScanResult} */
- function() {
- Promise.all(promises).then(resolve).catch(reject);
- });
- });
+ function(result, watcher, entry) {
+ // Collect promises for all files being added to results.
+ // The directory scan promise can't resolve until all
+ // file entries are completely promised.
+ var promises = [];
+
+ return fileOperationUtil.findEntriesRecursively(
+ entry,
+ /** @param {!Entry} entry */
+ function(entry) {
+ if (watcher.triggered) {
+ return;
+ }
+ if (entry.isDirectory) {
+ watcher.addDirectory(/** @type {!DirectoryEntry} */(entry));
+ } else {
+ promises.push(
+ result.onFileEntryFound(/** @type {!FileEntry} */(entry)));
+ }
+ })
+ .then(Promise.all.bind(Promise, promises));
};
/**
@@ -225,6 +252,11 @@ importer.DefaultScanResult = function(hashGenerator, historyLoader) {
this.fileEntries_ = [];
/**
+ * @private {boolean}
+ */
+ this.invalidated_ = false;
+
+ /**
* Hashcodes of all files included captured by this result object so-far.
* Used to dedupe newly discovered files against other files withing
* the ScanResult.
@@ -276,6 +308,10 @@ importer.DefaultScanResult.prototype.isFinal = function() {
return this.settled_;
};
+importer.DefaultScanResult.prototype.isInvalidated = function() {
+ return this.invalidated_;
+};
+
/** @override */
importer.DefaultScanResult.prototype.getFileEntries = function() {
return this.fileEntries_;
@@ -297,6 +333,13 @@ importer.DefaultScanResult.prototype.whenFinal = function() {
};
/**
+ * Invalidates this scan.
+ */
+importer.DefaultScanResult.prototype.invalidateScan = function() {
+ this.invalidated_ = true;
+};
+
+/**
* Handles files discovered during scanning.
*
* @param {!FileEntry} entry
@@ -385,3 +428,80 @@ importer.DefaultScanResult.prototype.addFileEntry_ = function(entry) {
}.bind(this));
};
+/**
+ * Watcher for directories.
+ * @interface
+ */
+importer.DirectoryWatcher = function() {};
+
+/**
+ * Registers new directory to be watched.
+ * @param {!DirectoryEntry} entry
+ */
+importer.DirectoryWatcher.prototype.addDirectory = function(entry) {};
+
+/**
+ * @typedef {function()}
+ */
+importer.DirectoryWatcherFactoryCallback;
+
+/**
+ * @typedef {function(importer.DirectoryWatcherFactoryCallback):
+ * !importer.DirectoryWatcher}
+ */
+importer.DirectoryWatcherFactory;
+
+/**
+ * Watcher for directories.
+ * @param {function()} callback Callback to be invoked when one of watched
+ * directories is changed.
+ * @implements {importer.DirectoryWatcher}
+ * @constructor
+ */
+importer.DefaultDirectoryWatcher = function(callback) {
+ this.callback_ = callback;
+ this.watchedDirectories_ = {};
+ this.triggered = false;
+ this.listener_ = null;
+};
+
+/**
+ * Creates new directory watcher.
+ * @param {function()} callback Callback to be invoked when one of watched
+ * directories is changed.
+ * @return {!importer.DirectoryWatcher}
+ */
+importer.DefaultDirectoryWatcher.create = function(callback) {
+ return new importer.DefaultDirectoryWatcher(callback);
+};
+
+/**
+ * Registers new directory to be watched.
+ * @param {!DirectoryEntry} entry
+ */
+importer.DefaultDirectoryWatcher.prototype.addDirectory = function(entry) {
+ if (!this.listener_) {
+ this.listener_ = this.onWatchedDirectoryModified_.bind(this);
+ chrome.fileManagerPrivate.onDirectoryChanged.addListener(
+ assert(this.listener_));
+ }
+ this.watchedDirectories_[entry.toURL()] = true;
+ chrome.fileManagerPrivate.addFileWatch(entry.toURL(), function() {});
+};
+
+/**
+ * @param {FileWatchEvent} event
+ * @private
+ */
+importer.DefaultDirectoryWatcher.prototype.onWatchedDirectoryModified_ =
+ function(event) {
+ if (!this.watchedDirectories_[event.entry.toURL()])
+ return;
+ this.triggered = true;
+ for (var url in this.watchedDirectories_) {
+ chrome.fileManagerPrivate.removeFileWatch(url, function() {});
+ }
+ chrome.fileManagerPrivate.onDirectoryChanged.removeListener(
+ assert(this.listener_));
+ this.callback_();
+};

Powered by Google App Engine
This is Rietveld 408576698