fix hot reload on windows (#2142)

This commit is contained in:
Evan Almloff authored and GitHub committed 2024-03-26 00:36:11 -07:00
1 parent 9942c8bfd1
commit e464294c66
5 files changed
+84 -51

No files matched your search

+25 -12
View File
@@ -14,7 +14,7 @@ use interprocess::local_socket::LocalSocketListener;
use std::{ use std::{
fs::create_dir_all, fs::create_dir_all,
process::{Child, Command}, process::{Child, Command},
sync::{Arc, Mutex, RwLock}, sync::{Arc, RwLock},
}; };
use tokio::sync::broadcast::{self}; use tokio::sync::broadcast::{self};
@@ -75,6 +75,22 @@ async fn serve<P: Platform + Send + 'static>(
serve: &ConfigOptsServe, serve: &ConfigOptsServe,
hot_reload_state: Option<HotReloadState>, hot_reload_state: Option<HotReloadState>,
) -> Result<()> { ) -> Result<()> {
let hot_reload: tokio::task::JoinHandle<Result<()>> = tokio::spawn({
let hot_reload_state = hot_reload_state.clone();
async move {
match hot_reload_state {
Some(hot_reload_state) => {
// The open interprocess sockets
start_desktop_hot_reload(hot_reload_state).await?;
}
None => {
std::future::pending::<()>().await;
}
}
Ok(())
}
});
let platform = RwLock::new(P::start(&config, serve)?); let platform = RwLock::new(P::start(&config, serve)?);
tracing::info!("🚀 Starting development server..."); tracing::info!("🚀 Starting development server...");
@@ -88,19 +104,11 @@ async fn serve<P: Platform + Send + 'static>(
}, },
&config, &config,
None, None,
hot_reload_state.clone(), hot_reload_state,
) )
.await?; .await?;
match hot_reload_state { hot_reload.await.unwrap()?;
Some(hot_reload_state) => {
// The open interprocess sockets
start_desktop_hot_reload(hot_reload_state).await?;
}
None => {
std::future::pending::<()>().await;
}
}
Ok(()) Ok(())
} }
@@ -115,7 +123,12 @@ async fn start_desktop_hot_reload(hot_reload_state: HotReloadState) -> Result<()
let _ = create_dir_all(target_dir); // `_all` is for good measure and future-proofness. let _ = create_dir_all(target_dir); // `_all` is for good measure and future-proofness.
let path = target_dir.join("dioxusin"); let path = target_dir.join("dioxusin");
clear_paths(&path); clear_paths(&path);
match LocalSocketListener::bind(path) { let listener = if cfg!(windows) {
LocalSocketListener::bind("@dioxusin")
} else {
LocalSocketListener::bind(path)
};
match listener {
Ok(local_socket_stream) => { Ok(local_socket_stream) => {
let aborted = Arc::new(Mutex::new(false)); let aborted = Arc::new(Mutex::new(false));
// States // States
+2
View File
@@ -49,6 +49,8 @@ futures-util = { workspace = true }
urlencoding = "2.1.2" urlencoding = "2.1.2"
async-trait = "0.1.68" async-trait = "0.1.68"
tao = { version = "0.26.1", features = ["rwh_05"] } tao = { version = "0.26.1", features = ["rwh_05"] }
[target.'cfg(unix)'.dependencies]
signal-hook = "0.3.17" signal-hook = "0.3.17"
[target.'cfg(any(target_os = "windows",target_os = "macos",target_os = "linux",target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))'.dependencies] [target.'cfg(any(target_os = "windows",target_os = "macos",target_os = "linux",target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))'.dependencies]
+18 -14
View File
@@ -474,22 +474,26 @@ impl App {
/// Whenever sigkill is sent, we shut down the app and save the window state /// Whenever sigkill is sent, we shut down the app and save the window state
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
fn connect_preserve_window_state_handler(&self) { fn connect_preserve_window_state_handler(&self) {
// Wire up the trap // TODO: make this work on windows
let target = self.shared.proxy.clone(); #[cfg(unix)]
std::thread::spawn(move || { {
use signal_hook::consts::{SIGINT, SIGTERM}; // Wire up the trap
let sigkill = signal_hook::iterator::Signals::new([SIGTERM, SIGINT]); let target = self.shared.proxy.clone();
if let Ok(mut sigkill) = sigkill { std::thread::spawn(move || {
for _ in sigkill.forever() { use signal_hook::consts::{SIGINT, SIGTERM};
if target.send_event(UserWindowEvent::Shutdown).is_err() { let sigkill = signal_hook::iterator::Signals::new([SIGTERM, SIGINT]);
std::process::exit(0); if let Ok(mut sigkill) = sigkill {
} for _ in sigkill.forever() {
if target.send_event(UserWindowEvent::Shutdown).is_err() {
std::process::exit(0);
}
// give it a moment for the event to be processed // give it a moment for the event to be processed
std::thread::sleep(std::time::Duration::from_secs(1)); std::thread::sleep(std::time::Duration::from_secs(1));
}
} }
} });
}); }
} }
} }
+7 -1
View File
@@ -173,7 +173,13 @@ pub fn init<Ctx: HotReloadingContext + Send + 'static>(cfg: Config<Ctx>) {
} }
} }
let local_socket_stream = match LocalSocketListener::bind(hot_reload_socket_path) { let listener = if cfg!(windows) {
LocalSocketListener::bind("@dioxusin")
} else {
LocalSocketListener::bind(hot_reload_socket_path)
};
let local_socket_stream = match listener {
Ok(local_socket_stream) => local_socket_stream, Ok(local_socket_stream) => local_socket_stream,
Err(err) => { Err(err) => {
println!("failed to connect to hot reloading\n{err}"); println!("failed to connect to hot reloading\n{err}");
+32 -24
View File
@@ -30,41 +30,49 @@ pub enum HotReloadMsg {
/// Connect to the hot reloading listener. The callback provided will be called every time a template change is detected /// Connect to the hot reloading listener. The callback provided will be called every time a template change is detected
pub fn connect(callback: impl FnMut(HotReloadMsg) + Send + 'static) { pub fn connect(callback: impl FnMut(HotReloadMsg) + Send + 'static) {
// FIXME: this is falling back onto the current directory when not running under cargo, which is how the CLI runs this. if cfg!(windows) {
// This needs to be fixed. connect_at(PathBuf::from("@dioxusin"), callback);
let _manifest_dir = std::env::var("CARGO_MANIFEST_DIR"); } else {
// FIXME: this is falling back onto the current directory when not running under cargo, which is how the CLI runs this.
// This needs to be fixed.
let _manifest_dir = std::env::var("CARGO_MANIFEST_DIR");
// get the cargo manifest directory, where the target dir lives // get the cargo manifest directory, where the target dir lives
let mut path = match _manifest_dir { let mut path = match _manifest_dir {
Ok(manifest_dir) => PathBuf::from(manifest_dir), Ok(manifest_dir) => PathBuf::from(manifest_dir),
Err(_) => std::env::current_dir().unwrap(), Err(_) => std::env::current_dir().unwrap(),
}; };
// walk the path until we a find a socket named `dioxusin` inside that folder's target directory // walk the path until we a find a socket named `dioxusin` inside that folder's target directory
loop { loop {
let maybe = path.join("target").join("dioxusin"); let maybe = path.join("target").join("dioxusin");
if maybe.exists() { if maybe.exists() {
path = maybe; path = maybe;
break; break;
}
// It's likely we're running under just cargo and not dx
path = match path.parent() {
Some(parent) => parent.to_path_buf(),
None => return,
};
} }
// It's likely we're running under just cargo and not dx println!("connecting to {:?}", path);
path = match path.parent() { connect_at(path, callback);
Some(parent) => parent.to_path_buf(),
None => return,
};
} }
println!("connecting to {:?}", path);
connect_at(path, callback);
} }
pub fn connect_at(socket: PathBuf, mut callback: impl FnMut(HotReloadMsg) + Send + 'static) { pub fn connect_at(socket: PathBuf, mut callback: impl FnMut(HotReloadMsg) + Send + 'static) {
std::thread::spawn(move || { std::thread::spawn(move || {
// There might be a socket since the we're not running under the hot reloading server // There might be a socket since the we're not running under the hot reloading server
let Ok(socket) = LocalSocketStream::connect(socket.clone()) else { let stream = if cfg!(windows) {
LocalSocketStream::connect("@dioxusin")
} else {
LocalSocketStream::connect(socket.clone())
};
let Ok(socket) = stream else {
println!( println!(
"could not find hot reloading server at {:?}, make sure it's running", "could not find hot reloading server at {:?}, make sure it's running",
socket socket