Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/devtools/client/netmonitor/src/connector/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 16 kB image not shown  

Quelle  index.js   Sprache: JAVA

 
/* 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";

const {
  ACTIVITY_TYPE,
  EVENTS,
  TEST_EVENTS,
} = require("resource://devtools/client/netmonitor/src/constants.js");
const FirefoxDataProvider = require("resource://devtools/client/netmonitor/src/connector/firefox-data-provider.js");
const {
  getDisplayedTimingMarker,
} = require("resource://devtools/client/netmonitor/src/selectors/index.js");

const {
  TYPES,
} = require("resource://devtools/shared/commands/resource/resource-command.js");

// Network throttling
loader.lazyRequireGetter(
  this,
  "throttlingProfiles",
  "resource://devtools/client/shared/components/throttling/profiles.js"
);

loader.lazyRequireGetter(
  this,
  "HarMetadataCollector",
  "resource://devtools/client/netmonitor/src/connector/har-metadata-collector.js",
  true
);

const DEVTOOLS_ENABLE_PERSISTENT_LOG_PREF = "devtools.netmonitor.persistlog";

/**
 * Connector to Firefox backend.
 */

class Connector {
  constructor() {
    // Public methods
    this.connect = this.connect.bind(this);
    this.disconnect = this.disconnect.bind(this);
    this.willNavigate = this.willNavigate.bind(this);
    this.navigate = this.navigate.bind(this);
    this.triggerActivity = this.triggerActivity.bind(this);
    this.viewSourceInDebugger = this.viewSourceInDebugger.bind(this);
    this.requestData = this.requestData.bind(this);
    this.getTimingMarker = this.getTimingMarker.bind(this);
    this.updateNetworkThrottling = this.updateNetworkThrottling.bind(this);

    // Internals
    this.getLongString = this.getLongString.bind(this);
    this.onResourceAvailable = this.onResourceAvailable.bind(this);
    this.onResourceUpdated = this.onResourceUpdated.bind(this);
    this.updatePersist = this.updatePersist.bind(this);

    this.networkFront = null;
  }

  static NETWORK_RESOURCES = [
    TYPES.NETWORK_EVENT,
    TYPES.NETWORK_EVENT_STACKTRACE,
    TYPES.WEBSOCKET,
    TYPES.SERVER_SENT_EVENT,
  ];

  get currentTarget() {
    return this.commands.targetCommand.targetFront;
  }

  /**
   * Connect to the backend.
   *
   * @param {Object} connection object with e.g. reference to the Toolbox.
   * @param {Object} actions (optional) is used to fire Redux actions to update store.
   * @param {Object} getState (optional) is used to get access to the state.
   */

  async connect(connection, actions, getState) {
    this.actions = actions;
    this.getState = getState;
    this.toolbox = connection.toolbox;
    this.commands = this.toolbox.commands;
    this.networkCommand = this.commands.networkCommand;

    // The owner object (NetMonitorAPI) received all events.
    this.owner = connection.owner;

    this.networkFront =
      await this.commands.watcherFront.getNetworkParentActor();

    this.dataProvider = new FirefoxDataProvider({
      commands: this.commands,
      actions: this.actions,
      owner: this.owner,
    });

    this._harMetadataCollector = new HarMetadataCollector(this.commands);
    await this._harMetadataCollector.connect();

    await this.commands.resourceCommand.watchResources([TYPES.DOCUMENT_EVENT], {
      onAvailable: this.onResourceAvailable,
    });

    await this.resume(false);

    // Server side persistance of the data across reload is disabled by default.
    // Ensure enabling it, if the related frontend pref is true.
    if (Services.prefs.getBoolPref(DEVTOOLS_ENABLE_PERSISTENT_LOG_PREF)) {
      await this.updatePersist();
    }
    Services.prefs.addObserver(
      DEVTOOLS_ENABLE_PERSISTENT_LOG_PREF,
      this.updatePersist
    );
  }

