fix macos hot reloading on forced exit
This commit is contained in:
1 parent
563a2b0953
commit
60abafb381
1 file changed
+168
-150
+168
-150
@@ -159,172 +159,190 @@ pub fn init<Ctx: HotReloadingContext + Send + 'static>(cfg: Config<Ctx>) {
|
|||||||
}
|
}
|
||||||
let file_map = Arc::new(Mutex::new(file_map));
|
let file_map = Arc::new(Mutex::new(file_map));
|
||||||
|
|
||||||
if let Ok(local_socket_stream) = LocalSocketListener::bind("@dioxusin") {
|
#[cfg(target_os = "macos")]
|
||||||
let aborted = Arc::new(Mutex::new(false));
|
{
|
||||||
|
// On unix, if you force quit the application, it can leave the file socket open
|
||||||
// listen for connections
|
// This will cause the local socket listener to fail to open
|
||||||
std::thread::spawn({
|
// We check if the file socket is already open from an old session and then delete it
|
||||||
let file_map = file_map.clone();
|
let paths = ["./dioxusin", "./@dioxusin"];
|
||||||
let channels = channels.clone();
|
for path in paths {
|
||||||
let aborted = aborted.clone();
|
let path = PathBuf::from(path);
|
||||||
let _ = local_socket_stream.set_nonblocking(true);
|
if path.exists() {
|
||||||
move || {
|
let _ = std::fs::remove_file(path);
|
||||||
loop {
|
|
||||||
if let Ok(mut connection) = local_socket_stream.accept() {
|
|
||||||
// send any templates than have changed before the socket connected
|
|
||||||
let templates: Vec<_> = {
|
|
||||||
file_map
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.map
|
|
||||||
.values()
|
|
||||||
.filter_map(|(_, template_slot)| *template_slot)
|
|
||||||
.collect()
|
|
||||||
};
|
|
||||||
for template in templates {
|
|
||||||
if !send_msg(
|
|
||||||
HotReloadMsg::UpdateTemplate(template),
|
|
||||||
&mut connection,
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
channels.lock().unwrap().push(connection);
|
|
||||||
if log {
|
|
||||||
println!("Connected to hot reloading 🚀");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if *aborted.lock().unwrap() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// watch for changes
|
match LocalSocketListener::bind("@dioxusin") {
|
||||||
std::thread::spawn(move || {
|
Ok(local_socket_stream) => {
|
||||||
let mut last_update_time = chrono::Local::now().timestamp();
|
let aborted = Arc::new(Mutex::new(false));
|
||||||
|
|
||||||
let (tx, rx) = std::sync::mpsc::channel();
|
// listen for connections
|
||||||
|
std::thread::spawn({
|
||||||
let mut watcher = RecommendedWatcher::new(tx, notify::Config::default()).unwrap();
|
let file_map = file_map.clone();
|
||||||
|
|
||||||
for path in listening_paths {
|
|
||||||
let full_path = crate_dir.join(path);
|
|
||||||
if let Err(err) = watcher.watch(&full_path, RecursiveMode::Recursive) {
|
|
||||||
if log {
|
|
||||||
println!(
|
|
||||||
"hot reloading failed to start watching {full_path:?}:\n{err:?}",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut rebuild = {
|
|
||||||
let aborted = aborted.clone();
|
|
||||||
let channels = channels.clone();
|
let channels = channels.clone();
|
||||||
|
let aborted = aborted.clone();
|
||||||
|
let _ = local_socket_stream.set_nonblocking(true);
|
||||||
move || {
|
move || {
|
||||||
if let Some(rebuild_callback) = &mut rebuild_with {
|
loop {
|
||||||
if log {
|
if let Ok(mut connection) = local_socket_stream.accept() {
|
||||||
println!("Rebuilding the application...");
|
// send any templates than have changed before the socket connected
|
||||||
}
|
let templates: Vec<_> = {
|
||||||
let shutdown = rebuild_callback();
|
file_map
|
||||||
|
.lock()
|
||||||
if shutdown {
|
.unwrap()
|
||||||
*aborted.lock().unwrap() = true;
|
.map
|
||||||
}
|
.values()
|
||||||
|
.filter_map(|(_, template_slot)| *template_slot)
|
||||||
for channel in &mut *channels.lock().unwrap() {
|
.collect()
|
||||||
send_msg(HotReloadMsg::Shutdown, channel);
|
};
|
||||||
}
|
for template in templates {
|
||||||
|
if !send_msg(
|
||||||
return shutdown;
|
HotReloadMsg::UpdateTemplate(template),
|
||||||
} else if log {
|
&mut connection,
|
||||||
println!(
|
) {
|
||||||
"Rebuild needed... shutting down hot reloading.\nManually rebuild the application to view futher changes."
|
continue;
|
||||||
);
|
}
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for evt in rx {
|
|
||||||
if chrono::Local::now().timestamp_millis() >= last_update_time {
|
|
||||||
if let Ok(evt) = evt {
|
|
||||||
let real_paths = evt
|
|
||||||
.paths
|
|
||||||
.iter()
|
|
||||||
.filter(|path| {
|
|
||||||
// skip non rust files
|
|
||||||
matches!(
|
|
||||||
path.extension().and_then(|p| p.to_str()),
|
|
||||||
Some("rs" | "toml" | "css" | "html" | "js")
|
|
||||||
) &&
|
|
||||||
// skip excluded paths
|
|
||||||
!excluded_paths.iter().any(|p| path.starts_with(p)) &&
|
|
||||||
// respect .gitignore
|
|
||||||
!gitignore
|
|
||||||
.matched_path_or_any_parents(path, false)
|
|
||||||
.is_ignore()
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// Give time for the change to take effect before reading the file
|
|
||||||
if !real_paths.is_empty() {
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut channels = channels.lock().unwrap();
|
|
||||||
for path in real_paths {
|
|
||||||
// if this file type cannot be hot reloaded, rebuild the application
|
|
||||||
if path.extension().and_then(|p| p.to_str()) != Some("rs")
|
|
||||||
&& rebuild()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// find changes to the rsx in the file
|
channels.lock().unwrap().push(connection);
|
||||||
match file_map
|
if log {
|
||||||
.lock()
|
println!("Connected to hot reloading 🚀");
|
||||||
.unwrap()
|
}
|
||||||
.update_rsx(path, crate_dir.as_path())
|
}
|
||||||
{
|
if *aborted.lock().unwrap() {
|
||||||
Ok(UpdateResult::UpdatedRsx(msgs)) => {
|
break;
|
||||||
for msg in msgs {
|
}
|
||||||
let mut i = 0;
|
}
|
||||||
while i < channels.len() {
|
}
|
||||||
let channel = &mut channels[i];
|
});
|
||||||
if send_msg(
|
|
||||||
HotReloadMsg::UpdateTemplate(msg),
|
// watch for changes
|
||||||
channel,
|
std::thread::spawn(move || {
|
||||||
) {
|
let mut last_update_time = chrono::Local::now().timestamp();
|
||||||
i += 1;
|
|
||||||
} else {
|
let (tx, rx) = std::sync::mpsc::channel();
|
||||||
channels.remove(i);
|
|
||||||
|
let mut watcher =
|
||||||
|
RecommendedWatcher::new(tx, notify::Config::default()).unwrap();
|
||||||
|
|
||||||
|
for path in listening_paths {
|
||||||
|
let full_path = crate_dir.join(path);
|
||||||
|
if let Err(err) = watcher.watch(&full_path, RecursiveMode::Recursive) {
|
||||||
|
if log {
|
||||||
|
println!(
|
||||||
|
"hot reloading failed to start watching {full_path:?}:\n{err:?}",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rebuild = {
|
||||||
|
let aborted = aborted.clone();
|
||||||
|
let channels = channels.clone();
|
||||||
|
move || {
|
||||||
|
if let Some(rebuild_callback) = &mut rebuild_with {
|
||||||
|
if log {
|
||||||
|
println!("Rebuilding the application...");
|
||||||
|
}
|
||||||
|
let shutdown = rebuild_callback();
|
||||||
|
|
||||||
|
if shutdown {
|
||||||
|
*aborted.lock().unwrap() = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for channel in &mut *channels.lock().unwrap() {
|
||||||
|
send_msg(HotReloadMsg::Shutdown, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return shutdown;
|
||||||
|
} else if log {
|
||||||
|
println!(
|
||||||
|
"Rebuild needed... shutting down hot reloading.\nManually rebuild the application to view futher changes."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for evt in rx {
|
||||||
|
if chrono::Local::now().timestamp_millis() >= last_update_time {
|
||||||
|
if let Ok(evt) = evt {
|
||||||
|
let real_paths = evt
|
||||||
|
.paths
|
||||||
|
.iter()
|
||||||
|
.filter(|path| {
|
||||||
|
// skip non rust files
|
||||||
|
matches!(
|
||||||
|
path.extension().and_then(|p| p.to_str()),
|
||||||
|
Some("rs" | "toml" | "css" | "html" | "js")
|
||||||
|
) &&
|
||||||
|
// skip excluded paths
|
||||||
|
!excluded_paths.iter().any(|p| path.starts_with(p)) &&
|
||||||
|
// respect .gitignore
|
||||||
|
!gitignore
|
||||||
|
.matched_path_or_any_parents(path, false)
|
||||||
|
.is_ignore()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Give time for the change to take effect before reading the file
|
||||||
|
if !real_paths.is_empty() {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut channels = channels.lock().unwrap();
|
||||||
|
for path in real_paths {
|
||||||
|
// if this file type cannot be hot reloaded, rebuild the application
|
||||||
|
if path.extension().and_then(|p| p.to_str()) != Some("rs")
|
||||||
|
&& rebuild()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// find changes to the rsx in the file
|
||||||
|
match file_map
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.update_rsx(path, crate_dir.as_path())
|
||||||
|
{
|
||||||
|
Ok(UpdateResult::UpdatedRsx(msgs)) => {
|
||||||
|
for msg in msgs {
|
||||||
|
let mut i = 0;
|
||||||
|
while i < channels.len() {
|
||||||
|
let channel = &mut channels[i];
|
||||||
|
if send_msg(
|
||||||
|
HotReloadMsg::UpdateTemplate(msg),
|
||||||
|
channel,
|
||||||
|
) {
|
||||||
|
i += 1;
|
||||||
|
} else {
|
||||||
|
channels.remove(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Ok(UpdateResult::NeedsRebuild) => {
|
||||||
Ok(UpdateResult::NeedsRebuild) => {
|
drop(channels);
|
||||||
drop(channels);
|
if rebuild() {
|
||||||
if rebuild() {
|
return;
|
||||||
return;
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
Err(err) => {
|
||||||
}
|
if log {
|
||||||
Err(err) => {
|
println!(
|
||||||
if log {
|
"hot reloading failed to update rsx:\n{err:?}"
|
||||||
println!(
|
);
|
||||||
"hot reloading failed to update rsx:\n{err:?}"
|
}
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
last_update_time = chrono::Local::now().timestamp_millis();
|
||||||
}
|
}
|
||||||
last_update_time = chrono::Local::now().timestamp_millis();
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
Err(error) => println!("failed to connect to hot reloading\n{error}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user