1// Copyright (c) 2011 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// TODO(akalin): Add mocking code for e.g. chrome.send() so that we 7// can test this without rebuilding chrome. 8chrome.sync = chrome.sync || {}; 9(function () { 10 11// This Event class is a simplified version of the one from 12// event_bindings.js. 13function Event() { 14 this.listeners_ = []; 15} 16 17Event.prototype.addListener = function(listener) { 18 this.listeners_.push(listener); 19}; 20 21Event.prototype.removeListener = function(listener) { 22 var i = this.findListener_(listener); 23 if (i == -1) { 24 return; 25 } 26 this.listeners_.splice(i, 1); 27}; 28 29Event.prototype.hasListener = function(listener) { 30 return this.findListener_(listener) > -1; 31}; 32 33Event.prototype.hasListeners = function(listener) { 34 return this.listeners_.length > 0; 35}; 36 37// Returns the index of the given listener, or -1 if not found. 38Event.prototype.findListener_ = function(listener) { 39 for (var i = 0; i < this.listeners_.length; i++) { 40 if (this.listeners_[i] == listener) { 41 return i; 42 } 43 } 44 return -1; 45}; 46 47// Fires the event. Called by the actual event callback. Any 48// exceptions thrown by a listener are caught and logged. 49Event.prototype.dispatch_ = function() { 50 var args = Array.prototype.slice.call(arguments); 51 for (var i = 0; i < this.listeners_.length; i++) { 52 try { 53 this.listeners_[i].apply(null, args); 54 } catch (e) { 55 if (e instanceof Error) { 56 // Non-standard, but useful. 57 console.error(e.stack); 58 } else { 59 console.error(e); 60 } 61 } 62 } 63}; 64 65// Service events. 66chrome.sync.onSyncServiceStateChanged = new Event(); 67 68// Notifier events. 69chrome.sync.onSyncNotificationStateChange = new Event(); 70chrome.sync.onSyncIncomingNotification = new Event(); 71 72// Manager events. 73chrome.sync.onChangesApplied = new Event(); 74chrome.sync.onChangesComplete = new Event(); 75chrome.sync.onSyncCycleCompleted = new Event(); 76chrome.sync.onAuthError = new Event(); 77chrome.sync.onUpdatedToken = new Event(); 78chrome.sync.onPassphraseRequired = new Event(); 79chrome.sync.onPassphraseAccepted = new Event(); 80chrome.sync.onEncryptionComplete = new Event(); 81chrome.sync.onMigrationNeededForTypes = new Event(); 82chrome.sync.onInitializationComplete = new Event(); 83chrome.sync.onPaused = new Event(); 84chrome.sync.onResumed = new Event(); 85chrome.sync.onStopSyncingPermanently = new Event(); 86chrome.sync.onClearServerDataSucceeded = new Event(); 87chrome.sync.onClearServerDataFailed = new Event(); 88 89function AsyncFunction(name) { 90 this.name_ = name; 91 this.callbacks_ = []; 92} 93 94// Calls the function, assuming the last argument is a callback to be 95// called with the return value. 96AsyncFunction.prototype.call = function() { 97 var args = Array.prototype.slice.call(arguments); 98 this.callbacks_.push(args.pop()); 99 chrome.send(this.name_, args); 100} 101 102// Handle a reply, assuming that messages are processed in FIFO order. 103AsyncFunction.prototype.handleReply = function() { 104 var args = Array.prototype.slice.call(arguments); 105 // Remove the callback before we call it since the callback may 106 // throw. 107 var callback = this.callbacks_.shift(); 108 callback.apply(null, args); 109} 110 111// Sync service functions. 112chrome.sync.getAboutInfo_ = new AsyncFunction('getAboutInfo'); 113chrome.sync.getAboutInfo = function(callback) { 114 chrome.sync.getAboutInfo_.call(callback); 115} 116 117// Notification functions. 118chrome.sync.getNotificationState_ = 119 new AsyncFunction('getNotificationState'); 120chrome.sync.getNotificationState = function(callback) { 121 chrome.sync.getNotificationState_.call(callback); 122} 123 124chrome.sync.getNotificationInfo_ = 125 new AsyncFunction('getNotificationInfo'); 126chrome.sync.getNotificationInfo = function(callback) { 127 chrome.sync.getNotificationInfo_.call(callback); 128} 129 130// Node lookup functions. 131chrome.sync.getRootNode_ = new AsyncFunction('getRootNode'); 132chrome.sync.getRootNode = function(callback) { 133 chrome.sync.getRootNode_.call(callback); 134} 135 136chrome.sync.getNodeById_ = new AsyncFunction('getNodeById'); 137chrome.sync.getNodeById = function(id, callback) { 138 chrome.sync.getNodeById_.call(id, callback); 139} 140 141})(); 142 143// TODO(akalin): Rewrite the C++ side to not need the handlers below. 144 145// Sync service event handlers. 146 147function onSyncServiceStateChanged() { 148 chrome.sync.onSyncServiceStateChanged.dispatch_(); 149} 150 151// Notification event handlers. 152 153function onSyncNotificationStateChange(notificationsEnabled) { 154 chrome.sync.onSyncNotificationStateChange.dispatch_(notificationsEnabled); 155} 156 157function onSyncIncomingNotification(changedTypes) { 158 chrome.sync.onSyncIncomingNotification.dispatch_(changedTypes); 159} 160 161// Sync manager event handlers. 162 163function onChangesApplied(modelType, changes) { 164 chrome.sync.onChangesApplied.dispatch_(modelType, changes); 165} 166 167function onChangesComplete(modelType) { 168 chrome.sync.onChangesComplete.dispatch_(modelType); 169} 170 171function onSyncCycleCompleted(snapshot) { 172 chrome.sync.onSyncCycleCompleted.dispatch_(snapshot); 173} 174 175function onAuthError(authError) { 176 chrome.sync.onAuthError.dispatch_(authError); 177} 178 179function onUpdatedToken(token) { 180 chrome.sync.onUpdatedToken.dispatch_(token); 181} 182 183function onPassphraseRequired(forDecryption) { 184 chrome.sync.onPassphraseRequired.dispatch_(forDecryption); 185} 186 187function onPassphraseAccepted(bootstrapToken) { 188 chrome.sync.onPassphraseAccepted.dispatch_(bootstrapToken); 189} 190 191function onEncryptionComplete(encrypted_types) { 192 chrome.sync.onEncryptionComplete.dispatch_(encrypted_types); 193} 194 195function onMigrationNeededForTypes(model_types) { 196 chrome.sync.onMigrationNeededForTypes.dispatch_(model_types); 197} 198 199function onInitializationComplete() { 200 chrome.sync.onInitializationComplete.dispatch_(); 201} 202 203function onPaused() { 204 chrome.sync.onPaused.dispatch_(); 205} 206 207function onResumed() { 208 chrome.sync.onResumed.dispatch_(); 209} 210 211function onStopSyncingPermanently() { 212 chrome.sync.onStopSyncingPermanently.dispatch_(); 213} 214 215function onClearServerDataSucceeded() { 216 chrome.sync.onClearServerDataSucceeded(); 217} 218 219function onClearServerDataFailed() { 220 chrome.sync.onClearServerDataFailed(); 221} 222 223// Function reply handlers. 224 225function onGetAboutInfoFinished(aboutInfo) { 226 chrome.sync.getAboutInfo_.handleReply(aboutInfo); 227} 228 229function onGetNotificationStateFinished(notificationState) { 230 chrome.sync.getNotificationState_.handleReply(notificationState); 231} 232 233function onGetRootNodeFinished(rootNode) { 234 chrome.sync.getRootNode_.handleReply(rootNode); 235} 236 237function onGetNodeByIdFinished(node) { 238 chrome.sync.getNodeById_.handleReply(node); 239} 240 241function onGetNotificationInfoFinished(notificationInfo) { 242 chrome.sync.getNotificationInfo_.handleReply(notificationInfo); 243} 244