  disconnect() {
    // As this function might be called twice, we need to guard if already called.
    if (this._destroyed) {
      return;
    }

    this._destroyed = true;

    this.commands.resourceCommand.unwatchResources([TYPES.DOCUMENT_EVENT], {
      onAvailable: this.onResourceAvailable,
    });

    this.pause();

    Services.prefs.removeObserver(
      DEVTOOLS_ENABLE_PERSISTENT_LOG_PREF,
      this.updatePersist
    );

    if (this.actions) {
      this.actions.batchReset();
    }

    this.dataProvider.destroy();
    this.dataProvider = null;
    this._harMetadataCollector.destroy();
  }

  /**
   * Clear network data from the connector.
   *
   * @param {object} options
   * @param {boolean} options.isExplicitClear
   *     Set to true if the call to clear requests is explicitly requested by
   *     the user, to false if this is an automated clear, eg on navigation.
   *
   */

  clear({ isExplicitClear }) {
    // Clear all the caches in the data provider
    this.dataProvider.clear();

    this._harMetadataCollector.clear();

    if (isExplicitClear) {
      // Only clear the resources if the clear was initiated explicitly by the
      // UI, in other cases (eg navigation) the server handles the cleanup.
      this.commands.resourceCommand.clearResources(Connector.NETWORK_RESOURCES);
      this.emitForTests("clear-network-resources");
    }

    // Disable the related network logs in the webconsole
    this.toolbox.disableAllConsoleNetworkLogs();
  }

  pause() {
    return this.commands.resourceCommand.unwatchResources(
      Connector.NETWORK_RESOURCES,
      {
        onAvailable: this.onResourceAvailable,
        onUpdated: this.onResourceUpdated,
      }
    );
  }

  resume(ignoreExistingResources = true) {
    return this.commands.resourceCommand.watchResources(
      Connector.NETWORK_RESOURCES,
      {
        onAvailable: this.onResourceAvailable,
        onUpdated: this.onResourceUpdated,
        ignoreExistingResources,
      }
    );
  }

  async onResourceAvailable(resources, { areExistingResources }) {
    for (const resource of resources) {
      if (resource.resourceType === TYPES.DOCUMENT_EVENT) {
        this.onDocEvent(resource, { areExistingResources });
        continue;
      }

      if (resource.resourceType === TYPES.NETWORK_EVENT) {
        this.dataProvider.onNetworkResourceAvailable(resource);
        continue;
      }

      if (resource.resourceType === TYPES.NETWORK_EVENT_STACKTRACE) {
        this.dataProvider.onStackTraceAvailable(resource);
        continue;
      }

      if (resource.resourceType === TYPES.WEBSOCKET) {
        const { wsMessageType } = resource;

        switch (wsMessageType) {
          case "webSocketOpened": {
            this.dataProvider.onWebSocketOpened(
              resource.httpChannelId,
              resource.effectiveURI,
              resource.protocols,
              resource.extensions
            );
            break;
          }
          case "webSocketClosed": {
            this.dataProvider.onWebSocketClosed(
              resource.httpChannelId,
              resource.wasClean,
              resource.code,
              resource.reason
            );
            break;
          }
          case "frameReceived": {
            this.dataProvider.onFrameReceived(
              resource.httpChannelId,
              resource.data
            );
            break;
          }
          case "frameSent": {
            this.dataProvider.onFrameSent(
              resource.httpChannelId,
              resource.data
            );
            break;
          }
        }
        continue;
      }

      if (resource.resourceType === TYPES.SERVER_SENT_EVENT) {
        const { messageType, httpChannelId, data } = resource;
        switch (messageType) {
          case "eventSourceConnectionClosed": {
            this.dataProvider.onEventSourceConnectionClosed(httpChannelId);
            break;
          }
          case "eventReceived": {
            this.dataProvider.onEventReceived(httpChannelId, data);
            break;
          }
        }
      }
    }
  }

  async onResourceUpdated(updates) {
    for (const { resource, update } of updates) {
      this.dataProvider.onNetworkResourceUpdated(resource, update);
    }
  }

  enableActions(enable) {
    this.dataProvider.enableActions(enable);
  }

