UNPKG

debug-server-next

Version:

Dev server for hippy-core.

206 lines (205 loc) 7.72 kB
// 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. /* eslint-disable rulesdir/no_underscored_properties */ import * as Common from '../common/common.js'; import * as Platform from '../platform/platform.js'; import { Target } from './Target.js'; let targetManagerInstance; export class TargetManager extends Common.ObjectWrapper.ObjectWrapper { _targets; _observers; _modelListeners; // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration // eslint-disable-next-line @typescript-eslint/no-explicit-any _modelObservers; _isSuspended; constructor() { super(); this._targets = new Set(); this._observers = new Set(); this._modelListeners = new Platform.MapUtilities.Multimap(); this._modelObservers = new Platform.MapUtilities.Multimap(); this._isSuspended = false; } static instance({ forceNew } = { forceNew: false }) { if (!targetManagerInstance || forceNew) { targetManagerInstance = new TargetManager(); } return targetManagerInstance; } static removeInstance() { targetManagerInstance = undefined; } onInspectedURLChange(target) { this.dispatchEventToListeners(Events.InspectedURLChanged, target); } onNameChange(target) { this.dispatchEventToListeners(Events.NameChanged, target); } async suspendAllTargets(reason) { if (this._isSuspended) { return; } this._isSuspended = true; this.dispatchEventToListeners(Events.SuspendStateChanged); const suspendPromises = Array.from(this._targets.values(), target => target.suspend(reason)); await Promise.all(suspendPromises); } async resumeAllTargets() { if (!this._isSuspended) { return; } this._isSuspended = false; this.dispatchEventToListeners(Events.SuspendStateChanged); const resumePromises = Array.from(this._targets.values(), target => target.resume()); await Promise.all(resumePromises); } allTargetsSuspended() { return this._isSuspended; } models(modelClass) { const result = []; for (const target of this._targets) { const model = target.model(modelClass); if (model) { result.push(model); } } return result; } inspectedURL() { const mainTarget = this.mainTarget(); return mainTarget ? mainTarget.inspectedURL() : ''; } observeModels(modelClass, observer) { const models = this.models(modelClass); this._modelObservers.set(modelClass, observer); for (const model of models) { observer.modelAdded(model); } } unobserveModels(modelClass, observer) { this._modelObservers.delete(modelClass, observer); } modelAdded(target, modelClass, model) { for (const observer of this._modelObservers.get(modelClass).values()) { observer.modelAdded(model); } } _modelRemoved(target, modelClass, model) { for (const observer of this._modelObservers.get(modelClass).values()) { observer.modelRemoved(model); } } addModelListener(modelClass, eventType, listener, thisObject) { for (const model of this.models(modelClass)) { model.addEventListener(eventType, listener, thisObject); } this._modelListeners.set(eventType, { modelClass: modelClass, thisObject: thisObject, listener: listener }); } removeModelListener(modelClass, eventType, listener, thisObject) { if (!this._modelListeners.has(eventType)) { return; } for (const model of this.models(modelClass)) { model.removeEventListener(eventType, listener, thisObject); } for (const info of this._modelListeners.get(eventType)) { if (info.modelClass === modelClass && info.listener === listener && info.thisObject === thisObject) { this._modelListeners.delete(eventType, info); } } } observeTargets(targetObserver) { if (this._observers.has(targetObserver)) { throw new Error('Observer can only be registered once'); } for (const target of this._targets) { targetObserver.targetAdded(target); } this._observers.add(targetObserver); } unobserveTargets(targetObserver) { this._observers.delete(targetObserver); } createTarget(id, name, type, parentTarget, sessionId, waitForDebuggerInPage, connection, targetInfo) { const target = new Target(this, id, name, type, parentTarget, sessionId || '', this._isSuspended, connection || null, targetInfo); if (waitForDebuggerInPage) { // @ts-ignore TODO(1063322): Find out where pageAgent() is set on Target/TargetBase. target.pageAgent().waitForDebugger(); } target.createModels(new Set(this._modelObservers.keysArray())); this._targets.add(target); // Iterate over a copy. _observers might be modified during iteration. for (const observer of [...this._observers]) { observer.targetAdded(target); } for (const modelClass of target.models().keys()) { const model = target.models().get(modelClass); this.modelAdded(target, modelClass, model); } for (const key of this._modelListeners.keysArray()) { for (const info of this._modelListeners.get(key)) { const model = target.model(info.modelClass); if (model) { model.addEventListener(key, info.listener, info.thisObject); } } } return target; } removeTarget(target) { if (!this._targets.has(target)) { return; } this._targets.delete(target); for (const modelClass of target.models().keys()) { const model = target.models().get(modelClass); this._modelRemoved(target, modelClass, model); } // Iterate over a copy. _observers might be modified during iteration. for (const observer of [...this._observers]) { observer.targetRemoved(target); } for (const key of this._modelListeners.keysArray()) { for (const info of this._modelListeners.get(key)) { const model = target.model(info.modelClass); if (model) { model.removeEventListener(key, info.listener, info.thisObject); } } } } targets() { return [...this._targets]; } targetById(id) { // TODO(dgozman): add a map id -> target. return this.targets().find(target => target.id() === id) || null; } mainTarget() { return this._targets.size ? this._targets.values().next().value : null; } } // TODO(crbug.com/1167717): Make this a const enum again // eslint-disable-next-line rulesdir/const_enum export var Events; (function (Events) { Events["AvailableTargetsChanged"] = "AvailableTargetsChanged"; Events["InspectedURLChanged"] = "InspectedURLChanged"; Events["NameChanged"] = "NameChanged"; Events["SuspendStateChanged"] = "SuspendStateChanged"; })(Events || (Events = {})); export class Observer { targetAdded(_target) { } targetRemoved(_target) { } } export class SDKModelObserver { modelAdded(_model) { } modelRemoved(_model) { } }