mirror of
https://github.com/lexmount/moli.git
synced 2026-09-28 08:01:37 +00:00
Split worker target projection by worker kind
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,854 @@
|
||||
use super::*;
|
||||
|
||||
pub(super) fn dedicated_worker_target_is_current(
|
||||
conn: &CdpConnection,
|
||||
browser_context_id: &str,
|
||||
renderer_instance_id: u64,
|
||||
target_id: &str,
|
||||
) -> bool {
|
||||
let Some(context) = conn.browser_context_by_id(browser_context_id) else {
|
||||
return false;
|
||||
};
|
||||
context
|
||||
.dedicated_worker_targets
|
||||
.get(&renderer_instance_id)
|
||||
.is_some_and(|target| {
|
||||
target.target_id == target_id
|
||||
&& context.target_page_residence_is_current(&target.owner_page)
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn register_dedicated_worker_target(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: &str,
|
||||
owner_page: TargetPageResidenceIdentity,
|
||||
owner_renderer_page: RendererPageResidenceIdentity,
|
||||
owner_page_network_sessions: Vec<Option<String>>,
|
||||
info: RendererDedicatedWorkerTargetInfo,
|
||||
) -> TargetPreparedOutputs {
|
||||
let mut outputs = TargetPreparedOutputs::default();
|
||||
if info.owner_local_host_id != owner_renderer_page.owner_local_host_id()
|
||||
|| info.page_id != owner_renderer_page.page_id()
|
||||
{
|
||||
return outputs;
|
||||
}
|
||||
if conn
|
||||
.browser_context_by_id(browser_context_id)
|
||||
.and_then(|context| {
|
||||
context.dedicated_worker_target_id_for_renderer_instance(info.instance_id)
|
||||
})
|
||||
.is_some()
|
||||
{
|
||||
return outputs;
|
||||
}
|
||||
let target_id = conn.gen_target_id();
|
||||
let request_url = match Url::parse(&info.request_url) {
|
||||
Ok(url) => url,
|
||||
Err(_) => return outputs,
|
||||
};
|
||||
let document_url = match Url::parse(&info.document_url) {
|
||||
Ok(url) => url,
|
||||
Err(_) => return outputs,
|
||||
};
|
||||
let owner_target_id = owner_page.target_id().unwrap_or_default().to_owned();
|
||||
let should_emit_created = conn.has_any_target_discovery();
|
||||
let created_snapshot = {
|
||||
let Some(context) = conn.browser_context_by_id_mut(browser_context_id) else {
|
||||
return TargetPreparedOutputs::default();
|
||||
};
|
||||
context.insert_dedicated_worker_target(crate::conn::DedicatedWorkerTargetState::new(
|
||||
owner_page.clone(),
|
||||
info.owner_local_host_id,
|
||||
info.instance_id,
|
||||
target_id.clone(),
|
||||
info.name,
|
||||
owner_page_network_sessions.clone(),
|
||||
));
|
||||
should_emit_created
|
||||
.then(|| context.devtools_target_info(&target_id))
|
||||
.flatten()
|
||||
};
|
||||
if let Some(target_info) = created_snapshot {
|
||||
outputs.push(WorkerTargetLifecycleOutput::DedicatedWorkerCreated {
|
||||
browser_context_id: browser_context_id.to_owned(),
|
||||
renderer_instance_id: info.instance_id,
|
||||
target_delta: PreparedTargetHostDelta::created(target_id.clone(), Some(target_info)),
|
||||
});
|
||||
}
|
||||
let timestamp = monotonic_timestamp_seconds();
|
||||
for session_id in &owner_page_network_sessions {
|
||||
let mut events = Vec::new();
|
||||
network::emit_request_will_be_sent(
|
||||
&mut events,
|
||||
session_id.as_deref(),
|
||||
&target_id,
|
||||
&owner_target_id,
|
||||
&owner_target_id,
|
||||
timestamp,
|
||||
&document_url,
|
||||
&request_url,
|
||||
"GET",
|
||||
None,
|
||||
&[],
|
||||
DevToolsNetworkResourceType::Script,
|
||||
SubresourceRequestInitiatorType::Other,
|
||||
None,
|
||||
false,
|
||||
None,
|
||||
&[],
|
||||
);
|
||||
if !events.is_empty() {
|
||||
outputs.push(WorkerTargetLifecycleOutput::DedicatedWorkerEvents {
|
||||
browser_context_id: browser_context_id.to_owned(),
|
||||
renderer_instance_id: info.instance_id,
|
||||
target_id: target_id.clone(),
|
||||
events,
|
||||
});
|
||||
}
|
||||
}
|
||||
outputs
|
||||
}
|
||||
|
||||
pub(super) fn record_dedicated_worker_main_script(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: &str,
|
||||
renderer_instance_id: u64,
|
||||
script_url: String,
|
||||
outcome: crate::conn::DedicatedWorkerMainScriptOutcome,
|
||||
) -> TargetPreparedOutputs {
|
||||
let mut outputs = TargetPreparedOutputs::default();
|
||||
let Some(owner_page) = conn
|
||||
.browser_context_by_id(browser_context_id)
|
||||
.and_then(|context| context.dedicated_worker_targets.get(&renderer_instance_id))
|
||||
.map(|target| target.owner_page.clone())
|
||||
else {
|
||||
return outputs;
|
||||
};
|
||||
let auto_attach_owners = dedicated_worker_auto_attach_owner_sessions(conn, &owner_page);
|
||||
let attached_sessions = auto_attach_owners
|
||||
.into_iter()
|
||||
.map(|owner| {
|
||||
let waiting = conn.auto_attach_owner_waits_for_debugger_on_start(owner.as_deref());
|
||||
(owner, conn.gen_session_id(), waiting)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let pause_failed_target_until_debugger_resume = attached_sessions
|
||||
.iter()
|
||||
.any(|(_, _, waiting_for_debugger)| *waiting_for_debugger);
|
||||
let should_emit_info_changed = conn.has_any_target_discovery();
|
||||
let (target_id, page_extra_events) = {
|
||||
let Some(context) = conn.browser_context_by_id_mut(browser_context_id) else {
|
||||
return outputs;
|
||||
};
|
||||
let Some(target) = context
|
||||
.dedicated_worker_targets
|
||||
.get_mut(&renderer_instance_id)
|
||||
else {
|
||||
return outputs;
|
||||
};
|
||||
let target_id = target.target_id.clone();
|
||||
let owner_page_network_sessions = target.owner_page_network_sessions.clone();
|
||||
let page_extra_events = dedicated_worker_main_script_page_extra_events(
|
||||
&target_id,
|
||||
&owner_page_network_sessions,
|
||||
&outcome,
|
||||
);
|
||||
target.record_main_script(
|
||||
script_url,
|
||||
outcome,
|
||||
pause_failed_target_until_debugger_resume,
|
||||
);
|
||||
(target_id, page_extra_events)
|
||||
};
|
||||
for (_session_id, events) in page_extra_events {
|
||||
outputs.push(WorkerTargetLifecycleOutput::DedicatedWorkerEvents {
|
||||
browser_context_id: browser_context_id.to_owned(),
|
||||
renderer_instance_id,
|
||||
target_id: target_id.clone(),
|
||||
events,
|
||||
});
|
||||
}
|
||||
let mut prepared_attaches = Vec::new();
|
||||
for (owner_session_id, session_id, waiting_for_debugger) in attached_sessions {
|
||||
let Some(target_info) = conn
|
||||
.prepare_auto_attached_dedicated_worker_session_binding_info_in_browser_context(
|
||||
browser_context_id,
|
||||
&target_id,
|
||||
session_id.clone(),
|
||||
)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let prepared_session = TargetAttachSessionCommit::auto_attached(
|
||||
session_id.clone(),
|
||||
owner_session_id,
|
||||
CdpSessionRoute::DedicatedWorkerTarget {
|
||||
browser_context_id: browser_context_id.to_owned(),
|
||||
target_id: target_id.clone(),
|
||||
},
|
||||
waiting_for_debugger,
|
||||
);
|
||||
if waiting_for_debugger
|
||||
&& let Some(context) = conn.browser_context_by_id_mut(browser_context_id)
|
||||
&& let Some(target) = context
|
||||
.dedicated_worker_targets
|
||||
.get_mut(&renderer_instance_id)
|
||||
{
|
||||
target.allow_main_script_network_replay_to(&session_id);
|
||||
}
|
||||
prepared_attaches.push(WorkerTargetLifecycleOutput::DedicatedWorkerAttached {
|
||||
browser_context_id: browser_context_id.to_owned(),
|
||||
renderer_instance_id,
|
||||
target_id: target_id.clone(),
|
||||
session_id,
|
||||
prepared_attach: PreparedTargetAttach::new(
|
||||
target_id.clone(),
|
||||
target_info,
|
||||
[prepared_session],
|
||||
),
|
||||
});
|
||||
}
|
||||
let changed_snapshot = should_emit_info_changed
|
||||
.then(|| {
|
||||
conn.browser_context_by_id(browser_context_id)
|
||||
.and_then(|context| context.devtools_target_info(&target_id))
|
||||
})
|
||||
.flatten();
|
||||
if let Some(target_info) = changed_snapshot {
|
||||
outputs.push(WorkerTargetLifecycleOutput::DedicatedWorkerInfoChanged {
|
||||
browser_context_id: browser_context_id.to_owned(),
|
||||
renderer_instance_id,
|
||||
target_id: target_id.clone(),
|
||||
target_delta: PreparedTargetHostDelta::info_changed(
|
||||
target_id.clone(),
|
||||
Some(target_info),
|
||||
),
|
||||
});
|
||||
}
|
||||
outputs
|
||||
.worker_target_lifecycle_outputs
|
||||
.extend(prepared_attaches);
|
||||
let enabled_sessions = conn
|
||||
.browser_context_by_id(browser_context_id)
|
||||
.and_then(|context| context.dedicated_worker_targets.get(&renderer_instance_id))
|
||||
.map(|target| {
|
||||
target
|
||||
.session_ids()
|
||||
.into_iter()
|
||||
.filter(|session_id| {
|
||||
target.network_enabled(session_id)
|
||||
&& !target.main_script_was_delivered_to(session_id)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
for session_id in enabled_sessions {
|
||||
let events = conn
|
||||
.browser_context_by_id(browser_context_id)
|
||||
.and_then(|context| context.dedicated_worker_targets.get(&renderer_instance_id))
|
||||
.and_then(|target| target.main_script())
|
||||
.map(|script| {
|
||||
dedicated_worker_main_script_worker_events(&target_id, Some(&session_id), script)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
if let Some(context) = conn.browser_context_by_id_mut(browser_context_id)
|
||||
&& let Some(target) = context
|
||||
.dedicated_worker_targets
|
||||
.get_mut(&renderer_instance_id)
|
||||
{
|
||||
target.mark_main_script_delivered_to(&session_id);
|
||||
}
|
||||
if !events.is_empty() {
|
||||
outputs.push(WorkerTargetLifecycleOutput::DedicatedWorkerEvents {
|
||||
browser_context_id: browser_context_id.to_owned(),
|
||||
renderer_instance_id,
|
||||
target_id: target_id.clone(),
|
||||
events,
|
||||
});
|
||||
}
|
||||
}
|
||||
outputs
|
||||
}
|
||||
|
||||
pub(in crate::domains::target) fn dedicated_worker_auto_attach_owner_session_allowed(
|
||||
conn: &CdpConnection,
|
||||
owner_session_id: Option<&str>,
|
||||
owner_page: &TargetPageResidenceIdentity,
|
||||
) -> bool {
|
||||
let Some(owner_session_id) = owner_session_id else {
|
||||
return false;
|
||||
};
|
||||
conn.target_page_residence_identity_for_session(Some(owner_session_id))
|
||||
.as_ref()
|
||||
== Some(owner_page)
|
||||
}
|
||||
|
||||
pub(super) fn shared_worker_auto_attach_owner_sessions(
|
||||
conn: &CdpConnection,
|
||||
) -> Vec<Option<String>> {
|
||||
conn.auto_attach_owner_sessions_for_target_type("shared_worker")
|
||||
.into_iter()
|
||||
.filter(|owner_session_id| {
|
||||
super::super::browser_level_auto_attach_owner_session_allowed(
|
||||
conn,
|
||||
owner_session_id.as_deref(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(super) fn service_worker_auto_attach_owner_sessions(
|
||||
conn: &CdpConnection,
|
||||
) -> Vec<Option<String>> {
|
||||
conn.auto_attach_owner_sessions_for_target_type("service_worker")
|
||||
.into_iter()
|
||||
.filter(|owner_session_id| {
|
||||
super::super::browser_level_auto_attach_owner_session_allowed(
|
||||
conn,
|
||||
owner_session_id.as_deref(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(super) fn dedicated_worker_auto_attach_owner_sessions(
|
||||
conn: &CdpConnection,
|
||||
owner_page: &TargetPageResidenceIdentity,
|
||||
) -> Vec<Option<String>> {
|
||||
conn.auto_attach_owner_sessions_for_target_type("worker")
|
||||
.into_iter()
|
||||
.filter(|owner_session_id| {
|
||||
dedicated_worker_auto_attach_owner_session_allowed(
|
||||
conn,
|
||||
owner_session_id.as_deref(),
|
||||
owner_page,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(super) fn dedicated_worker_main_script_page_extra_events(
|
||||
request_id: &str,
|
||||
sessions: &[Option<String>],
|
||||
outcome: &crate::conn::DedicatedWorkerMainScriptOutcome,
|
||||
) -> Vec<(Option<String>, Vec<BackgroundProtocolEvent>)> {
|
||||
let response = match outcome {
|
||||
crate::conn::DedicatedWorkerMainScriptOutcome::Loaded(response) => Some(response.as_ref()),
|
||||
crate::conn::DedicatedWorkerMainScriptOutcome::Failed { response, .. } => {
|
||||
response.as_deref()
|
||||
}
|
||||
};
|
||||
let Some(response) = response else {
|
||||
return Vec::new();
|
||||
};
|
||||
let has_network_extra_info =
|
||||
response.network_request_headers().is_some() || response.request_cookie_report.is_some();
|
||||
if !has_network_extra_info {
|
||||
return Vec::new();
|
||||
}
|
||||
let default_cookie_report = moli_cookie_jar::StoredCookieQueryReport::default();
|
||||
let cookie_report = response
|
||||
.request_cookie_report
|
||||
.as_ref()
|
||||
.unwrap_or(&default_cookie_report);
|
||||
sessions
|
||||
.iter()
|
||||
.map(|session_id| {
|
||||
let mut events = Vec::new();
|
||||
network::emit_request_will_be_sent_extra_info(
|
||||
&mut events,
|
||||
session_id.as_deref(),
|
||||
request_id,
|
||||
response.network_request_headers().unwrap_or_default(),
|
||||
cookie_report,
|
||||
monotonic_timestamp_seconds(),
|
||||
);
|
||||
network::emit_response_received_extra_info(
|
||||
&mut events,
|
||||
session_id.as_deref(),
|
||||
request_id,
|
||||
&response.headers,
|
||||
response.status,
|
||||
&response.cookie_set_reports,
|
||||
);
|
||||
(session_id.clone(), events)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(super) fn dedicated_worker_main_script_worker_events(
|
||||
target_id: &str,
|
||||
session_id: Option<&str>,
|
||||
script: &crate::conn::DedicatedWorkerMainScriptSnapshot,
|
||||
) -> Vec<BackgroundProtocolEvent> {
|
||||
let mut events = Vec::new();
|
||||
let timestamp = monotonic_timestamp_seconds();
|
||||
let response = match &script.outcome {
|
||||
crate::conn::DedicatedWorkerMainScriptOutcome::Loaded(response) => Some(response.as_ref()),
|
||||
crate::conn::DedicatedWorkerMainScriptOutcome::Failed { response, .. } => {
|
||||
response.as_deref()
|
||||
}
|
||||
};
|
||||
if let Some(response) = response {
|
||||
let has_extra_info = response.network_request_headers().is_some()
|
||||
|| response.request_cookie_report.is_some();
|
||||
network::emit_response_received_without_extra_info_event(
|
||||
&mut events,
|
||||
session_id,
|
||||
target_id,
|
||||
target_id,
|
||||
target_id,
|
||||
timestamp,
|
||||
&response.final_url,
|
||||
response.status,
|
||||
None,
|
||||
&response.headers,
|
||||
response.body_bytes().len(),
|
||||
response.from_cache,
|
||||
response.negotiated_http_version,
|
||||
has_extra_info,
|
||||
DevToolsNetworkResourceType::Script,
|
||||
);
|
||||
}
|
||||
match &script.outcome {
|
||||
crate::conn::DedicatedWorkerMainScriptOutcome::Loaded(response) => {
|
||||
network::emit_loading_finished(
|
||||
&mut events,
|
||||
session_id,
|
||||
target_id,
|
||||
target_id,
|
||||
target_id,
|
||||
timestamp,
|
||||
response.body_bytes().len(),
|
||||
DevToolsNetworkResourceType::Script,
|
||||
);
|
||||
}
|
||||
crate::conn::DedicatedWorkerMainScriptOutcome::Failed { error_message, .. } => {
|
||||
network::emit_loading_failed(
|
||||
&mut events,
|
||||
session_id,
|
||||
target_id,
|
||||
target_id,
|
||||
target_id,
|
||||
timestamp,
|
||||
dedicated_worker_loading_error_text(error_message),
|
||||
DevToolsNetworkResourceType::Script,
|
||||
);
|
||||
}
|
||||
}
|
||||
events
|
||||
}
|
||||
|
||||
pub(super) fn dedicated_worker_loading_error_text(error_message: &str) -> &str {
|
||||
error_message
|
||||
.split_ascii_whitespace()
|
||||
.find(|part| part.starts_with("net::ERR_"))
|
||||
.map(|part| {
|
||||
part.trim_end_matches(|character: char| {
|
||||
!character.is_ascii_alphanumeric() && character != '_'
|
||||
})
|
||||
})
|
||||
.unwrap_or("net::ERR_FAILED")
|
||||
}
|
||||
|
||||
pub(in crate::domains) fn dedicated_worker_main_script_network_replay_for_session(
|
||||
conn: &mut CdpConnection,
|
||||
session_id: &str,
|
||||
) -> Vec<BackgroundProtocolEvent> {
|
||||
let Some(crate::conn::CdpSessionRoute::DedicatedWorkerTarget {
|
||||
browser_context_id,
|
||||
target_id,
|
||||
}) = conn.session_route(Some(session_id))
|
||||
else {
|
||||
return Vec::new();
|
||||
};
|
||||
let Some(renderer_instance_id) = conn
|
||||
.browser_context_by_id(&browser_context_id)
|
||||
.and_then(|context| context.dedicated_worker_target(&target_id))
|
||||
.map(|target| target.renderer_instance_id)
|
||||
else {
|
||||
return Vec::new();
|
||||
};
|
||||
let events = conn
|
||||
.browser_context_by_id(&browser_context_id)
|
||||
.and_then(|context| context.dedicated_worker_targets.get(&renderer_instance_id))
|
||||
.filter(|target| {
|
||||
target.network_enabled(session_id)
|
||||
&& target.main_script_network_replay_allowed_for(session_id)
|
||||
&& !target.main_script_was_delivered_to(session_id)
|
||||
})
|
||||
.and_then(|target| target.main_script())
|
||||
.map(|script| {
|
||||
dedicated_worker_main_script_worker_events(&target_id, Some(session_id), script)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
if events.is_empty() {
|
||||
return events;
|
||||
}
|
||||
if let Some(context) = conn.browser_context_by_id_mut(&browser_context_id)
|
||||
&& let Some(target) = context
|
||||
.dedicated_worker_targets
|
||||
.get_mut(&renderer_instance_id)
|
||||
{
|
||||
target.mark_main_script_delivered_to(session_id);
|
||||
}
|
||||
events
|
||||
}
|
||||
|
||||
pub(in crate::domains) fn release_failed_dedicated_worker_target_after_debugger_resume(
|
||||
conn: &mut CdpConnection,
|
||||
session_id: Option<&str>,
|
||||
) -> Option<Vec<BackgroundProtocolEvent>> {
|
||||
let session_id = session_id?;
|
||||
let crate::conn::CdpSessionRoute::DedicatedWorkerTarget {
|
||||
browser_context_id,
|
||||
target_id,
|
||||
} = conn.session_route(Some(session_id))?
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
let renderer_instance_id = {
|
||||
let target = conn
|
||||
.browser_context_by_id_mut(&browser_context_id)?
|
||||
.dedicated_worker_target_mut(&target_id)?;
|
||||
if !target.release_deferred_renderer_destroyed_for_debugger_resume() {
|
||||
return None;
|
||||
}
|
||||
target.renderer_instance_id
|
||||
};
|
||||
let outputs = prepare_dedicated_worker_target_retirement(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
renderer_instance_id,
|
||||
DedicatedWorkerRetirementCause::OwnerRetired,
|
||||
);
|
||||
Some(commit_failed_dedicated_worker_retirement_sync(
|
||||
conn, outputs,
|
||||
))
|
||||
}
|
||||
|
||||
pub(in crate::domains) async fn retire_dedicated_worker_targets_for_replaced_page_async(
|
||||
conn: &mut CdpConnection,
|
||||
replaced_page_owner: &TargetPageResidenceIdentity,
|
||||
) -> Vec<BackgroundProtocolEvent> {
|
||||
let renderer_instance_ids = conn
|
||||
.browser_context_by_id(replaced_page_owner.browser_context_id())
|
||||
.map(|context| {
|
||||
context
|
||||
.dedicated_worker_targets
|
||||
.iter()
|
||||
.filter_map(|(renderer_instance_id, target)| {
|
||||
(&target.owner_page == replaced_page_owner).then_some(*renderer_instance_id)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let mut events = Vec::new();
|
||||
for renderer_instance_id in renderer_instance_ids {
|
||||
let outputs = prepare_dedicated_worker_target_retirement(
|
||||
conn,
|
||||
replaced_page_owner.browser_context_id(),
|
||||
renderer_instance_id,
|
||||
DedicatedWorkerRetirementCause::OwnerRetired,
|
||||
);
|
||||
for output in outputs.worker_target_lifecycle_outputs {
|
||||
match commit_dedicated_worker_retirement_output_async(conn, output).await {
|
||||
Ok(output_events) => events.extend(output_events),
|
||||
Err(output) => {
|
||||
debug_assert!(
|
||||
false,
|
||||
"Page replacement DedicatedWorker retirement contained non-terminal output: {output:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
events
|
||||
}
|
||||
|
||||
pub(super) async fn commit_dedicated_worker_retirement_output_async(
|
||||
conn: &mut CdpConnection,
|
||||
output: WorkerTargetLifecycleOutput,
|
||||
) -> Result<Vec<BackgroundProtocolEvent>, WorkerTargetLifecycleOutput> {
|
||||
let mut events = Vec::new();
|
||||
match output {
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerDetached {
|
||||
target_delta,
|
||||
cleanup_plan,
|
||||
} => {
|
||||
if let Some(target_delta) = target_delta {
|
||||
events.extend(
|
||||
conn.prepared_target_info_changed_event_plan_for_discovery_owners(target_delta),
|
||||
);
|
||||
}
|
||||
let mut response_events = Vec::new();
|
||||
let outcome = super::super::session_disposal::dispose_dedicated_worker_session_after_prepared_state_delta_async(
|
||||
conn,
|
||||
&mut events,
|
||||
&mut response_events,
|
||||
cleanup_plan,
|
||||
)
|
||||
.await
|
||||
.expect("retired dedicated-worker session cleanup should succeed");
|
||||
let (event_plan, predecessor) = outcome.into_parts();
|
||||
debug_assert!(
|
||||
predecessor.is_none(),
|
||||
"DedicatedWorker disposal cannot publish a Page renderer fence"
|
||||
);
|
||||
events.extend(response_events);
|
||||
events.extend(event_plan);
|
||||
}
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerDestroyed {
|
||||
browser_context_id,
|
||||
renderer_instance_id,
|
||||
target_id,
|
||||
target_delta,
|
||||
} => {
|
||||
let removed = conn
|
||||
.browser_context_by_id_mut(&browser_context_id)
|
||||
.and_then(|context| {
|
||||
let target = context
|
||||
.dedicated_worker_targets
|
||||
.get(&renderer_instance_id)?;
|
||||
(target.target_id == target_id).then(|| {
|
||||
context.remove_dedicated_worker_target_by_renderer_instance(
|
||||
renderer_instance_id,
|
||||
)
|
||||
})
|
||||
})
|
||||
.flatten();
|
||||
if removed.is_none() {
|
||||
return Ok(events);
|
||||
}
|
||||
if let Some(target_delta) = target_delta {
|
||||
events.extend(conn.prepared_target_host_delta_event_plan(target_delta));
|
||||
}
|
||||
}
|
||||
output => return Err(output),
|
||||
}
|
||||
Ok(events)
|
||||
}
|
||||
|
||||
pub(super) fn commit_failed_dedicated_worker_retirement_sync(
|
||||
conn: &mut CdpConnection,
|
||||
outputs: TargetPreparedOutputs,
|
||||
) -> Vec<BackgroundProtocolEvent> {
|
||||
let retirement_identity = outputs
|
||||
.worker_target_lifecycle_outputs
|
||||
.iter()
|
||||
.find_map(|output| match output {
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerDestroyed {
|
||||
browser_context_id,
|
||||
renderer_instance_id,
|
||||
target_id,
|
||||
..
|
||||
} => Some((
|
||||
browser_context_id.clone(),
|
||||
*renderer_instance_id,
|
||||
target_id.clone(),
|
||||
)),
|
||||
_ => None,
|
||||
});
|
||||
let Some((browser_context_id, renderer_instance_id, target_id)) = retirement_identity else {
|
||||
return Vec::new();
|
||||
};
|
||||
let removed = conn
|
||||
.browser_context_by_id_mut(&browser_context_id)
|
||||
.and_then(|context| {
|
||||
let target = context
|
||||
.dedicated_worker_targets
|
||||
.get(&renderer_instance_id)?;
|
||||
(target.target_id == target_id).then(|| {
|
||||
context.remove_dedicated_worker_target_by_renderer_instance(renderer_instance_id)
|
||||
})
|
||||
})
|
||||
.flatten();
|
||||
if removed.is_none() {
|
||||
return Vec::new();
|
||||
}
|
||||
let mut events = Vec::new();
|
||||
for output in outputs.worker_target_lifecycle_outputs {
|
||||
match output {
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerDetached {
|
||||
target_delta,
|
||||
cleanup_plan,
|
||||
} => {
|
||||
if let Some(target_delta) = target_delta {
|
||||
events.extend(
|
||||
conn.prepared_target_info_changed_event_plan_for_discovery_owners(
|
||||
target_delta,
|
||||
),
|
||||
);
|
||||
}
|
||||
events.extend(
|
||||
super::super::session_disposal::dispose_removed_dedicated_worker_session_after_failed_retirement(
|
||||
conn,
|
||||
cleanup_plan,
|
||||
),
|
||||
);
|
||||
}
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerDestroyed { target_delta, .. } => {
|
||||
if let Some(target_delta) = target_delta {
|
||||
events.extend(conn.prepared_target_host_delta_event_plan(target_delta));
|
||||
}
|
||||
}
|
||||
output => {
|
||||
debug_assert!(
|
||||
false,
|
||||
"failed DedicatedWorker retirement contained non-terminal output: {output:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
events
|
||||
}
|
||||
|
||||
pub(super) fn record_dedicated_worker_target_runtime_inspector_messages(
|
||||
conn: &CdpConnection,
|
||||
browser_context_id: &str,
|
||||
renderer_instance_id: u64,
|
||||
inspector_session_id: Option<String>,
|
||||
messages: Vec<RendererRuntimeInspectorMessage>,
|
||||
) -> TargetPreparedOutputs {
|
||||
let mut outputs = TargetPreparedOutputs::default();
|
||||
let Some(target) = conn
|
||||
.browser_context_by_id(browser_context_id)
|
||||
.and_then(|context| context.dedicated_worker_targets.get(&renderer_instance_id))
|
||||
else {
|
||||
return outputs;
|
||||
};
|
||||
let target_id = target.target_id.clone();
|
||||
let session_ids = if let Some(session_id) = inspector_session_id {
|
||||
target
|
||||
.is_session(&session_id)
|
||||
.then_some(vec![session_id])
|
||||
.unwrap_or_default()
|
||||
} else {
|
||||
target.session_ids()
|
||||
};
|
||||
for session_id in session_ids {
|
||||
outputs.push(
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerRuntimeInspectorMessages {
|
||||
browser_context_id: browser_context_id.to_owned(),
|
||||
renderer_instance_id,
|
||||
target_id: target_id.clone(),
|
||||
session_id,
|
||||
messages: messages.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
outputs
|
||||
}
|
||||
|
||||
pub(super) fn record_dedicated_worker_target_console_message(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: &str,
|
||||
renderer_instance_id: u64,
|
||||
message: RendererSharedWorkerConsoleMessage,
|
||||
) -> TargetPreparedOutputs {
|
||||
let mut outputs = TargetPreparedOutputs::default();
|
||||
let Some(context) = conn.browser_context_by_id_mut(browser_context_id) else {
|
||||
return outputs;
|
||||
};
|
||||
let Some(target) = context
|
||||
.dedicated_worker_targets
|
||||
.get_mut(&renderer_instance_id)
|
||||
else {
|
||||
return outputs;
|
||||
};
|
||||
target.record_console_message(message);
|
||||
let target_id = target.target_id.clone();
|
||||
let console_end = target.console_message_count();
|
||||
for session_id in target.session_ids() {
|
||||
let console_messages = target.pending_console_domain_messages(&session_id).to_vec();
|
||||
let runtime_messages = target
|
||||
.pending_runtime_console_messages(&session_id)
|
||||
.to_vec();
|
||||
if console_messages.is_empty() && runtime_messages.is_empty() {
|
||||
continue;
|
||||
}
|
||||
outputs.push(
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerConsoleMessages {
|
||||
browser_context_id: browser_context_id.to_owned(),
|
||||
renderer_instance_id,
|
||||
target_id: target_id.clone(),
|
||||
session_id,
|
||||
console_messages,
|
||||
runtime_messages,
|
||||
console_end,
|
||||
},
|
||||
);
|
||||
}
|
||||
outputs
|
||||
}
|
||||
|
||||
pub(super) fn prepare_dedicated_worker_target_retirement(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: &str,
|
||||
renderer_instance_id: u64,
|
||||
cause: DedicatedWorkerRetirementCause,
|
||||
) -> TargetPreparedOutputs {
|
||||
let mut outputs = TargetPreparedOutputs::default();
|
||||
if matches!(cause, DedicatedWorkerRetirementCause::RendererDestroyed)
|
||||
&& conn
|
||||
.browser_context_by_id_mut(browser_context_id)
|
||||
.and_then(|context| {
|
||||
context
|
||||
.dedicated_worker_targets
|
||||
.get_mut(&renderer_instance_id)
|
||||
})
|
||||
.is_some_and(|target| target.defer_renderer_destroyed_for_debugger_resume())
|
||||
{
|
||||
return outputs;
|
||||
}
|
||||
let target_id = match conn
|
||||
.browser_context_by_id(browser_context_id)
|
||||
.and_then(|context| {
|
||||
context.dedicated_worker_target_id_for_renderer_instance(renderer_instance_id)
|
||||
}) {
|
||||
Some(target_id) => target_id.to_owned(),
|
||||
None => return outputs,
|
||||
};
|
||||
let destroyed_delta = conn
|
||||
.has_any_target_discovery()
|
||||
.then(|| conn.prepare_destroyed_target_host_delta(&target_id))
|
||||
.flatten();
|
||||
let mut detached_delta = conn
|
||||
.browser_context_by_id(browser_context_id)
|
||||
.and_then(|context| {
|
||||
let target = context.dedicated_worker_target(&target_id)?;
|
||||
if !target.has_session() {
|
||||
return None;
|
||||
}
|
||||
let mut target_info = context.devtools_target_info(&target_id)?;
|
||||
target_info.attached = false;
|
||||
Some(PreparedTargetHostDelta::info_changed(
|
||||
target_id.clone(),
|
||||
Some(target_info),
|
||||
))
|
||||
});
|
||||
let Some(context) = conn.browser_context_by_id(browser_context_id) else {
|
||||
return outputs;
|
||||
};
|
||||
let Some(target) = context.dedicated_worker_targets.get(&renderer_instance_id) else {
|
||||
return outputs;
|
||||
};
|
||||
for session_id in target.session_ids() {
|
||||
outputs.push(WorkerTargetLifecycleOutput::DedicatedWorkerDetached {
|
||||
target_delta: detached_delta.take(),
|
||||
cleanup_plan: TargetSessionDetachCleanupPlan::new(
|
||||
target_id.clone(),
|
||||
session_id,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
});
|
||||
}
|
||||
outputs.push(WorkerTargetLifecycleOutput::DedicatedWorkerDestroyed {
|
||||
browser_context_id: browser_context_id.to_owned(),
|
||||
renderer_instance_id,
|
||||
target_id,
|
||||
target_delta: destroyed_delta,
|
||||
});
|
||||
outputs
|
||||
}
|
||||
@@ -0,0 +1,566 @@
|
||||
use super::*;
|
||||
|
||||
pub(in crate::domains) async fn project_worker_target_output_async(
|
||||
output: ProtocolOutputSlot,
|
||||
conn: &mut CdpConnection,
|
||||
context: &mut ProtocolOutputProjectionContext<'_>,
|
||||
prepared_outputs: Option<&mut ProtocolOutputPayloads>,
|
||||
) {
|
||||
match output {
|
||||
ProtocolOutputSlot::SharedWorkerTargetLifecycle
|
||||
| ProtocolOutputSlot::ServiceWorkerTargetLifecycle
|
||||
| ProtocolOutputSlot::DedicatedWorkerTargetLifecycle => {}
|
||||
_ => panic!("non-Target output routed through the Target projector: {output:?}"),
|
||||
}
|
||||
emit_target_lifecycle_events(conn, context, prepared_outputs).await;
|
||||
}
|
||||
|
||||
pub(super) async fn emit_target_lifecycle_events(
|
||||
conn: &mut CdpConnection,
|
||||
context: &mut ProtocolOutputProjectionContext<'_>,
|
||||
prepared_outputs: Option<&mut ProtocolOutputPayloads>,
|
||||
) {
|
||||
let Some(events) = prepared_outputs
|
||||
.and_then(ProtocolOutputPayloads::target_mut)
|
||||
.and_then(TargetPreparedOutputSlot::take_worker_target_lifecycle_outputs)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let mut side_effects = events::TargetProtocolSideEffects::default();
|
||||
for event in events {
|
||||
let event = match commit_dedicated_worker_retirement_output_async(conn, event).await {
|
||||
Ok(events) => {
|
||||
side_effects.extend_background_events(events);
|
||||
continue;
|
||||
}
|
||||
Err(event) => event,
|
||||
};
|
||||
match event {
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerEvents {
|
||||
browser_context_id,
|
||||
renderer_instance_id,
|
||||
target_id,
|
||||
events,
|
||||
} => {
|
||||
if dedicated_worker_target_is_current(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
renderer_instance_id,
|
||||
&target_id,
|
||||
) {
|
||||
side_effects.extend_background_events(events);
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerConsoleMessages {
|
||||
browser_context_id,
|
||||
renderer_instance_id,
|
||||
target_id,
|
||||
session_id,
|
||||
console_messages,
|
||||
runtime_messages,
|
||||
console_end,
|
||||
} => {
|
||||
if !dedicated_worker_target_is_current(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
renderer_instance_id,
|
||||
&target_id,
|
||||
) || !conn
|
||||
.browser_context_by_id(&browser_context_id)
|
||||
.and_then(|context| context.dedicated_worker_targets.get(&renderer_instance_id))
|
||||
.is_some_and(|target| target.is_session(&session_id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
side_effects.extend_background_events(console_message_added_events(
|
||||
&session_id,
|
||||
&console_messages,
|
||||
));
|
||||
side_effects.extend_background_events(runtime_console_api_called_events(
|
||||
&session_id,
|
||||
&runtime_messages,
|
||||
));
|
||||
if let Some(target) = conn
|
||||
.browser_context_by_id_mut(&browser_context_id)
|
||||
.and_then(|context| {
|
||||
context
|
||||
.dedicated_worker_targets
|
||||
.get_mut(&renderer_instance_id)
|
||||
})
|
||||
.filter(|target| target.target_id == target_id)
|
||||
{
|
||||
if !console_messages.is_empty() {
|
||||
target.mark_console_domain_emitted(&session_id, console_end);
|
||||
}
|
||||
if !runtime_messages.is_empty() {
|
||||
target.mark_runtime_console_emitted(&session_id, console_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerCreated {
|
||||
browser_context_id,
|
||||
renderer_instance_id,
|
||||
target_delta,
|
||||
} => {
|
||||
if dedicated_worker_target_is_current(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
renderer_instance_id,
|
||||
target_delta.target_id(),
|
||||
) {
|
||||
side_effects.extend_background_events(
|
||||
conn.prepared_target_host_delta_event_plan(target_delta),
|
||||
);
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerInfoChanged {
|
||||
browser_context_id,
|
||||
renderer_instance_id,
|
||||
target_id,
|
||||
target_delta,
|
||||
} => {
|
||||
if dedicated_worker_target_is_current(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
renderer_instance_id,
|
||||
&target_id,
|
||||
) {
|
||||
side_effects.extend_background_events(
|
||||
conn.prepared_target_host_delta_event_plan(target_delta),
|
||||
);
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerAttached {
|
||||
browser_context_id,
|
||||
renderer_instance_id,
|
||||
target_id,
|
||||
session_id,
|
||||
prepared_attach,
|
||||
} => {
|
||||
let current = conn
|
||||
.browser_context_by_id(&browser_context_id)
|
||||
.and_then(|context| context.dedicated_worker_targets.get(&renderer_instance_id))
|
||||
.is_some_and(|target| {
|
||||
target.target_id == target_id && target.is_session(&session_id)
|
||||
});
|
||||
if current {
|
||||
side_effects.extend_background_events(
|
||||
conn.commit_prepared_dedicated_worker_attach_event_plan(prepared_attach),
|
||||
);
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerDetached { .. }
|
||||
| WorkerTargetLifecycleOutput::DedicatedWorkerDestroyed { .. } => {
|
||||
unreachable!("DedicatedWorker retirement outputs are committed before projection")
|
||||
}
|
||||
WorkerTargetLifecycleOutput::SharedWorkerAttachmentEvents { attachment, events } => {
|
||||
if attachment.is_current() {
|
||||
side_effects.extend_background_events(events);
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::SharedWorkerCreated { target_delta } => {
|
||||
side_effects.extend_background_events(
|
||||
conn.prepared_target_host_delta_event_plan(target_delta),
|
||||
);
|
||||
}
|
||||
WorkerTargetLifecycleOutput::SharedWorkerAttached {
|
||||
attachment,
|
||||
prepared_attach,
|
||||
} => {
|
||||
if !attachment.is_current() {
|
||||
continue;
|
||||
}
|
||||
side_effects.extend_background_events(
|
||||
conn.commit_prepared_attach_event_plan(prepared_attach),
|
||||
);
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerVersionEvents { version, events } => {
|
||||
if version.is_current() {
|
||||
side_effects.extend_background_events(events);
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerAttachmentEvents { attachment, events } => {
|
||||
if attachment.is_current() {
|
||||
side_effects.extend_background_events(events);
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerRunEvents { run, events } => {
|
||||
if run.is_current() {
|
||||
side_effects.extend_background_events(events);
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerRuntimeEvents { runtime, events } => {
|
||||
if runtime.is_current() {
|
||||
side_effects.extend_background_events(events);
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerCreated {
|
||||
version,
|
||||
target_delta,
|
||||
} => {
|
||||
if version.is_current() {
|
||||
side_effects.extend_background_events(
|
||||
conn.prepared_target_host_delta_event_plan(target_delta),
|
||||
);
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerAttached {
|
||||
attachment,
|
||||
prepared_attach,
|
||||
} => {
|
||||
if attachment.is_current() {
|
||||
side_effects.extend_background_events(
|
||||
conn.commit_prepared_attach_event_plan(prepared_attach),
|
||||
);
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::SharedWorkerDetached {
|
||||
retirement,
|
||||
cleanup_plan,
|
||||
} => {
|
||||
if !retirement.is_current() {
|
||||
continue;
|
||||
}
|
||||
assert_eq!(
|
||||
cleanup_plan.target_id(),
|
||||
retirement.identity().target_id(),
|
||||
"shared-worker detach plan must retain its exact target"
|
||||
);
|
||||
assert_eq!(
|
||||
cleanup_plan.session_id(),
|
||||
retirement.identity().session_id(),
|
||||
"shared-worker detach plan must retain its exact attachment"
|
||||
);
|
||||
let event_plan =
|
||||
super::super::session_disposal::dispose_removed_worker_session_async(
|
||||
conn,
|
||||
cleanup_plan,
|
||||
)
|
||||
.await
|
||||
.expect("retired shared-worker session cleanup should succeed");
|
||||
side_effects.extend_background_events(event_plan);
|
||||
retirement.retire();
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerDetached {
|
||||
retirement,
|
||||
cleanup_plan,
|
||||
} => {
|
||||
if !retirement.is_current() {
|
||||
continue;
|
||||
}
|
||||
assert_eq!(
|
||||
cleanup_plan.target_id(),
|
||||
retirement.identity().target_id(),
|
||||
"service-worker detach plan must retain its exact version target"
|
||||
);
|
||||
assert_eq!(
|
||||
cleanup_plan.session_id(),
|
||||
retirement.identity().session_id(),
|
||||
"service-worker detach plan must retain its exact attachment"
|
||||
);
|
||||
let event_plan =
|
||||
super::super::session_disposal::dispose_removed_worker_session_async(
|
||||
conn,
|
||||
cleanup_plan,
|
||||
)
|
||||
.await
|
||||
.expect("retired service-worker session cleanup should succeed");
|
||||
side_effects.extend_background_events(event_plan);
|
||||
retirement.retire();
|
||||
}
|
||||
WorkerTargetLifecycleOutput::SharedWorkerDestroyed { target_delta } => {
|
||||
side_effects.extend_background_events(
|
||||
conn.prepared_target_host_delta_event_plan(target_delta),
|
||||
);
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerRunRetired { retirement } => {
|
||||
assert!(
|
||||
retirement.is_current(),
|
||||
"service-worker run retirement must be consumed exactly once in source order"
|
||||
);
|
||||
retirement.retire();
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerDestroyed {
|
||||
retirement,
|
||||
target_delta,
|
||||
} => {
|
||||
assert!(
|
||||
retirement.is_current(),
|
||||
"service-worker version retirement must be consumed exactly once"
|
||||
);
|
||||
if let Some(target_delta) = target_delta {
|
||||
assert_eq!(
|
||||
target_delta.target_id(),
|
||||
retirement.identity().target_id(),
|
||||
"service-worker destruction must retain its exact version target"
|
||||
);
|
||||
side_effects.extend_background_events(
|
||||
conn.prepared_target_host_delta_event_plan(target_delta),
|
||||
);
|
||||
}
|
||||
retirement.retire();
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerConsoleMessages {
|
||||
runtime,
|
||||
messages,
|
||||
console_end: _,
|
||||
} => {
|
||||
if runtime.is_current() {
|
||||
side_effects.extend_background_events(console_message_added_events(
|
||||
runtime.session_id(),
|
||||
&messages,
|
||||
));
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::SharedWorkerConsoleMessages {
|
||||
attachment,
|
||||
messages,
|
||||
console_end,
|
||||
} => {
|
||||
if !attachment.is_current() {
|
||||
continue;
|
||||
}
|
||||
side_effects.extend_background_events(console_message_added_events(
|
||||
attachment.session_id(),
|
||||
&messages,
|
||||
));
|
||||
mark_exact_shared_worker_console_domain_emitted(conn, &attachment, console_end);
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerRuntimeConsoleMessages {
|
||||
runtime,
|
||||
messages,
|
||||
console_end: _,
|
||||
} => {
|
||||
if runtime.is_current() {
|
||||
side_effects.extend_background_events(runtime_console_api_called_events(
|
||||
runtime.session_id(),
|
||||
&messages,
|
||||
));
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::SharedWorkerRuntimeConsoleMessages {
|
||||
attachment,
|
||||
messages,
|
||||
console_end,
|
||||
} => {
|
||||
if !attachment.is_current() {
|
||||
continue;
|
||||
}
|
||||
side_effects.extend_background_events(runtime_console_api_called_events(
|
||||
attachment.session_id(),
|
||||
&messages,
|
||||
));
|
||||
mark_exact_shared_worker_runtime_console_emitted(conn, &attachment, console_end);
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerRuntimeExceptionMessages {
|
||||
runtime,
|
||||
messages,
|
||||
exception_start,
|
||||
exception_end: _,
|
||||
} => {
|
||||
if runtime.is_current() {
|
||||
side_effects.extend_background_events(runtime_exception_thrown_events(
|
||||
runtime.session_id(),
|
||||
&messages,
|
||||
exception_start,
|
||||
));
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerFetchDiagnostics {
|
||||
runtime,
|
||||
diagnostics,
|
||||
diagnostic_start,
|
||||
diagnostic_end: _,
|
||||
} => {
|
||||
if runtime.is_current() {
|
||||
side_effects.extend_background_events(service_worker_fetch_diagnostic_events(
|
||||
runtime.session_id(),
|
||||
runtime.target_id(),
|
||||
&diagnostics,
|
||||
diagnostic_start,
|
||||
));
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::ServiceWorkerRuntimeInspectorMessages {
|
||||
runtime,
|
||||
background_events,
|
||||
response_events,
|
||||
pending_runtime_console,
|
||||
pending_runtime_exceptions,
|
||||
} => {
|
||||
if !runtime.is_current() {
|
||||
continue;
|
||||
}
|
||||
let session_id = runtime.session_id();
|
||||
side_effects.extend_background_events(background_events);
|
||||
if service_worker_runtime_is_registry_current(conn, &runtime) {
|
||||
replay_shared_worker_runtime_bindings_for_session_async(conn, Some(session_id))
|
||||
.await;
|
||||
}
|
||||
side_effects.extend_background_events(response_events);
|
||||
if let Some((messages, _console_end)) = pending_runtime_console {
|
||||
side_effects.extend_background_events(runtime_console_api_called_events(
|
||||
session_id, &messages,
|
||||
));
|
||||
}
|
||||
if let Some((messages, exception_start, _exception_end)) =
|
||||
pending_runtime_exceptions
|
||||
{
|
||||
side_effects.extend_background_events(runtime_exception_thrown_events(
|
||||
session_id,
|
||||
&messages,
|
||||
exception_start,
|
||||
));
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::SharedWorkerRuntimeInspectorMessages {
|
||||
attachment,
|
||||
messages,
|
||||
} => {
|
||||
if !attachment.is_current() {
|
||||
continue;
|
||||
}
|
||||
let session_id = attachment.session_id();
|
||||
let mut response_events = Vec::new();
|
||||
let mut background_events = Vec::new();
|
||||
let current_response_seen = route_worker_runtime_inspector_messages_into(
|
||||
conn,
|
||||
messages,
|
||||
session_id,
|
||||
&mut response_events,
|
||||
&mut background_events,
|
||||
);
|
||||
debug_assert!(!current_response_seen);
|
||||
side_effects.extend_background_events(background_events);
|
||||
let pending_runtime_console =
|
||||
exact_shared_worker_pending_runtime_console(conn, &attachment);
|
||||
replay_shared_worker_runtime_bindings_for_session_async(conn, Some(session_id))
|
||||
.await;
|
||||
side_effects.extend_background_events(response_events);
|
||||
if let Some((messages, console_end)) = pending_runtime_console {
|
||||
side_effects.extend_background_events(runtime_console_api_called_events(
|
||||
session_id, &messages,
|
||||
));
|
||||
mark_exact_shared_worker_runtime_console_emitted(
|
||||
conn,
|
||||
&attachment,
|
||||
console_end,
|
||||
);
|
||||
}
|
||||
}
|
||||
WorkerTargetLifecycleOutput::DedicatedWorkerRuntimeInspectorMessages {
|
||||
browser_context_id,
|
||||
renderer_instance_id,
|
||||
target_id,
|
||||
session_id,
|
||||
messages,
|
||||
} => {
|
||||
if !dedicated_worker_target_is_current(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
renderer_instance_id,
|
||||
&target_id,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
let mut response_events = Vec::new();
|
||||
let mut background_events = Vec::new();
|
||||
let current_response_seen = route_worker_runtime_inspector_messages_into(
|
||||
conn,
|
||||
messages,
|
||||
&session_id,
|
||||
&mut response_events,
|
||||
&mut background_events,
|
||||
);
|
||||
debug_assert!(!current_response_seen);
|
||||
side_effects.extend_background_events(background_events);
|
||||
replay_shared_worker_runtime_bindings_for_session_async(conn, Some(&session_id))
|
||||
.await;
|
||||
side_effects.extend_background_events(response_events);
|
||||
}
|
||||
}
|
||||
}
|
||||
for event in side_effects.into_background_events() {
|
||||
context.command.push_protocol_event(event);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn route_worker_runtime_inspector_messages_into(
|
||||
conn: &mut CdpConnection,
|
||||
messages: Vec<RendererRuntimeInspectorMessage>,
|
||||
session_id: &str,
|
||||
response_events: &mut Vec<BackgroundProtocolEvent>,
|
||||
background_events: &mut Vec<BackgroundProtocolEvent>,
|
||||
) -> bool {
|
||||
let owner = crate::conn::CommandOwnerScope::for_session(session_id);
|
||||
conn.route_renderer_runtime_inspector_messages_for_owner_with_background_events_into(
|
||||
messages,
|
||||
None,
|
||||
&owner,
|
||||
response_events,
|
||||
background_events,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn console_message_added_events(
|
||||
session_id: &str,
|
||||
messages: &[RuntimeConsoleMessageSnapshot],
|
||||
) -> Vec<BackgroundProtocolEvent> {
|
||||
messages
|
||||
.iter()
|
||||
.map(|message| {
|
||||
let (level, text) = console_message_level_and_text(&message.message);
|
||||
console_message_added_background_event(Some(session_id), "console-api", level, text, "")
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(super) fn runtime_console_api_called_events(
|
||||
session_id: &str,
|
||||
messages: &[RuntimeConsoleMessageSnapshot],
|
||||
) -> Vec<BackgroundProtocolEvent> {
|
||||
let base_timestamp = monotonic_timestamp_seconds();
|
||||
messages
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, message)| {
|
||||
let (console_type, text) = runtime_console_message_type_and_text(&message.message);
|
||||
runtime_console_api_called_background_event(
|
||||
Some(session_id),
|
||||
None,
|
||||
console_type,
|
||||
text,
|
||||
&message.args,
|
||||
message.stack.as_deref(),
|
||||
message.execution_context_id,
|
||||
base_timestamp + ((index + 1) as f64 * 0.000_001),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(super) fn runtime_exception_thrown_events(
|
||||
session_id: &str,
|
||||
messages: &[ServiceWorkerRuntimeExceptionSnapshot],
|
||||
exception_start: usize,
|
||||
) -> Vec<BackgroundProtocolEvent> {
|
||||
let base_timestamp = monotonic_timestamp_seconds();
|
||||
messages
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(offset, message)| {
|
||||
let exception_index = exception_start + offset;
|
||||
runtime_exception_thrown_background_event(
|
||||
Some(session_id),
|
||||
None,
|
||||
&message.message.message,
|
||||
&message.message.filename,
|
||||
message.execution_context_id,
|
||||
exception_index,
|
||||
base_timestamp + ((offset + 1) as f64 * 0.000_001),
|
||||
Some(u64::from(message.message.lineno.saturating_sub(1))),
|
||||
Some(u64::from(message.message.colno.saturating_sub(1))),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
use super::*;
|
||||
|
||||
pub(super) fn push_service_worker_version_events(
|
||||
outputs: &mut TargetPreparedOutputs,
|
||||
version: TargetServiceWorkerVersionIdentity,
|
||||
events: Vec<BackgroundProtocolEvent>,
|
||||
) {
|
||||
if events.is_empty() {
|
||||
return;
|
||||
}
|
||||
outputs.push(WorkerTargetLifecycleOutput::ServiceWorkerVersionEvents { version, events });
|
||||
}
|
||||
|
||||
pub(super) fn push_service_worker_run_events(
|
||||
outputs: &mut TargetPreparedOutputs,
|
||||
run: TargetServiceWorkerRunIdentity,
|
||||
events: Vec<BackgroundProtocolEvent>,
|
||||
) {
|
||||
if events.is_empty() {
|
||||
return;
|
||||
}
|
||||
outputs.push(WorkerTargetLifecycleOutput::ServiceWorkerRunEvents { run, events });
|
||||
}
|
||||
|
||||
pub(super) fn push_service_worker_attachment_events(
|
||||
outputs: &mut TargetPreparedOutputs,
|
||||
attachment: TargetServiceWorkerProtocolAttachmentIdentity,
|
||||
events: Vec<BackgroundProtocolEvent>,
|
||||
) {
|
||||
if events.is_empty() {
|
||||
return;
|
||||
}
|
||||
outputs.push(WorkerTargetLifecycleOutput::ServiceWorkerAttachmentEvents { attachment, events });
|
||||
}
|
||||
|
||||
pub(super) fn push_service_worker_runtime_events(
|
||||
outputs: &mut TargetPreparedOutputs,
|
||||
runtime: TargetServiceWorkerRuntimeAttachmentIdentity,
|
||||
events: Vec<BackgroundProtocolEvent>,
|
||||
) {
|
||||
if events.is_empty() {
|
||||
return;
|
||||
}
|
||||
outputs.push(WorkerTargetLifecycleOutput::ServiceWorkerRuntimeEvents { runtime, events });
|
||||
}
|
||||
|
||||
pub(super) fn shared_worker_target_lifecycle_outputs_for_events(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: String,
|
||||
events: Vec<RendererSharedWorkerTargetEvent>,
|
||||
) -> TargetPreparedOutputs {
|
||||
let mut outputs = TargetPreparedOutputs::default();
|
||||
for event in events {
|
||||
match event {
|
||||
RendererSharedWorkerTargetEvent::Created(info) => {
|
||||
let owner_target_id =
|
||||
conn.browser_context_by_id(&browser_context_id)
|
||||
.and_then(|context| {
|
||||
context.target_id_for_renderer_owner_local_host_id(
|
||||
info.owner_local_host_id,
|
||||
)
|
||||
});
|
||||
outputs.extend(register_shared_worker_target(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
owner_target_id,
|
||||
info,
|
||||
));
|
||||
}
|
||||
RendererSharedWorkerTargetEvent::Destroyed { instance_id } => {
|
||||
outputs.extend(remove_shared_worker_target(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
instance_id,
|
||||
));
|
||||
}
|
||||
RendererSharedWorkerTargetEvent::Console {
|
||||
instance_id,
|
||||
message,
|
||||
} => {
|
||||
outputs.extend(record_shared_worker_target_console_message(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
instance_id,
|
||||
message,
|
||||
));
|
||||
}
|
||||
RendererSharedWorkerTargetEvent::RuntimeInspectorMessages {
|
||||
instance_id,
|
||||
inspector_session_id,
|
||||
messages,
|
||||
} => {
|
||||
outputs.extend(record_shared_worker_target_runtime_inspector_messages(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
instance_id,
|
||||
inspector_session_id,
|
||||
messages,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
outputs
|
||||
}
|
||||
|
||||
pub(in crate::domains) fn shared_worker_target_lifecycle_prepared_outputs_for_event(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: String,
|
||||
event: RendererSharedWorkerTargetEvent,
|
||||
) -> TargetPreparedOutputs {
|
||||
shared_worker_target_lifecycle_outputs_for_events(conn, browser_context_id, vec![event])
|
||||
}
|
||||
|
||||
pub(in crate::domains) fn service_worker_target_lifecycle_prepared_outputs_for_event(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: String,
|
||||
event: RendererServiceWorkerTargetEvent,
|
||||
) -> TargetPreparedOutputs {
|
||||
service_worker_target_lifecycle_outputs_for_events(conn, browser_context_id, vec![event])
|
||||
}
|
||||
|
||||
pub(in crate::domains) fn dedicated_worker_target_lifecycle_prepared_outputs_for_event(
|
||||
conn: &mut CdpConnection,
|
||||
owner: &CommandOwnerScope,
|
||||
event: RendererDedicatedWorkerTargetEvent,
|
||||
) -> TargetPreparedOutputs {
|
||||
let Some(owner_page) = conn.target_page_residence_identity_for_owner(owner) else {
|
||||
return TargetPreparedOutputs::default();
|
||||
};
|
||||
let Some(owner_renderer_page) = conn.renderer_page_residence_identity_for_owner(owner) else {
|
||||
return TargetPreparedOutputs::default();
|
||||
};
|
||||
let browser_context_id = owner_page.browser_context_id().to_owned();
|
||||
let owner_page_network_sessions = conn.network_event_session_ids_for_owner(owner);
|
||||
dedicated_worker_target_lifecycle_outputs_for_events(
|
||||
conn,
|
||||
browser_context_id,
|
||||
owner_page,
|
||||
owner_renderer_page,
|
||||
owner_page_network_sessions,
|
||||
vec![event],
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn dedicated_worker_target_lifecycle_outputs_for_events(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: String,
|
||||
owner_page: TargetPageResidenceIdentity,
|
||||
owner_renderer_page: RendererPageResidenceIdentity,
|
||||
owner_page_network_sessions: Vec<Option<String>>,
|
||||
events: Vec<RendererDedicatedWorkerTargetEvent>,
|
||||
) -> TargetPreparedOutputs {
|
||||
let mut outputs = TargetPreparedOutputs::default();
|
||||
for event in events {
|
||||
match event {
|
||||
RendererDedicatedWorkerTargetEvent::Created(info) => {
|
||||
outputs.extend(register_dedicated_worker_target(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
owner_page.clone(),
|
||||
owner_renderer_page,
|
||||
owner_page_network_sessions.clone(),
|
||||
info,
|
||||
));
|
||||
}
|
||||
RendererDedicatedWorkerTargetEvent::ScriptLoaded {
|
||||
instance_id,
|
||||
script_url,
|
||||
response,
|
||||
} => {
|
||||
outputs.extend(record_dedicated_worker_main_script(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
instance_id,
|
||||
script_url,
|
||||
crate::conn::DedicatedWorkerMainScriptOutcome::Loaded(response),
|
||||
));
|
||||
}
|
||||
RendererDedicatedWorkerTargetEvent::ScriptLoadFailed {
|
||||
instance_id,
|
||||
script_url,
|
||||
error_message,
|
||||
response,
|
||||
} => {
|
||||
outputs.extend(record_dedicated_worker_main_script(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
instance_id,
|
||||
script_url,
|
||||
crate::conn::DedicatedWorkerMainScriptOutcome::Failed {
|
||||
error_message,
|
||||
response,
|
||||
},
|
||||
));
|
||||
}
|
||||
RendererDedicatedWorkerTargetEvent::Console {
|
||||
instance_id,
|
||||
message,
|
||||
} => {
|
||||
outputs.extend(record_dedicated_worker_target_console_message(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
instance_id,
|
||||
message,
|
||||
));
|
||||
}
|
||||
RendererDedicatedWorkerTargetEvent::RuntimeInspectorMessages {
|
||||
instance_id,
|
||||
inspector_session_id,
|
||||
messages,
|
||||
} => {
|
||||
outputs.extend(record_dedicated_worker_target_runtime_inspector_messages(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
instance_id,
|
||||
inspector_session_id,
|
||||
messages,
|
||||
));
|
||||
}
|
||||
RendererDedicatedWorkerTargetEvent::Destroyed { instance_id } => {
|
||||
outputs.extend(prepare_dedicated_worker_target_retirement(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
instance_id,
|
||||
DedicatedWorkerRetirementCause::RendererDestroyed,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
outputs
|
||||
}
|
||||
|
||||
pub(super) fn service_worker_target_lifecycle_outputs_for_events(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: String,
|
||||
events: Vec<RendererServiceWorkerTargetEvent>,
|
||||
) -> TargetPreparedOutputs {
|
||||
let mut outputs = TargetPreparedOutputs::default();
|
||||
for event in events {
|
||||
match event {
|
||||
RendererServiceWorkerTargetEvent::Created { info, active_run } => {
|
||||
outputs.extend(register_service_worker_target_with_active_run(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
info,
|
||||
active_run,
|
||||
));
|
||||
}
|
||||
RendererServiceWorkerTargetEvent::Started { version_id, run } => {
|
||||
outputs.extend(record_service_worker_target_started(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
version_id,
|
||||
run,
|
||||
));
|
||||
}
|
||||
RendererServiceWorkerTargetEvent::Stopped {
|
||||
version_id,
|
||||
run,
|
||||
reason,
|
||||
} => {
|
||||
outputs.extend(record_service_worker_target_stopped(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
version_id,
|
||||
run,
|
||||
reason,
|
||||
));
|
||||
}
|
||||
RendererServiceWorkerTargetEvent::Destroyed {
|
||||
version_id,
|
||||
active_run,
|
||||
} => {
|
||||
outputs.extend(remove_service_worker_target(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
version_id,
|
||||
active_run,
|
||||
));
|
||||
}
|
||||
RendererServiceWorkerTargetEvent::VersionUpdated { version_id, status } => {
|
||||
outputs.extend(record_service_worker_target_version_updated(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
version_id,
|
||||
status,
|
||||
));
|
||||
}
|
||||
RendererServiceWorkerTargetEvent::Console {
|
||||
version_id,
|
||||
run,
|
||||
message,
|
||||
} => {
|
||||
outputs.extend(record_service_worker_target_console_message(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
version_id,
|
||||
run,
|
||||
message,
|
||||
));
|
||||
}
|
||||
RendererServiceWorkerTargetEvent::Exception {
|
||||
version_id,
|
||||
run,
|
||||
message,
|
||||
} => {
|
||||
outputs.extend(record_service_worker_target_exception_message(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
version_id,
|
||||
run,
|
||||
message,
|
||||
));
|
||||
}
|
||||
RendererServiceWorkerTargetEvent::FetchDiagnostic {
|
||||
version_id,
|
||||
run,
|
||||
diagnostic,
|
||||
} => {
|
||||
outputs.extend(record_service_worker_target_fetch_diagnostic(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
version_id,
|
||||
run,
|
||||
diagnostic,
|
||||
));
|
||||
}
|
||||
RendererServiceWorkerTargetEvent::RuntimeInspectorMessages {
|
||||
version_id,
|
||||
run,
|
||||
inspector_session_id,
|
||||
messages,
|
||||
} => {
|
||||
outputs.extend(record_service_worker_target_runtime_inspector_messages(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
version_id,
|
||||
run,
|
||||
inspector_session_id,
|
||||
messages,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
outputs
|
||||
}
|
||||
|
||||
pub(super) fn append_service_worker_domain_snapshot(
|
||||
conn: &CdpConnection,
|
||||
browser_context_id: &str,
|
||||
version: TargetServiceWorkerVersionIdentity,
|
||||
outputs: &mut TargetPreparedOutputs,
|
||||
) {
|
||||
let session_ids =
|
||||
service_worker::enabled_sessions_for_browser_context(conn, browser_context_id);
|
||||
if session_ids.is_empty() {
|
||||
return;
|
||||
}
|
||||
let events =
|
||||
service_worker::snapshot_events_for_browser_context(conn, browser_context_id, &session_ids);
|
||||
push_service_worker_version_events(outputs, version, events);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,433 @@
|
||||
use super::*;
|
||||
|
||||
pub(super) fn register_shared_worker_target(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: &str,
|
||||
owner_target_id: Option<String>,
|
||||
info: RendererSharedWorkerTargetInfo,
|
||||
) -> TargetPreparedOutputs {
|
||||
let mut outputs = TargetPreparedOutputs::default();
|
||||
if conn
|
||||
.browser_context_by_id(browser_context_id)
|
||||
.and_then(|context| context.shared_worker_target_id_for_renderer_instance(info.instance_id))
|
||||
.is_some()
|
||||
{
|
||||
return outputs;
|
||||
}
|
||||
let target_id = conn.gen_target_id();
|
||||
let should_emit_created = conn.has_any_target_discovery();
|
||||
let auto_attach_owners = shared_worker_auto_attach_owner_sessions(conn);
|
||||
let attached_sessions = auto_attach_owners
|
||||
.iter()
|
||||
.map(|owner| {
|
||||
(
|
||||
owner.clone(),
|
||||
conn.gen_session_id(),
|
||||
conn.auto_attach_owner_waits_for_debugger_on_start(owner.as_deref()),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let created_snapshot = {
|
||||
let Some(context) = conn.browser_context_by_id_mut(browser_context_id) else {
|
||||
return outputs;
|
||||
};
|
||||
context.insert_shared_worker_target(SharedWorkerTargetState::new(
|
||||
info.owner_local_host_id,
|
||||
info.instance_id,
|
||||
target_id.clone(),
|
||||
owner_target_id,
|
||||
info.url,
|
||||
info.name,
|
||||
));
|
||||
if should_emit_created {
|
||||
let snapshot = context.devtools_target_info(&target_id);
|
||||
debug_assert!(snapshot.is_some());
|
||||
snapshot
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
let mut attached_outputs = Vec::new();
|
||||
for (owner_session_id, session_id, waiting_for_debugger) in attached_sessions {
|
||||
if let Some(target_info) = conn
|
||||
.prepare_auto_attached_shared_worker_session_binding_info_in_browser_context(
|
||||
browser_context_id,
|
||||
&target_id,
|
||||
session_id.clone(),
|
||||
)
|
||||
{
|
||||
let attachment = conn
|
||||
.browser_context_by_id(browser_context_id)
|
||||
.and_then(|context| context.shared_worker_target(&target_id))
|
||||
.and_then(|target| {
|
||||
target.protocol_attachment_identity(browser_context_id, &session_id)
|
||||
})
|
||||
.expect("new shared-worker session must expose its exact attachment identity");
|
||||
let prepared_session = TargetAttachSessionCommit::auto_attached(
|
||||
session_id,
|
||||
owner_session_id,
|
||||
CdpSessionRoute::SharedWorkerTarget {
|
||||
browser_context_id: browser_context_id.to_owned(),
|
||||
target_id: target_id.clone(),
|
||||
},
|
||||
waiting_for_debugger,
|
||||
);
|
||||
assert!(
|
||||
matches!(
|
||||
prepared_session.route(),
|
||||
CdpSessionRoute::SharedWorkerTarget {
|
||||
browser_context_id: route_browser_context_id,
|
||||
target_id: route_target_id,
|
||||
} if route_browser_context_id == browser_context_id
|
||||
&& route_target_id == &target_id
|
||||
),
|
||||
"shared-worker auto-attach must freeze its exact target route at capture"
|
||||
);
|
||||
attached_outputs.push((
|
||||
attachment,
|
||||
PreparedTargetAttach::new(target_id.clone(), target_info, [prepared_session]),
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(target_info) = created_snapshot {
|
||||
outputs.push(WorkerTargetLifecycleOutput::SharedWorkerCreated {
|
||||
target_delta: PreparedTargetHostDelta::created(target_id.clone(), Some(target_info)),
|
||||
});
|
||||
}
|
||||
for (attachment, prepared_attach) in attached_outputs {
|
||||
outputs.push(WorkerTargetLifecycleOutput::SharedWorkerAttached {
|
||||
attachment,
|
||||
prepared_attach,
|
||||
});
|
||||
}
|
||||
outputs
|
||||
}
|
||||
|
||||
pub(super) fn remove_shared_worker_target(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: &str,
|
||||
renderer_instance_id: SharedWorkerInstanceId,
|
||||
) -> TargetPreparedOutputs {
|
||||
remove_shared_worker_target_with_reason(
|
||||
conn,
|
||||
browser_context_id,
|
||||
renderer_instance_id,
|
||||
"Target closed",
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn remove_shared_worker_target_with_reason(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: &str,
|
||||
renderer_instance_id: SharedWorkerInstanceId,
|
||||
reason: &'static str,
|
||||
) -> TargetPreparedOutputs {
|
||||
let mut outputs = TargetPreparedOutputs::default();
|
||||
let should_emit_destroyed = conn.has_any_target_discovery();
|
||||
let target_id = {
|
||||
let Some(context) = conn.browser_context_by_id(browser_context_id) else {
|
||||
return outputs;
|
||||
};
|
||||
let Some(target_id) = context
|
||||
.shared_worker_target_id_for_renderer_instance(renderer_instance_id)
|
||||
.map(str::to_owned)
|
||||
else {
|
||||
return outputs;
|
||||
};
|
||||
target_id
|
||||
};
|
||||
let destroyed_delta = should_emit_destroyed
|
||||
.then(|| conn.prepare_destroyed_target_host_delta(&target_id))
|
||||
.flatten();
|
||||
let Some(context) = conn.browser_context_by_id_mut(browser_context_id) else {
|
||||
return outputs;
|
||||
};
|
||||
let Some(mut target) =
|
||||
context.remove_shared_worker_target_by_renderer_instance(renderer_instance_id)
|
||||
else {
|
||||
return outputs;
|
||||
};
|
||||
let session_ids = target.session_ids();
|
||||
let mut pending_await_direct_outputs = Vec::new();
|
||||
let mut pending_await_claimed_outputs = Vec::new();
|
||||
for session_id in &session_ids {
|
||||
let attachment = target
|
||||
.protocol_attachment_identity(browser_context_id, session_id)
|
||||
.expect("removed shared-worker session must retain its exact attachment identity");
|
||||
let mut pending_await_direct_events = Vec::new();
|
||||
let mut pending_await_claimed_events = Vec::new();
|
||||
conn.fail_pending_inspector_awaits_for_session_owner_background_events_into(
|
||||
&mut pending_await_direct_events,
|
||||
&mut pending_await_claimed_events,
|
||||
Some(session_id),
|
||||
reason,
|
||||
);
|
||||
CdpConnection::fail_pending_inspector_awaits_from_shared_worker_target_session_background_events_into(
|
||||
&mut pending_await_direct_events,
|
||||
&mut target,
|
||||
session_id,
|
||||
reason,
|
||||
);
|
||||
if !pending_await_direct_events.is_empty() {
|
||||
pending_await_direct_outputs.push((attachment.clone(), pending_await_direct_events));
|
||||
}
|
||||
if !pending_await_claimed_events.is_empty() {
|
||||
pending_await_claimed_outputs.push((attachment, pending_await_claimed_events));
|
||||
}
|
||||
}
|
||||
for (attachment, events) in pending_await_direct_outputs
|
||||
.into_iter()
|
||||
.chain(pending_await_claimed_outputs)
|
||||
{
|
||||
outputs
|
||||
.push(WorkerTargetLifecycleOutput::SharedWorkerAttachmentEvents { attachment, events });
|
||||
}
|
||||
for session_id in session_ids {
|
||||
let retirement = target
|
||||
.take_protocol_attachment_retirement(browser_context_id, &session_id)
|
||||
.expect("removed shared-worker session must transfer its attachment scope");
|
||||
outputs.push(WorkerTargetLifecycleOutput::SharedWorkerDetached {
|
||||
cleanup_plan: TargetSessionDetachCleanupPlan::new(
|
||||
target_id.clone(),
|
||||
session_id,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
retirement,
|
||||
});
|
||||
}
|
||||
if let Some(target_delta) = destroyed_delta {
|
||||
outputs.push(WorkerTargetLifecycleOutput::SharedWorkerDestroyed { target_delta });
|
||||
}
|
||||
outputs
|
||||
}
|
||||
|
||||
pub(in crate::domains::target) async fn close_shared_worker_target_for_target_close_async(
|
||||
conn: &mut CdpConnection,
|
||||
target_id: &str,
|
||||
command_context: &mut crate::conn::CommandDispatchContext,
|
||||
) -> bool {
|
||||
let Some((browser_context_id, renderer_runtime, instance_id)) =
|
||||
conn.browser_context.as_ref().and_then(|context| {
|
||||
let target = context.shared_worker_target(target_id)?;
|
||||
Some((
|
||||
context.id.clone(),
|
||||
context.renderer_runtime(),
|
||||
target.renderer_instance_id,
|
||||
))
|
||||
})
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
renderer_runtime.close_shared_worker_for_target_close(instance_id);
|
||||
let outputs = remove_shared_worker_target(conn, &browser_context_id, instance_id);
|
||||
let mut prepared_outputs =
|
||||
ProtocolOutputPayloads::from_slot(TargetPreparedOutputSlot::from_outputs(outputs));
|
||||
let owner = CommandOwnerScope::capture(conn, None);
|
||||
emit_target_lifecycle_events(
|
||||
conn,
|
||||
&mut ProtocolOutputProjectionContext::new(&owner, command_context),
|
||||
Some(&mut prepared_outputs),
|
||||
)
|
||||
.await;
|
||||
true
|
||||
}
|
||||
|
||||
pub(in crate::domains::target) async fn close_dedicated_worker_target_for_target_close_async(
|
||||
conn: &mut CdpConnection,
|
||||
target_id: &str,
|
||||
command_context: &mut crate::conn::CommandDispatchContext,
|
||||
) -> bool {
|
||||
let Some((browser_context_id, renderer_runtime, instance_id)) =
|
||||
conn.browser_context.as_ref().and_then(|context| {
|
||||
let target = context.dedicated_worker_target(target_id)?;
|
||||
Some((
|
||||
context.id.clone(),
|
||||
context.renderer_runtime(),
|
||||
target.renderer_instance_id,
|
||||
))
|
||||
})
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
renderer_runtime.close_dedicated_worker_for_devtools(instance_id);
|
||||
let outputs = prepare_dedicated_worker_target_retirement(
|
||||
conn,
|
||||
&browser_context_id,
|
||||
instance_id,
|
||||
DedicatedWorkerRetirementCause::OwnerRetired,
|
||||
);
|
||||
let mut prepared_outputs =
|
||||
ProtocolOutputPayloads::from_slot(TargetPreparedOutputSlot::from_outputs(outputs));
|
||||
let owner = CommandOwnerScope::capture(conn, None);
|
||||
emit_target_lifecycle_events(
|
||||
conn,
|
||||
&mut ProtocolOutputProjectionContext::new(&owner, command_context),
|
||||
Some(&mut prepared_outputs),
|
||||
)
|
||||
.await;
|
||||
true
|
||||
}
|
||||
|
||||
pub(super) fn record_shared_worker_target_console_message(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: &str,
|
||||
renderer_instance_id: SharedWorkerInstanceId,
|
||||
message: RendererSharedWorkerConsoleMessage,
|
||||
) -> TargetPreparedOutputs {
|
||||
let mut outputs = TargetPreparedOutputs::default();
|
||||
let Some(context) = conn.browser_context_by_id_mut(browser_context_id) else {
|
||||
return outputs;
|
||||
};
|
||||
let Some(target_id) = context
|
||||
.shared_worker_target_id_for_renderer_instance(renderer_instance_id)
|
||||
.map(str::to_owned)
|
||||
else {
|
||||
// Worker inspector messages can race with target destruction. Once the
|
||||
// renderer instance has no CDP target, late messages are stale and must
|
||||
// not recreate target state or replay into a later fresh worker.
|
||||
return outputs;
|
||||
};
|
||||
let Some(target) = context.shared_worker_target_mut(&target_id) else {
|
||||
return outputs;
|
||||
};
|
||||
target.record_console_message(message);
|
||||
for session_id in target.session_ids() {
|
||||
let attachment = target
|
||||
.protocol_attachment_identity(browser_context_id, &session_id)
|
||||
.expect("shared-worker output session must retain its exact attachment identity");
|
||||
let console_messages = target.pending_console_domain_messages(&session_id).to_vec();
|
||||
if !console_messages.is_empty() {
|
||||
outputs.push(WorkerTargetLifecycleOutput::SharedWorkerConsoleMessages {
|
||||
attachment: attachment.clone(),
|
||||
messages: console_messages,
|
||||
console_end: target.console_message_count(),
|
||||
});
|
||||
}
|
||||
let runtime_messages = target
|
||||
.pending_runtime_console_messages(&session_id)
|
||||
.to_vec();
|
||||
if !runtime_messages.is_empty() {
|
||||
outputs.push(
|
||||
WorkerTargetLifecycleOutput::SharedWorkerRuntimeConsoleMessages {
|
||||
attachment,
|
||||
messages: runtime_messages,
|
||||
console_end: target.console_message_count(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
outputs
|
||||
}
|
||||
|
||||
pub(super) fn record_shared_worker_target_runtime_inspector_messages(
|
||||
conn: &mut CdpConnection,
|
||||
browser_context_id: &str,
|
||||
renderer_instance_id: SharedWorkerInstanceId,
|
||||
inspector_session_id: Option<String>,
|
||||
messages: Vec<RendererRuntimeInspectorMessage>,
|
||||
) -> TargetPreparedOutputs {
|
||||
let mut outputs = TargetPreparedOutputs::default();
|
||||
if messages.is_empty() {
|
||||
return outputs;
|
||||
}
|
||||
let Some(context) = conn.browser_context_by_id_mut(browser_context_id) else {
|
||||
return outputs;
|
||||
};
|
||||
let Some(target_id) = context
|
||||
.shared_worker_target_id_for_renderer_instance(renderer_instance_id)
|
||||
.map(str::to_owned)
|
||||
else {
|
||||
return outputs;
|
||||
};
|
||||
let Some(target) = context.shared_worker_target_mut(&target_id) else {
|
||||
return outputs;
|
||||
};
|
||||
let session_ids = if let Some(session_id) = inspector_session_id {
|
||||
if !target.is_session(&session_id) {
|
||||
return outputs;
|
||||
}
|
||||
vec![session_id]
|
||||
} else {
|
||||
target.session_ids()
|
||||
};
|
||||
for session_id in session_ids {
|
||||
let attachment = target
|
||||
.protocol_attachment_identity(browser_context_id, &session_id)
|
||||
.expect("shared-worker inspector route must retain its exact attachment identity");
|
||||
outputs.push(
|
||||
WorkerTargetLifecycleOutput::SharedWorkerRuntimeInspectorMessages {
|
||||
attachment,
|
||||
messages: messages.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
outputs
|
||||
}
|
||||
|
||||
pub(super) fn exact_shared_worker_target<'a>(
|
||||
conn: &'a CdpConnection,
|
||||
attachment: &TargetSharedWorkerProtocolAttachmentIdentity,
|
||||
) -> Option<&'a SharedWorkerTargetState> {
|
||||
if !attachment.is_current() {
|
||||
return None;
|
||||
}
|
||||
let target = conn
|
||||
.browser_context_by_id(attachment.browser_context_id())?
|
||||
.shared_worker_target(attachment.target_id())?;
|
||||
(target.renderer_owner_local_host_id == attachment.renderer_owner_local_host_id()
|
||||
&& target.renderer_instance_id == attachment.renderer_instance_id()
|
||||
&& target.owner_target_id() == attachment.owner_target_id()
|
||||
&& target.is_session(attachment.session_id()))
|
||||
.then_some(target)
|
||||
}
|
||||
|
||||
pub(super) fn exact_shared_worker_target_mut<'a>(
|
||||
conn: &'a mut CdpConnection,
|
||||
attachment: &TargetSharedWorkerProtocolAttachmentIdentity,
|
||||
) -> Option<&'a mut SharedWorkerTargetState> {
|
||||
if !attachment.is_current() {
|
||||
return None;
|
||||
}
|
||||
let target = conn
|
||||
.browser_context_by_id_mut(attachment.browser_context_id())?
|
||||
.shared_worker_target_mut(attachment.target_id())?;
|
||||
(target.renderer_owner_local_host_id == attachment.renderer_owner_local_host_id()
|
||||
&& target.renderer_instance_id == attachment.renderer_instance_id()
|
||||
&& target.owner_target_id() == attachment.owner_target_id()
|
||||
&& target.is_session(attachment.session_id()))
|
||||
.then_some(target)
|
||||
}
|
||||
|
||||
pub(super) fn exact_shared_worker_pending_runtime_console(
|
||||
conn: &CdpConnection,
|
||||
attachment: &TargetSharedWorkerProtocolAttachmentIdentity,
|
||||
) -> Option<(Vec<RuntimeConsoleMessageSnapshot>, usize)> {
|
||||
let target = exact_shared_worker_target(conn, attachment)?;
|
||||
let messages = target
|
||||
.pending_runtime_console_messages(attachment.session_id())
|
||||
.to_vec();
|
||||
(!messages.is_empty()).then(|| (messages, target.console_message_count()))
|
||||
}
|
||||
|
||||
pub(super) fn mark_exact_shared_worker_console_domain_emitted(
|
||||
conn: &mut CdpConnection,
|
||||
attachment: &TargetSharedWorkerProtocolAttachmentIdentity,
|
||||
console_end: usize,
|
||||
) {
|
||||
if let Some(target) = exact_shared_worker_target_mut(conn, attachment) {
|
||||
target.mark_console_domain_emitted(attachment.session_id(), console_end);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn mark_exact_shared_worker_runtime_console_emitted(
|
||||
conn: &mut CdpConnection,
|
||||
attachment: &TargetSharedWorkerProtocolAttachmentIdentity,
|
||||
console_end: usize,
|
||||
) {
|
||||
if let Some(target) = exact_shared_worker_target_mut(conn, attachment) {
|
||||
target.mark_runtime_console_emitted(attachment.session_id(), console_end);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user