  willNavigate() {
    if (this.actions) {
      if (!Services.prefs.getBoolPref(DEVTOOLS_ENABLE_PERSISTENT_LOG_PREF)) {
        this.actions.batchReset();
        this.actions.clearRequests({ isExplicitClear: false });
      } else {
        // If the log is persistent, just clear all accumulated timing markers.
        this.actions.clearTimingMarkers();
      }
    }

    if (this.actions && this.getState) {
      const state = this.getState();
      // Resume is done automatically on page reload/navigation.
      if (!state.requests.recording) {
        this.actions.toggleRecording();
      }

      // Stop any ongoing search.
      if (state.search.ongoingSearch) {
        this.actions.stopOngoingSearch();
      }
    }
  }

  navigate() {
    if (!this.dataProvider.hasPendingRequests()) {
      this.onReloaded();
      return;
    }
    const listener = () => {
      if (this.dataProvider && this.dataProvider.hasPendingRequests()) {
        return;
      }
      if (this.owner) {
        this.owner.off(EVENTS.PAYLOAD_READY, listener);
      }
      // Netmonitor may already be destroyed,
      // so do not try to notify the listeners
      if (this.dataProvider) {
        this.onReloaded();
      }
    };
    if (this.owner) {
      this.owner.on(EVENTS.PAYLOAD_READY, listener);
    }
  }

  onReloaded() {
    const panel = this.toolbox.getPanel("netmonitor");
    if (panel) {
      panel.emit("reloaded");
    }
  }

  /**
   * The "DOMContentLoaded" and "Load" events sent by the console actor.
   *
   * @param {object} resource The DOCUMENT_EVENT resource
   */

  onDocEvent(resource, { areExistingResources }) {
    if (!resource.targetFront.isTopLevel) {
      // Only consider top level document, and ignore remote iframes top document
      return;
    }

    // Netmonitor does not support dom-loading
    if (
      resource.name != "dom-interactive" &&
      resource.name != "dom-complete" &&
      resource.name != "will-navigate"
    ) {
      return;
    }

    if (resource.name == "will-navigate") {
      // When we open the netmonitor while the page already started loading,
      // we don't want to clear it. So here, we ignore will-navigate events
      // which were stored in the ResourceCommand cache and only consider
      // the live one coming straight from the server.
      if (!areExistingResources) {
        this.willNavigate();
      }
      return;
    }

    if (this.actions) {
      this.actions.addTimingMarker(resource);
    }

    if (resource.name === "dom-complete") {
      this.navigate();
    }

    this.emitForTests(TEST_EVENTS.TIMELINE_EVENT, resource);
  }

  async updatePersist() {
    const enabled = Services.prefs.getBoolPref(
      DEVTOOLS_ENABLE_PERSISTENT_LOG_PREF
    );

    await this.networkFront.setPersist(enabled);

    this.emitForTests(TEST_EVENTS.PERSIST_CHANGED, enabled);
  }

  /**
   * Triggers a specific "activity" to be performed by the frontend.
   * This can be, for example, triggering reloads or enabling/disabling cache.
   *
   * @param {number} type The activity type. See the ACTIVITY_TYPE const.
   * @return {object} A promise resolved once the activity finishes and the frontend
   *                  is back into "standby" mode.
   */

