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