diff options
Diffstat (limited to 'devtools/client/aboutdebugging/src/modules/runtime-default-preferences.js')
-rw-r--r-- | devtools/client/aboutdebugging/src/modules/runtime-default-preferences.js | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/devtools/client/aboutdebugging/src/modules/runtime-default-preferences.js b/devtools/client/aboutdebugging/src/modules/runtime-default-preferences.js new file mode 100644 index 0000000000..02c06334f7 --- /dev/null +++ b/devtools/client/aboutdebugging/src/modules/runtime-default-preferences.js @@ -0,0 +1,101 @@ +/* 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/. */ + +"use strict"; + +/** + * This module provides a workaround for remote debugging when a preference is + * defined in the firefox preference file (browser/app/profile/firefox.js) but + * still read from the server, without any default value. + * + * This causes the server to crash and can't easily be recovered. + * + * While we work on better linting to prevent such issues (Bug 1660182), this + * module will be able to set default values for all missing preferences. + */ + +const PREFERENCE_TYPES = { + BOOL: "BOOL", + CHAR: "CHAR", + INT: "INT", +}; +exports.PREFERENCE_TYPES = PREFERENCE_TYPES; + +/** + * Expected properties for the preference descriptors: + * - prefName {String}: the name of the preference. + * - defaultValue {String|Bool|Number}: the value to set if the preference is + * missing. + * - trait {String}: the name of the trait corresponding to this pref on the + * PreferenceFront. + * - type {String}: the preference type (either BOOL, CHAR or INT). + */ +const DEFAULT_PREFERENCES = []; +exports.DEFAULT_PREFERENCES = DEFAULT_PREFERENCES; + +const METHODS = { + [PREFERENCE_TYPES.BOOL]: { + setPref: "setBoolPref", + getPref: "getBoolPref", + }, + [PREFERENCE_TYPES.CHAR]: { + setPref: "setCharPref", + getPref: "getCharPref", + }, + [PREFERENCE_TYPES.INT]: { + setPref: "setIntPref", + getPref: "getIntPref", + }, +}; + +/** + * Set default values for all the provided preferences on the runtime + * corresponding to the provided clientWrapper, if needed. + * + * Note: prefDescriptors will most likely be DEFAULT_PREFERENCES when + * used in production code, but can be parameterized for tests. + * + * @param {ClientWrapper} clientWrapper + * @param {Array} prefDescriptors + * Array of preference descriptors, see DEFAULT_PREFERENCES. + */ +async function setDefaultPreferencesIfNeeded(clientWrapper, prefDescriptors) { + if (!prefDescriptors || prefDescriptors.length === 0) { + return; + } + + const preferenceFront = await clientWrapper.getFront("preference"); + const preferenceTraits = await preferenceFront.getTraits(); + + // Note: using Promise.all here fails because the request/responses get mixed. + for (const prefDescriptor of prefDescriptors) { + // If the fix for this preference is already on this server, skip it. + if (preferenceTraits[prefDescriptor.trait]) { + continue; + } + + await setDefaultPreference(preferenceFront, prefDescriptor); + } +} +exports.setDefaultPreferencesIfNeeded = setDefaultPreferencesIfNeeded; + +async function setDefaultPreference(preferenceFront, prefDescriptor) { + const { prefName, type, defaultValue } = prefDescriptor; + + if (!Object.values(PREFERENCE_TYPES).includes(type)) { + throw new Error(`Unsupported type for setDefaultPreference "${type}"`); + } + + const prefMethods = METHODS[type]; + try { + // Try to read the preference only to check if the call is successful. + // If not, this means the preference is missing and should be initialized. + await preferenceFront[prefMethods.getPref](prefName); + } catch (e) { + console.warn( + `Preference "${prefName}"" is not set on the remote runtime. Setting default value.` + ); + await preferenceFront[prefMethods.setPref](prefName, defaultValue); + } +} |