Weave.sys.mjs (5723B)
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/. */ 4 5 import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; 6 7 const lazy = {}; 8 ChromeUtils.defineESModuleGetters(lazy, { 9 CLIENT_NOT_CONFIGURED: "resource://services-sync/constants.sys.mjs", 10 FileUtils: "resource://gre/modules/FileUtils.sys.mjs", 11 }); 12 13 XPCOMUtils.defineLazyPreferenceGetter( 14 lazy, 15 "syncUsername", 16 "services.sync.username" 17 ); 18 19 /** 20 * Sync's XPCOM service. 21 * 22 * It is named "Weave" for historical reasons. 23 * 24 * It's worth noting how Sync is lazily loaded. We register a timer that 25 * loads Sync a few seconds after app startup. This is so Sync does not 26 * adversely affect application start time. 27 * 28 * If Sync is not configured, no extra Sync code is loaded. If an 29 * external component (say the UI) needs to interact with Sync, it 30 * should use the promise-base function whenLoaded() - something like the 31 * following: 32 * 33 * // 1. Grab a handle to the Sync XPCOM service. 34 * let service = Cc["@mozilla.org/weave/service;1"] 35 * .getService(Components.interfaces.nsISupports) 36 * .wrappedJSObject; 37 * 38 * // 2. Use the .then method of the promise. 39 * service.whenLoaded().then(() => { 40 * // You are free to interact with "Weave." objects. 41 * return; 42 * }); 43 * 44 * And that's it! However, if you really want to avoid promises and do it 45 * old-school, then 46 * 47 * // 1. Get a reference to the service as done in (1) above. 48 * 49 * // 2. Check if the service has been initialized. 50 * if (service.ready) { 51 * // You are free to interact with "Weave." objects. 52 * return; 53 * } 54 * 55 * // 3. Install "ready" listener. 56 * Services.obs.addObserver(function onReady() { 57 * Services.obs.removeObserver(onReady, "weave:service:ready"); 58 * 59 * // You are free to interact with "Weave." objects. 60 * }, "weave:service:ready", false); 61 * 62 * // 4. Trigger loading of Sync. 63 * service.ensureLoaded(); 64 */ 65 export function WeaveService() { 66 this.wrappedJSObject = this; 67 this.ready = false; 68 } 69 70 WeaveService.prototype = { 71 classID: Components.ID("{74b89fb0-f200-4ae8-a3ec-dd164117f6de}"), 72 73 QueryInterface: ChromeUtils.generateQI([ 74 "nsIObserver", 75 "nsISupportsWeakReference", 76 ]), 77 78 get Weave() { 79 const { Weave } = ChromeUtils.importESModule( 80 "resource://services-sync/main.sys.mjs" 81 ); 82 return Weave; 83 }, 84 85 ensureLoaded() { 86 // Side-effect of accessing the service is that it is instantiated. 87 this.Weave.Service; 88 }, 89 90 whenLoaded() { 91 if (this.ready) { 92 return Promise.resolve(); 93 } 94 let onReadyPromise = new Promise(resolve => { 95 Services.obs.addObserver(function onReady() { 96 Services.obs.removeObserver(onReady, "weave:service:ready"); 97 resolve(); 98 }, "weave:service:ready"); 99 }); 100 this.ensureLoaded(); 101 return onReadyPromise; 102 }, 103 104 init() { 105 // Force Weave service to load if it hasn't triggered from overlays 106 this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 107 this.timer.initWithCallback( 108 { 109 notify: () => { 110 let isConfigured = false; 111 // We only load more if it looks like Sync is configured. 112 if (this.enabled) { 113 // We have an associated FxAccount. So, do a more thorough check. 114 // This will import a number of modules and thus increase memory 115 // accordingly. We could potentially copy code performed by 116 // this check into this file if our above code is yielding too 117 // many false positives. 118 var { Weave } = ChromeUtils.importESModule( 119 "resource://services-sync/main.sys.mjs" 120 ); 121 isConfigured = 122 Weave.Status.checkSetup() != lazy.CLIENT_NOT_CONFIGURED; 123 } 124 if (isConfigured) { 125 this.ensureLoaded(); 126 } 127 }, 128 }, 129 10000, 130 Ci.nsITimer.TYPE_ONE_SHOT 131 ); 132 }, 133 134 /** 135 * Whether Sync appears to be enabled. 136 * 137 * This returns true if we have an associated FxA account and Sync is enabled. 138 * 139 * It does *not* perform a robust check to see if the client is working. 140 * For that, you'll want to check Weave.Status.checkSetup(). 141 */ 142 get enabled() { 143 return ( 144 !!lazy.syncUsername && 145 Services.prefs.getBoolPref("identity.fxaccounts.enabled") 146 ); 147 }, 148 }; 149 150 export function AboutWeaveLog() {} 151 AboutWeaveLog.prototype = { 152 classID: Components.ID("{d28f8a0b-95da-48f4-b712-caf37097be41}"), 153 154 QueryInterface: ChromeUtils.generateQI([ 155 "nsIAboutModule", 156 "nsISupportsWeakReference", 157 ]), 158 159 getURIFlags() { 160 return 0; 161 }, 162 163 newChannel(aURI, aLoadInfo) { 164 let dir = lazy.FileUtils.getDir("ProfD", ["weave", "logs"]); 165 try { 166 dir.create(Ci.nsIFile.DIRECTORY_TYPE, lazy.FileUtils.PERMS_DIRECTORY); 167 } catch (ex) { 168 if (ex.result != Cr.NS_ERROR_FILE_ALREADY_EXISTS) { 169 throw ex; 170 } 171 // Ignore the exception due to a directory that already exists. 172 } 173 let uri = Services.io.newFileURI(dir); 174 let channel = Services.io.newChannelFromURIWithLoadInfo(uri, aLoadInfo); 175 176 channel.originalURI = aURI; 177 178 // Ensure that the about page has the same privileges as a regular directory 179 // view. That way links to files can be opened. make sure we use the correct 180 // origin attributes when creating the principal for accessing the 181 // about:sync-log data. 182 let principal = Services.scriptSecurityManager.createContentPrincipal( 183 uri, 184 aLoadInfo.originAttributes 185 ); 186 187 channel.owner = principal; 188 return channel; 189 }, 190 };