Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 'use strict'; | 5 'use strict'; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * @fileoverview Utility objects and functions for Google Now extension. | 8 * @fileoverview Utility objects and functions for Google Now extension. |
| 9 * Most important entities here: | 9 * Most important entities here: |
| 10 * (1) 'wrapper' is a module used to add error handling and other services to | 10 * (1) 'wrapper' is a module used to add error handling and other services to |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 316 verify(!isInWrappedCallback, 'Re-entering instrumented callback'); | 316 verify(!isInWrappedCallback, 'Re-entering instrumented callback'); |
| 317 isInWrappedCallback = true; | 317 isInWrappedCallback = true; |
| 318 | 318 |
| 319 if (!opt_isEventListener) | 319 if (!opt_isEventListener) |
| 320 delete pendingCallbacks[callbackId]; | 320 delete pendingCallbacks[callbackId]; |
| 321 | 321 |
| 322 if (wrapperPluginInstance) | 322 if (wrapperPluginInstance) |
| 323 wrapperPluginInstance.prologue(); | 323 wrapperPluginInstance.prologue(); |
| 324 | 324 |
| 325 // Call the original callback. | 325 // Call the original callback. |
| 326 callback.apply(null, arguments); | 326 var returnValue = callback.apply(null, arguments); |
| 327 | 327 |
| 328 if (wrapperPluginInstance) | 328 if (wrapperPluginInstance) |
| 329 wrapperPluginInstance.epilogue(); | 329 wrapperPluginInstance.epilogue(); |
| 330 | 330 |
| 331 verify(isInWrappedCallback, | 331 verify(isInWrappedCallback, |
| 332 'Instrumented callback is not instrumented upon exit'); | 332 'Instrumented callback is not instrumented upon exit'); |
| 333 isInWrappedCallback = false; | 333 isInWrappedCallback = false; |
| 334 | |
| 335 return returnValue; | |
| 334 } catch (error) { | 336 } catch (error) { |
| 335 reportError(error); | 337 reportError(error); |
| 336 } | 338 } |
| 337 }; | 339 }; |
| 338 } | 340 } |
| 339 | 341 |
| 340 /** | 342 /** |
| 341 * Returns an instrumented function. | 343 * Returns an instrumented function. |
| 342 * @param {!Array.<string>} functionIdentifierParts Path to the chrome.* | 344 * @param {!Array.<string>} functionIdentifierParts Path to the chrome.* |
| 343 * function. | 345 * function. |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 427 checkInWrappedCallback: checkInWrappedCallback, | 429 checkInWrappedCallback: checkInWrappedCallback, |
| 428 debugGetStateString: debugGetStateString | 430 debugGetStateString: debugGetStateString |
| 429 }; | 431 }; |
| 430 })(); | 432 })(); |
| 431 | 433 |
| 432 wrapper.instrumentChromeApiFunction('alarms.get', 1); | 434 wrapper.instrumentChromeApiFunction('alarms.get', 1); |
| 433 wrapper.instrumentChromeApiFunction('alarms.onAlarm.addListener', 0); | 435 wrapper.instrumentChromeApiFunction('alarms.onAlarm.addListener', 0); |
| 434 wrapper.instrumentChromeApiFunction('identity.getAuthToken', 1); | 436 wrapper.instrumentChromeApiFunction('identity.getAuthToken', 1); |
| 435 wrapper.instrumentChromeApiFunction('identity.onSignInChanged.addListener', 0); | 437 wrapper.instrumentChromeApiFunction('identity.onSignInChanged.addListener', 0); |
| 436 wrapper.instrumentChromeApiFunction('identity.removeCachedAuthToken', 1); | 438 wrapper.instrumentChromeApiFunction('identity.removeCachedAuthToken', 1); |
| 439 wrapper.instrumentChromeApiFunction('storage.local.get', 1); | |
| 437 wrapper.instrumentChromeApiFunction('webstorePrivate.getBrowserLogin', 0); | 440 wrapper.instrumentChromeApiFunction('webstorePrivate.getBrowserLogin', 0); |
| 438 | 441 |
| 439 /** | 442 /** |
| 440 * Promise adapter for all JS promises to the task manager. | 443 * Promise adapter for all JS promises to the task manager. |
| 441 */ | 444 */ |
| 442 function registerPromiseAdapter() { | 445 function registerPromiseAdapter() { |
| 443 var originalThen = Promise.prototype.then; | 446 var originalThen = Promise.prototype.then; |
| 444 var originalCatch = Promise.prototype.catch; | 447 var originalCatch = Promise.prototype.catch; |
| 445 | 448 |
| 446 /** | 449 /** |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 562 maybeCallback, sameTracker, otherTracker) { | 565 maybeCallback, sameTracker, otherTracker) { |
| 563 // If sameTracker.callbacks is undefined, we've reached an ending state | 566 // If sameTracker.callbacks is undefined, we've reached an ending state |
| 564 // that means this callback will never be called back. | 567 // that means this callback will never be called back. |
| 565 // We will still forward this call on to let the promise system | 568 // We will still forward this call on to let the promise system |
| 566 // handle further processing, but since this promise is in an ending state | 569 // handle further processing, but since this promise is in an ending state |
| 567 // we can be confident it will never be called back. | 570 // we can be confident it will never be called back. |
| 568 if (isCallable(maybeCallback) && sameTracker.callbacks) { | 571 if (isCallable(maybeCallback) && sameTracker.callbacks) { |
| 569 var handler = wrapper.wrapCallback(function() { | 572 var handler = wrapper.wrapCallback(function() { |
| 570 if (sameTracker.callbacks) { | 573 if (sameTracker.callbacks) { |
| 571 clearTracker(otherTracker); | 574 clearTracker(otherTracker); |
| 572 maybeCallback.apply(null, arguments); | 575 return maybeCallback.apply(null, arguments); |
| 573 } | 576 } |
| 574 }, false); | 577 }, false); |
| 575 sameTracker.callbacks.push(handler); | 578 sameTracker.callbacks.push(handler); |
| 576 return handler; | 579 return handler; |
| 577 } else { | 580 } else { |
| 578 return maybeCallback; | 581 return maybeCallback; |
| 579 } | 582 } |
| 580 } | 583 } |
| 581 | 584 |
| 582 /** | 585 /** |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 612 return { | 615 return { |
| 613 handleThen: handleThen, | 616 handleThen: handleThen, |
| 614 handleCatch: handleCatch | 617 handleCatch: handleCatch |
| 615 }; | 618 }; |
| 616 } | 619 } |
| 617 } | 620 } |
| 618 | 621 |
| 619 registerPromiseAdapter(); | 622 registerPromiseAdapter(); |
| 620 | 623 |
| 621 /** | 624 /** |
| 625 * Control promise rejection. | |
| 626 * @enum {boolean} | |
| 627 */ | |
| 628 var PromiseRejection = { | |
| 629 /** Disallow promise rejection */ | |
| 630 DISALLOW: false, | |
| 631 /** Allow promise rejection */ | |
| 632 ALLOW: true | |
| 633 }; | |
| 634 | |
| 635 /** | |
| 636 * Provides the promise equivalent of instrumented.storage.local.get. | |
| 637 * @param {Object} defaultStorageObject Default storage object to fill. | |
| 638 * @param {boolean=} opt_allowPromiseRejection If PromiseRejection.ALLOW, | |
|
vadimt
2014/02/28 20:21:05
Should be {PromiseRejection=}
robliao
2014/02/28 20:39:49
Done.
| |
| 639 * allow promise rejection on errors, otherwise the default storage | |
| 640 * object is resolved. | |
| 641 * @return {Promise} A promise that fills the default storage object. On | |
| 642 * failure, if promise rejection is allowed, the promise is rejected, | |
| 643 * otherwise it is resolved to the default storage object. | |
| 644 */ | |
| 645 function fillFromChromeLocalStorage( | |
| 646 defaultStorageObject, | |
| 647 opt_allowPromiseRejection) { | |
| 648 return new Promise(function(resolve, reject) { | |
| 649 instrumented.storage.local.get(defaultStorageObject, function(items) { | |
| 650 if (items) { | |
| 651 resolve(items); | |
| 652 } else if (opt_allowPromiseRejection === PromiseRejection.ALLOW) { | |
| 653 reject(); | |
| 654 } else { | |
| 655 resolve(defaultStorageObject); | |
| 656 } | |
| 657 }); | |
| 658 }); | |
| 659 } | |
| 660 | |
| 661 /** | |
| 622 * Builds the object to manage tasks (mutually exclusive chains of events). | 662 * Builds the object to manage tasks (mutually exclusive chains of events). |
| 623 * @param {function(string, string): boolean} areConflicting Function that | 663 * @param {function(string, string): boolean} areConflicting Function that |
| 624 * checks if a new task can't be added to a task queue that contains an | 664 * checks if a new task can't be added to a task queue that contains an |
| 625 * existing task. | 665 * existing task. |
| 626 * @return {Object} Task manager interface. | 666 * @return {Object} Task manager interface. |
| 627 */ | 667 */ |
| 628 function buildTaskManager(areConflicting) { | 668 function buildTaskManager(areConflicting) { |
| 629 /** | 669 /** |
| 630 * Queue of scheduled tasks. The first element, if present, corresponds to the | 670 * Queue of scheduled tasks. The first element, if present, corresponds to the |
| 631 * currently running task. | 671 * currently running task. |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 852 chrome.alarms.clear(alarmName); | 892 chrome.alarms.clear(alarmName); |
| 853 chrome.storage.local.remove(currentDelayStorageKey); | 893 chrome.storage.local.remove(currentDelayStorageKey); |
| 854 } | 894 } |
| 855 | 895 |
| 856 /** | 896 /** |
| 857 * Plans for the next attempt. | 897 * Plans for the next attempt. |
| 858 * @param {function()} callback Completion callback. It will be invoked after | 898 * @param {function()} callback Completion callback. It will be invoked after |
| 859 * the planning is done. | 899 * the planning is done. |
| 860 */ | 900 */ |
| 861 function planForNext(callback) { | 901 function planForNext(callback) { |
| 862 instrumented.storage.local.get(currentDelayStorageKey, function(items) { | 902 var request = {}; |
| 863 if (!items) { | 903 request[currentDelayStorageKey] = undefined; |
| 864 items = {}; | 904 fillFromChromeLocalStorage(request, PromiseRejection.ALLOW) |
| 865 items[currentDelayStorageKey] = maximumDelaySeconds; | 905 .catch(function() { |
| 866 } | 906 request[currentDelayStorageKey] = maximumDelaySeconds; |
| 867 console.log('planForNext-get-storage ' + JSON.stringify(items)); | 907 return Promise.resolve(request); |
| 868 scheduleNextAttempt(items[currentDelayStorageKey]); | 908 }).then(function(items) { |
| 869 callback(); | 909 console.log('planForNext-get-storage ' + JSON.stringify(items)); |
| 870 }); | 910 scheduleNextAttempt(items[currentDelayStorageKey]); |
| 911 callback(); | |
| 912 }); | |
| 871 } | 913 } |
| 872 | 914 |
| 873 instrumented.alarms.onAlarm.addListener(function(alarm) { | 915 instrumented.alarms.onAlarm.addListener(function(alarm) { |
| 874 if (alarm.name == alarmName) | 916 if (alarm.name == alarmName) |
| 875 isRunning(function(running) { | 917 isRunning(function(running) { |
| 876 if (running) | 918 if (running) |
| 877 attempt(); | 919 attempt(); |
| 878 }); | 920 }); |
| 879 }); | 921 }); |
| 880 | 922 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 950 function addListener(callback) { | 992 function addListener(callback) { |
| 951 listeners.push(callback); | 993 listeners.push(callback); |
| 952 } | 994 } |
| 953 | 995 |
| 954 /** | 996 /** |
| 955 * Checks if the last signed in state matches the current one. | 997 * Checks if the last signed in state matches the current one. |
| 956 * If it doesn't, it notifies the listeners of the change. | 998 * If it doesn't, it notifies the listeners of the change. |
| 957 */ | 999 */ |
| 958 function checkAndNotifyListeners() { | 1000 function checkAndNotifyListeners() { |
| 959 isSignedIn().then(function(signedIn) { | 1001 isSignedIn().then(function(signedIn) { |
| 960 instrumented.storage.local.get('lastSignedInState', function(items) { | 1002 fillFromChromeLocalStorage({lastSignedInState: undefined}) |
| 961 items = items || {}; | 1003 .then(function(items) { |
| 962 if (items.lastSignedInState != signedIn) { | 1004 if (items.lastSignedInState != signedIn) { |
| 963 chrome.storage.local.set( | 1005 chrome.storage.local.set( |
| 964 {lastSignedInState: signedIn}); | 1006 {lastSignedInState: signedIn}); |
| 965 listeners.forEach(function(callback) { | 1007 listeners.forEach(function(callback) { |
| 966 callback(); | 1008 callback(); |
| 967 }); | 1009 }); |
| 968 } | 1010 } |
| 1011 }); | |
| 969 }); | 1012 }); |
| 970 }); | |
| 971 } | 1013 } |
| 972 | 1014 |
| 973 instrumented.identity.onSignInChanged.addListener(function() { | 1015 instrumented.identity.onSignInChanged.addListener(function() { |
| 974 checkAndNotifyListeners(); | 1016 checkAndNotifyListeners(); |
| 975 }); | 1017 }); |
| 976 | 1018 |
| 977 instrumented.alarms.onAlarm.addListener(function(alarm) { | 1019 instrumented.alarms.onAlarm.addListener(function(alarm) { |
| 978 if (alarm.name == alarmName) | 1020 if (alarm.name == alarmName) |
| 979 checkAndNotifyListeners(); | 1021 checkAndNotifyListeners(); |
| 980 }); | 1022 }); |
| 981 | 1023 |
| 982 // Poll for the sign in state every hour. | 1024 // Poll for the sign in state every hour. |
| 983 // One hour is just an arbitrary amount of time chosen. | 1025 // One hour is just an arbitrary amount of time chosen. |
| 984 chrome.alarms.create(alarmName, {periodInMinutes: 60}); | 1026 chrome.alarms.create(alarmName, {periodInMinutes: 60}); |
| 985 | 1027 |
| 986 return { | 1028 return { |
| 987 addListener: addListener, | 1029 addListener: addListener, |
| 988 getAuthToken: getAuthToken, | 1030 getAuthToken: getAuthToken, |
| 989 isSignedIn: isSignedIn, | 1031 isSignedIn: isSignedIn, |
| 990 removeToken: removeToken | 1032 removeToken: removeToken |
| 991 }; | 1033 }; |
| 992 } | 1034 } |
| OLD | NEW |