Commit 22d1d35a authored by François Degros's avatar François Degros Committed by Commit Bot

Files app: VolumeManager's mountArchive and unmount return a Promise

Changed VolumeManager's methods mountArchive() and unmount() to make
them return a Promise instead of taking completion callbacks.

Change-Id: I9debd4c7edc8256f24f539f81bac088c44edd09a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1727653Reviewed-by: default avatarFrançois Degros <fdegros@chromium.org>
Reviewed-by: default avatarAustin Tankiang <austinct@chromium.org>
Commit-Queue: François Degros <fdegros@chromium.org>
Cr-Commit-Position: refs/heads/master@{#683027}
parent 90c92d1f
...@@ -388,31 +388,16 @@ class FilteredVolumeManager extends cr.EventTarget { ...@@ -388,31 +388,16 @@ class FilteredVolumeManager extends cr.EventTarget {
return volumeInfo; return volumeInfo;
} }
/** /** @override */
* Requests to mount the archive file. async mountArchive(fileUrl) {
* @param {string} fileUrl The path to the archive file to be mounted. await this.initialized_;
* @param {function(VolumeInfo)} successCallback Called with the VolumeInfo return this.volumeManager_.mountArchive(fileUrl);
* instance.
* @param {function(VolumeManagerCommon.VolumeError)} errorCallback Called
* when an error occurs.
*/
mountArchive(fileUrl, successCallback, errorCallback) {
this.ensureInitialized(() => {
this.volumeManager_.mountArchive(fileUrl, successCallback, errorCallback);
});
} }
/** /** @override */
* Requests unmount the specified volume. async unmount(volumeInfo) {
* @param {!VolumeInfo} volumeInfo Volume to be unmounted. await this.initialized_;
* @param {function()} successCallback Called on success. return this.volumeManager_.unmount(volumeInfo);
* @param {function(VolumeManagerCommon.VolumeError)} errorCallback Called
* when an error occurs.
*/
unmount(volumeInfo, successCallback, errorCallback) {
this.ensureInitialized(() => {
this.volumeManager_.unmount(volumeInfo, successCallback, errorCallback);
});
} }
/** /**
......
...@@ -37,20 +37,18 @@ class VolumeManager { ...@@ -37,20 +37,18 @@ class VolumeManager {
/** /**
* @param {string} fileUrl File url to the archive file. * @param {string} fileUrl File url to the archive file.
* @param {function(VolumeInfo)} successCallback Success callback. * @return {!Promise<!VolumeInfo>} Fulfilled on success, otherwise rejected
* @param {function(VolumeManagerCommon.VolumeError)} errorCallback Error * with a VolumeManagerCommon.VolumeError.
* callback.
*/ */
mountArchive(fileUrl, successCallback, errorCallback) {} mountArchive(fileUrl) {}
/** /**
* Unmounts a volume. * Unmounts a volume.
* @param {!VolumeInfo} volumeInfo Volume to be unmounted. * @param {!VolumeInfo} volumeInfo Volume to be unmounted.
* @param {function()} successCallback Success callback. * @return {!Promise<void>} Fulfilled on success, otherwise rejected with a
* @param {function(VolumeManagerCommon.VolumeError)} errorCallback Error * VolumeManagerCommon.VolumeError.
* callback.
*/ */
unmount(volumeInfo, successCallback, errorCallback) {} unmount(volumeInfo) {}
/** /**
* Configures a volume. * Configures a volume.
...@@ -132,4 +130,3 @@ class VolumeManager { ...@@ -132,4 +130,3 @@ class VolumeManager {
* @typedef {!CustomEvent<!VolumeInfo>} * @typedef {!CustomEvent<!VolumeInfo>}
*/ */
let ExternallyUnmountedEvent; let ExternallyUnmountedEvent;
...@@ -190,11 +190,11 @@ class MockVolumeManager { ...@@ -190,11 +190,11 @@ class MockVolumeManager {
return volumeInfo; return volumeInfo;
} }
mountArchive(fileUrl, successCallback, errorCallback) { async mountArchive(fileUrl) {
throw new Error('Not implemented'); throw new Error('Not implemented');
} }
unmount(volumeInfo, successCallback, errorCallback) { async unmount(volumeInfo) {
throw new Error('Not implemented'); throw new Error('Not implemented');
} }
......
...@@ -142,9 +142,9 @@ class VolumeManagerImpl extends cr.EventTarget { ...@@ -142,9 +142,9 @@ class VolumeManagerImpl extends cr.EventTarget {
try { try {
// Create VolumeInfo for each volume. // Create VolumeInfo for each volume.
await Promise.all(volumeMetadataList.map(async (volumeMetadata) => { await Promise.all(volumeMetadataList.map(async (volumeMetadata) => {
console.warn(`Initializing volume: ${volumeMetadata.volumeId}`); console.warn(`Initializing volume '${volumeMetadata.volumeId}'`);
const volumeInfo = await this.addVolumeMetadata_(volumeMetadata); const volumeInfo = await this.addVolumeMetadata_(volumeMetadata);
console.warn(`Initialized volume: ${volumeInfo.volumeId}`); console.warn(`Initialized volume '${volumeInfo.volumeId}'`);
})); }));
console.warn(`Initialized all ${volumeMetadataList.length} volumes`); console.warn(`Initialized all ${volumeMetadataList.length} volumes`);
...@@ -187,7 +187,8 @@ class VolumeManagerImpl extends cr.EventTarget { ...@@ -187,7 +187,8 @@ class VolumeManagerImpl extends cr.EventTarget {
break; break;
} }
console.error(`Cannot mount volume: ${event.status}`); console.error(`Cannot mount '${event.volumeMetadata.sourcePath}': ${
event.status}`);
this.finishRequest_(requestKey, event.status); this.finishRequest_(requestKey, event.status);
break; break;
...@@ -202,7 +203,7 @@ class VolumeManagerImpl extends cr.EventTarget { ...@@ -202,7 +203,7 @@ class VolumeManagerImpl extends cr.EventTarget {
null; null;
if (event.status === 'success' && !requested && volumeInfo) { if (event.status === 'success' && !requested && volumeInfo) {
console.warn(`Unmounted volume without request: ${volumeId}`); console.warn(`Unmounted '${volumeId}' without request`);
this.dispatchEvent( this.dispatchEvent(
new CustomEvent('externally-unmounted', {detail: volumeInfo})); new CustomEvent('externally-unmounted', {detail: volumeInfo}));
} }
...@@ -212,7 +213,6 @@ class VolumeManagerImpl extends cr.EventTarget { ...@@ -212,7 +213,6 @@ class VolumeManagerImpl extends cr.EventTarget {
this.volumeInfoList.remove(event.volumeMetadata.volumeId); this.volumeInfoList.remove(event.volumeMetadata.volumeId);
} }
console.warn(`Unmounted volume: ${volumeId}`);
break; break;
} }
} finally { } finally {
...@@ -234,19 +234,24 @@ class VolumeManagerImpl extends cr.EventTarget { ...@@ -234,19 +234,24 @@ class VolumeManagerImpl extends cr.EventTarget {
} }
/** @override */ /** @override */
mountArchive(fileUrl, successCallback, errorCallback) { async mountArchive(fileUrl) {
chrome.fileManagerPrivate.addMount(fileUrl, sourcePath => { const path = await new Promise(resolve => {
console.info(`Mount request: url=${fileUrl}; sourcePath=${sourcePath}`); chrome.fileManagerPrivate.addMount(fileUrl, resolve);
const requestKey = this.makeRequestKey_('mount', sourcePath);
this.startRequest_(requestKey, successCallback, errorCallback);
}); });
console.warn(`Mounting '${path}'`);
const key = this.makeRequestKey_('mount', path);
const volumeInfo = await this.startRequest_(key);
console.warn(`Mounted '${path}' as '${volumeInfo.volumeId}'`);
return volumeInfo;
} }
/** @override */ /** @override */
unmount(volumeInfo, successCallback, errorCallback) { async unmount(volumeInfo) {
console.warn(`Unmounting '${volumeInfo.volumeId}'`);
chrome.fileManagerPrivate.removeMount(volumeInfo.volumeId); chrome.fileManagerPrivate.removeMount(volumeInfo.volumeId);
const requestKey = this.makeRequestKey_('unmount', volumeInfo.volumeId); const key = this.makeRequestKey_('unmount', volumeInfo.volumeId);
this.startRequest_(requestKey, successCallback, errorCallback); await this.startRequest_(key);
console.warn(`Unmounted '${volumeInfo.volumeId}'`);
} }
/** @override */ /** @override */
...@@ -442,13 +447,12 @@ class VolumeManagerImpl extends cr.EventTarget { ...@@ -442,13 +447,12 @@ class VolumeManagerImpl extends cr.EventTarget {
/** /**
* @param {string} key Key produced by |makeRequestKey_|. * @param {string} key Key produced by |makeRequestKey_|.
* @param {function(VolumeInfo)} successCallback To be called when the request * @return {!Promise<!VolumeInfo>} Fulfilled on success, otherwise rejected
* finishes successfully. * with a VolumeManagerCommon.VolumeError.
* @param {function(VolumeManagerCommon.VolumeError)} errorCallback To be
* called when the request fails.
* @private * @private
*/ */
startRequest_(key, successCallback, errorCallback) { startRequest_(key) {
return new Promise((successCallback, errorCallback) => {
if (key in this.requests_) { if (key in this.requests_) {
const request = this.requests_[key]; const request = this.requests_[key];
request.successCallbacks.push(successCallback); request.successCallbacks.push(successCallback);
...@@ -462,6 +466,7 @@ class VolumeManagerImpl extends cr.EventTarget { ...@@ -462,6 +466,7 @@ class VolumeManagerImpl extends cr.EventTarget {
this.onTimeout_.bind(this, key), volumeManagerUtil.TIMEOUT) this.onTimeout_.bind(this, key), volumeManagerUtil.TIMEOUT)
}; };
} }
});
} }
/** /**
......
...@@ -189,11 +189,9 @@ function testMountArchiveAndUnmount(callback) { ...@@ -189,11 +189,9 @@ function testMountArchiveAndUnmount(callback) {
const numberOfVolumes = volumeManager.volumeInfoList.length; const numberOfVolumes = volumeManager.volumeInfoList.length;
// Mount an archive // Mount an archive
const mounted = new Promise( const mounted = volumeManager.mountArchive(
(resolve, reject) => volumeManager.mountArchive(
'filesystem:chrome-extension://extensionid/external/' + 'filesystem:chrome-extension://extensionid/external/' +
'Downloads-test/foobar.zip', 'Downloads-test/foobar.zip');
resolve, reject));
mockChrome.fileManagerPrivate.onMountCompleted.dispatchEvent({ mockChrome.fileManagerPrivate.onMountCompleted.dispatchEvent({
eventType: 'mount', eventType: 'mount',
...@@ -219,9 +217,7 @@ function testMountArchiveAndUnmount(callback) { ...@@ -219,9 +217,7 @@ function testMountArchiveAndUnmount(callback) {
const entry = const entry =
new MockFileEntry(new MockFileSystem('archive:foobar.zip'), '/foo.txt'); new MockFileEntry(new MockFileSystem('archive:foobar.zip'), '/foo.txt');
const volumeInfo = volumeManager.getVolumeInfo(entry); const volumeInfo = volumeManager.getVolumeInfo(entry);
await new Promise( await volumeManager.unmount(volumeInfo);
(resolve, reject) =>
volumeManager.unmount(volumeInfo, resolve, reject));
assertEquals(numberOfVolumes, volumeManager.volumeInfoList.length); assertEquals(numberOfVolumes, volumeManager.volumeInfoList.length);
}; };
......
...@@ -97,9 +97,7 @@ volumeManagerUtil.createVolumeInfo = volumeMetadata => { ...@@ -97,9 +97,7 @@ volumeManagerUtil.createVolumeInfo = volumeMetadata => {
break; break;
} }
console.warn( console.warn(`Getting file system '${volumeMetadata.volumeId}'`);
'Requesting file system: ' + volumeMetadata.volumeType + ' ' +
volumeMetadata.volumeId);
return util return util
.timeoutPromise( .timeoutPromise(
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
...@@ -132,7 +130,7 @@ volumeManagerUtil.createVolumeInfo = volumeMetadata => { ...@@ -132,7 +130,7 @@ volumeManagerUtil.createVolumeInfo = volumeMetadata => {
if (chrome.runtime.lastError) { if (chrome.runtime.lastError) {
reject(chrome.runtime.lastError.message); reject(chrome.runtime.lastError.message);
} else if (!entries[0]) { } else if (!entries[0]) {
reject('Resolving for external context failed.'); reject('Resolving for external context failed');
} else { } else {
resolve(entries[0].filesystem); resolve(entries[0].filesystem);
} }
...@@ -145,7 +143,7 @@ volumeManagerUtil.createVolumeInfo = volumeMetadata => { ...@@ -145,7 +143,7 @@ volumeManagerUtil.createVolumeInfo = volumeMetadata => {
.then( .then(
/** @param {!FileSystem} fileSystem */ /** @param {!FileSystem} fileSystem */
fileSystem => { fileSystem => {
console.warn('File system obtained: ' + volumeMetadata.volumeId); console.warn(`Got file system '${volumeMetadata.volumeId}'`);
if (volumeMetadata.volumeType === if (volumeMetadata.volumeType ===
VolumeManagerCommon.VolumeType.DRIVE) { VolumeManagerCommon.VolumeType.DRIVE) {
// After file system is mounted, we "read" drive grand root // After file system is mounted, we "read" drive grand root
...@@ -156,7 +154,7 @@ volumeManagerUtil.createVolumeInfo = volumeMetadata => { ...@@ -156,7 +154,7 @@ volumeManagerUtil.createVolumeInfo = volumeMetadata => {
fileSystem.root.createReader().readEntries( fileSystem.root.createReader().readEntries(
() => {/* do nothing */}, error => { () => {/* do nothing */}, error => {
console.warn( console.warn(
'Triggering full feed fetch has failed: ' + error.name); `Triggering full feed fetch has failed: ${error.name}`);
}); });
} }
return new VolumeInfoImpl( return new VolumeInfoImpl(
...@@ -178,9 +176,8 @@ volumeManagerUtil.createVolumeInfo = volumeMetadata => { ...@@ -178,9 +176,8 @@ volumeManagerUtil.createVolumeInfo = volumeMetadata => {
.catch( .catch(
/** @param {*} error */ /** @param {*} error */
error => { error => {
console.warn( console.error(`Cannot mount file system '${
'Failed to mount a file system: ' + volumeMetadata.volumeId + volumeMetadata.volumeId}': ${error.stack || error}`);
' because of: ' + (error.stack || error));
// TODO(crbug/847729): Report a mount error via UMA. // TODO(crbug/847729): Report a mount error via UMA.
......
...@@ -544,7 +544,12 @@ CommandHandler.COMMANDS_ = {}; ...@@ -544,7 +544,12 @@ CommandHandler.COMMANDS_ = {};
* Unmounts external drive. * Unmounts external drive.
*/ */
CommandHandler.COMMANDS_['unmount'] = new class extends Command { CommandHandler.COMMANDS_['unmount'] = new class extends Command {
execute(event, fileManager) { /**
* @param {!Event} event Command event.
* @param {!CommandHandlerDeps} fileManager CommandHandlerDeps.
* @private
*/
async executeImpl_(event, fileManager) {
/** @param {VolumeManagerCommon.VolumeType=} opt_volumeType */ /** @param {VolumeManagerCommon.VolumeType=} opt_volumeType */
const errorCallback = opt_volumeType => { const errorCallback = opt_volumeType => {
if (opt_volumeType === VolumeManagerCommon.VolumeType.REMOVABLE) { if (opt_volumeType === VolumeManagerCommon.VolumeType.REMOVABLE) {
...@@ -556,11 +561,6 @@ CommandHandler.COMMANDS_['unmount'] = new class extends Command { ...@@ -556,11 +561,6 @@ CommandHandler.COMMANDS_['unmount'] = new class extends Command {
} }
}; };
const successCallback = () => {
const msg = strf('A11Y_VOLUME_EJECT', label);
fileManager.ui.speakA11yMessage(msg);
};
// Find volumes to unmount. // Find volumes to unmount.
let volumes = []; let volumes = [];
let label = ''; let label = '';
...@@ -587,11 +587,22 @@ CommandHandler.COMMANDS_['unmount'] = new class extends Command { ...@@ -587,11 +587,22 @@ CommandHandler.COMMANDS_['unmount'] = new class extends Command {
} }
// Eject volumes of which there may be multiple. // Eject volumes of which there may be multiple.
for (let i = 0; i < volumes.length; i++) { const promises = volumes.map(async (volume) => {
fileManager.volumeManager.unmount( try {
volumes[i], (i == volumes.length - 1) ? successCallback : () => {}, await fileManager.volumeManager.unmount(volume);
errorCallback.bind(null, volumes[i].volumeType)); } catch (error) {
console.error(
`Cannot unmount ${volume.volumeId}: ${error.stack || error}`);
errorCallback(volume.volumeType);
} }
});
await Promise.all(promises);
fileManager.ui.speakA11yMessage(strf('A11Y_VOLUME_EJECT', label));
}
execute(event, fileManager) {
this.executeImpl_(event, fileManager);
} }
/** @override */ /** @override */
......
...@@ -886,44 +886,45 @@ class FileTasks { ...@@ -886,44 +886,45 @@ class FileTasks {
} }
/** /**
* The core implementation of mounts archives. * The core implementation of mount archives.
* @private * @private
*/ */
mountArchivesInternal_() { async mountArchivesInternal_() {
const tracker = this.directoryModel_.createDirectoryChangeTracker(); const tracker = this.directoryModel_.createDirectoryChangeTracker();
tracker.start(); tracker.start();
try {
// TODO(mtomasz): Move conversion from entry to url to custom bindings. // TODO(mtomasz): Move conversion from entry to url to custom bindings.
// crbug.com/345527. // crbug.com/345527.
const urls = util.entriesToURLs(this.entries_); const urls = util.entriesToURLs(this.entries_);
for (let index = 0; index < urls.length; ++index) { const promises = urls.map(async (url) => {
// TODO(mtomasz): Pass Entry instead of URL. try {
this.volumeManager_.mountArchive(urls[index], volumeInfo => { const volumeInfo = await this.volumeManager_.mountArchive(url);
if (tracker.hasChanged) { if (tracker.hasChanged) {
tracker.stop();
return; return;
} }
volumeInfo.resolveDisplayRoot(
displayRoot => { try {
const displayRoot = await volumeInfo.resolveDisplayRoot();
if (tracker.hasChanged) { if (tracker.hasChanged) {
tracker.stop();
return; return;
} }
this.directoryModel_.changeDirectoryEntry(displayRoot); this.directoryModel_.changeDirectoryEntry(displayRoot);
}, } catch (error) {
() => { console.error('Cannot resolve display root after mounting:', error);
console.warn( }
'Failed to resolve the display root after mounting.'); } catch (error) {
tracker.stop();
});
}, ((url, error) => {
tracker.stop();
const path = util.extractFilePath(url); const path = util.extractFilePath(url);
const namePos = path.lastIndexOf('/'); const namePos = path.lastIndexOf('/');
this.ui_.alertDialog.show( this.ui_.alertDialog.show(
strf('ARCHIVE_MOUNT_FAILED', path.substr(namePos + 1), error), strf('ARCHIVE_MOUNT_FAILED', path.substr(namePos + 1), error),
null, null); null, null);
}).bind(null, urls[index])); }
});
await Promise.all(promises);
} finally {
tracker.stop();
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment