Home | History | Annotate | Download | only in sync_internals
      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 
      5 var chrome = chrome || {};
      6 // TODO(akalin): Add mocking code for e.g. chrome.send() so that we
      7 // can test this without rebuilding chrome.
      8 chrome.sync = chrome.sync || {};
      9 (function () {
     10 
     11 // This Event class is a simplified version of the one from
     12 // event_bindings.js.
     13 function Event() {
     14   this.listeners_ = [];
     15 }
     16 
     17 Event.prototype.addListener = function(listener) {
     18   this.listeners_.push(listener);
     19 };
     20 
     21 Event.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 
     29 Event.prototype.hasListener = function(listener) {
     30   return this.findListener_(listener) > -1;
     31 };
     32 
     33 Event.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.
     38 Event.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.
     49 Event.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.
     66 chrome.sync.onSyncServiceStateChanged = new Event();
     67 
     68 // Notifier events.
     69 chrome.sync.onSyncNotificationStateChange = new Event();
     70 chrome.sync.onSyncIncomingNotification = new Event();
     71 
     72 // Manager events.
     73 chrome.sync.onChangesApplied = new Event();
     74 chrome.sync.onChangesComplete = new Event();
     75 chrome.sync.onSyncCycleCompleted = new Event();
     76 chrome.sync.onAuthError = new Event();
     77 chrome.sync.onUpdatedToken = new Event();
     78 chrome.sync.onPassphraseRequired = new Event();
     79 chrome.sync.onPassphraseAccepted = new Event();
     80 chrome.sync.onEncryptionComplete = new Event();
     81 chrome.sync.onMigrationNeededForTypes = new Event();
     82 chrome.sync.onInitializationComplete = new Event();
     83 chrome.sync.onPaused = new Event();
     84 chrome.sync.onResumed = new Event();
     85 chrome.sync.onStopSyncingPermanently = new Event();
     86 chrome.sync.onClearServerDataSucceeded = new Event();
     87 chrome.sync.onClearServerDataFailed = new Event();
     88 
     89 function 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.
     96 AsyncFunction.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.
    103 AsyncFunction.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.
    112 chrome.sync.getAboutInfo_ = new AsyncFunction('getAboutInfo');
    113 chrome.sync.getAboutInfo = function(callback) {
    114   chrome.sync.getAboutInfo_.call(callback);
    115 }
    116 
    117 // Notification functions.
    118 chrome.sync.getNotificationState_ =
    119     new AsyncFunction('getNotificationState');
    120 chrome.sync.getNotificationState = function(callback) {
    121   chrome.sync.getNotificationState_.call(callback);
    122 }
    123 
    124 chrome.sync.getNotificationInfo_ =
    125     new AsyncFunction('getNotificationInfo');
    126 chrome.sync.getNotificationInfo = function(callback) {
    127   chrome.sync.getNotificationInfo_.call(callback);
    128 }
    129 
    130 // Node lookup functions.
    131 chrome.sync.getRootNode_ = new AsyncFunction('getRootNode');
    132 chrome.sync.getRootNode = function(callback) {
    133   chrome.sync.getRootNode_.call(callback);
    134 }
    135 
    136 chrome.sync.getNodeById_ = new AsyncFunction('getNodeById');
    137 chrome.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 
    147 function onSyncServiceStateChanged() {
    148   chrome.sync.onSyncServiceStateChanged.dispatch_();
    149 }
    150 
    151 // Notification event handlers.
    152 
    153 function onSyncNotificationStateChange(notificationsEnabled) {
    154   chrome.sync.onSyncNotificationStateChange.dispatch_(notificationsEnabled);
    155 }
    156 
    157 function onSyncIncomingNotification(changedTypes) {
    158   chrome.sync.onSyncIncomingNotification.dispatch_(changedTypes);
    159 }
    160 
    161 // Sync manager event handlers.
    162 
    163 function onChangesApplied(modelType, changes) {
    164   chrome.sync.onChangesApplied.dispatch_(modelType, changes);
    165 }
    166 
    167 function onChangesComplete(modelType) {
    168   chrome.sync.onChangesComplete.dispatch_(modelType);
    169 }
    170 
    171 function onSyncCycleCompleted(snapshot) {
    172   chrome.sync.onSyncCycleCompleted.dispatch_(snapshot);
    173 }
    174 
    175 function onAuthError(authError) {
    176   chrome.sync.onAuthError.dispatch_(authError);
    177 }
    178 
    179 function onUpdatedToken(token) {
    180   chrome.sync.onUpdatedToken.dispatch_(token);
    181 }
    182 
    183 function onPassphraseRequired(forDecryption) {
    184   chrome.sync.onPassphraseRequired.dispatch_(forDecryption);
    185 }
    186 
    187 function onPassphraseAccepted(bootstrapToken) {
    188   chrome.sync.onPassphraseAccepted.dispatch_(bootstrapToken);
    189 }
    190 
    191 function onEncryptionComplete(encrypted_types) {
    192   chrome.sync.onEncryptionComplete.dispatch_(encrypted_types);
    193 }
    194 
    195 function onMigrationNeededForTypes(model_types) {
    196   chrome.sync.onMigrationNeededForTypes.dispatch_(model_types);
    197 }
    198 
    199 function onInitializationComplete() {
    200   chrome.sync.onInitializationComplete.dispatch_();
    201 }
    202 
    203 function onPaused() {
    204   chrome.sync.onPaused.dispatch_();
    205 }
    206 
    207 function onResumed() {
    208   chrome.sync.onResumed.dispatch_();
    209 }
    210 
    211 function onStopSyncingPermanently() {
    212   chrome.sync.onStopSyncingPermanently.dispatch_();
    213 }
    214 
    215 function onClearServerDataSucceeded() {
    216   chrome.sync.onClearServerDataSucceeded();
    217 }
    218 
    219 function onClearServerDataFailed() {
    220   chrome.sync.onClearServerDataFailed();
    221 }
    222 
    223 // Function reply handlers.
    224 
    225 function onGetAboutInfoFinished(aboutInfo) {
    226   chrome.sync.getAboutInfo_.handleReply(aboutInfo);
    227 }
    228 
    229 function onGetNotificationStateFinished(notificationState) {
    230   chrome.sync.getNotificationState_.handleReply(notificationState);
    231 }
    232 
    233 function onGetRootNodeFinished(rootNode) {
    234   chrome.sync.getRootNode_.handleReply(rootNode);
    235 }
    236 
    237 function onGetNodeByIdFinished(node) {
    238   chrome.sync.getNodeById_.handleReply(node);
    239 }
    240 
    241 function onGetNotificationInfoFinished(notificationInfo) {
    242   chrome.sync.getNotificationInfo_.handleReply(notificationInfo);
    243 }
    244