gecko-dev/services/sync/Weave.sys.mjs

190 lines
5.5 KiB
JavaScript

/* 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/. */
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
});
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"syncUsername",
"services.sync.username"
);
/**
* Sync's XPCOM service.
*
* It is named "Weave" for historical reasons.
*
* It's worth noting how Sync is lazily loaded. We register a timer that
* loads Sync a few seconds after app startup. This is so Sync does not
* adversely affect application start time.
*
* If Sync is not configured, no extra Sync code is loaded. If an
* external component (say the UI) needs to interact with Sync, it
* should use the promise-base function whenLoaded() - something like the
* following:
*
* // 1. Grab a handle to the Sync XPCOM service.
* let service = Cc["@mozilla.org/weave/service;1"]
* .getService(Components.interfaces.nsISupports)
* .wrappedJSObject;
*
* // 2. Use the .then method of the promise.
* service.whenLoaded().then(() => {
* // You are free to interact with "Weave." objects.
* return;
* });
*
* And that's it! However, if you really want to avoid promises and do it
* old-school, then
*
* // 1. Get a reference to the service as done in (1) above.
*
* // 2. Check if the service has been initialized.
* if (service.ready) {
* // You are free to interact with "Weave." objects.
* return;
* }
*
* // 3. Install "ready" listener.
* Services.obs.addObserver(function onReady() {
* Services.obs.removeObserver(onReady, "weave:service:ready");
*
* // You are free to interact with "Weave." objects.
* }, "weave:service:ready", false);
*
* // 4. Trigger loading of Sync.
* service.ensureLoaded();
*/
export function WeaveService() {
this.wrappedJSObject = this;
this.ready = false;
}
WeaveService.prototype = {
classID: Components.ID("{74b89fb0-f200-4ae8-a3ec-dd164117f6de}"),
QueryInterface: ChromeUtils.generateQI([
"nsIObserver",
"nsISupportsWeakReference",
]),
get Weave() {
const { Weave } = ChromeUtils.importESModule(
"resource://services-sync/main.sys.mjs"
);
return Weave;
},
ensureLoaded() {
// Side-effect of accessing the service is that it is instantiated.
this.Weave.Service;
},
whenLoaded() {
if (this.ready) {
return Promise.resolve();
}
let onReadyPromise = new Promise(resolve => {
Services.obs.addObserver(function onReady() {
Services.obs.removeObserver(onReady, "weave:service:ready");
resolve();
}, "weave:service:ready");
});
this.ensureLoaded();
return onReadyPromise;
},
init() {
// Force Weave service to load if it hasn't triggered from overlays
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.timer.initWithCallback(
{
notify: () => {
let isConfigured = false;
// We only load more if it looks like Sync is configured.
if (this.enabled) {
// We have an associated FxAccount. So, do a more thorough check.
// This will import a number of modules and thus increase memory
// accordingly. We could potentially copy code performed by
// this check into this file if our above code is yielding too
// many false positives.
var { Weave } = ChromeUtils.importESModule(
"resource://services-sync/main.sys.mjs"
);
isConfigured =
Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED;
}
if (isConfigured) {
this.ensureLoaded();
}
},
},
10000,
Ci.nsITimer.TYPE_ONE_SHOT
);
},
/**
* Whether Sync appears to be enabled.
*
* This returns true if we have an associated FxA account and Sync is enabled.
*
* It does *not* perform a robust check to see if the client is working.
* For that, you'll want to check Weave.Status.checkSetup().
*/
get enabled() {
return (
!!lazy.syncUsername &&
Services.prefs.getBoolPref("identity.fxaccounts.enabled")
);
},
};
export function AboutWeaveLog() {}
AboutWeaveLog.prototype = {
classID: Components.ID("{d28f8a0b-95da-48f4-b712-caf37097be41}"),
QueryInterface: ChromeUtils.generateQI([
"nsIAboutModule",
"nsISupportsWeakReference",
]),
getURIFlags(aURI) {
return 0;
},
newChannel(aURI, aLoadInfo) {
let dir = lazy.FileUtils.getDir("ProfD", ["weave", "logs"]);
try {
dir.create(Ci.nsIFile.DIRECTORY_TYPE, lazy.FileUtils.PERMS_DIRECTORY);
} catch (ex) {
if (ex.result != Cr.NS_ERROR_FILE_ALREADY_EXISTS) {
throw ex;
}
// Ignore the exception due to a directory that already exists.
}
let uri = Services.io.newFileURI(dir);
let channel = Services.io.newChannelFromURIWithLoadInfo(uri, aLoadInfo);
channel.originalURI = aURI;
// Ensure that the about page has the same privileges as a regular directory
// view. That way links to files can be opened. make sure we use the correct
// origin attributes when creating the principal for accessing the
// about:sync-log data.
let principal = Services.scriptSecurityManager.createContentPrincipal(
uri,
aLoadInfo.originAttributes
);
channel.owner = principal;
return channel;
},
};