chrome-devtools-frontend
Version:
Chrome DevTools UI
179 lines (143 loc) • 6.56 kB
text/typescript
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import type * as Common from '../common/common.js';
import * as i18n from '../i18n/i18n.js';
import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
import {CategorizedBreakpoint} from './CategorizedBreakpoint.js';
import {Capability, type Target} from './Target.js';
import {SDKModel} from './SDKModel.js';
import {TargetManager, type SDKModelObserver} from './TargetManager.js';
const UIStrings = {
/**
* @description Category of breakpoints
*/
auctionWorklet: 'Ad Auction Worklet',
/**
* @description Name of a breakpoint type.
* https://github.com/WICG/turtledove/blob/main/FLEDGE.md#32-on-device-bidding
*/
beforeBidderWorkletBiddingStart: 'Bidder Bidding Phase Start',
/**
* @description Name of a breakpoint type.
* https://github.com/WICG/turtledove/blob/main/FLEDGE.md#52-buyer-reporting-on-render-and-ad-events
*/
beforeBidderWorkletReportingStart: 'Bidder Reporting Phase Start',
/**
* @description Name of a breakpoint type.
* https://github.com/WICG/turtledove/blob/main/FLEDGE.md#23-scoring-bids
*/
beforeSellerWorkletScoringStart: 'Seller Scoring Phase Start',
/**
* @description Name of a breakpoint type.
* https://github.com/WICG/turtledove/blob/main/FLEDGE.md#51-seller-reporting-on-render
*/
beforeSellerWorkletReportingStart: 'Seller Reporting Phase Start',
};
const str_ = i18n.i18n.registerUIStrings('core/sdk/EventBreakpointsModel.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
const enum InstrumentationNames {
BeforeBidderWorkletBiddingStart = 'beforeBidderWorkletBiddingStart',
BeforeBidderWorkletReportingStart = 'beforeBidderWorkletReportingStart',
BeforeSellerWorkletScoringStart = 'beforeSellerWorkletScoringStart',
BeforeSellerWorkletReportingStart = 'beforeSellerWorkletReportingStart',
}
function getTitleForInstrumentationName(instrumentationName: InstrumentationNames): Common.UIString.LocalizedString {
switch (instrumentationName) {
case InstrumentationNames.BeforeBidderWorkletBiddingStart:
return i18nString(UIStrings.beforeBidderWorkletBiddingStart);
case InstrumentationNames.BeforeBidderWorkletReportingStart:
return i18nString(UIStrings.beforeBidderWorkletReportingStart);
case InstrumentationNames.BeforeSellerWorkletScoringStart:
return i18nString(UIStrings.beforeSellerWorkletScoringStart);
case InstrumentationNames.BeforeSellerWorkletReportingStart:
return i18nString(UIStrings.beforeSellerWorkletReportingStart);
}
}
export class EventBreakpointsModel extends SDKModel<void> {
readonly agent: ProtocolProxyApi.EventBreakpointsApi;
constructor(target: Target) {
super(target);
this.agent = target.eventBreakpointsAgent();
}
}
// This implementation (as opposed to similar class in DOMDebuggerModel) is for
// instrumentation breakpoints in targets that run JS but do not have a DOM.
class EventListenerBreakpoint extends CategorizedBreakpoint {
readonly instrumentationName: string;
constructor(instrumentationName: InstrumentationNames, category: string) {
super(category, getTitleForInstrumentationName(instrumentationName));
this.instrumentationName = instrumentationName;
}
override setEnabled(enabled: boolean): void {
if (this.enabled() === enabled) {
return;
}
super.setEnabled(enabled);
for (const model of TargetManager.instance().models(EventBreakpointsModel)) {
this.updateOnModel(model);
}
}
updateOnModel(model: EventBreakpointsModel): void {
if (this.enabled()) {
void model.agent.invoke_setInstrumentationBreakpoint({eventName: this.instrumentationName});
} else {
void model.agent.invoke_removeInstrumentationBreakpoint({eventName: this.instrumentationName});
}
}
static readonly instrumentationPrefix = 'instrumentation:';
}
let eventBreakpointManagerInstance: EventBreakpointsManager;
export class EventBreakpointsManager implements SDKModelObserver<EventBreakpointsModel> {
readonly #eventListenerBreakpointsInternal: EventListenerBreakpoint[] = [];
constructor() {
this.createInstrumentationBreakpoints(i18nString(UIStrings.auctionWorklet), [
InstrumentationNames.BeforeBidderWorkletBiddingStart,
InstrumentationNames.BeforeBidderWorkletReportingStart,
InstrumentationNames.BeforeSellerWorkletScoringStart,
InstrumentationNames.BeforeSellerWorkletReportingStart,
]);
TargetManager.instance().observeModels(EventBreakpointsModel, this);
}
static instance(opts: {
forceNew: boolean|null,
} = {forceNew: null}): EventBreakpointsManager {
const {forceNew} = opts;
if (!eventBreakpointManagerInstance || forceNew) {
eventBreakpointManagerInstance = new EventBreakpointsManager();
}
return eventBreakpointManagerInstance;
}
private createInstrumentationBreakpoints(category: string, instrumentationNames: InstrumentationNames[]): void {
for (const instrumentationName of instrumentationNames) {
this.#eventListenerBreakpointsInternal.push(new EventListenerBreakpoint(instrumentationName, category));
}
}
eventListenerBreakpoints(): EventListenerBreakpoint[] {
return this.#eventListenerBreakpointsInternal.slice();
}
resolveEventListenerBreakpointTitle(auxData: {
eventName: string,
}): string|null {
const breakpoint = this.resolveEventListenerBreakpoint(auxData);
return breakpoint ? breakpoint.title() : null;
}
resolveEventListenerBreakpoint(auxData: {eventName: string}): EventListenerBreakpoint|null {
const eventName = auxData.eventName;
if (!eventName.startsWith(EventListenerBreakpoint.instrumentationPrefix)) {
return null;
}
const instrumentationName = eventName.substring(EventListenerBreakpoint.instrumentationPrefix.length);
return this.#eventListenerBreakpointsInternal.find(b => b.instrumentationName === instrumentationName) || null;
}
modelAdded(eventBreakpointModel: EventBreakpointsModel): void {
for (const breakpoint of this.#eventListenerBreakpointsInternal) {
if (breakpoint.enabled()) {
breakpoint.updateOnModel(eventBreakpointModel);
}
}
}
modelRemoved(_eventBreakpointModel: EventBreakpointsModel): void {
}
}
SDKModel.register(EventBreakpointsModel, {capabilities: Capability.EventBreakpoints, autostart: false});