tor-browser

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

actions.js (6114B)


      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 "use strict";
      6 
      7 const selectors = require("resource://devtools/client/performance-new/store/selectors.js");
      8 
      9 /**
     10 * @typedef {import("../@types/perf").Action} Action
     11 * @typedef {import("../@types/perf").Library} Library
     12 * @typedef {import("../@types/perf").PerfFront} PerfFront
     13 * @typedef {import("../@types/perf").SymbolTableAsTuple} SymbolTableAsTuple
     14 * @typedef {import("../@types/perf").RecordingState} RecordingState
     15 * @typedef {import("../@types/perf").InitializeStoreValues} InitializeStoreValues
     16 * @typedef {import("../@types/perf").RecordingSettings} RecordingSettings
     17 * @typedef {import("../@types/perf").Presets} Presets
     18 * @typedef {import("../@types/perf").PanelWindow} PanelWindow
     19 */
     20 
     21 /**
     22 * @template T
     23 * @typedef {import("../@types/perf").ThunkAction<T>} ThunkAction<T>
     24 */
     25 
     26 /**
     27 * This is the result of the initial questions about the state of the profiler.
     28 *
     29 * @param {boolean} isActive
     30 * @return {Action}
     31 */
     32 exports.reportProfilerReady = isActive => ({
     33  type: "REPORT_PROFILER_READY",
     34  isActive,
     35 });
     36 
     37 /**
     38 * Dispatched when the profiler starting is observed.
     39 *
     40 * @return {Action}
     41 */
     42 exports.reportProfilerStarted = () => ({
     43  type: "REPORT_PROFILER_STARTED",
     44 });
     45 
     46 /**
     47 * Dispatched when the profiler stopping is observed.
     48 *
     49 * @return {Action}
     50 */
     51 exports.reportProfilerStopped = () => ({
     52  type: "REPORT_PROFILER_STOPPED",
     53 });
     54 
     55 /**
     56 * Updates the recording settings for the interval.
     57 *
     58 * @param {number} interval
     59 * @return {Action}
     60 */
     61 exports.changeInterval = interval => ({
     62  type: "CHANGE_INTERVAL",
     63  interval,
     64 });
     65 
     66 /**
     67 * Updates the recording settings for the entries.
     68 *
     69 * @param {number} entries
     70 * @return {Action}
     71 */
     72 exports.changeEntries = entries => ({
     73  type: "CHANGE_ENTRIES",
     74  entries,
     75 });
     76 
     77 /**
     78 * Updates the recording settings for the features.
     79 *
     80 * @param {string[]} features
     81 * @return {ThunkAction<void>}
     82 */
     83 exports.changeFeatures = features => {
     84  return ({ dispatch, getState }) => {
     85    let promptEnvRestart = null;
     86    if (selectors.getPageContext(getState()) === "aboutprofiling") {
     87      // TODO Bug 1615431 - The old popup supported restarting the browser, but
     88      // this hasn't been updated yet for the about:profiling workflow, because
     89      // jstracer is disabled for now.
     90      if (
     91        !Services.env.get("JS_TRACE_LOGGING") &&
     92        features.includes("jstracer")
     93      ) {
     94        promptEnvRestart = "JS_TRACE_LOGGING";
     95      }
     96    }
     97 
     98    dispatch({
     99      type: "CHANGE_FEATURES",
    100      features,
    101      promptEnvRestart,
    102    });
    103  };
    104 };
    105 
    106 /**
    107 * Updates the recording settings for the threads.
    108 *
    109 * @param {string[]} threads
    110 * @return {Action}
    111 */
    112 exports.changeThreads = threads => ({
    113  type: "CHANGE_THREADS",
    114  threads,
    115 });
    116 
    117 /**
    118 * Change the preset.
    119 *
    120 * @param {Presets} presets
    121 * @param {string} presetName
    122 * @return {Action}
    123 */
    124 exports.changePreset = (presets, presetName) => ({
    125  type: "CHANGE_PRESET",
    126  presetName,
    127  // Also dispatch the preset so that the reducers can pre-fill the values
    128  // from a preset.
    129  preset: presets[presetName],
    130 });
    131 
    132 /**
    133 * Updates the recording settings for the objdirs.
    134 *
    135 * @param {string[]} objdirs
    136 * @return {Action}
    137 */
    138 exports.changeObjdirs = objdirs => ({
    139  type: "CHANGE_OBJDIRS",
    140  objdirs,
    141 });
    142 
    143 /**
    144 * Receive the values to initialize the store. See the reducer for what values
    145 * are expected.
    146 *
    147 * @param {InitializeStoreValues} values
    148 * @return {Action}
    149 */
    150 exports.initializeStore = values => {
    151  return {
    152    type: "INITIALIZE_STORE",
    153    ...values,
    154  };
    155 };
    156 
    157 /**
    158 * Whenever the preferences are updated, this action is dispatched to update the
    159 * redux store.
    160 *
    161 * @param {RecordingSettings} recordingSettingsFromPreferences
    162 * @return {Action}
    163 */
    164 exports.updateSettingsFromPreferences = recordingSettingsFromPreferences => {
    165  return {
    166    type: "UPDATE_SETTINGS_FROM_PREFERENCES",
    167    recordingSettingsFromPreferences,
    168  };
    169 };
    170 
    171 /**
    172 * Start a new recording with the perfFront and update the internal recording state.
    173 *
    174 * @param {PerfFront} perfFront
    175 * @return {ThunkAction<void>}
    176 */
    177 exports.startRecording = perfFront => {
    178  return ({ dispatch, getState }) => {
    179    const recordingSettings = selectors.getRecordingSettings(getState());
    180    // In the case of the profiler popup, the startProfiler can be synchronous.
    181    // In order to properly allow the React components to handle the state changes
    182    // make sure and change the recording state first, then start the profiler.
    183    dispatch({ type: "REQUESTING_TO_START_RECORDING" });
    184    perfFront.startProfiler(recordingSettings);
    185  };
    186 };
    187 
    188 /**
    189 * Stops the profiler, and opens the profile in a new window.
    190 *
    191 * @param {PerfFront} perfFront
    192 * @return {ThunkAction<Promise<MockedExports.ProfileAndAdditionalInformation>>}
    193 */
    194 exports.getProfileAndStopProfiler = perfFront => {
    195  return async ({ dispatch }) => {
    196    dispatch({ type: "REQUESTING_PROFILE" });
    197    const profileAndAdditionalInformation =
    198      await perfFront.getProfileAndStopProfiler();
    199    dispatch({ type: "OBTAINED_PROFILE" });
    200    return profileAndAdditionalInformation;
    201  };
    202 };
    203 
    204 /**
    205 * Stops the profiler, but does not try to retrieve the profile.
    206 *
    207 * @param {PerfFront} perfFront
    208 * @return {ThunkAction<void>}
    209 */
    210 exports.stopProfilerAndDiscardProfile = perfFront => {
    211  return async ({ dispatch }) => {
    212    dispatch({ type: "REQUESTING_TO_STOP_RECORDING" });
    213 
    214    try {
    215      await perfFront.stopProfilerAndDiscardProfile();
    216    } catch (error) {
    217      /** @type {any} */
    218      const anyWindow = window;
    219      /** @type {PanelWindow} - Coerce the window into the PanelWindow. */
    220      const { gIsPanelDestroyed } = anyWindow;
    221 
    222      if (gIsPanelDestroyed) {
    223        // This error is most likely "Connection closed, pending request" as the
    224        // command can race with closing the panel. Do not report an error. It's
    225        // most likely fine.
    226      } else {
    227        throw error;
    228      }
    229    }
    230  };
    231 };