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