  triggerActivity(type) {
    // Puts the frontend into "standby" (when there's no particular activity).
    const standBy = () => {
      this.currentActivity = ACTIVITY_TYPE.NONE;
    };

    // Reconfigures the tab, optionally triggering a reload.
    const reconfigureTab = async options => {
      await this.commands.targetConfigurationCommand.updateConfiguration(
        options
      );
    };

    // Reconfigures the tab and waits for the target to finish navigating.
    const reconfigureTabAndReload = async options => {
      await reconfigureTab(options);
      await this.commands.targetCommand.reloadTopLevelTarget();
    };

    switch (type) {
      case ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT:
        return reconfigureTabAndReload({}).then(standBy);
      case ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED:
        this.currentActivity = ACTIVITY_TYPE.ENABLE_CACHE;
        this.commands.resourceCommand
          .waitForNextResource(
            this.commands.resourceCommand.TYPES.DOCUMENT_EVENT,
            {
              ignoreExistingResources: true,
              predicate(resource) {
                return resource.name == "will-navigate";
              },
            }
          )
          .then(() => {
            this.currentActivity = type;
          });
        return reconfigureTabAndReload({
          cacheDisabled: false,
        }).then(standBy);
      case ACTIVITY_TYPE.RELOAD.WITH_CACHE_DISABLED:
        this.currentActivity = ACTIVITY_TYPE.DISABLE_CACHE;
        this.commands.resourceCommand
          .waitForNextResource(
            this.commands.resourceCommand.TYPES.DOCUMENT_EVENT,
            {
              ignoreExistingResources: true,
              predicate(resource) {
                return resource.name == "will-navigate";
              },
            }
          )
          .then(() => {
            this.currentActivity = type;
          });
        return reconfigureTabAndReload({
          cacheDisabled: true,
        }).then(standBy);
      case ACTIVITY_TYPE.ENABLE_CACHE:
        this.currentActivity = type;
        return reconfigureTab({
          cacheDisabled: false,
        }).then(standBy);
      case ACTIVITY_TYPE.DISABLE_CACHE:
        this.currentActivity = type;
        return reconfigureTab({
          cacheDisabled: true,
        }).then(standBy);
    }
    this.currentActivity = ACTIVITY_TYPE.NONE;
    return Promise.reject(new Error("Invalid activity type"));
  }

  /**
   * Fetches the full text of a LongString.
   *
   * @param {object|string} stringGrip
   *        The long string grip containing the corresponding actor.
   *        If you pass in a plain string (by accident or because you're lazy),
   *        then a promise of the same string is simply returned.
   * @return {object}
   *         A promise that is resolved when the full string contents
   *         are available, or rejected if something goes wrong.
   */

  getLongString(stringGrip) {
    return this.dataProvider.getLongString(stringGrip);
  }

  /**
   * Used for HAR generation.
   */

  getHarData() {
    return this._harMetadataCollector.getHarData();
  }

  /**
   * Getter that returns the current toolbox instance.
   * @return {Toolbox} toolbox instance
   */

  getToolbox() {
    return this.toolbox;
  }

  /**
   * Open a given source in Debugger
   * @param {string} sourceURL source url
   * @param {number} sourceLine source line number
   */

  viewSourceInDebugger(sourceURL, sourceLine, sourceColumn) {
    if (this.toolbox) {
      this.toolbox.viewSourceInDebugger(sourceURL, sourceLine, sourceColumn);
    }
  }

  /**
   * Fetch networkEventUpdate websocket message from back-end when
   * data provider is connected.
   * @param {object} request network request instance
   * @param {string} type NetworkEventUpdate type
   */

  requestData(request, type) {
    return this.dataProvider.requestData(request, type);
  }

  getTimingMarker(name) {
    if (!this.getState) {
      return -1;
    }

    const state = this.getState();
    return getDisplayedTimingMarker(state, name);
  }

  async updateNetworkThrottling(enabled, profile) {
    if (!enabled) {
      this.networkFront.clearNetworkThrottling();
      await this.commands.targetConfigurationCommand.updateConfiguration({
        setTabOffline: false,
      });
    } else {
      // The profile can be either a profile id which is used to
      // search the predefined throttle profiles or a profile object
      // as defined in the trottle tests.
      if (typeof profile === "string") {
        profile = throttlingProfiles.profiles.find(({ id }) => id == profile);
      }
      const { download, upload, latency, id } = profile;

      // The offline profile has download and upload set to false
      await this.commands.targetConfigurationCommand.updateConfiguration({
        setTabOffline: id === throttlingProfiles.PROFILE_CONSTANTS.OFFLINE,
      });

      await this.networkFront.setNetworkThrottling({
        downloadThroughput: download,
        uploadThroughput: upload,
        latency,
      });
    }

    this.emitForTests(TEST_EVENTS.THROTTLING_CHANGED, { profile });
  }

  /**
   * Fire events for the owner object. These events are only
   * used in tests so, don't fire them in production release.
   */

  emitForTests(type, data) {
    if (this.owner) {
      this.owner.emitForTests(type, data);
    }
  }
}
module.exports.Connector = Connector;

Messung V0.5
C=93 H=99 G=95

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.