bug 872605 add ability to update provider manifest, r=markh
☠☠ backed out by a257161ff235 ☠ ☠
authorShane Caraveo <scaraveo@mozilla.com>
Sun, 23 Jun 2013 16:02:07 -0400
changeset 147705 9661a68f0bff3d64d30fefc0658a1ab127c2ff74
parent 147704 76820c6dff7b9eedf9b8840e40d8d5c8bdc5cd8f
child 147706 a0dfe6abef7391aaa7d828cfd3ec63e36ffc2c0f
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarkh
bugs872605
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 872605 add ability to update provider manifest, r=markh
browser/base/content/test/social/browser_addons.js
browser/base/content/test/social/social_activate.html
browser/base/content/test/social/social_worker.js
browser/modules/Social.jsm
toolkit/components/social/SocialService.jsm
toolkit/components/social/WorkerAPI.jsm
--- a/browser/base/content/test/social/browser_addons.js
+++ b/browser/base/content/test/social/browser_addons.js
@@ -15,17 +15,18 @@ let manifest = { // builtin provider
   workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
   iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
 };
 let manifest2 = { // used for testing install
   name: "provider 2",
   origin: "https://test1.example.com",
   sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar.html",
   workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js",
-  iconURL: "https://test1.example.com/browser/browser/base/content/test/moz.png"
+  iconURL: "https://test1.example.com/browser/browser/base/content/test/moz.png",
+  version: 1
 };
 
 function test() {
   waitForExplicitFinish();
 
   let prefname = getManifestPrefname(manifest);
   setBuiltinManifestPref(prefname, manifest);
   // ensure that manifest2 is NOT showing as builtin
@@ -267,10 +268,54 @@ var tests = {
       Social.installProvider(doc, manifest2, function(addonManifest) {
         Services.prefs.clearUserPref("social.directories");
         SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
           Social.uninstallProvider(addonManifest.origin);
           gBrowser.removeTab(tab);
         });
       });
     });
+  },
+  testUpgradeProviderFromWorker: function(next) {
+    // add the provider, change the pref, add it again. The provider at that
+    // point should be upgraded
+    let activationURL = manifest2.origin + "/browser/browser/base/content/test/social/social_activate.html"
+    addTab(activationURL, function(tab) {
+      let doc = tab.linkedBrowser.contentDocument;
+      let installFrom = doc.nodePrincipal.origin;
+      Services.prefs.setCharPref("social.whitelist", installFrom);
+      Social.installProvider(doc, manifest2, function(addonManifest) {
+        SocialService.addBuiltinProvider(addonManifest.origin, function(provider) {
+          Social.enabled = true;
+          checkSocialUI();
+          is(Social.provider.manifest.version, 1, "manifest version is 1")
+          // watch for the provider-update and tell the worker to update
+          SocialService.registerProviderListener(function providerListener(topic, data) {
+            if (topic != "provider-update")
+              return;
+            SocialService.unregisterProviderListener(providerListener);
+            observeProviderSet(function() {
+              Services.prefs.clearUserPref("social.whitelist");
+              executeSoon(function() {
+                is(Social.provider.manifest.version, 2, "manifest version is 2");
+                Social.uninstallProvider(addonManifest.origin);
+                gBrowser.removeTab(tab);
+                next();
+              })
+            });
+          });
+          let port = Social.provider.getWorkerPort();
+          port.postMessage({topic: "worker.update", data: true});
+        });
+      });
+    });
   }
 }
+
+
+function observeProviderSet(cb) {
+  Services.obs.addObserver(function providerSet(subject, topic, data) {
+    Services.obs.removeObserver(providerSet, "social:provider-set");
+    info("social:provider-set observer was notified");
+    // executeSoon to let the browser UI observers run first
+    executeSoon(cb);
+  }, "social:provider-set", false);
+}
\ No newline at end of file
--- a/browser/base/content/test/social/social_activate.html
+++ b/browser/base/content/test/social/social_activate.html
@@ -15,17 +15,17 @@ var data = {
   "sidebarURL": "/browser/browser/base/content/test/social/social_sidebar.html",
   "workerURL": "/browser/browser/base/content/test/social/social_worker.js",
 
   // should be available for display purposes
   "description": "A short paragraph about this provider",
   "author": "Shane Caraveo, Mozilla",
 
   // optional
-  "version": "1.0"
+  "version": 1
 }
 
 function activate(node) {
   node.setAttribute("data-service", JSON.stringify(data));
   var event = new CustomEvent("ActivateSocialFeature");
   node.dispatchEvent(event);
 }
 
