tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

initializer.js (7981B)


      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 // @ts-check
      5 /* exported gInit, gDestroy, loader */
      6 
      7 /**
      8 * @typedef {import("../@types/perf").PerfFront} PerfFront
      9 * @typedef {import("../@types/perf").PreferenceFront} PreferenceFront
     10 * @typedef {import("../@types/perf").RecordingSettings} RecordingSettings
     11 * @typedef {import("../@types/perf").PageContext} PageContext
     12 * @typedef {import("../@types/perf").PanelWindow} PanelWindow
     13 * @typedef {import("../@types/perf").Store} Store
     14 * @typedef {import("../@types/perf").ProfileCaptureResult} ProfileCaptureResult
     15 * @typedef {import("../@types/perf").ProfilerViewMode} ProfilerViewMode
     16 * @typedef {import("../@types/perf").RootTraits} RootTraits
     17 */
     18 "use strict";
     19 
     20 {
     21  // Create the browser loader, but take care not to conflict with
     22  // TypeScript. See devtools/client/performance-new/typescript.md and
     23  // the section on "Do not overload require" for more information.
     24 
     25  const { BrowserLoader } = ChromeUtils.importESModule(
     26    "resource://devtools/shared/loader/browser-loader.sys.mjs"
     27  );
     28  const browserLoader = BrowserLoader({
     29    baseURI: "resource://devtools/client/performance-new/",
     30    window,
     31  });
     32 
     33  /**
     34   * @type {any} - Coerce the current scope into an `any`, and assign the
     35   *     loaders to the scope. They can then be used freely below.
     36   */
     37  const scope = this;
     38  scope.require = browserLoader.require;
     39  scope.loader = browserLoader.loader;
     40 }
     41 
     42 const ReactDOM = require("resource://devtools/client/shared/vendor/react-dom.mjs");
     43 const React = require("resource://devtools/client/shared/vendor/react.mjs");
     44 const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js");
     45 const {
     46  FluentL10n,
     47 } = require("resource://devtools/client/shared/fluent-l10n/fluent-l10n.js");
     48 const Provider = React.createFactory(
     49  require("resource://devtools/client/shared/vendor/react-redux.js").Provider
     50 );
     51 const LocalizationProvider = React.createFactory(
     52  FluentReact.LocalizationProvider
     53 );
     54 const DevToolsPanel = React.createFactory(
     55  require("resource://devtools/client/performance-new/components/panel/DevToolsPanel.js")
     56 );
     57 const ProfilerEventHandling = React.createFactory(
     58  require("resource://devtools/client/performance-new/components/panel/ProfilerEventHandling.js")
     59 );
     60 const ProfilerPreferenceObserver = React.createFactory(
     61  require("resource://devtools/client/performance-new/components/shared/ProfilerPreferenceObserver.js")
     62 );
     63 const createStore = require("resource://devtools/client/shared/redux/create-store.js");
     64 const selectors = require("resource://devtools/client/performance-new/store/selectors.js");
     65 const reducers = require("resource://devtools/client/performance-new/store/reducers.js");
     66 const actions = require("resource://devtools/client/performance-new/store/actions.js");
     67 const {
     68  openProfilerTab,
     69 } = require("resource://devtools/client/performance-new/shared/browser.js");
     70 const { createLocalSymbolicationService } = ChromeUtils.importESModule(
     71  "resource://devtools/shared/performance-new/symbolication.sys.mjs"
     72 );
     73 const { registerProfileCaptureForBrowser } = ChromeUtils.importESModule(
     74  "resource://devtools/client/performance-new/shared/background.sys.mjs"
     75 );
     76 const { presets, getProfilerViewModeForCurrentPreset } =
     77  ChromeUtils.importESModule(
     78    "resource://devtools/shared/performance-new/prefs-presets.sys.mjs"
     79  );
     80 
     81 /**
     82 * This file initializes the DevTools Panel UI. It is in charge of initializing
     83 * the DevTools specific environment, and then passing those requirements into
     84 * the UI.
     85 */
     86 
     87 /**
     88 * Initialize the panel by creating a redux store, and render the root component.
     89 *
     90 * @param {PerfFront} perfFront - The Perf actor's front. Used to start and stop recordings.
     91 * @param {RootTraits} traits - The traits coming from the root actor. This
     92 *                              makes it possible to change some code path
     93 *                              depending on the server version.
     94 * @param {PageContext} pageContext - The context that the UI is being loaded in under.
     95 * @param {(() => void)} openAboutProfiling - Optional call to open about:profiling
     96 */
     97 async function gInit(perfFront, traits, pageContext, openAboutProfiling) {
     98  const store = createStore(reducers);
     99  const isSupportedPlatform = await perfFront.isSupportedPlatform();
    100  const supportedFeatures = await perfFront.getSupportedFeatures();
    101 
    102  {
    103    // Expose the store as a global, for testing.
    104    const anyWindow = /** @type {any} */ (window);
    105    const panelWindow = /** @type {PanelWindow} */ (anyWindow);
    106    // The store variable is a `ReduxStore`, not our `Store` type, as defined
    107    // in perf.d.ts. Coerce it into the `Store` type.
    108    const anyStore = /** @type {any} */ (store);
    109    panelWindow.gStore = anyStore;
    110  }
    111 
    112  const l10n = new FluentL10n();
    113  await l10n.init([
    114    "devtools/client/perftools.ftl",
    115    // For -brand-shorter-name used in some profiler preset descriptions.
    116    "branding/brand.ftl",
    117    // Needed for the onboarding UI
    118    "devtools/client/toolbox-options.ftl",
    119    "toolkit/branding/brandings.ftl",
    120  ]);
    121 
    122  // Do some initialization, especially with privileged things that are part of the
    123  // the browser.
    124  store.dispatch(
    125    actions.initializeStore({
    126      isSupportedPlatform,
    127      presets,
    128      supportedFeatures,
    129      pageContext,
    130    })
    131  );
    132 
    133  /**
    134   * @param {MockedExports.ProfileAndAdditionalInformation | null} profileAndAdditionalInformation
    135   * @param {Error | string} [error]
    136   */
    137  const onProfileReceived = async (profileAndAdditionalInformation, error) => {
    138    const objdirs = selectors.getObjdirs(store.getState());
    139    const profilerViewMode = getProfilerViewModeForCurrentPreset(pageContext);
    140    const browser = await openProfilerTab({ profilerViewMode });
    141 
    142    if (error || !profileAndAdditionalInformation) {
    143      if (!error) {
    144        error =
    145          "No profile data has been passed to onProfileReceived, and no specific error has been specified. This is unexpected.";
    146      }
    147      /**
    148       * @type {ProfileCaptureResult}
    149       */
    150      const profileCaptureResult = {
    151        type: "ERROR",
    152        error: typeof error === "string" ? new Error(error) : error,
    153      };
    154      registerProfileCaptureForBrowser(
    155        browser,
    156        profileCaptureResult,
    157        null,
    158        null
    159      );
    160      return;
    161    }
    162 
    163    const { profile, additionalInformation } = profileAndAdditionalInformation;
    164    const sharedLibraries = additionalInformation?.sharedLibraries ?? [];
    165    if (!sharedLibraries.length) {
    166      console.error(
    167        `[devtools perf] No shared libraries information have been retrieved from the profiled target, this is unexpected.`
    168      );
    169    }
    170    const symbolicationService = createLocalSymbolicationService(
    171      sharedLibraries,
    172      objdirs,
    173      perfFront
    174    );
    175 
    176    /**
    177     * @type {ProfileCaptureResult}
    178     */
    179    const profileCaptureResult = { type: "SUCCESS", profile };
    180 
    181    registerProfileCaptureForBrowser(
    182      browser,
    183      profileCaptureResult,
    184      symbolicationService,
    185      additionalInformation?.jsSources ?? null
    186    );
    187  };
    188 
    189  const onEditSettingsLinkClicked = openAboutProfiling;
    190 
    191  ReactDOM.render(
    192    Provider(
    193      { store },
    194      LocalizationProvider(
    195        { bundles: l10n.getBundles() },
    196        React.createElement(
    197          React.Fragment,
    198          null,
    199          ProfilerEventHandling({ perfFront, traits }),
    200          ProfilerPreferenceObserver(),
    201          DevToolsPanel({
    202            perfFront,
    203            onProfileReceived,
    204            onEditSettingsLinkClicked,
    205          })
    206        )
    207      )
    208    ),
    209    document.querySelector("#root")
    210  );
    211 
    212  window.addEventListener("unload", () => gDestroy(), { once: true });
    213 }
    214 
    215 function gDestroy() {
    216  const root = document.querySelector("#root");
    217  if (root) {
    218    ReactDOM.unmountComponentAtNode(root);
    219  }
    220 }