• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5'use strict';
6
7/**
8 * Handler of the background page for the drive sync events.
9 * @param {ProgressCenter} progressCenter Progress center to submit the
10 *     progressing items.
11 * @constructor
12 */
13function DriveSyncHandler(progressCenter) {
14  /**
15   * Progress center to submit the progressing item.
16   * @type {ProgressCenter}
17   * @private
18   */
19  this.progressCenter_ = progressCenter;
20
21  /**
22   * Counter for progress ID.
23   * @type {number}
24   * @private
25   */
26  this.idCounter_ = 0;
27
28  /**
29   * Map of file urls and progress center items.
30   * @type {Object.<string, ProgressCenterItem>}
31   * @private
32   */
33  this.items_ = {};
34
35  /**
36   * Async queue.
37   * @type {AsyncUtil.Queue}
38   * @private
39   */
40  this.queue_ = new AsyncUtil.Queue();
41
42  // Register events.
43  chrome.fileBrowserPrivate.onFileTransfersUpdated.addListener(
44      this.onFileTransfersUpdated_.bind(this));
45  chrome.fileBrowserPrivate.onDriveSyncError.addListener(
46      this.onDriveSyncError_.bind(this));
47}
48
49/**
50 * Completed event name.
51 * @type {string}
52 * @const
53 */
54DriveSyncHandler.COMPLETED_EVENT = 'completed';
55
56/**
57 * Progress ID of the drive sync.
58 * @type {string}
59 * @const
60 */
61DriveSyncHandler.PROGRESS_ITEM_ID_PREFIX = 'drive-sync-';
62
63DriveSyncHandler.prototype = {
64  __proto__: cr.EventTarget.prototype,
65
66  /**
67   * @return {boolean} Whether the handler is having syncing items or not.
68   */
69  get syncing() {
70    // Check if this.items_ has properties or not.
71    for (var url in this.items_) {
72      return true;
73    }
74    return false;
75  }
76};
77
78/**
79 * Handles file transfer updated events.
80 * @param {Array.<FileTransferStatus>} statusList List of drive status.
81 * @private
82 */
83DriveSyncHandler.prototype.onFileTransfersUpdated_ = function(statusList) {
84  var completed = false;
85  for (var i = 0; i < statusList.length; i++) {
86    var status = statusList[i];
87    switch (status.transferState) {
88      case 'in_progress':
89      case 'started':
90        this.updateItem_(status);
91        break;
92      case 'completed':
93      case 'failed':
94        this.removeItem_(status);
95        if (!this.syncing)
96          this.dispatchEvent(new Event(DriveSyncHandler.COMPLETED_EVENT));
97        break;
98      default:
99        throw new Error(
100            'Invalid transfer state: ' + status.transferState + '.');
101    }
102  }
103};
104
105/**
106 * Updates the item involved with the given status.
107 * @param {FileTransferStatus} status Transfer status.
108 * @private
109 */
110DriveSyncHandler.prototype.updateItem_ = function(status) {
111  this.queue_.run(function(callback) {
112    if (this.items_[status.fileUrl]) {
113      callback();
114      return;
115    }
116    webkitResolveLocalFileSystemURL(status.fileUrl, function(entry) {
117      var item = new ProgressCenterItem();
118      item.id =
119          DriveSyncHandler.PROGRESS_ITEM_ID_PREFIX + (this.idCounter_++);
120      item.type = ProgressItemType.SYNC;
121      item.quiet = true;
122      item.message = strf('SYNC_FILE_NAME', entry.name);
123      item.cancelCallback = this.requestCancel_.bind(this, entry);
124      this.items_[status.fileUrl] = item;
125      callback();
126    }.bind(this), function(error) {
127      console.warn('Resolving URL ' + status.fileUrl + ' is failed: ', error);
128      callback();
129    });
130  }.bind(this));
131  this.queue_.run(function(callback) {
132    var item = this.items_[status.fileUrl];
133    if (!item) {
134      callback();
135      return;
136    }
137    item.progressValue = status.processed || 0;
138    item.progressMax = status.total || 1;
139    this.progressCenter_.updateItem(item);
140    callback();
141  }.bind(this));
142};
143
144/**
145 * Removes the item involved with the given status.
146 * @param {FileTransferStatus} status Transfer status.
147 * @private
148 */
149DriveSyncHandler.prototype.removeItem_ = function(status) {
150  this.queue_.run(function(callback) {
151    var item = this.items_[status.fileUrl];
152    if (!item) {
153      callback();
154      return;
155    }
156    item.state = status.transferState === 'completed' ?
157        ProgressItemState.COMPLETED : ProgressItemState.CANCELED;
158    this.progressCenter_.updateItem(item);
159    delete this.items_[status.fileUrl];
160    callback();
161  }.bind(this));
162};
163
164/**
165 * Requests to cancel for the given files' drive sync.
166 * @param {Entry} entry Entry to be canceled.
167 * @private
168 */
169DriveSyncHandler.prototype.requestCancel_ = function(entry) {
170  chrome.fileBrowserPrivate.cancelFileTransfers([entry.toURL()], function() {});
171};
172
173/**
174 * Handles drive's sync errors.
175 * @param {DriveSyncErrorEvent} event Drive sync error event.
176 * @private
177 */
178DriveSyncHandler.prototype.onDriveSyncError_ = function(event) {
179  webkitResolveLocalFileSystemURL(event.fileUrl, function(entry) {
180    var item;
181    item = new ProgressCenterItem();
182    item.id = DriveSyncHandler.PROGRESS_ITEM_ID_PREFIX + (this.idCounter_++);
183    item.type = ProgressItemType.SYNC;
184    item.quiet = true;
185    item.state = ProgressItemState.ERROR;
186    switch (event.type) {
187      case 'delete_without_permission':
188        item.message =
189            strf('SYNC_DELETE_WITHOUT_PERMISSION_ERROR', entry.name);
190        break;
191      case 'service_unavailable':
192        item.message = str('SYNC_SERVICE_UNAVAILABLE_ERROR');
193        break;
194      case 'misc':
195        item.message = strf('SYNC_MISC_ERROR', entry.name);
196        break;
197    }
198    this.progressCenter_.updateItem(item);
199  }.bind(this));
200};
201