--- a/browser/base/content/test/social/social_worker.js
+++ b/browser/base/content/test/social/social_worker.js
@@ -132,11 +132,18 @@ onconnect = function(e) {
         break;
       case "test-isVisible-response":
         testPort.postMessage({topic: "got-isVisible-response", result: event.data.result});
         break;
       case "share-data-message":
         if (testPort)
           testPort.postMessage({topic:"got-share-data-message", result: event.data.result});
         break;
+      case "worker.update":
+        apiPort.postMessage({topic: 'social.manifest-get'});
+        break;
+      case "social.manifest":
+        event.data.data.version = 2;
+        apiPort.postMessage({topic: 'social.manifest-set', data: event.data.data});
+        break;
     }
   }
 }
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -157,16 +157,33 @@ this.Social = {
     }.bind(this));
 
     // Register an observer for changes to the provider list
     SocialService.registerProviderListener(function providerListener(topic, data) {
       // An engine change caused by adding/removing a provider should notify
       if (topic == "provider-added" || topic == "provider-removed") {
         this._updateProviderCache(data);
         Services.obs.notifyObservers(null, "social:providers-changed", null);
+        return;
+      }
+      if (topic == "provider-update") {
+        // a provider has self-updated its manifest, we need to update our
+        // cache and possibly reload if it was the current provider.
+        let provider = data;
+        SocialService.getOrderedProviderList(function(providers) {
+          Social._updateProviderCache(providers);
+          Services.obs.notifyObservers(null, "social:providers-changed", null);
+          // if we need a reload, do it now
+          if (provider.enabled) {
+            Social.enabled = false;
+            Services.tm.mainThread.dispatch(function() {
+              Social.enabled = true;
+            }, Components.interfaces.nsIThread.DISPATCH_NORMAL);
+          }
+        });
       }
     }.bind(this));
   },
 
   // Called to update our cache of providers and set the current provider
   _updateProviderCache: function (providers) {
     this.providers = providers;
 
--- a/toolkit/components/social/SocialService.jsm
+++ b/toolkit/components/social/SocialService.jsm
@@ -638,16 +638,46 @@ this.SocialService = {
         installer.install();
         break;
       default:
         throw new Error("SocialService.installProvider: Invalid install type "+installType+"\n");
         break;
     }
   },
 
+  /**
+   * updateProvider is used from the worker to self-update.  Since we do not
+   * have knowledge of the currently selected provider here, we will notify
+   * the front end to deal with any reload.
+   */
+  updateProvider: function(aDOMDocument, aManifest, aCallback) {
+    let installOrigin = aDOMDocument.nodePrincipal.origin;
+    let installType = this.getOriginActivationType(installOrigin);
+    // if we get data, we MUST have a valid manifest generated from the data
+    let manifest = this._manifestFromData(installType, aManifest, aDOMDocument.nodePrincipal);
+    if (!manifest)
+      throw new Error("SocialService.installProvider: service configuration is invalid from " + installOrigin);
+
+    // overwrite the preference
+    let string = Cc["@mozilla.org/supports-string;1"].
+                 createInstance(Ci.nsISupportsString);
+    string.data = JSON.stringify(manifest);
+    Services.prefs.setComplexValue(getPrefnameFromOrigin(manifest.origin), Ci.nsISupportsString, string);
+
+    // overwrite the existing provider then notify the front end so it can
+    // handle any reload that might be necessary.
+    if (ActiveProviders.has(manifest.origin)) {
+      let provider = new SocialProvider(manifest);
+      SocialServiceInternal.providers[provider.origin] = provider;
+      // update the cache and ui, reload provider if necessary
+      this._notifyProviderListeners("provider-update", provider);
+    }
+
+  },
+
   uninstallProvider: function(origin) {
     let manifest = SocialServiceInternal.getManifestByOrigin(origin);
     let addon = new AddonWrapper(manifest);
     addon.uninstall();
   }
 };
 
 /**
@@ -706,16 +736,20 @@ SocialProvider.prototype = {
 
     if (enable) {
       this._activate();
     } else {
       this._terminate();
     }
   },
 
+  get manifest() {
+    return SocialServiceInternal.getManifestByOrigin(this.origin);
+  },
+
   // Reference to a workerAPI object for this provider. Null if the provider has
   // no FrameWorker, or is disabled.
   workerAPI: null,
 
   // Contains information related to the user's profile. Populated by the
   // workerAPI via updateUserProfile.
   // Properties:
   //   iconURL, portrait, userName, displayName, profileURL
--- a/toolkit/components/social/WorkerAPI.jsm
+++ b/toolkit/components/social/WorkerAPI.jsm
@@ -44,16 +44,26 @@ WorkerAPI.prototype = {
     try {
       handler.call(this, data);
     } catch (ex) {
       Cu.reportError("WorkerAPI: failed to handle message '" + topic + "': " + ex + "\n" + ex.stack);
     }
   },
 
   handlers: {
+    "social.manifest-get": function(data) {
+      // retreive the currently installed manifest from firefox
+      this._port.postMessage({topic: "social.manifest", data: this._provider.manifest});
+    },
+    "social.manifest-set": function(data) {
+      // the provider will get reloaded as a result of this call
+      let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
+      let document = this._port._window.document;
+      SocialService.updateProvider(document, data);
+    },
     "social.reload-worker": function(data) {
       getFrameWorkerHandle(this._provider.workerURL, null)._worker.reload();
       // the frameworker is going to be reloaded, send the initialization
       // so it can have the same startup sequence as if it were loaded
       // the first time.  This will be queued until the frameworker is ready.
       this._port.postMessage({topic: "social.initialize"});
     },
     "social.user-profile": function (data) {