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 3 // found in the LICENSE file. 4 5 var chrome = chrome || {}; 6 7 // TODO(akalin): Add mocking code for e.g. chrome.send() so that we 8 // can test this without rebuilding chrome. 9 10 /** 11 * Organize sync event listeners and asynchronous requests. 12 * This object is one of a kind; its constructor is not public. 13 * @type {Object} 14 */ 15 chrome.sync = chrome.sync || {}; 16 (function() { 17 18 // This Event class is a simplified version of the one from 19 // event_bindings.js. 20 function Event() { 21 this.listeners_ = []; 22 } 23 24 Event.prototype.addListener = function(listener) { 25 this.listeners_.push(listener); 26 }; 27 28 Event.prototype.removeListener = function(listener) { 29 var i = this.findListener_(listener); 30 if (i == -1) { 31 return; 32 } 33 this.listeners_.splice(i, 1); 34 }; 35 36 Event.prototype.hasListener = function(listener) { 37 return this.findListener_(listener) > -1; 38 }; 39 40 Event.prototype.hasListeners = function(listener) { 41 return this.listeners_.length > 0; 42 }; 43 44 // Returns the index of the given listener, or -1 if not found. 45 Event.prototype.findListener_ = function(listener) { 46 for (var i = 0; i < this.listeners_.length; i++) { 47 if (this.listeners_[i] == listener) { 48 return i; 49 } 50 } 51 return -1; 52 }; 53 54 // Fires the event. Called by the actual event callback. Any 55 // exceptions thrown by a listener are caught and logged. 56 Event.prototype.fire = function() { 57 var args = Array.prototype.slice.call(arguments); 58 for (var i = 0; i < this.listeners_.length; i++) { 59 try { 60 this.listeners_[i].apply(null, args); 61 } catch (e) { 62 if (e instanceof Error) { 63 // Non-standard, but useful. 64 console.error(e.stack); 65 } else { 66 console.error(e); 67 } 68 } 69 } 70 }; 71 72 chrome.sync.events = { 73 'service': [ 74 'onServiceStateChanged' 75 ], 76 77 // See chrome/browser/sync/engine/syncapi.h for docs. 78 'notifier': [ 79 'onNotificationStateChange', 80 'onIncomingNotification' 81 ], 82 83 'manager': [ 84 'onChangesApplied', 85 'onChangesComplete', 86 'onSyncCycleCompleted', 87 'onConnectionStatusChange', 88 'onUpdatedToken', 89 'onPassphraseRequired', 90 'onPassphraseAccepted', 91 'onInitializationComplete', 92 'onStopSyncingPermanently', 93 'onClearServerDataSucceeded', 94 'onClearServerDataFailed', 95 'onEncryptedTypesChanged', 96 'onEncryptionComplete', 97 'onActionableError', 98 ], 99 100 'transaction': [ 101 'onTransactionWrite', 102 ] 103 }; 104 105 for (var eventType in chrome.sync.events) { 106 var events = chrome.sync.events[eventType]; 107 for (var i = 0; i < events.length; ++i) { 108 var event = events[i]; 109 chrome.sync[event] = new Event(); 110 } 111 } 112 113 function makeSyncFunction(name) { 114 var callbacks = []; 115 116 // Calls the function, assuming the last argument is a callback to be 117 // called with the return value. 118 var fn = function() { 119 var args = Array.prototype.slice.call(arguments); 120 callbacks.push(args.pop()); 121 chrome.send(name, args); 122 }; 123 124 // Handle a reply, assuming that messages are processed in FIFO order. 125 // Called by SyncInternalsUI::HandleJsReply(). 126 fn.handleReply = function() { 127 var args = Array.prototype.slice.call(arguments); 128 // Remove the callback before we call it since the callback may 129 // throw. 130 var callback = callbacks.shift(); 131 callback.apply(null, args); 132 }; 133 134 return fn; 135 } 136 137 var syncFunctions = [ 138 // Sync service functions. 139 'getAboutInfo', 140 141 // Notification functions. See chrome/browser/sync/engine/syncapi.h 142 // for docs. 143 'getNotificationState', 144 'getNotificationInfo', 145 146 // Client server communication logging functions. 147 'getClientServerTraffic', 148 149 // Node lookup functions. See chrome/browser/sync/engine/syncapi.h 150 // for docs. 151 'getRootNodeDetails', 152 'getNodeSummariesById', 153 'getNodeDetailsById', 154 'getChildNodeIds', 155 'getAllNodes', 156 ]; 157 158 for (var i = 0; i < syncFunctions.length; ++i) { 159 var syncFunction = syncFunctions[i]; 160 chrome.sync[syncFunction] = makeSyncFunction(syncFunction); 161 } 162 163 /** 164 * Returns an object which measures elapsed time. 165 */ 166 chrome.sync.makeTimer = function() { 167 var start = new Date(); 168 169 return { 170 /** 171 * @return {number} The number of seconds since the timer was 172 * created. 173 */ 174 get elapsedSeconds() { 175 return ((new Date()).getTime() - start.getTime()) / 1000.0; 176 } 177 }; 178 }; 179 180 })(); 181