| Index: ui/file_manager/file_manager/background/js/volume_manager_util.js
|
| diff --git a/ui/file_manager/file_manager/background/js/volume_manager_util.js b/ui/file_manager/file_manager/background/js/volume_manager_util.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fb90b29ff1d6df9afa0a0baca2ff1fbcebef88cb
|
| --- /dev/null
|
| +++ b/ui/file_manager/file_manager/background/js/volume_manager_util.js
|
| @@ -0,0 +1,212 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +/**
|
| + * Utilities for volume manager implementation.
|
| + */
|
| +var volumeManagerUtil = {};
|
| +
|
| +/**
|
| + * Time in milliseconds that we wait a response for. If no response on
|
| + * mount/unmount received the request supposed failed.
|
| + * @const {number}
|
| + */
|
| +volumeManagerUtil.TIMEOUT = 15 * 60 * 1000;
|
| +
|
| +/**
|
| + * @const {string}
|
| + */
|
| +volumeManagerUtil.TIMEOUT_STR_REQUEST_FILE_SYSTEM =
|
| + 'timeout(requestFileSystem)';
|
| +
|
| +/**
|
| + * @const {string}
|
| + */
|
| +volumeManagerUtil.TIMEOUT_STR_RESOLVE_ISOLATED_ENTRIES =
|
| + 'timeout(resolveIsolatedEntries)';
|
| +
|
| +/**
|
| + * Throws an Error when the given error is not in
|
| + * VolumeManagerCommon.VolumeError.
|
| + *
|
| + * @param {string} error Status string usually received from APIs.
|
| + */
|
| +volumeManagerUtil.validateError = function(error) {
|
| + for (var key in VolumeManagerCommon.VolumeError) {
|
| + if (error === VolumeManagerCommon.VolumeError[key])
|
| + return;
|
| + }
|
| +
|
| + throw new Error('Invalid mount error: ' + error);
|
| +};
|
| +
|
| +/**
|
| + * Builds the VolumeInfo data from VolumeMetadata.
|
| + * @param {VolumeMetadata} volumeMetadata Metadata instance for the volume.
|
| + * @return {!Promise.<VolumeInfo>} Promise settled with the VolumeInfo instance.
|
| + */
|
| +volumeManagerUtil.createVolumeInfo = function(volumeMetadata) {
|
| + var localizedLabel;
|
| + switch (volumeMetadata.volumeType) {
|
| + case VolumeManagerCommon.VolumeType.DOWNLOADS:
|
| + localizedLabel = str('DOWNLOADS_DIRECTORY_LABEL');
|
| + break;
|
| + case VolumeManagerCommon.VolumeType.DRIVE:
|
| + localizedLabel = str('DRIVE_DIRECTORY_LABEL');
|
| + break;
|
| + default:
|
| + // TODO(mtomasz): Calculate volumeLabel for all types of volumes in the
|
| + // C++ layer.
|
| + localizedLabel = volumeMetadata.volumeLabel ||
|
| + volumeMetadata.volumeId.split(':', 2)[1];
|
| + break;
|
| + }
|
| +
|
| + console.debug('Requesting file system.');
|
| + return util.timeoutPromise(
|
| + new Promise(function(resolve, reject) {
|
| + chrome.fileSystem.requestFileSystem(
|
| + {
|
| + volumeId: volumeMetadata.volumeId,
|
| + writable: !volumeMetadata.isReadOnly
|
| + },
|
| + function(isolatedFileSystem) {
|
| + if (chrome.runtime.lastError)
|
| + reject(chrome.runtime.lastError.message);
|
| + else
|
| + resolve(isolatedFileSystem);
|
| + });
|
| + }),
|
| + volumeManagerUtil.TIMEOUT,
|
| + volumeManagerUtil.TIMEOUT_STR_REQUEST_FILE_SYSTEM +
|
| + ': ' + volumeMetadata.volumeId)
|
| + .then(
|
| + /**
|
| + * @param {!FileSystem} isolatedFileSystem
|
| + */
|
| + function(isolatedFileSystem) {
|
| + // Since File System API works on isolated entries only, we need to
|
| + // convert it back to external one.
|
| + // TODO(mtomasz): Make Files app work on isolated entries.
|
| + return util.timeoutPromise(
|
| + new Promise(function(resolve, reject) {
|
| + chrome.fileManagerPrivate.resolveIsolatedEntries(
|
| + [isolatedFileSystem.root],
|
| + function(entries) {
|
| + if (chrome.runtime.lastError)
|
| + reject(chrome.runtime.lastError.message);
|
| + else if (!entries[0])
|
| + reject('Resolving for external context failed.');
|
| + else
|
| + resolve(entries[0].filesystem);
|
| + });
|
| + }),
|
| + volumeManagerUtil.TIMEOUT,
|
| + volumeManagerUtil.TIMEOUT_STR_RESOLVE_ISOLATED_ENTRIES +
|
| + ': ' + volumeMetadata.volumeId);
|
| + })
|
| + .then(
|
| + /**
|
| + * @param {!FileSystem} fileSystem
|
| + */
|
| + function(fileSystem) {
|
| + console.debug('File system obtained: ' + volumeMetadata.volumeId);
|
| + if (volumeMetadata.volumeType ===
|
| + VolumeManagerCommon.VolumeType.DRIVE) {
|
| + // After file system is mounted, we "read" drive grand root
|
| + // entry at first. This triggers full feed fetch on background.
|
| + // Note: we don't need to handle errors here, because even if
|
| + // it fails, accessing to some path later will just become
|
| + // a fast-fetch and it re-triggers full-feed fetch.
|
| + fileSystem.root.createReader().readEntries(
|
| + function() { /* do nothing */ },
|
| + function(error) {
|
| + console.error(
|
| + 'Triggering full feed fetch is failed: ' +
|
| + error.name);
|
| + });
|
| + }
|
| + return new VolumeInfoImpl(
|
| + /** @type {VolumeManagerCommon.VolumeType} */
|
| + (volumeMetadata.volumeType),
|
| + volumeMetadata.volumeId,
|
| + fileSystem,
|
| + volumeMetadata.mountCondition,
|
| + volumeMetadata.deviceType,
|
| + volumeMetadata.devicePath,
|
| + volumeMetadata.isReadOnly,
|
| + volumeMetadata.profile,
|
| + localizedLabel,
|
| + volumeMetadata.extensionId,
|
| + volumeMetadata.hasMedia,
|
| + volumeMetadata.configurable,
|
| + volumeMetadata.watchable,
|
| + /** @type {VolumeManagerCommon.Source} */
|
| + (volumeMetadata.source));
|
| + })
|
| + .catch(
|
| + /**
|
| + * @param {*} error
|
| + */
|
| + function(error) {
|
| + console.error('Failed to mount a file system: ' +
|
| + volumeMetadata.volumeId + ' because of: ' +
|
| + (error.stack || error));
|
| + volumeManagerUtil.reportMountError(volumeMetadata, error);
|
| +
|
| + return new VolumeInfoImpl(
|
| + /** @type {VolumeManagerCommon.VolumeType} */
|
| + (volumeMetadata.volumeType),
|
| + volumeMetadata.volumeId,
|
| + null, // File system is not found.
|
| + volumeMetadata.mountCondition,
|
| + volumeMetadata.deviceType,
|
| + volumeMetadata.devicePath,
|
| + volumeMetadata.isReadOnly,
|
| + volumeMetadata.profile,
|
| + localizedLabel,
|
| + volumeMetadata.extensionId,
|
| + volumeMetadata.hasMedia,
|
| + volumeMetadata.configurable,
|
| + volumeMetadata.watchable,
|
| + /** @type {VolumeManagerCommon.Source} */
|
| + (volumeMetadata.source));
|
| + });
|
| +};
|
| +
|
| +/**
|
| + * Reports a mount error to analytics in the form of
|
| + * "mount {errorType} {volumeType}", like
|
| + * "mount timeout(resolveIsolatedEntries) provided:ZipUnpacker".
|
| + * Note that errorType and volumeType must be an element of fixed set of strings
|
| + * to avoid sending dynamic strings to analytics.
|
| + *
|
| + * @param {VolumeMetadata} volumeMetadata
|
| + * @param {*} error
|
| + */
|
| +volumeManagerUtil.reportMountError = function(volumeMetadata, error) {
|
| + var errorType = 'error';
|
| + if (error instanceof Error) {
|
| + if (error.message.startsWith(
|
| + volumeManagerUtil.TIMEOUT_STR_REQUEST_FILE_SYSTEM)) {
|
| + errorType = volumeManagerUtil.TIMEOUT_STR_REQUEST_FILE_SYSTEM;
|
| + }
|
| + if (error.message.startsWith(
|
| + volumeManagerUtil.TIMEOUT_STR_RESOLVE_ISOLATED_ENTRIES)) {
|
| + errorType = volumeManagerUtil.TIMEOUT_STR_RESOLVE_ISOLATED_ENTRIES;
|
| + }
|
| + }
|
| + var volumeType = volumeMetadata.volumeType;
|
| + if (volumeMetadata.volumeType === VolumeManagerCommon.VolumeType.PROVIDED) {
|
| + volumeType += ':' + metrics.getFileSystemProviderName(
|
| + volumeMetadata.extensionId);
|
| + }
|
| + var description = 'mount ' + errorType + ' ' + volumeType;
|
| + var fatal =
|
| + volumeMetadata.volumeType === VolumeManagerCommon.VolumeType.DOWNLOADS ||
|
| + volumeMetadata.volumeType === VolumeManagerCommon.VolumeType.DRIVE;
|
| +
|
| + if (window.background && window.background.tracker)
|
| + window.background.tracker.sendException(description, fatal);
|
| +};
|
|
|