sources.js (3448B)
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 5 "use strict"; 6 7 const Targets = require("resource://devtools/server/actors/targets/index.js"); 8 9 const { 10 STATES: THREAD_STATES, 11 } = require("resource://devtools/server/actors/thread.js"); 12 13 /** 14 * Start watching for all JS sources related to a given Target Actor. 15 * This will notify about existing sources, but also the ones created in future. 16 * 17 * @param TargetActor targetActor 18 * The target actor from which we should observe sources 19 * @param Object options 20 * Dictionary object with following attributes: 21 * - onAvailable: mandatory function 22 * This will be called for each resource. 23 */ 24 class SourceWatcher { 25 constructor() { 26 this.onNewSource = this.onNewSource.bind(this); 27 } 28 29 async watch(targetActor, { onAvailable }) { 30 // The Browser Toolbox uses the Content Process target's Thread actor to debug all scripts 31 // running into a given process. This includes WindowGlobal scripts. 32 // Because of this, and in such configuration, we have to ignore the WindowGlobal targets. 33 if ( 34 targetActor.sessionContext.type == "all" && 35 !targetActor.sessionContext.enableWindowGlobalThreadActors && 36 targetActor.targetType === Targets.TYPES.FRAME && 37 targetActor.typeName != "parentProcessTarget" 38 ) { 39 return; 40 } 41 42 const { threadActor } = targetActor; 43 this.sourcesManager = targetActor.sourcesManager; 44 this.onAvailable = onAvailable; 45 46 threadActor.attach({}); 47 48 // Disable `ThreadActor.newSource` RDP event in order to avoid unnecessary traffic 49 threadActor.disableNewSourceEvents(); 50 51 threadActor.sourcesManager.on("newSource", this.onNewSource); 52 53 // For WindowGlobal, Content process and Service Worker targets, 54 // the thread actor is fully managed by the server codebase. 55 // For these targets, the actor should be "attached" (initialized) right away in order 56 // to start observing the sources. 57 // 58 // For regular and shared Workers, the thread actor is still managed by the client. 59 // The client will call `attach` (bug 1691986) later, which will also resume worker execution. 60 const isTargetCreation = threadActor.state == THREAD_STATES.DETACHED; 61 const { targetType } = targetActor; 62 if ( 63 isTargetCreation && 64 targetType != Targets.TYPES.WORKER && 65 targetType != Targets.TYPES.SHARED_WORKER 66 ) { 67 await threadActor.attach({}); 68 } 69 70 // Before fetching all sources, process existing ones. 71 // The ThreadActor is already up and running before this code runs 72 // and have sources already registered and for which newSource event already fired. 73 const sources = []; 74 for (const sourceActor of threadActor.sourcesManager.iter()) { 75 const resource = sourceActor.form(); 76 sources.push(resource); 77 } 78 onAvailable(sources); 79 80 // Requesting all sources should end up emitting newSource on threadActor.sourcesManager 81 threadActor.addAllSources(); 82 } 83 84 /** 85 * Stop watching for sources 86 */ 87 destroy() { 88 if (this.sourcesManager) { 89 this.sourcesManager.off("newSource", this.onNewSource); 90 } 91 } 92 93 onNewSource(source) { 94 const resource = source.form(); 95 this.onAvailable([resource]); 96 } 97 } 98 99 module.exports = SourceWatcher;