Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion desktop/src/cef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ use crate::wrapper::{WgpuContext, deserialize_editor_message};

mod consts;
mod context;
mod dirs;
mod input;
mod internal;
mod ipc;
Expand Down
18 changes: 8 additions & 10 deletions desktop/src/cef/context/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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");
Expand All @@ -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)?;
Expand All @@ -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)?;
Expand Down Expand Up @@ -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")]
Expand Down Expand Up @@ -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");
Expand Down
7 changes: 6 additions & 1 deletion desktop/src/cef/context/multithreaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Expand Down
17 changes: 2 additions & 15 deletions desktop/src/cef/context/singlethreaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ 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;

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,
Comment thread
timon-schelling marked this conversation as resolved.
}

impl CefContext for SingleThreadedCefContext {
Expand Down Expand Up @@ -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));
}
}
}
}
}

Expand All @@ -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 changes: 0 additions & 24 deletions desktop/src/cef/dirs.rs

This file was deleted.

70 changes: 67 additions & 3 deletions desktop/src/dirs.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
use std::fs::create_dir_all;
use std::path::PathBuf;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use crate::consts::{APP_DIRECTORY_NAME, APP_DOCUMENTS_DIRECTORY_NAME};

pub(crate) fn ensure_dir_exists(path: &PathBuf) {
if !path.exists() {
create_dir_all(path).unwrap_or_else(|_| panic!("Failed to create directory at {path:?}"));
fs::create_dir_all(path).unwrap_or_else(|_| panic!("Failed to create directory at {path:?}"));
}
}

fn clear_dir(path: &PathBuf) {
let Ok(entries) = fs::read_dir(path) else {
tracing::error!("Failed to read directory at {path:?}");
return;
};
for entry in entries.flatten() {
let entry_path = entry.path();
if entry_path.is_dir() {
if let Err(e) = fs::remove_dir_all(&entry_path) {
tracing::error!("Failed to remove directory at {:?}: {}", entry_path, e);
}
} else if entry_path.is_file() {
if let Err(e) = fs::remove_file(&entry_path) {
tracing::error!("Failed to remove file at {:?}: {}", entry_path, e);
}
}
}
}

Expand All @@ -15,8 +35,52 @@ pub(crate) fn app_data_dir() -> PathBuf {
path
}

fn app_tmp_dir() -> PathBuf {
let path = std::env::temp_dir().join(APP_DIRECTORY_NAME);
ensure_dir_exists(&path);
path
}

pub(crate) fn app_tmp_dir_cleanup() {
clear_dir(&app_tmp_dir());
}

pub(crate) fn app_autosave_documents_dir() -> PathBuf {
let path = app_data_dir().join(APP_DOCUMENTS_DIRECTORY_NAME);
ensure_dir_exists(&path);
path
}

/// Temporary directory that is automatically deleted when dropped.
pub struct TempDir {
path: PathBuf,
}

impl TempDir {
pub fn new() -> io::Result<Self> {
Self::new_with_parent(app_tmp_dir())
}

pub fn new_with_parent(parent: impl AsRef<Path>) -> io::Result<Self> {
let random_suffix = format!("{:032x}", rand::random::<u128>());
let name = format!("{}_{}", std::process::id(), random_suffix);
let path = parent.as_ref().join(name);
fs::create_dir_all(&path)?;
Comment thread
timon-schelling marked this conversation as resolved.
Ok(Self { path })
}
}

impl Drop for TempDir {
fn drop(&mut self) {
let result = fs::remove_dir_all(&self.path);
if let Err(e) = result {
tracing::error!("Failed to remove temporary directory at {:?}: {}", self.path, e);
}
}
}

impl AsRef<Path> for TempDir {
fn as_ref(&self) -> &Path {
&self.path
}
}
2 changes: 2 additions & 0 deletions desktop/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ pub fn start() {
}
};

dirs::app_tmp_dir_cleanup();

let prefs = preferences::read();

// Must be called before event loop initialization or native window integrations will break
Expand Down
10 changes: 10 additions & 0 deletions desktop/src/persist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ impl PersistentData {
}

pub(crate) fn load_from_disk(&mut self) {
delete_old_cef_browser_directory();

let path = Self::state_file_path();
let data = match std::fs::read_to_string(&path) {
Ok(d) => d,
Expand Down Expand Up @@ -157,3 +159,11 @@ impl PersistentData {
path
}
}

// TODO: Eventually remove this cleanup code for the old "browser" CEF directory
fn delete_old_cef_browser_directory() {
let old_browser_dir = crate::dirs::app_data_dir().join("browser");
if old_browser_dir.is_dir() {
let _ = std::fs::remove_dir_all(&old_browser_dir);
}
}