Home | History | Annotate | Download | only in sync_internals
      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