blob: 103613eefafb25ee818a99c12dfbc38b3f4d537f [file] [log] [blame]
// Copyright 2016 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.
/**
* @constructor
* @extends {WebInspector.SDKModel}
* @param {!WebInspector.Target} target
*/
WebInspector.SubTargetsManager = function(target)
{
WebInspector.SDKModel.call(this, WebInspector.SubTargetsManager, target);
target.registerTargetDispatcher(new WebInspector.SubTargetsDispatcher(this));
this._lastAnonymousTargetId = 0;
this._agent = target.targetAgent();
/** @type {!Map<string, !WebInspector.TargetInfo>} */
this._allTargets = new Map();
/** @type {!Map<string, !WebInspector.Target>} */
this._attachedTargets = new Map();
/** @type {!Map<string, !WebInspector.SubTargetConnection>} */
this._connections = new Map();
this._agent.setAutoAttach(true /* autoAttach */, true /* waitForDebuggerOnStart */);
this._agent.setAttachToFrames(Runtime.experiments.isEnabled("autoAttachToCrossProcessSubframes"));
}
/** @enum {symbol} */
WebInspector.SubTargetsManager.Events = {
SubTargetAdded: Symbol("SubTargetAdded"),
SubTargetRemoved: Symbol("SubTargetRemoved"),
}
WebInspector.SubTargetsManager._InfoSymbol = Symbol("SubTargetInfo");
WebInspector.SubTargetsManager.prototype = {
/**
* @override
* @return {!Promise}
*/
suspendModel: function()
{
var fulfill;
var promise = new Promise(f => fulfill = f);
this._agent.setAutoAttach(true /* autoAttach */, false /* waitForDebuggerOnStart */, fulfill);
return promise;
},
/**
* @override
* @return {!Promise}
*/
resumeModel: function()
{
var fulfill;
var promise = new Promise(f => fulfill = f);
this._agent.setAutoAttach(true /* autoAttach */, true /* waitForDebuggerOnStart */, fulfill);
return promise;
},
/**
* @override
*/
dispose: function()
{
for (var connection of this._connections.values())
connection.close();
this._connections.clear();
this._attachedTargets.clear();
},
/**
* @param {!TargetAgent.TargetID} targetId
*/
activateTarget: function(targetId)
{
this._agent.activateTarget(targetId);
},
/**
* @param {!TargetAgent.TargetID} targetId
* @param {function(?WebInspector.TargetInfo)=} callback
*/
getTargetInfo: function(targetId, callback)
{
/**
* @param {?Protocol.Error} error
* @param {?TargetAgent.TargetInfo} targetInfo
*/
function innerCallback(error, targetInfo)
{
if (error) {
console.error(error);
callback(null);
return;
}
if (targetInfo)
callback(new WebInspector.TargetInfo(targetInfo));
else
callback(null)
}
this._agent.getTargetInfo(targetId, innerCallback);
},
/**
* @param {string} targetId
* @return {?WebInspector.Target}
*/
targetForId: function(targetId)
{
return this._attachedTargets.get(targetId) || null;
},
/**
* @param {!WebInspector.Target} target
* @return {?WebInspector.TargetInfo}
*/
targetInfo: function(target)
{
return target[WebInspector.SubTargetsManager._InfoSymbol] || null;
},
/**
* @param {string} type
* @return {number}
*/
_capabilitiesForType: function(type)
{
if (type === "worker")
return WebInspector.Target.Capability.JS | WebInspector.Target.Capability.Log;
if (type === "service_worker")
return WebInspector.Target.Capability.Log | WebInspector.Target.Capability.Network | WebInspector.Target.Capability.Worker;
if (type === "iframe")
return WebInspector.Target.Capability.Browser | WebInspector.Target.Capability.DOM |
WebInspector.Target.Capability.JS | WebInspector.Target.Capability.Log |
WebInspector.Target.Capability.Network | WebInspector.Target.Capability.Worker;
return 0;
},
/**
* @param {!WebInspector.TargetInfo} targetInfo
*/
_targetCreated: function(targetInfo)
{
console.assert(!this._allTargets.has(targetInfo.id));
console.assert(!this._attachedTargets.has(targetInfo.id));
this._allTargets.set(targetInfo.id, targetInfo);
},
/**
* @param {string} targetId
*/
_targetRemoved: function(targetId)
{
console.assert(this._allTargets.has(targetId));
console.assert(!this._attachedTargets.has(targetId));
this._allTargets.delete(targetId);
},
/**
* @param {string} targetId
* @param {boolean} waitingForDebugger
*/
_attachedToTarget: function(targetId, waitingForDebugger)
{
var targetInfo = /** @type {!WebInspector.TargetInfo} */ (this._allTargets.get(targetId));
var connection = new WebInspector.SubTargetConnection(this._agent, targetId);
this._connections.set(targetId, connection);
var targetName = "";
if (targetInfo.type !== "iframe") {
var parsedURL = targetInfo.url.asParsedURL();
targetName = parsedURL ? parsedURL.lastPathComponentWithFragment() : "#" + (++this._lastAnonymousTargetId);
}
var target = WebInspector.targetManager.createTarget(targetName, this._capabilitiesForType(targetInfo.type), connection, this.target());
target[WebInspector.SubTargetsManager._InfoSymbol] = targetInfo;
this._attachedTargets.set(targetId, target);
// Only pause new worker if debugging SW - we are going through the pause on start checkbox.
var mainIsServiceWorker = !this.target().parentTarget() && this.target().hasWorkerCapability() && !this.target().hasBrowserCapability();
if (mainIsServiceWorker && waitingForDebugger)
target.debuggerAgent().pause();
target.runtimeAgent().runIfWaitingForDebugger();
this.dispatchEventToListeners(WebInspector.SubTargetsManager.Events.SubTargetAdded, target);
},
/**
* @param {string} targetId
*/
_detachedFromTarget: function(targetId)
{
var connection = this._connections.get(targetId);
if (connection)
connection._reportClosed();
this._connections.delete(targetId);
var target = this._attachedTargets.get(targetId);
this._attachedTargets.delete(targetId);
this.dispatchEventToListeners(WebInspector.SubTargetsManager.Events.SubTargetRemoved, target);
},
/**
* @param {string} targetId
* @param {string} message
*/
_receivedMessageFromTarget: function(targetId, message)
{
var connection = this._connections.get(targetId);
if (connection)
connection.dispatch(message);
},
__proto__: WebInspector.SDKModel.prototype
}
/**
* @constructor
* @implements {TargetAgent.Dispatcher}
* @param {!WebInspector.SubTargetsManager} manager
*/
WebInspector.SubTargetsDispatcher = function(manager)
{
this._manager = manager;
}
WebInspector.SubTargetsDispatcher.prototype = {
/**
* @override
* @param {!TargetAgent.TargetInfo} targetInfo
*/
targetCreated: function(targetInfo)
{
this._manager._targetCreated(new WebInspector.TargetInfo(targetInfo));
},
/**
* @override
* @param {string} targetId
*/
targetRemoved: function(targetId)
{
this._manager._targetRemoved(targetId);
},
/**
* @override
* @param {string} targetId
* @param {boolean} waitingForDebugger
*/
attachedToTarget: function(targetId, waitingForDebugger)
{
this._manager._attachedToTarget(targetId, waitingForDebugger);
},
/**
* @override
* @param {string} targetId
*/
detachedFromTarget: function(targetId)
{
this._manager._detachedFromTarget(targetId);
},
/**
* @override
* @param {string} targetId
* @param {string} message
*/
receivedMessageFromTarget: function(targetId, message)
{
this._manager._receivedMessageFromTarget(targetId, message);
}
}
/**
* @constructor
* @extends {InspectorBackendClass.Connection}
* @param {!Protocol.TargetAgent} agent
* @param {string} targetId
*/
WebInspector.SubTargetConnection = function(agent, targetId)
{
InspectorBackendClass.Connection.call(this);
this._agent = agent;
this._targetId = targetId;
}
WebInspector.SubTargetConnection.prototype = {
/**
* @override
* @param {!Object} messageObject
*/
sendMessage: function(messageObject)
{
this._agent.sendMessageToTarget(this._targetId, JSON.stringify(messageObject));
},
/**
* @override
*/
forceClose: function()
{
this._agent.detachFromTarget(this._targetId);
},
_reportClosed: function()
{
this.connectionClosed("target_terminated");
},
__proto__: InspectorBackendClass.Connection.prototype
}
/**
* @constructor
* @param {!TargetAgent.TargetInfo} payload
*/
WebInspector.TargetInfo = function(payload)
{
this.id = payload.targetId;
this.url = payload.url;
this.type = payload.type;
if (this.type !== "page" && this.type !== "iframe") {
this.title = WebInspector.UIString("Worker: %s", this.url);
this.canActivate = false;
} else {
this.title = payload.title;
this.canActivate = true;
}
}