Desktop: Use the OS temp directory for CEF caches (#4030)

* Desktop: Use the OS temp dir

* Review
This commit is contained in:
Timon
2026-04-15 10:47:45 +00:00
committed by GitHub
parent 60f16d72a5
commit 2a2a60883d
8 changed files with 95 additions and 54 deletions
+8 -10
View File
@@ -4,15 +4,15 @@ use cef::{
App, BrowserSettings, CefString, Client, DictionaryValue, ImplCommandLine, ImplRequestContext, LogSeverity, RequestContextSettings, SchemeHandlerFactory, Settings, WindowInfo, api_hash,
browser_host_create_browser_sync, execute_process,
};
use std::path::{Path, PathBuf};
use std::path::Path;
use super::CefContext;
use super::singlethreaded::SingleThreadedCefContext;
use crate::cef::CefEventHandler;
use crate::cef::consts::{RESOURCE_DOMAIN, RESOURCE_SCHEME};
use crate::cef::dirs::{create_instance_dir, delete_instance_dirs};
use crate::cef::input::InputState;
use crate::cef::internal::{BrowserProcessAppImpl, BrowserProcessClientImpl, RenderProcessAppImpl, SchemeHandlerFactoryImpl};
use crate::dirs::TempDir;
pub(crate) struct CefContextBuilder<H: CefEventHandler> {
pub(crate) args: Args,
@@ -97,8 +97,7 @@ impl<H: CefEventHandler> CefContextBuilder<H> {
#[cfg(target_os = "macos")]
pub(crate) fn initialize(self, event_handler: H, disable_gpu_acceleration: bool) -> Result<impl CefContext, InitError> {
delete_instance_dirs();
let instance_dir = create_instance_dir();
let instance_dir = TempDir::new().expect("Failed to create temporary directory for CEF instance");
let exe = std::env::current_exe().expect("cannot get current exe path");
let app_root = exe.parent().and_then(|p| p.parent()).expect("bad path structure").parent().expect("bad path structure");
@@ -108,7 +107,7 @@ impl<H: CefEventHandler> CefContextBuilder<H> {
multi_threaded_message_loop: 0,
external_message_pump: 1,
no_sandbox: 1, // GPU helper crashes when running with sandbox
..Self::common_settings(&instance_dir)
..Self::common_settings(instance_dir.as_ref())
};
self.initialize_inner(&event_handler, settings)?;
@@ -118,14 +117,13 @@ impl<H: CefEventHandler> CefContextBuilder<H> {
#[cfg(not(target_os = "macos"))]
pub(crate) fn initialize(self, event_handler: H, disable_gpu_acceleration: bool) -> Result<impl CefContext, InitError> {
delete_instance_dirs();
let instance_dir = create_instance_dir();
let instance_dir = TempDir::new().expect("Failed to create temporary directory for CEF instance");
let settings = Settings {
multi_threaded_message_loop: 1,
#[cfg(target_os = "linux")]
no_sandbox: 1,
..Self::common_settings(&instance_dir)
..Self::common_settings(instance_dir.as_ref())
};
self.initialize_inner(&event_handler, settings)?;
@@ -157,7 +155,7 @@ impl<H: CefEventHandler> CefContextBuilder<H> {
}
}
fn create_browser<H: CefEventHandler>(event_handler: H, instance_dir: PathBuf, disable_gpu_acceleration: bool) -> Result<SingleThreadedCefContext, InitError> {
fn create_browser<H: CefEventHandler>(event_handler: H, instance_dir: TempDir, disable_gpu_acceleration: bool) -> Result<SingleThreadedCefContext, InitError> {
let mut client = Client::new(BrowserProcessClientImpl::new(&event_handler));
#[cfg(feature = "accelerated_paint")]
@@ -211,7 +209,7 @@ fn create_browser<H: CefEventHandler>(event_handler: H, instance_dir: PathBuf, d
event_handler: Box::new(event_handler),
browser,
input_state: InputState::default(),
instance_dir,
_instance_dir: instance_dir,
})
} else {
tracing::error!("Failed to create browser");
+6 -1
View File
@@ -54,7 +54,12 @@ impl CefContext for MultiThreadedCefContextProxy {
impl Drop for MultiThreadedCefContextProxy {
fn drop(&mut self) {
// Force dropping underlying context on the UI thread
run_on_ui_thread(move || drop(CONTEXT.take()));
let (sync_drop_tx, sync_drop_rx) = std::sync::mpsc::channel();
run_on_ui_thread(move || {
drop(CONTEXT.take());
let _ = sync_drop_tx.send(());
});
let _ = sync_drop_rx.recv();
}
}
+2 -15
View File
@@ -4,6 +4,7 @@ use winit::event::WindowEvent;
use crate::cef::input::InputState;
use crate::cef::ipc::{MessageType, SendMessage};
use crate::cef::{CefEventHandler, input};
use crate::dirs::TempDir;
use super::CefContext;
@@ -11,7 +12,7 @@ pub(super) struct SingleThreadedCefContext {
pub(super) event_handler: Box<dyn CefEventHandler>,
pub(super) browser: Browser,
pub(super) input_state: InputState,
pub(super) instance_dir: std::path::PathBuf,
pub(super) _instance_dir: TempDir,
}
impl CefContext for SingleThreadedCefContext {
@@ -46,19 +47,6 @@ impl Drop for SingleThreadedCefContext {
// CEF wants us to close the browser before shutting down, otherwise it may run longer that necessary.
self.browser.host().unwrap().close_browser(1);
cef::shutdown();
// Sometimes some CEF processes still linger at this point and hold file handles to the cache directory.
// To mitigate this, we try to remove the directory multiple times with some delay.
// TODO: find a better solution if possible.
for _ in 0..30 {
match std::fs::remove_dir_all(&self.instance_dir) {
Ok(_) => break,
Err(e) => {
tracing::warn!("Failed to remove CEF cache directory, retrying...: {e}");
std::thread::sleep(std::time::Duration::from_millis(100));
}
}
}
}
}
@@ -68,7 +56,6 @@ impl SendMessage for SingleThreadedCefContext {
tracing::error!("Main frame is not available, cannot send message");
return;
};
frame.send_message(message_type, message);
}
}
-24
View File
@@ -1,24 +0,0 @@
use std::path::PathBuf;
use crate::dirs::{app_data_dir, ensure_dir_exists};
static CEF_DIR_NAME: &str = "browser";
pub(crate) fn delete_instance_dirs() {
let cef_dir = app_data_dir().join(CEF_DIR_NAME);
if let Ok(entries) = std::fs::read_dir(&cef_dir) {
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
let _ = std::fs::remove_dir_all(&path);
}
}
}
}
pub(crate) fn create_instance_dir() -> PathBuf {
let instance_id: String = (0..32).map(|_| format!("{:x}", rand::random::<u8>() % 16)).collect();
let path = app_data_dir().join(CEF_DIR_NAME).join(instance_id);
ensure_dir_exists(&path);
path
}