Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(504)

Side by Side Diff: chrome/browser/resources/file_manager/js/metadata/metadata_cache.js

Issue 10384155: [filemanager] Content metadata moved to the cache. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Handling content metadata for not-present gdata files. Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 /** 5 /**
6 * MetadataCache is a map from url to an object containing properties. 6 * MetadataCache is a map from url to an object containing properties.
7 * Properties are divided by types, and all properties of one type are accessed 7 * Properties are divided by types, and all properties of one type are accessed
8 * at once. 8 * at once.
9 * Some of the properties: 9 * Some of the properties:
10 * { 10 * {
11 * filesystem: size, modificationTime, icon 11 * filesystem: size, modificationTime
12 * internal: presence 12 * internal: presence
13 * gdata: pinned, present, hosted, editUrl, contentUrl, availableOffline 13 * gdata: pinned, present, hosted, editUrl, contentUrl, availableOffline
14 * fetchedMedia: width, height, etc.
15 * streaming: url
16 *
17 * Following are not fetched for non-present gdata files.
18 * media: artist, album, title, width, height, imageTransform, etc.
14 * thumbnail: url, transform 19 * thumbnail: url, transform
15 * media: artist, album, title
16 * } 20 * }
17 * 21 *
18 * Typical usages: 22 * Typical usages:
19 * { 23 * {
20 * cache.get([entry1, entry2], 'gdata', function(gdata) { 24 * cache.get([entry1, entry2], 'gdata', function(gdata) {
21 * if (gdata[0].pinned && gdata[1].pinned) alert("They are both pinned!"); 25 * if (gdata[0].pinned && gdata[1].pinned) alert("They are both pinned!");
22 * }); 26 * });
23 * 27 *
24 * cache.set(entry, 'internal', {presence: 'deleted'}); 28 * cache.set(entry, 'internal', {presence: 'deleted'});
25 * 29 *
(...skipping 29 matching lines...) Expand all
55 * re - regexp of urls; 59 * re - regexp of urls;
56 * type - metadata type; 60 * type - metadata type;
57 * callback - the callback. 61 * callback - the callback.
58 * TODO(dgozman): pass entries to observer if present. 62 * TODO(dgozman): pass entries to observer if present.
59 * @private 63 * @private
60 */ 64 */
61 this.observers_ = []; 65 this.observers_ = [];
62 this.observerId_ = 0; 66 this.observerId_ = 0;
63 67
64 this.batchCount_ = 0; 68 this.batchCount_ = 0;
69 this.totalCount_ = 0;
70
71 /**
72 * Time of first get query of the current batch. Items updated later than this
73 * will not be evicted.
74 * @private
75 */
76 this.lastBatchStart_ = new Date();
65 } 77 }
66 78
67 /** 79 /**
68 * Observer type: it will be notified if the url changed is exactlt the same 80 * Observer type: it will be notified if the url changed is exactlt the same
69 * as the url passed. 81 * as the url passed.
70 */ 82 */
71 MetadataCache.EXACT = 0; 83 MetadataCache.EXACT = 0;
72 84
73 /** 85 /**
74 * Observer type: it will be notified if the url changed is an immediate child 86 * Observer type: it will be notified if the url changed is an immediate child
75 * of the url passed. 87 * of the url passed.
76 */ 88 */
77 MetadataCache.CHILDREN = 1; 89 MetadataCache.CHILDREN = 1;
78 90
79 /** 91 /**
80 * Observer type: it will be notified if the url changed is any descendant 92 * Observer type: it will be notified if the url changed is any descendant
81 * of the url passed. 93 * of the url passed.
82 */ 94 */
83 MetadataCache.DESCENDANTS = 2; 95 MetadataCache.DESCENDANTS = 2;
84 96
85 /** 97 /**
98 * Minimum number of items in cache to start eviction.
99 */
100 MetadataCache.EVICTION_NUMBER = 1000;
101
102 /**
86 * @return {MetadataCache!} The cache with all providers. 103 * @return {MetadataCache!} The cache with all providers.
87 */ 104 */
88 MetadataCache.createFull = function() { 105 MetadataCache.createFull = function() {
89 var cache = new MetadataCache(); 106 var cache = new MetadataCache();
90 cache.providers_.push(new FilesystemProvider()); 107 cache.providers_.push(new FilesystemProvider());
91 cache.providers_.push(new GDataProvider()); 108 cache.providers_.push(new GDataProvider());
109 cache.providers_.push(new ContentProvider());
92 return cache; 110 return cache;
93 }; 111 };
94 112
95 /** 113 /**
114 * @return {boolean} Whether all providers are ready.
115 */
116 MetadataCache.prototype.isInitialized = function() {
117 for (var index = 0; index < this.providers_.length; index++) {
118 if (!this.providers_[index].isInitialized()) return false;
119 }
120 return true;
121 };
122
123 /**
96 * Fetches the metadata, puts it in the cache, and passes to callback. 124 * Fetches the metadata, puts it in the cache, and passes to callback.
97 * If required metadata is already in the cache, does not fetch it again. 125 * If required metadata is already in the cache, does not fetch it again.
98 * @param {string|Entry|Array.<string|Entry>} items The list of entries or 126 * @param {string|Entry|Array.<string|Entry>} items The list of entries or
99 * file urls. May be just a single item. 127 * file urls. May be just a single item.
100 * @param {string} type The metadata type. 128 * @param {string} type The metadata type.
101 * @param {Function(Object)} callback The metadata is passed to callback. 129 * @param {Function(Object)} callback The metadata is passed to callback.
102 */ 130 */
103 MetadataCache.prototype.get = function(items, type, callback) { 131 MetadataCache.prototype.get = function(items, type, callback) {
104 if (!(items instanceof Array)) { 132 if (!(items instanceof Array)) {
105 this.getOne(items, type, callback); 133 this.getOne(items, type, callback);
(...skipping 24 matching lines...) Expand all
130 } 158 }
131 }; 159 };
132 160
133 /** 161 /**
134 * Fetches the metadata for one Entry/FileUrl. See comments to |get|. 162 * Fetches the metadata for one Entry/FileUrl. See comments to |get|.
135 * @param {Entry|string} item The entry or url. 163 * @param {Entry|string} item The entry or url.
136 * @param {string} type Metadata type. 164 * @param {string} type Metadata type.
137 * @param {Function(Object)} callback The callback. 165 * @param {Function(Object)} callback The callback.
138 */ 166 */
139 MetadataCache.prototype.getOne = function(item, type, callback) { 167 MetadataCache.prototype.getOne = function(item, type, callback) {
168 if (type.indexOf('|') != -1) {
169 var types = type.split('|');
170 var result = {};
171 var typesLeft = types.length;
172
173 function onOneType(requestedType, metadata) {
174 result[requestedType] = metadata;
175 typesLeft--;
176 if (typesLeft == 0) callback(result);
177 }
178
179 for (var index = 0; index < types.length; index++) {
180 this.getOne(item, types[index], onOneType.bind(null, types[index]));
181 }
182 return;
183 }
184
140 var url = this.itemToUrl_(item); 185 var url = this.itemToUrl_(item);
141 186
142 // Passing entry to fetchers may save one round-trip to APIs. 187 // Passing entry to fetchers may save one round-trip to APIs.
143 var fsEntry = item === url ? null : item; 188 var fsEntry = item === url ? null : item;
144 callback = callback || function() {}; 189 callback = callback || function() {};
145 190
146 if (!(url in this.cache_)) 191 if (!(url in this.cache_)) {
147 this.cache_[url] = this.createEmptyEntry_(); 192 this.cache_[url] = this.createEmptyEntry_();
193 this.totalCount_++;
194 }
148 195
149 var entry = this.cache_[url]; 196 var entry = this.cache_[url];
150 197
151 if (type in entry.properties) { 198 if (type in entry.properties) {
152 callback(entry.properties[type]); 199 callback(entry.properties[type]);
153 return; 200 return;
154 } 201 }
155 202
156 this.startBatchUpdates(); 203 this.startBatchUpdates();
157 var providers = this.providers_.slice(); 204 var providers = this.providers_.slice();
158 var currentProvider; 205 var currentProvider;
159 var self = this; 206 var self = this;
160 207
161 function onFetched() { 208 function onFetched() {
162 if (type in entry.properties) { 209 if (type in entry.properties) {
163 self.endBatchUpdates(); 210 self.endBatchUpdates();
164 // Got properties from provider. 211 // Got properties from provider.
165 callback(entry.properties[type]); 212 callback(entry.properties[type]);
166 } else { 213 } else {
167 tryNextProvider(); 214 tryNextProvider();
168 } 215 }
169 } 216 }
170 217
171 function onProviderProperties(properties) { 218 function onProviderProperties(properties) {
172 var id = currentProvider.getId(); 219 var id = currentProvider.getId();
173 var fetchedCallbacks = entry[id].callbacks; 220 var fetchedCallbacks = entry[id].callbacks;
174 delete entry[id].callbacks; 221 delete entry[id].callbacks;
175 entry[id].time = new Date(); 222 entry.time = new Date();
176 self.mergeProperties_(url, properties); 223 self.mergeProperties_(url, properties);
177 224
178 for (var index = 0; index < fetchedCallbacks.length; index++) { 225 for (var index = 0; index < fetchedCallbacks.length; index++) {
179 fetchedCallbacks[index](); 226 fetchedCallbacks[index]();
180 } 227 }
181 } 228 }
182 229
183 function queryProvider() { 230 function queryProvider() {
184 var id = currentProvider.getId(); 231 var id = currentProvider.getId();
185 if ('callbacks' in entry[id]) { 232 if ('callbacks' in entry[id]) {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 * @param {string} type The metadata type. 288 * @param {string} type The metadata type.
242 * @param {Array.<Object>} values List of corresponding metadata values. 289 * @param {Array.<Object>} values List of corresponding metadata values.
243 */ 290 */
244 MetadataCache.prototype.set = function(items, type, values) { 291 MetadataCache.prototype.set = function(items, type, values) {
245 if (!(items instanceof Array)) 292 if (!(items instanceof Array))
246 items = [items]; 293 items = [items];
247 294
248 this.startBatchUpdates(); 295 this.startBatchUpdates();
249 for (var index = 0; index < items.length; index++) { 296 for (var index = 0; index < items.length; index++) {
250 var url = this.itemToUrl_(items[index]); 297 var url = this.itemToUrl_(items[index]);
251 if (!(url in this.cache_)) 298 if (!(url in this.cache_)) {
252 this.cache_[url] = this.createEmptyEntry_(); 299 this.cache_[url] = this.createEmptyEntry_();
300 this.totalCount_++;
301 }
253 this.cache_[url].properties[type] = values[index]; 302 this.cache_[url].properties[type] = values[index];
254 this.notifyObservers_(url, type); 303 this.notifyObservers_(url, type);
255 } 304 }
256 this.endBatchUpdates(); 305 this.endBatchUpdates();
257 }; 306 };
258 307
259 /** 308 /**
260 * Clears the cached metadata values. 309 * Clears the cached metadata values.
261 * @param {string|Entry|Array.<string|Entry>} items The list of entries or 310 * @param {string|Entry|Array.<string|Entry>} items The list of entries or
262 * file urls. May be just a single item. 311 * file urls. May be just a single item.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 } 364 }
316 } 365 }
317 return false; 366 return false;
318 }; 367 };
319 368
320 /** 369 /**
321 * Start batch updates. 370 * Start batch updates.
322 */ 371 */
323 MetadataCache.prototype.startBatchUpdates = function() { 372 MetadataCache.prototype.startBatchUpdates = function() {
324 this.batchCount_++; 373 this.batchCount_++;
374 if (this.batchCount_ == 1)
375 this.lastBatchStart_ = new Date();
325 }; 376 };
326 377
327 /** 378 /**
328 * End batch updates. Notifies observers if all nested updates are finished. 379 * End batch updates. Notifies observers if all nested updates are finished.
329 */ 380 */
330 MetadataCache.prototype.endBatchUpdates = function() { 381 MetadataCache.prototype.endBatchUpdates = function() {
331 this.batchCount_--; 382 this.batchCount_--;
332 if (this.batchCount_ != 0) return; 383 if (this.batchCount_ != 0) return;
384 if (this.totalCount_ > MetadataCache.EVICTION_NUMBER)
385 this.evict_();
333 for (var index = 0; index < this.observers_.length; index++) { 386 for (var index = 0; index < this.observers_.length; index++) {
334 var observer = this.observers_[index]; 387 var observer = this.observers_[index];
335 var urls = []; 388 var urls = [];
336 var properties = []; 389 var properties = [];
337 for (var url in observer.pending) { 390 for (var url in observer.pending) {
338 if (observer.pending.hasOwnProperty(url) && url in this.cache_) { 391 if (observer.pending.hasOwnProperty(url) && url in this.cache_) {
339 urls.push(url); 392 urls.push(url);
340 properties.push(this.cache_[url].properties[observer.type] || null); 393 properties.push(this.cache_[url].properties[observer.type] || null);
341 } 394 }
342 } 395 }
(...skipping 18 matching lines...) Expand all
361 // Observer expects array of urls and array of properties. 414 // Observer expects array of urls and array of properties.
362 observer.callback([url], [this.cache_[url].properties[type] || null]); 415 observer.callback([url], [this.cache_[url].properties[type] || null]);
363 } else { 416 } else {
364 observer.pending[url] = true; 417 observer.pending[url] = true;
365 } 418 }
366 } 419 }
367 } 420 }
368 }; 421 };
369 422
370 /** 423 /**
424 * Removes the oldest items from the cache.
425 * This method never removes the items from last batch.
426 * @private
427 */
428 MetadataCache.prototype.evict_ = function() {
429 var toRemove = [];
430 var removeCount = this.totalCount_ -
431 Math.round(MetadataCache.EVICTION_NUMBER / 2);
Vladislav Kaznacheev 2012/05/16 12:46:28 This computations needs a comment
dgozman 2012/05/16 15:12:11 Done.
432 for (var url in this.cache_) {
433 if (this.cache_.hasOwnProperty(url) &&
434 this.cache_[url].time < this.lastBatchStart_) {
435 toRemove.push(url);
436 }
437 }
438
439 toRemove.sort(function(a, b) {
440 var aTime = this.cache_[a].time;
441 var bTime = this.cache_[b].time;
442 return aTime < bTime ? -1 : aTime > bTime ? 1 : 0;
443 });
444
445 removeCount = Math.min(removeCount, toRemove.length);
446 this.totalCount_ -= removeCount;
447 for (var index = 0; index < removeCount; index++) {
448 delete this.cache_[toRemove[index]];
449 }
450 };
451
452 /**
371 * Converts Entry or file url to url. 453 * Converts Entry or file url to url.
372 * @param {string|Entry} item Item to convert. 454 * @param {string|Entry} item Item to convert.
373 * @return {string} File url. 455 * @return {string} File url.
374 * @private 456 * @private
375 */ 457 */
376 MetadataCache.prototype.itemToUrl_ = function(item) { 458 MetadataCache.prototype.itemToUrl_ = function(item) {
377 if (typeof(item) == 'string') 459 if (typeof(item) == 'string')
378 return item; 460 return item;
379 else 461 else
380 return item.toURL(); 462 return item.toURL();
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 * @return {boolean} Whether this provider provides this metadata. 512 * @return {boolean} Whether this provider provides this metadata.
431 */ 513 */
432 MetadataProvider2.prototype.providesType = function(type) { return false; }; 514 MetadataProvider2.prototype.providesType = function(type) { return false; };
433 515
434 /** 516 /**
435 * @return {string} Unique provider id. 517 * @return {string} Unique provider id.
436 */ 518 */
437 MetadataProvider2.prototype.getId = function() { return ''; }; 519 MetadataProvider2.prototype.getId = function() { return ''; };
438 520
439 /** 521 /**
522 * @return {boolean} Whether provider is ready.
523 */
524 MetadataProvider2.prototype.isInitialized = function() { return true; };
525
526 /**
440 * Fetches the metadata. It's suggested to return all the metadata this provider 527 * Fetches the metadata. It's suggested to return all the metadata this provider
441 * can fetch at once. 528 * can fetch at once.
442 * @param {string} url File url. 529 * @param {string} url File url.
443 * @param {string} type Requested metadata type. 530 * @param {string} type Requested metadata type.
444 * @param {Function(Object)} callback Callback expects a map from metadata type 531 * @param {Function(Object)} callback Callback expects a map from metadata type
445 * to metadata value. 532 * to metadata value.
446 * @param {Entry=} opt_entry The file entry if present. 533 * @param {Entry=} opt_entry The file entry if present.
447 */ 534 */
448 MetadataProvider2.prototype.fetch = function(url, type, callback, opt_entry) { 535 MetadataProvider2.prototype.fetch = function(url, type, callback, opt_entry) {
449 throw new Error('Default metadata provider cannot fetch.'); 536 throw new Error('Default metadata provider cannot fetch.');
450 }; 537 };
451 538
452 539
453 /** 540 /**
454 * Provider of filesystem metadata. 541 * Provider of filesystem metadata.
455 * This provider returns the following objects: 542 * This provider returns the following objects:
456 * filesystem: { 543 * filesystem: { size, modificationTime }
457 * size;
458 * modificationTime;
459 * icon - string describing icon type;
460 * }
461 * @constructor 544 * @constructor
462 */ 545 */
463 function FilesystemProvider() { 546 function FilesystemProvider() {
464 MetadataProvider2.call(this, 'filesystem'); 547 MetadataProvider2.call(this);
465 } 548 }
466 549
467 FilesystemProvider.prototype = { 550 FilesystemProvider.prototype = {
468 __proto__: MetadataProvider2.prototype 551 __proto__: MetadataProvider2.prototype
469 }; 552 };
470 553
471 /** 554 /**
472 * @param {string} url The url. 555 * @param {string} url The url.
473 * @return {boolean} Whether this provider supports the url. 556 * @return {boolean} Whether this provider supports the url.
474 */ 557 */
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 onEntry(opt_entry); 602 onEntry(opt_entry);
520 else 603 else
521 webkitResolveLocalFileSystemURL(url, onEntry, onError); 604 webkitResolveLocalFileSystemURL(url, onEntry, onError);
522 }; 605 };
523 606
524 /** 607 /**
525 * Provider of gdata metadata. 608 * Provider of gdata metadata.
526 * This provider returns the following objects: 609 * This provider returns the following objects:
527 * gdata: { pinned, hosted, present, dirty, editUrl, contentUrl } 610 * gdata: { pinned, hosted, present, dirty, editUrl, contentUrl }
528 * thumbnail: { url, transform } 611 * thumbnail: { url, transform }
612 * streaming: { url }
529 * @constructor 613 * @constructor
530 */ 614 */
531 function GDataProvider() { 615 function GDataProvider() {
532 MetadataProvider2.call(this, 'gdata'); 616 MetadataProvider2.call(this);
533 617
534 // We batch metadata fetches into single API call. 618 // We batch metadata fetches into single API call.
535 this.urls_ = []; 619 this.urls_ = [];
536 this.callbacks_ = []; 620 this.callbacks_ = [];
537 this.scheduled_ = false; 621 this.scheduled_ = false;
538 622
539 this.callApiBound_ = this.callApi_.bind(this); 623 this.callApiBound_ = this.callApi_.bind(this);
540 } 624 }
541 625
542 GDataProvider.prototype = { 626 GDataProvider.prototype = {
(...skipping 12 matching lines...) Expand all
555 */ 639 */
556 GDataProvider.prototype.supportsUrl = function(url) { 640 GDataProvider.prototype.supportsUrl = function(url) {
557 return GDataProvider.URL_PATTERN.test(url); 641 return GDataProvider.URL_PATTERN.test(url);
558 }; 642 };
559 643
560 /** 644 /**
561 * @param {string} type The metadata type. 645 * @param {string} type The metadata type.
562 * @return {boolean} Whether this provider provides this metadata. 646 * @return {boolean} Whether this provider provides this metadata.
563 */ 647 */
564 GDataProvider.prototype.providesType = function(type) { 648 GDataProvider.prototype.providesType = function(type) {
565 return type == 'gdata' || type == 'thumbnail'; 649 return type == 'gdata' || type == 'thumbnail' ||
650 type == 'streaming' || type == 'media';
566 }; 651 };
567 652
568 /** 653 /**
569 * @return {string} Unique provider id. 654 * @return {string} Unique provider id.
570 */ 655 */
571 GDataProvider.prototype.getId = function() { return 'gdata'; }; 656 GDataProvider.prototype.getId = function() { return 'gdata'; };
572 657
573 /** 658 /**
574 * Fetches the metadata. 659 * Fetches the metadata.
575 * @param {string} url File url. 660 * @param {string} url File url.
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
641 result.gdata = { 726 result.gdata = {
642 present: data.isPresent, 727 present: data.isPresent,
643 pinned: data.isPinned, 728 pinned: data.isPinned,
644 hosted: data.isHosted, 729 hosted: data.isHosted,
645 dirty: data.isDirty, 730 dirty: data.isDirty,
646 availableOffline: GDataProvider.isAvailableOffline(data), 731 availableOffline: GDataProvider.isAvailableOffline(data),
647 availableWhenMetered: GDataProvider.isAvailableWhenMetered(data), 732 availableWhenMetered: GDataProvider.isAvailableWhenMetered(data),
648 contentUrl: (data.contentUrl || '').replace(/\?.*$/gi, ''), 733 contentUrl: (data.contentUrl || '').replace(/\?.*$/gi, ''),
649 editUrl: data.editUrl || '' 734 editUrl: data.editUrl || ''
650 }; 735 };
736
737 if (!data.isPresent) {
738 // Block the local fetch for gdata files, which require downloading.
739 result.thumbnail = { url: '', transform: null };
740 result.media = {};
741 }
742
651 if ('thumbnailUrl' in data) { 743 if ('thumbnailUrl' in data) {
652 result.thumbnail = { 744 result.thumbnail = {
653 url: data.thumbnailUrl, 745 url: data.thumbnailUrl,
654 transform: '' 746 transform: null
655 }; 747 };
656 } 748 }
749 if (data.isPresent && ('contentUrl' in data)) {
750 result.streaming = {
751 url: data.contentUrl.replace(/\?.*$/gi, '')
752 };
753 }
657 return result; 754 return result;
658 }; 755 };
756
757
758 /**
759 * Provider of content metadata.
760 * This provider returns the following objects:
761 * thumbnail: { url, transform }
762 * media: { artist, album, title, width, height, imageTransform, etc. }
763 * fetchedMedia: { same fields here }
Vladislav Kaznacheev 2012/05/16 12:46:28 Please explain why we need fetchedMedia
dgozman 2012/05/16 15:12:11 Explained in comment at the start of file.
764 * @constructor
765 */
766 function ContentProvider() {
767 MetadataProvider2.call(this);
768
769 // Pass all URLs to the metadata reader until we have a correct filter.
770 this.urlFilter_ = /.*/;
771
772 var path = document.location.pathname;
773 var workerPath = document.location.origin +
774 path.substring(0, path.lastIndexOf('/') + 1) +
775 'js/metadata/metadata_dispatcher.js';
776
777 this.dispatcher_ = new Worker(workerPath);
778 this.dispatcher_.onmessage = this.onMessage_.bind(this);
779 this.dispatcher_.postMessage({verb: 'init'});
780
781 // Initialization is not complete until the Worker sends back the
782 // 'initialized' message. See below.
783 this.initialized_ = false;
784
785 // Map from url to callback.
786 // Note that simultaneous requests for same url are handled in MetadataCache.
787 this.callbacks_ = {};
788 }
789
790 ContentProvider.prototype = {
791 __proto__: MetadataProvider2.prototype
792 };
793
794 /**
795 * @param {string} url The url.
796 * @return {boolean} Whether this provider supports the url.
797 */
798 ContentProvider.prototype.supportsUrl = function(url) {
799 return url.match(this.urlFilter_);
800 };
801
802 /**
803 * @param {string} type The metadata type.
804 * @return {boolean} Whether this provider provides this metadata.
805 */
806 ContentProvider.prototype.providesType = function(type) {
807 return type == 'thumbnail' || type == 'fetchedMedia' || type == 'media';
808 };
809
810 /**
811 * @return {string} Unique provider id.
812 */
813 ContentProvider.prototype.getId = function() { return 'content'; };
814
815 /**
816 * Fetches the metadata.
817 * @param {string} url File url.
818 * @param {string} type Requested metadata type.
819 * @param {Function(Object)} callback Callback expects a map from metadata type
820 * to metadata value.
821 * @param {Entry=} opt_entry The file entry if present.
822 */
823 ContentProvider.prototype.fetch = function(url, type, callback, opt_entry) {
824 if (opt_entry && opt_entry.isDirectory) {
825 callback({});
826 return;
827 }
828 this.callbacks_[url] = callback;
829 this.dispatcher_.postMessage({verb: 'request', arguments: [url]});
830 };
831
832 /**
833 * Dispatch a message from a metadata reader to the appropriate on* method.
834 * @param {Object} event The event.
835 * @private
836 */
837 ContentProvider.prototype.onMessage_ = function(event) {
838 var data = event.data;
839
840 var methodName =
841 'on' + data.verb.substr(0, 1).toUpperCase() + data.verb.substr(1) + '_';
842
843 if (!(methodName in this)) {
844 console.log('Unknown message from metadata reader: ' + data.verb, data);
845 return;
846 }
847
848 this[methodName].apply(this, data.arguments);
849 };
850
851 /**
852 * @return {boolean} Whether provider is ready.
853 */
854 ContentProvider.prototype.isInitialized = function() {
855 return this.initialized_;
856 };
857
858 /**
859 * Handles the 'initialized' message from the metadata reader Worker.
860 * @param {Object} regexp Regexp of supported urls.
861 * @private
862 */
863 ContentProvider.prototype.onInitialized_ = function(regexp) {
864 this.urlFilter_ = regexp;
865
866 // Tests can monitor for this state with
867 // ExtensionTestMessageListener listener("worker-initialized");
868 // ASSERT_TRUE(listener.WaitUntilSatisfied());
869 // Automated tests need to wait for this, otherwise we crash in
870 // browser_test cleanup because the worker process still has
871 // URL requests in-flight.
872 chrome.test.sendMessage('worker-initialized');
Vladislav Kaznacheev 2012/05/16 12:46:28 This will be the second place where this message i
dgozman 2012/05/16 15:12:11 Done, as discussed offline.
873 this.initialized_ = true;
874 };
875
876 /**
877 * Handles the 'result' message from the worker.
878 * @param {string} url File url.
879 * @param {Object} metadata The metadata.
880 * @private
881 */
882 ContentProvider.prototype.onResult_ = function(url, metadata) {
883 var callback = this.callbacks_[url];
884 delete this.callbacks_[url];
885
886 var result = {};
887
888 if ('thumbnailURL' in metadata) {
889 metadata.thumbnailTransform = metadata.thumbnailTransform || null;
890 result.thumbnail = {
891 url: metadata.thumbnailURL,
892 transform: metadata.thumbnailTransform
893 };
894 delete metadata.thumbnailURL;
895 delete metadata.thumbnailTransform;
896 }
897
898 for (var key in metadata) {
899 if (metadata.hasOwnProperty(key)) {
900 if (!('media' in result)) result.media = {};
901 result.media[key] = metadata[key];
902 }
903 }
904
905 if ('media' in result) {
906 result.fetchedMedia = result.media;
907 }
908
909 callback(result);
910 };
911
912 /**
913 * Handles the 'error' message from the worker.
914 * @param {string} url File url.
915 * @param {string} step Step failed.
916 * @param {string} error Error description.
917 * @param {Object?} metadata The metadata, if available.
918 * @private
919 */
920 ContentProvider.prototype.onError_ = function(url, step, error, metadata) {
921 console.warn('metadata: ' + url + ': ' + step + ': ' + error);
922 metadata = metadata || {};
923 // Prevent asking for thumbnail again.
924 metadata.thumbnailURL = '';
925 this.onResult_(url, metadata);
926 };
927
928 /**
929 * Handles the 'log' message from the worker.
930 * @param {Array.<*>} arglist Log arguments.
931 * @private
932 */
933 ContentProvider.prototype.onLog_ = function(arglist) {
934 console.log.apply(console, ['metadata:'].concat(arglist));
935 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698