Bug 781952 - Part 2: Move cluster management out of service.js; r=rnewman
authorGregory Szorc <gps@mozilla.com>
Tue, 14 Aug 2012 11:34:20 -0700
changeset 111035 172d339df58589cb94c456586de9ff5ae72a8c4f
parent 111034 0dfcb4b9a89b6e7ae60744a70d62fb0ebe91bbf5
child 111036 4a0f07b83709a3dded10fe7e0eecc070551411e7
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersrnewman
bugs781952
milestone17.0a1
Bug 781952 - Part 2: Move cluster management out of service.js; r=rnewman
services/sync/Makefile.in
services/sync/modules/service.js
services/sync/modules/stages/cluster.js
services/sync/modules/stages/enginesync.js
services/sync/tests/unit/test_service_cluster.js
--- a/services/sync/Makefile.in
+++ b/services/sync/Makefile.in
@@ -52,16 +52,17 @@ sync_engine_modules := \
   forms.js \
   history.js \
   passwords.js \
   prefs.js \
   tabs.js \
   $(NULL)
 
 sync_stage_modules := \
+  cluster.js \
   enginesync.js \
   $(NULL)
 
 DIRS += locales
 TEST_DIRS += tests
 
 EXTRA_COMPONENTS := \
   SyncComponents.manifest \
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -29,16 +29,17 @@ Cu.import("resource://services-common/pr
 Cu.import("resource://services-sync/identity.js");
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/resource.js");
 Cu.import("resource://services-sync/rest.js");
 Cu.import("resource://services-sync/status.js");
 Cu.import("resource://services-sync/policies.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-sync/main.js");
+Cu.import("resource://services-sync/stages/cluster.js");
 Cu.import("resource://services-sync/stages/enginesync.js");
 
 const STORAGE_INFO_TYPES = [INFO_COLLECTIONS,
                             INFO_COLLECTION_USAGE,
                             INFO_COLLECTION_COUNTS,
                             INFO_QUOTA];
 
 /*
@@ -289,16 +290,18 @@ WeaveSvc.prototype = {
     ErrorHandler.init();
 
     this._log = Log4Moz.repository.getLogger("Sync.Service");
     this._log.level =
       Log4Moz.Level[Svc.Prefs.get("log.logger.service.main")];
 
     this._log.info("Loading Weave " + WEAVE_VERSION);
 
+    this._clusterManager = new ClusterManager(this);
+
     this.enabled = true;
 
     this._registerEngines();
 
     let ua = Cc["@mozilla.org/network/protocol;1?name=http"].
       getService(Ci.nsIHttpProtocolHandler).userAgent;
     this._log.info(ua);
 
@@ -418,79 +421,24 @@ WeaveSvc.prototype = {
       // The enabled status being changed back to what it was before.
       Svc.Prefs.reset("engineStatusChanged." + engine);
     } else {
       // Remember that the engine status changed locally until the next sync.
       Svc.Prefs.set("engineStatusChanged." + engine, true);
     }
   },
 
-  // gets cluster from central LDAP server and returns it, or null on error
-  _findCluster: function _findCluster() {
-    this._log.debug("Finding cluster for user " + this._identity.username);
-
-    let fail;
-    let res = new Resource(this.userAPI + this._identity.username + "/node/weave");
-    try {
-      let node = res.get();
-      switch (node.status) {
-        case 400:
-          Status.login = LOGIN_FAILED_LOGIN_REJECTED;
-          fail = "Find cluster denied: " + ErrorHandler.errorStr(node);
-          break;
-        case 404:
-          this._log.debug("Using serverURL as data cluster (multi-cluster support disabled)");
-          return this.serverURL;
-        case 0:
-        case 200:
-          if (node == "null") {
-            node = null;
-          }
-          this._log.trace("_findCluster successfully returning " + node);
-          return node;
-        default:
-          ErrorHandler.checkServerError(node);
-          fail = "Unexpected response code: " + node.status;
-          break;
-      }
-    } catch (e) {
-      this._log.debug("Network error on findCluster");
-      Status.login = LOGIN_FAILED_NETWORK_ERROR;
-      ErrorHandler.checkServerError(e);
-      fail = e;
-    }
-    throw fail;
-  },
-
-  // gets cluster from central LDAP server and sets this.clusterURL
-  _setCluster: function _setCluster() {
-    // Make sure we didn't get some unexpected response for the cluster
-    let cluster = this._findCluster();
-    this._log.debug("Cluster value = " + cluster);
-    if (cluster == null)
-      return false;
-
-    // Don't update stuff if we already have the right cluster
-    if (cluster == this.clusterURL)
-      return false;
-
-    this._log.debug("Setting cluster to " + cluster);
-    this.clusterURL = cluster;
-    Svc.Prefs.set("lastClusterUpdate", Date.now().toString());
-    return true;
-  },
-
   // Update cluster if required.
   // Returns false if the update was not required.
   _updateCluster: function _updateCluster() {
     this._log.info("Updating cluster.");
     let cTime = Date.now();
     let lastUp = parseFloat(Svc.Prefs.get("lastClusterUpdate"));
     if (!lastUp || ((cTime - lastUp) >= CLUSTER_BACKOFF)) {
-      return this._setCluster();
+      return this._clusterManager.setCluster();
     }
     return false;
   },
 
   /**
    * Perform the info fetch as part of a login or key fetch.
    */
   _fetchInfo: function _fetchInfo(url) {
@@ -650,17 +598,17 @@ WeaveSvc.prototype = {
       Status.login = MASTER_PASSWORD_LOCKED;
       return false;
     }
 
     try {
       // Make sure we have a cluster to verify against.
       // This is a little weird, if we don't get a node we pretend
       // to succeed, since that probably means we just don't have storage.
-      if (this.clusterURL == "" && !this._setCluster()) {
+      if (this.clusterURL == "" && !this._clusterManager.setCluster()) {
         Status.sync = NO_SYNC_NODE_FOUND;
         Svc.Obs.notify("weave:service:sync:delayed");
         return true;
       }
 
       // Fetch collection info on every startup.
       let test = new Resource(this.infoURL).get();
 
@@ -690,17 +638,17 @@ WeaveSvc.prototype = {
           return false;
 
         case 401:
           this._log.warn("401: login failed.");
           // Fall through to the 404 case.
 
         case 404:
           // Check that we're verifying with the correct cluster
-          if (this._setCluster()) {
+          if (this._clusterManager.setCluster()) {
             return this.verifyLogin();
           }
 
           // We must have the right cluster, but the server doesn't expect us
           Status.login = LOGIN_FAILED_LOGIN_REJECTED;
           return false;
 
         default:
new file mode 100644
--- /dev/null
+++ b/services/sync/modules/stages/cluster.js
@@ -0,0 +1,95 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const EXPORTED_SYMBOLS = ["ClusterManager"];
+
+const {utils: Cu} = Components;
+
+Cu.import("resource://services-common/log4moz.js");
+Cu.import("resource://services-sync/constants.js");
+Cu.import("resource://services-sync/policies.js");
+Cu.import("resource://services-sync/resource.js");
+Cu.import("resource://services-sync/status.js");
+Cu.import("resource://services-sync/util.js");
+
+/**
+ * Contains code for managing the Sync cluster we are in.
+ */
+function ClusterManager(service) {
+  this._log = Log4Moz.repository.getLogger("Sync.Service");
+  this._log.level = Log4Moz.Level[Svc.Prefs.get("log.logger.service.main")];
+
+  this.service = service;
+}
+ClusterManager.prototype = {
+  get identity() {
+    return this.service._identity;
+  },
+
+  /**
+   * Obtain the cluster for the current user.
+   *
+   * Returns the string URL of the cluster or null on error.
+   */
+  _findCluster: function _findCluster() {
+    this._log.debug("Finding cluster for user " + this.identity.username);
+
+    let fail;
+    let res = new Resource(this.service.userAPI + this.identity.username +
+                           "/node/weave");
+    try {
+      let node = res.get();
+      switch (node.status) {
+        case 400:
+          Status.login = LOGIN_FAILED_LOGIN_REJECTED;
+          fail = "Find cluster denied: " + ErrorHandler.errorStr(node);
+          break;
+        case 404:
+          this._log.debug("Using serverURL as data cluster (multi-cluster support disabled)");
+          return this.service.serverURL;
+        case 0:
+        case 200:
+          if (node == "null") {
+            node = null;
+          }
+          this._log.trace("_findCluster successfully returning " + node);
+          return node;
+        default:
+          ErrorHandler.checkServerError(node);
+          fail = "Unexpected response code: " + node.status;
+          break;
+      }
+    } catch (e) {
+      this._log.debug("Network error on findCluster");
+      Status.login = LOGIN_FAILED_NETWORK_ERROR;
+      ErrorHandler.checkServerError(e);
+      fail = e;
+    }
+    throw fail;
+  },
+
+  /**
+   * Determine the cluster for the current user and update state.
+   */
+  setCluster: function setCluster() {
+    // Make sure we didn't get some unexpected response for the cluster.
+    let cluster = this._findCluster();
+    this._log.debug("Cluster value = " + cluster);
+    if (cluster == null) {
+      return false;
+    }
+
+    // Don't update stuff if we already have the right cluster
+    if (cluster == this.service.clusterURL) {
+      return false;
+    }
+
+    this._log.debug("Setting cluster to " + cluster);
+    this.service.clusterURL = cluster;
+    Svc.Prefs.set("lastClusterUpdate", Date.now().toString());
+
+    return true;
+  },
+};
+Object.freeze(ClusterManager.prototype);
--- a/services/sync/modules/stages/enginesync.js
+++ b/services/sync/modules/stages/enginesync.js
@@ -54,17 +54,17 @@ EngineSynchronizer.prototype = {
       // this is a purposeful abort rather than a failure, so don't set
       // any status bits
       reason = "Can't sync: " + reason;
       this.onComplete(new Error("Can't sync: " + reason));
       return;
     }
 
     // If we don't have a node, get one. If that fails, retry in 10 minutes.
-    if (this.service.clusterURL == "" && !this.service._setCluster()) {
+    if (!this.service.clusterURL && !this.service._clusterManager.setCluster()) {
       Status.sync = NO_SYNC_NODE_FOUND;
       this._log.info("No cluster URL found. Cannot sync.");
       this.onComplete(null);
       return;
     }
 
     // Ping the server with a special info request once a day.
     let infoURL = this.service.infoURL;
--- a/services/sync/tests/unit/test_service_cluster.js
+++ b/services/sync/tests/unit/test_service_cluster.js
@@ -15,51 +15,51 @@ function test_findCluster() {
   _("Test Service._findCluster()");
   let server;
   try {
     Service.serverURL = TEST_SERVER_URL;
     Identity.account = "johndoe";
 
     _("_findCluster() throws on network errors (e.g. connection refused).");
     do_check_throws(function() {
-      Service._findCluster();
+      Service._clusterManager._findCluster();
     });
 
     server = httpd_setup({
       "/user/1.0/johndoe/node/weave": httpd_handler(200, "OK", "http://weave.user.node/"),
       "/user/1.0/jimdoe/node/weave": httpd_handler(200, "OK", "null"),
       "/user/1.0/janedoe/node/weave": httpd_handler(404, "Not Found", "Not Found"),
       "/user/1.0/juliadoe/node/weave": httpd_handler(400, "Bad Request", "Bad Request"),
       "/user/1.0/joedoe/node/weave": httpd_handler(500, "Server Error", "Server Error")
     });
 
     _("_findCluster() returns the user's cluster node");
-    let cluster = Service._findCluster();
+    let cluster = Service._clusterManager._findCluster();
     do_check_eq(cluster, "http://weave.user.node/");
 
     _("A 'null' response is converted to null.");
     Identity.account = "jimdoe";
-    cluster = Service._findCluster();
+    cluster = Service._clusterManager._findCluster();
     do_check_eq(cluster, null);
 
     _("If a 404 is encountered, the server URL is taken as the cluster URL");
     Identity.account = "janedoe";
-    cluster = Service._findCluster();
+    cluster = Service._clusterManager._findCluster();
     do_check_eq(cluster, Service.serverURL);
 
     _("A 400 response will throw an error.");
     Identity.account = "juliadoe";
     do_check_throws(function() {
-      Service._findCluster();
+      Service._clusterManager._findCluster();
     });
 
     _("Any other server response (e.g. 500) will throw an error.");
     Identity.account = "joedoe";
     do_check_throws(function() {
-      Service._findCluster();
+      Service._clusterManager._findCluster();
     });
 
   } finally {
     Svc.Prefs.resetBranch("");
     if (server) {
       server.stop(runNextTest);
     }
   }
@@ -75,26 +75,26 @@ function test_setCluster() {
   try {
     Service.serverURL = TEST_SERVER_URL;
     Identity.account = "johndoe";
 
     _("Check initial state.");
     do_check_eq(Service.clusterURL, "");
 
     _("Set the cluster URL.");
-    do_check_true(Service._setCluster());
+    do_check_true(Service._clusterManager.setCluster());
     do_check_eq(Service.clusterURL, "http://weave.user.node/");
 
     _("Setting it again won't make a difference if it's the same one.");
-    do_check_false(Service._setCluster());
+    do_check_false(Service._clusterManager.setCluster());
     do_check_eq(Service.clusterURL, "http://weave.user.node/");
 
     _("A 'null' response won't make a difference either.");
     Identity.account = "jimdoe";
-    do_check_false(Service._setCluster());
+    do_check_false(Service._clusterManager.setCluster());
     do_check_eq(Service.clusterURL, "http://weave.user.node/");
 
   } finally {
     Svc.Prefs.resetBranch("");
     server.stop(runNextTest);
   }
 }