fix(servo): retire sessions on internal navigation

This commit is contained in:
2026-07-09 22:37:17 -04:00
parent b422ac1631
commit 31fc1acf17
9 changed files with 571 additions and 93 deletions
@@ -1,8 +1,17 @@
use std::path::PathBuf;
use crate::services::{servo_live::ServoLiveClient, servo_profile_data::TransientProfileDataDir};
use ely_domain::{ProfileId, TabId};
use super::{LiveRuntimeClient, LiveRuntimeWorker};
use crate::services::{
ProfileDataMode,
servo_live::{ServoLiveClient, ServoLivePermissionGrant},
servo_profile_data::TransientProfileDataDir,
};
use super::{
LiveRuntimeClient, LiveRuntimeWorker, WebSurfaceRuntime, WebSurfaceRuntimeFrame,
WebSurfaceRuntimeScope,
};
pub(super) type LiveRuntimeClientFactory =
fn(PathBuf) -> Result<Box<dyn LiveRuntimeClient>, String>;
@@ -18,10 +27,36 @@ pub(super) fn new_servo_live_client(
pub(super) struct ScopedWorker {
pub(super) worker: LiveRuntimeWorker,
pub(super) transient_profile_data_dir: Option<TransientProfileDataDir>,
allow_once_grants: Vec<ServoLivePermissionGrant>,
}
impl ScopedWorker {
pub(super) fn new(
worker: LiveRuntimeWorker,
transient_profile_data_dir: Option<TransientProfileDataDir>,
) -> Self {
Self { worker, transient_profile_data_dir, allow_once_grants: Vec::new() }
}
pub(super) fn track_allow_once_grants(&mut self, grants: &[ServoLivePermissionGrant]) {
for grant in grants {
if !self.allow_once_grants.contains(grant) {
self.allow_once_grants.push(grant.clone());
}
}
}
pub(super) fn mark_permission_consumed(&mut self, consumed: &ServoLivePermissionGrant) {
self.allow_once_grants.retain(|grant| grant != consumed);
}
fn take_allow_once_grants(&mut self) -> Vec<ServoLivePermissionGrant> {
std::mem::take(&mut self.allow_once_grants)
}
}
pub(super) fn shutdown_scoped_worker(scoped: ScopedWorker) -> Result<(), String> {
let ScopedWorker { worker, transient_profile_data_dir } = scoped;
let ScopedWorker { worker, transient_profile_data_dir, .. } = scoped;
drop(worker);
let Some(directory) = transient_profile_data_dir else {
return Ok(());
@@ -30,3 +65,72 @@ pub(super) fn shutdown_scoped_worker(scoped: ScopedWorker) -> Result<(), String>
.close()
.map_err(|error| format!("failed to remove transient Servo profile data: {error}"))
}
impl WebSurfaceRuntime {
pub(in crate::shell) fn reconcile_tab_scope(
&mut self,
tab_id: &TabId,
profile_id: &ProfileId,
profile_data_mode: ProfileDataMode,
) -> Vec<ServoLivePermissionGrant> {
let scope = WebSurfaceRuntimeScope::new(profile_id.clone(), profile_data_mode);
self.detach_tab_from_previous_scope(tab_id, &scope);
self.take_retired_permission_consumptions()
}
pub(in crate::shell) fn close_tab(&mut self, tab_id: &TabId) {
let Some(session) = self.sessions.remove(tab_id) else {
return;
};
let has_remaining_session =
self.sessions.values().any(|candidate| candidate.scope == session.scope);
if session.scope.is_transient() && !has_remaining_session {
self.remove_worker(&session.scope);
} else if let Some(scoped) = self.workers.get(&session.scope) {
scoped.worker.submit_close(tab_id.as_str().to_string());
}
}
pub(super) fn retire_scoped_worker_permissions(&mut self, scoped: &mut ScopedWorker) {
for grant in scoped.take_allow_once_grants() {
if !self.retired_permission_consumptions.contains(&grant) {
self.retired_permission_consumptions.push(grant);
}
}
}
pub(in crate::shell) fn take_retired_permission_consumptions(
&mut self,
) -> Vec<ServoLivePermissionGrant> {
std::mem::take(&mut self.retired_permission_consumptions)
}
pub(super) fn take_retired_permission_frames(&mut self) -> Vec<WebSurfaceRuntimeFrame> {
self.take_retired_permission_consumptions()
.into_iter()
.map(WebSurfaceRuntimeFrame::PermissionConsumed)
.collect()
}
pub(super) fn detach_tab_from_previous_scope(
&mut self,
tab_id: &TabId,
scope: &WebSurfaceRuntimeScope,
) {
let Some(previous_scope) = self.sessions.get(tab_id).map(|session| session.scope.clone())
else {
return;
};
if &previous_scope == scope {
return;
}
self.sessions.remove(tab_id);
let has_remaining_session =
self.sessions.values().any(|candidate| candidate.scope == previous_scope);
if previous_scope.is_transient() && !has_remaining_session {
self.remove_worker(&previous_scope);
} else if let Some(scoped) = self.workers.get(&previous_scope) {
scoped.worker.submit_close(tab_id.as_str().to_string());
}
}
}