Bug 518864 - Persist "next sync time" across events that disable sync
authorEdward Lee <edilee@mozilla.com>
Fri, 25 Sep 2009 11:46:29 -0700
changeset 45778 a69e679cea80ef1186bd4f1e395be1aa9c6d3111
parent 45777 fdadc8600cf25c7e4043aa5826236b0e1334cc62
child 45779 d8ff8ef2d6a4c15c97f100d870e9809f34c1e5d5
push idunknown
push userunknown
push dateunknown
bugs518864
Bug 518864 - Persist "next sync time" across events that disable sync Save a nextSync value in a pref and use it to trigger a sync-on-idle if the "next sync time" already passed when logging in. Make sure to default to backoff time first, then next sync, then use the default.
services/sync/modules/service.js
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -250,16 +250,20 @@ WeaveSvc.prototype = {
   set isQuitting(value) { this._isQuitting = value; },
 
   get keyGenEnabled() { return this._keyGenEnabled; },
   set keyGenEnabled(value) { this._keyGenEnabled = value; },
 
   get enabled() { return Svc.Prefs.get("enabled"); },
   set enabled(value) { Svc.Prefs.set("enabled", value); },
 
+  // nextSync is in milliseconds, but prefs can't hold that much
+  get nextSync() Svc.Prefs.get("nextSync", 0) * 1000,
+  set nextSync(value) Svc.Prefs.set("nextSync", Math.floor(value / 1000)),
+
   get status() { return this._status; },
 
   get locked() { return this._locked; },
   lock: function Svc_lock() {
     if (this._locked)
       return false;
     this._locked = true;
     return true;
@@ -663,40 +667,28 @@ WeaveSvc.prototype = {
     res.authenticator = new NoOpAuthenticator();
     res.headers['Content-Type'] = 'application/x-www-form-urlencoded';
     let ret = res.post('uid=' + username);
     if (ret.indexOf("Further instructions have been sent") >= 0)
       return true;
     return false;
   },
 
-  _autoConnectAttempts: 0,
-  _autoConnect: function WeaveSvc__attemptAutoConnect() {
-    try {
-      if (!this.username || !this.password || !this.passphrase)
-        return;
+  _autoConnect: let (attempts = 0) function _autoConnect() {
+    // Can't autoconnect if we're missing these values
+    if (!this.username || !this.password || !this.passphrase)
+      return;
 
-      let failureReason;
-      if (Svc.IO.offline)
-        failureReason = "Application is offline";
-      else if (this.login()) {
-        this.syncOnIdle();
-        return;
-      }
+    // Nothing more to do on a successful login
+    if (this.login())
+      return;
 
-      failureReason = this.status.sync;
-    }
-    catch (ex) {
-      failureReason = ex;
-    }
-
-    this._autoConnectAttempts++;
-    let interval = this._calculateBackoff(this._autoConnectAttempts,
-                                          SCHEDULED_SYNC_INTERVAL);
-    this._log.debug("Autoconnect failed: " + failureReason + "; retrying in " +
+    // Something failed, so try again some time later
+    let interval = this._calculateBackoff(++attempts, 60 * 1000);
+    this._log.debug("Autoconnect failed: " + this.status.login + "; retry in " +
       Math.ceil(interval / 1000) + " sec.");
     Utils.delay(function() this._autoConnect(), interval, this, "_autoTimer");
   },
 
   persistLogin: function persistLogin() {
     // Canceled master password prompt can prevent these from succeeding
     try {
       ID.get("WeaveID").persist();
@@ -1035,21 +1027,40 @@ WeaveSvc.prototype = {
                     IDLE_TIME + " seconds of inactivity.");
     Svc.Idle.addIdleObserver(this, IDLE_TIME);
   },
 
   /**
    * Set a timer for the next sync
    */
   _scheduleNextSync: function WeaveSvc__scheduleNextSync(interval) {
-    if (!interval)
-      interval = this.status.backoffInterval || SCHEDULED_SYNC_INTERVAL;
+    // Figure out when to sync next if not given a interval to wait
+    if (interval == null) {
+      // Make sure we backoff we we need to
+      if (this.status.backoffInterval != 0)
+        interval = this.status.backoffInterval;
+      // Check if we had a pending sync from last time
+      else if (this.nextSync != 0)
+        interval = this.nextSync - Date.now();
+      // Use the default sync interval
+      else 
+        interval = SCHEDULED_SYNC_INTERVAL;
+    }
+
+    // Start the sync right away if we're already late
+    if (interval <= 0) {
+      this.syncOnIdle();
+      return;
+    }
 
     this._log.debug("Next sync in " + Math.ceil(interval / 1000) + " sec.");
     Utils.delay(function() this.syncOnIdle(), interval, this, "_syncTimer");
+
+    // Save the next sync time in-case sync is disabled (logout/offline/etc.)
+    this.nextSync = Date.now() + interval;
   },
 
   _syncErrors: 0,
   /**
    * Deal with sync errors appropriately
    */
   _handleSyncError: function WeaveSvc__handleSyncError() {
     this._syncErrors++;
@@ -1094,16 +1105,17 @@ WeaveSvc.prototype = {
       // this is a purposeful abort rather than a failure, so don't set
       // any status bits
       reason = "Can't sync: " + reason;
       throw reason;
     }
 
     // Clear out any potentially pending syncs now that we're syncing
     this._clearSyncTriggers();
+    this.nextSync = 0;
 
     if (!(this._remoteSetup()))
       throw "aborting sync, remote setup failed";
 
     // Figure out what the last modified time is for each collection
     let info = new Resource(this.infoURL).get();
     if (!info.success)
       throw "aborting sync, failed to get collections";