Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Namespace | 5 // Namespace |
| 6 var importer = importer || {}; | 6 var importer = importer || {}; |
| 7 | 7 |
| 8 /** | 8 /** |
| 9 * Interface providing access to information about active import processes. | 9 * Interface providing access to information about active import processes. |
| 10 * | 10 * |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 25 | 25 |
| 26 /** | 26 /** |
| 27 * Handler for importing media from removable devices into the user's Drive. | 27 * Handler for importing media from removable devices into the user's Drive. |
| 28 * | 28 * |
| 29 * @constructor | 29 * @constructor |
| 30 * @implements {importer.ImportRunner} | 30 * @implements {importer.ImportRunner} |
| 31 * @struct | 31 * @struct |
| 32 * | 32 * |
| 33 * @param {!ProgressCenter} progressCenter | 33 * @param {!ProgressCenter} progressCenter |
| 34 * @param {!importer.HistoryLoader} historyLoader | 34 * @param {!importer.HistoryLoader} historyLoader |
| 35 * @param {!importer.DuplicateFinder.Factory} duplicateFinderFactory | |
| 36 * @param {!analytics.Tracker} tracker | 35 * @param {!analytics.Tracker} tracker |
| 37 */ | 36 */ |
| 38 importer.MediaImportHandler = | 37 importer.MediaImportHandler = |
|
mtomasz
2015/03/05 04:36:53
nit: Will it fit in one line? If not, then we brea
Steve McKay
2015/03/05 21:39:03
Done.
| |
| 39 function(progressCenter, historyLoader, duplicateFinderFactory, tracker) { | 38 function(progressCenter, historyLoader, tracker) { |
| 40 /** @private {!ProgressCenter} */ | 39 /** @private {!ProgressCenter} */ |
| 41 this.progressCenter_ = progressCenter; | 40 this.progressCenter_ = progressCenter; |
| 42 | 41 |
| 43 /** @private {!importer.HistoryLoader} */ | 42 /** @private {!importer.HistoryLoader} */ |
| 44 this.historyLoader_ = historyLoader; | 43 this.historyLoader_ = historyLoader; |
| 45 | 44 |
| 46 /** @private {!importer.TaskQueue} */ | 45 /** @private {!importer.TaskQueue} */ |
| 47 this.queue_ = new importer.TaskQueue(); | 46 this.queue_ = new importer.TaskQueue(); |
| 48 | 47 |
| 49 // Prevent the system from sleeping while imports are active. | 48 // Prevent the system from sleeping while imports are active. |
| 50 this.queue_.setActiveCallback(function() { | 49 this.queue_.setActiveCallback(function() { |
| 51 chrome.power.requestKeepAwake('system'); | 50 chrome.power.requestKeepAwake('system'); |
| 52 }); | 51 }); |
| 53 this.queue_.setIdleCallback(function() { | 52 this.queue_.setIdleCallback(function() { |
| 54 chrome.power.releaseKeepAwake(); | 53 chrome.power.releaseKeepAwake(); |
| 55 }); | 54 }); |
| 56 | 55 |
| 57 /** @private {!importer.DuplicateFinder.Factory} */ | |
| 58 this.duplicateFinderFactory_ = duplicateFinderFactory; | |
| 59 | |
| 60 /** @private {!analytics.Tracker} */ | 56 /** @private {!analytics.Tracker} */ |
| 61 this.tracker_ = tracker; | 57 this.tracker_ = tracker; |
| 62 | 58 |
| 63 /** @private {number} */ | 59 /** @private {number} */ |
| 64 this.nextTaskId_ = 0; | 60 this.nextTaskId_ = 0; |
| 65 }; | 61 }; |
| 66 | 62 |
| 67 /** @override */ | 63 /** @override */ |
| 68 importer.MediaImportHandler.prototype.importFromScanResult = | 64 importer.MediaImportHandler.prototype.importFromScanResult = |
| 69 function(scanResult, destination, directoryPromise) { | 65 function(scanResult, destination, directoryPromise) { |
| 70 | 66 |
| 71 var task = new importer.MediaImportHandler.ImportTask( | 67 var task = new importer.MediaImportHandler.ImportTask( |
| 72 this.generateTaskId_(), | 68 this.generateTaskId_(), |
| 73 this.historyLoader_, | 69 this.historyLoader_, |
| 74 scanResult, | 70 scanResult, |
| 75 directoryPromise, | 71 directoryPromise, |
| 76 this.duplicateFinderFactory_.create(), | |
| 77 destination, | 72 destination, |
| 78 this.tracker_); | 73 this.tracker_); |
| 79 | 74 |
| 80 task.addObserver(this.onTaskProgress_.bind(this, task)); | 75 task.addObserver(this.onTaskProgress_.bind(this, task)); |
| 81 | 76 |
| 82 this.queue_.queueTask(task); | 77 this.queue_.queueTask(task); |
| 83 | 78 |
| 84 return task; | 79 return task; |
| 85 }; | 80 }; |
| 86 | 81 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 148 * FileOperationManager.CopyTask) but this is a temporary state of affairs. | 143 * FileOperationManager.CopyTask) but this is a temporary state of affairs. |
| 149 * | 144 * |
| 150 * @constructor | 145 * @constructor |
| 151 * @extends {importer.TaskQueue.BaseTask} | 146 * @extends {importer.TaskQueue.BaseTask} |
| 152 * @struct | 147 * @struct |
| 153 * | 148 * |
| 154 * @param {string} taskId | 149 * @param {string} taskId |
| 155 * @param {!importer.HistoryLoader} historyLoader | 150 * @param {!importer.HistoryLoader} historyLoader |
| 156 * @param {!importer.ScanResult} scanResult | 151 * @param {!importer.ScanResult} scanResult |
| 157 * @param {!Promise<!DirectoryEntry>} directoryPromise | 152 * @param {!Promise<!DirectoryEntry>} directoryPromise |
| 158 * @param {!importer.DuplicateFinder} duplicateFinder A duplicate-finder linked | |
| 159 * to the import destination, that will be used to deduplicate imports. | |
| 160 * @param {!importer.Destination} destination The logical destination. | 153 * @param {!importer.Destination} destination The logical destination. |
| 161 * @param {!analytics.Tracker} tracker | 154 * @param {!analytics.Tracker} tracker |
| 162 */ | 155 */ |
| 163 importer.MediaImportHandler.ImportTask = function( | 156 importer.MediaImportHandler.ImportTask = function( |
| 164 taskId, | 157 taskId, |
| 165 historyLoader, | 158 historyLoader, |
| 166 scanResult, | 159 scanResult, |
| 167 directoryPromise, | 160 directoryPromise, |
| 168 duplicateFinder, | |
| 169 destination, | 161 destination, |
| 170 tracker) { | 162 tracker) { |
| 171 | 163 |
| 172 importer.TaskQueue.BaseTask.call(this, taskId); | 164 importer.TaskQueue.BaseTask.call(this, taskId); |
| 173 /** @private {string} */ | 165 /** @private {string} */ |
| 174 this.taskId_ = taskId; | 166 this.taskId_ = taskId; |
| 175 | 167 |
| 176 /** @private {!importer.Destination} */ | 168 /** @private {!importer.Destination} */ |
| 177 this.destination_ = destination; | 169 this.destination_ = destination; |
| 178 | 170 |
| 179 /** @private {!Promise<!DirectoryEntry>} */ | 171 /** @private {!Promise<!DirectoryEntry>} */ |
| 180 this.directoryPromise_ = directoryPromise; | 172 this.directoryPromise_ = directoryPromise; |
| 181 | 173 |
| 182 /** @private {!importer.DuplicateFinder} */ | |
| 183 this.deduplicator_ = duplicateFinder; | |
| 184 | |
| 185 /** @private {!importer.ScanResult} */ | 174 /** @private {!importer.ScanResult} */ |
| 186 this.scanResult_ = scanResult; | 175 this.scanResult_ = scanResult; |
| 187 | 176 |
| 188 /** @private {!importer.HistoryLoader} */ | 177 /** @private {!importer.HistoryLoader} */ |
| 189 this.historyLoader_ = historyLoader; | 178 this.historyLoader_ = historyLoader; |
| 190 | 179 |
| 191 /** @private {!analytics.Tracker} */ | 180 /** @private {!analytics.Tracker} */ |
| 192 this.tracker_ = tracker; | 181 this.tracker_ = tracker; |
| 193 | 182 |
| 194 /** @private {number} */ | 183 /** @private {number} */ |
| 195 this.totalBytes_ = 0; | 184 this.totalBytes_ = 0; |
| 196 | 185 |
| 197 /** @private {number} */ | 186 /** @private {number} */ |
| 198 this.processedBytes_ = 0; | 187 this.processedBytes_ = 0; |
| 199 | 188 |
| 200 /** @private {number} */ | 189 /** @private {number} */ |
| 201 this.remainingFilesCount_ = 0; | 190 this.remainingFilesCount_ = 0; |
| 202 | 191 |
| 203 /** @private {?function()} */ | 192 /** @private {?function()} */ |
| 204 this.cancelCallback_ = null; | 193 this.cancelCallback_ = null; |
| 205 | 194 |
| 206 /** @private {boolean} Indicates whether this task was canceled. */ | 195 /** @private {boolean} Indicates whether this task was canceled. */ |
| 207 this.canceled_ = false; | 196 this.canceled_ = false; |
| 208 | 197 |
| 209 /** @private {number} Number of files deduped by content dedupe. */ | |
| 210 this.dedupeCount_ = 0; | |
| 211 | |
| 212 /** @private {number} */ | 198 /** @private {number} */ |
| 213 this.errorCount_ = 0; | 199 this.errorCount_ = 0; |
| 214 }; | 200 }; |
| 215 | 201 |
| 216 /** @struct */ | 202 /** @struct */ |
| 217 importer.MediaImportHandler.ImportTask.prototype = { | 203 importer.MediaImportHandler.ImportTask.prototype = { |
| 218 /** @return {number} Number of imported bytes */ | 204 /** @return {number} Number of imported bytes */ |
| 219 get processedBytes() { return this.processedBytes_; }, | 205 get processedBytes() { return this.processedBytes_; }, |
| 220 | 206 |
| 221 /** @return {number} Total number of bytes to import */ | 207 /** @return {number} Total number of bytes to import */ |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 270 // (including calling #requestCancel again). | 256 // (including calling #requestCancel again). |
| 271 var cancelCallback = this.cancelCallback_; | 257 var cancelCallback = this.cancelCallback_; |
| 272 this.cancelCallback_ = null; | 258 this.cancelCallback_ = null; |
| 273 cancelCallback(); | 259 cancelCallback(); |
| 274 } | 260 } |
| 275 }; | 261 }; |
| 276 | 262 |
| 277 /** @private */ | 263 /** @private */ |
| 278 importer.MediaImportHandler.ImportTask.prototype.initialize_ = function() { | 264 importer.MediaImportHandler.ImportTask.prototype.initialize_ = function() { |
| 279 var stats = this.scanResult_.getStatistics(); | 265 var stats = this.scanResult_.getStatistics(); |
| 280 | |
| 281 this.remainingFilesCount_ = stats.newFileCount; | 266 this.remainingFilesCount_ = stats.newFileCount; |
| 282 this.totalBytes_ = stats.sizeBytes; | 267 this.totalBytes_ = stats.sizeBytes; |
| 283 this.notify(importer.TaskQueue.UpdateType.PROGRESS); | 268 this.notify(importer.TaskQueue.UpdateType.PROGRESS); |
| 284 | 269 |
| 285 this.tracker_.send(metrics.ImportEvents.STARTED); | 270 this.tracker_.send(metrics.ImportEvents.STARTED); |
| 286 this.tracker_.send(metrics.ImportEvents.HISTORY_DEDUPE_COUNT | |
| 287 .value(stats.duplicateFileCount)); | |
| 288 }; | 271 }; |
| 289 | 272 |
| 290 /** | 273 /** |
| 291 * Initiates an import to the given location. This should only be called once | 274 * Initiates an import to the given location. This should only be called once |
| 292 * the scan result indicates that it is ready. | 275 * the scan result indicates that it is ready. |
| 293 * | 276 * |
| 294 * @private | 277 * @private |
| 295 */ | 278 */ |
| 296 importer.MediaImportHandler.ImportTask.prototype.importScanEntries_ = | 279 importer.MediaImportHandler.ImportTask.prototype.importScanEntries_ = |
| 297 function() { | 280 function() { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 309 * @param {!DirectoryEntry} destinationDirectory | 292 * @param {!DirectoryEntry} destinationDirectory |
| 310 * @param {function()} completionCallback Called after this operation is | 293 * @param {function()} completionCallback Called after this operation is |
| 311 * complete. | 294 * complete. |
| 312 * @param {!FileEntry} entry The entry to import. | 295 * @param {!FileEntry} entry The entry to import. |
| 313 * @private | 296 * @private |
| 314 */ | 297 */ |
| 315 importer.MediaImportHandler.ImportTask.prototype.importOne_ = | 298 importer.MediaImportHandler.ImportTask.prototype.importOne_ = |
| 316 function(destinationDirectory, completionCallback, entry) { | 299 function(destinationDirectory, completionCallback, entry) { |
| 317 if (this.canceled_) { | 300 if (this.canceled_) { |
| 318 this.notify(importer.TaskQueue.UpdateType.CANCELED); | 301 this.notify(importer.TaskQueue.UpdateType.CANCELED); |
| 319 this.tracker_.send(metrics.ImportEvents.CANCELLED); | 302 this.sendImportStats_(false); |
| 320 this.sendImportStats_(); | |
| 321 return; | 303 return; |
| 322 } | 304 } |
| 323 | 305 |
| 324 this.deduplicator_.checkDuplicate(entry) | 306 this.copy_(entry, destinationDirectory) |
| 325 .then( | |
| 326 /** @param {boolean} isDuplicate */ | |
| 327 function(isDuplicate) { | |
| 328 if (isDuplicate) { | |
| 329 // If the given file is a duplicate, don't import it again. Just | |
| 330 // update the progress indicator. | |
| 331 this.dedupeCount_++; | |
| 332 this.markAsImported_(entry); | |
| 333 this.processedBytes_ += entry.size; | |
| 334 this.notify(importer.TaskQueue.UpdateType.PROGRESS); | |
| 335 return Promise.resolve(); | |
| 336 } else { | |
| 337 return this.copy_(entry, destinationDirectory); | |
| 338 } | |
| 339 }.bind(this)) | |
| 340 // Regardless of the result of this copy, push on to the next file. | 307 // Regardless of the result of this copy, push on to the next file. |
| 341 .then(completionCallback) | 308 .then(completionCallback) |
| 342 .catch( | 309 .catch( |
| 343 /** @param {*} error */ | 310 /** @param {*} error */ |
| 344 function(error) { | 311 function(error) { |
| 345 importer.getLogger().catcher('import-task-import-one')(error); | 312 importer.getLogger().catcher('import-task-import-one')(error); |
| 346 completionCallback(); | 313 completionCallback(); |
| 347 }); | 314 }); |
| 348 }; | 315 }; |
| 349 | 316 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 472 /** @param {!importer.ImportHistory} history */ | 439 /** @param {!importer.ImportHistory} history */ |
| 473 function(history) { | 440 function(history) { |
| 474 history.markImported(entry, this.destination_); | 441 history.markImported(entry, this.destination_); |
| 475 }.bind(this)) | 442 }.bind(this)) |
| 476 .catch(importer.getLogger().catcher('import-task-mark-as-imported')); | 443 .catch(importer.getLogger().catcher('import-task-mark-as-imported')); |
| 477 }; | 444 }; |
| 478 | 445 |
| 479 /** @private */ | 446 /** @private */ |
| 480 importer.MediaImportHandler.ImportTask.prototype.onSuccess_ = function() { | 447 importer.MediaImportHandler.ImportTask.prototype.onSuccess_ = function() { |
| 481 this.notify(importer.TaskQueue.UpdateType.COMPLETE); | 448 this.notify(importer.TaskQueue.UpdateType.COMPLETE); |
| 482 this.tracker_.send(metrics.ImportEvents.ENDED); | 449 this.sendImportStats_(true); |
|
mtomasz
2015/03/05 04:36:53
nit: enum or /* arg_name */ for this true? It's im
Steve McKay
2015/03/05 21:39:03
Done.
| |
| 483 this.sendImportStats_(); | |
| 484 }; | 450 }; |
| 485 | 451 |
| 486 /** | 452 /** |
| 487 * Sends import statistics to analytics. | 453 * Sends import statistics to analytics. |
| 454 * | |
| 455 * @param {boolean} completedSuccessfully True if task | |
|
Ben Kwa
2015/03/05 20:05:10
suggestion: You could reuse the TaskQueue.UpdateTy
Steve McKay
2015/03/05 21:39:03
Done.
| |
| 456 * wasn't cancelled or err'd out. | |
| 488 */ | 457 */ |
| 489 importer.MediaImportHandler.ImportTask.prototype.sendImportStats_ = function() { | 458 importer.MediaImportHandler.ImportTask.prototype.sendImportStats_ = |
| 459 function(completedSuccessfully) { | |
| 460 var scanStats = this.scanResult_.getStatistics(); | |
| 461 | |
| 462 if (!completedSuccessfully) { | |
| 463 this.tracker_.send(metrics.ImportEvents.CANCELLED); | |
| 464 } else { | |
| 465 // Ideally we'd report bytes imported for cancelled imports too. | |
| 466 // We just don't have the information needed to do this accurately. | |
|
Ben Kwa
2015/03/05 20:05:10
The processedBytes_ counter should be a fairly acc
Steve McKay
2015/03/05 21:39:03
Perfect!
| |
| 467 var megaBytes = Math.floor(scanStats.sizeBytes / (1024 * 1024)); | |
| 468 this.tracker_.send( | |
|
Ben Kwa
2015/03/05 20:05:10
We also need to do this.tracker_.send(metrics.Impo
Steve McKay
2015/03/05 21:39:03
Removed that as there are plenty of surrogate even
| |
| 469 metrics.ImportEvents.MEGABYTES_IMPORTED.value(megaBytes)); | |
| 470 } | |
| 471 | |
| 472 // FYI, if the task was cancelled we substract the remaining files | |
| 473 // from the number of files in the scanStats. | |
| 474 var importFileCount = scanStats.newFileCount - this.remainingFilesCount_; | |
| 490 this.tracker_.send( | 475 this.tracker_.send( |
| 491 metrics.ImportEvents.CONTENT_DEDUPE_COUNT | 476 metrics.ImportEvents.FILES_IMPORTED.value(importFileCount)); |
| 492 .value(this.dedupeCount_)); | 477 |
| 493 // TODO(kenobi): Send correct import byte counts. | 478 if (this.errorCount_ > 0) { |
| 494 var importFileCount = this.scanResult_.getStatistics().newFileCount - | 479 this.tracker_.send(metrics.ImportEvents.ERRORS.value(this.errorCount_)); |
| 495 (this.dedupeCount_ + this.remainingFilesCount_); | 480 } |
| 481 | |
| 482 // Finally we want to report on the number of duplicates | |
| 483 // that were identified during scanning. | |
| 484 var totalDeduped = 0; | |
| 485 Object.keys(scanStats.duplicates).forEach( | |
| 486 /** | |
| 487 * @param {!importer.Disposition} disposition | |
| 488 * @this {importer.MediaImportHandler.ImportTask} | |
| 489 */ | |
| 490 function(disposition) { | |
| 491 var count = scanStats.duplicates[disposition]; | |
| 492 totalDeduped += count; | |
| 493 this.tracker_.send( | |
| 494 metrics.ImportEvents.FILES_DEDUPLICATED | |
| 495 .label(disposition) | |
| 496 .value(count)); | |
| 497 }.bind(this)); | |
| 498 | |
| 496 this.tracker_.send( | 499 this.tracker_.send( |
| 497 metrics.ImportEvents.FILE_COUNT | 500 metrics.ImportEvents.FILES_DEDUPLICATED |
| 498 .value(importFileCount)); | 501 .label('all-duplicates') |
| 499 | 502 .value(totalDeduped)); |
| 500 this.tracker_.send(metrics.ImportEvents.ERROR.value(this.errorCount_)); | |
| 501 | |
| 502 // Send aggregate deduplication timings, to avoid flooding analytics with one | |
| 503 // timing per file. | |
| 504 var deduplicatorStats = this.deduplicator_.getStatistics(); | |
| 505 this.tracker_.sendTiming( | |
| 506 metrics.Categories.ACQUISITION, | |
| 507 metrics.timing.Variables.COMPUTE_HASH, | |
| 508 deduplicatorStats.computeHashTime, | |
| 509 'In Place'); | |
| 510 this.tracker_.sendTiming( | |
| 511 metrics.Categories.ACQUISITION, | |
| 512 metrics.timing.Variables.SEARCH_BY_HASH, | |
| 513 deduplicatorStats.searchHashTime); | |
| 514 | |
| 515 }; | 503 }; |
| OLD | NEW |