1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const Cc = Components.classes;
6 const Ci = Components.interfaces;
7 const Cu = Components.utils;
9 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
10 Cu.import("resource://gre/modules/Services.jsm");
11 Cu.import("resource://gre/modules/FileUtils.jsm");
12 Cu.import("resource://gre/modules/Promise.jsm");
13 Cu.import("resource://services-sync/util.js");
15 const SYNC_PREFS_BRANCH = "services.sync.";
19 * Sync's XPCOM service.
21 * It is named "Weave" for historical reasons.
23 * It's worth noting how Sync is lazily loaded. We register a timer that
24 * loads Sync a few seconds after app startup. This is so Sync does not
25 * adversely affect application start time.
27 * If Sync is not configured, no extra Sync code is loaded. If an
28 * external component (say the UI) needs to interact with Sync, it
29 * should use the promise-base function whenLoaded() - something like the
32 * // 1. Grab a handle to the Sync XPCOM service.
33 * let service = Cc["@mozilla.org/weave/service;1"]
34 * .getService(Components.interfaces.nsISupports)
37 * // 2. Use the .then method of the promise.
38 * service.whenLoaded().then(() => {
39 * // You are free to interact with "Weave." objects.
43 * And that's it! However, if you really want to avoid promises and do it
46 * // 1. Get a reference to the service as done in (1) above.
48 * // 2. Check if the service has been initialized.
49 * if (service.ready) {
50 * // You are free to interact with "Weave." objects.
54 * // 3. Install "ready" listener.
55 * Services.obs.addObserver(function onReady() {
56 * Services.obs.removeObserver(onReady, "weave:service:ready");
58 * // You are free to interact with "Weave." objects.
59 * }, "weave:service:ready", false);
61 * // 4. Trigger loading of Sync.
62 * service.ensureLoaded();
64 function WeaveService() {
65 this.wrappedJSObject = this;
68 WeaveService.prototype = {
69 classID: Components.ID("{74b89fb0-f200-4ae8-a3ec-dd164117f6de}"),
71 QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
72 Ci.nsISupportsWeakReference]),
74 ensureLoaded: function () {
75 Components.utils.import("resource://services-sync/main.js");
77 // Side-effect of accessing the service is that it is instantiated.
81 whenLoaded: function() {
83 return Promise.resolve();
85 let deferred = Promise.defer();
87 Services.obs.addObserver(function onReady() {
88 Services.obs.removeObserver(onReady, "weave:service:ready");
90 }, "weave:service:ready", false);
92 return deferred.promise;
96 * Whether Firefox Accounts is enabled.
100 get fxAccountsEnabled() {
102 // Old sync guarantees '@' will never appear in the username while FxA
103 // uses the FxA email address - so '@' is the flag we use.
104 let username = Services.prefs.getCharPref(SYNC_PREFS_BRANCH + "username");
105 return !username || username.contains('@');
107 return true; // No username == only allow FxA to be configured.
112 * Whether Sync appears to be enabled.
114 * This returns true if all the Sync preferences for storing account
115 * and server configuration are populated.
117 * It does *not* perform a robust check to see if the client is working.
118 * For that, you'll want to check Weave.Status.checkSetup().
121 let prefs = Services.prefs.getBranch(SYNC_PREFS_BRANCH);
122 return prefs.prefHasUserValue("username") &&
123 prefs.prefHasUserValue("clusterURL");
126 observe: function (subject, topic, data) {
129 let os = Cc["@mozilla.org/observer-service;1"].
130 getService(Ci.nsIObserverService);
131 os.addObserver(this, "final-ui-startup", true);
134 case "final-ui-startup":
135 // Force Weave service to load if it hasn't triggered from overlays
136 this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
137 this.timer.initWithCallback({
139 let isConfigured = false;
140 // We only load more if it looks like Sync is configured.
141 let prefs = Services.prefs.getBranch(SYNC_PREFS_BRANCH);
142 if (prefs.prefHasUserValue("username")) {
143 // We have a username. So, do a more thorough check. This will
144 // import a number of modules and thus increase memory
145 // accordingly. We could potentially copy code performed by
146 // this check into this file if our above code is yielding too
147 // many false positives.
148 Components.utils.import("resource://services-sync/main.js");
149 isConfigured = Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED;
151 let getHistogramById = Services.telemetry.getHistogramById;
152 getHistogramById("WEAVE_CONFIGURED").add(isConfigured);
154 getHistogramById("WEAVE_CONFIGURED_MASTER_PASSWORD").add(Utils.mpEnabled());
158 }, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
164 function AboutWeaveLog() {}
165 AboutWeaveLog.prototype = {
166 classID: Components.ID("{d28f8a0b-95da-48f4-b712-caf37097be41}"),
168 QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule,
169 Ci.nsISupportsWeakReference]),
171 getURIFlags: function(aURI) {
175 newChannel: function(aURI) {
176 let dir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
177 let uri = Services.io.newFileURI(dir);
178 let channel = Services.io.newChannelFromURI(uri);
179 channel.originalURI = aURI;
181 // Ensure that the about page has the same privileges as a regular directory
182 // view. That way links to files can be opened.
183 let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
184 .getService(Ci.nsIScriptSecurityManager);
185 let principal = ssm.getNoAppCodebasePrincipal(uri);
186 channel.owner = principal;
191 const components = [WeaveService, AboutWeaveLog];
192 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);