fix web imports and extract hot reload handlers into seperate files (#484)

This commit is contained in:
Demonthos authored and GitHub committed 2022-07-04 13:18:11 -05:00
1 parent 7e454e770a
commit 3a5d1a2ff8
5 files changed
+154 -154

No files matched your search

+1 -86
View File
@@ -52,92 +52,7 @@ impl DesktopController {
// allow other proccesses to send the new rsx text to the @dioxusin ipc channel and recieve erros on the @dioxusout channel
#[cfg(feature = "hot-reload")]
{
use dioxus_rsx_interpreter::{
error::Error, ErrorHandler, SetManyRsxMessage, RSX_CONTEXT,
};
use interprocess::local_socket::{LocalSocketListener, LocalSocketStream};
use std::io::{BufRead, BufReader, Write};
use std::time::Duration;
fn handle_error(
connection: std::io::Result<LocalSocketStream>,
) -> Option<LocalSocketStream> {
connection
.map_err(|error| eprintln!("Incoming connection failed: {}", error))
.ok()
}
let latest_in_connection: Arc<Mutex<Option<BufReader<LocalSocketStream>>>> =
Arc::new(Mutex::new(None));
let latest_in_connection_handle = latest_in_connection.clone();
let latest_out_connection: Arc<Mutex<Option<BufReader<LocalSocketStream>>>> =
Arc::new(Mutex::new(None));
let latest_out_connection_handle = latest_out_connection.clone();
struct DesktopErrorHandler {
latest_connection: Arc<Mutex<Option<BufReader<LocalSocketStream>>>>,
}
impl ErrorHandler for DesktopErrorHandler {
fn handle_error(&self, err: Error) {
if let Some(conn) = &mut *self.latest_connection.lock().unwrap() {
conn.get_mut()
.write_all(
(serde_json::to_string(&err).unwrap() + "\n").as_bytes(),
)
.unwrap();
} else {
panic!("{}", err);
}
}
}
RSX_CONTEXT.set_error_handler(DesktopErrorHandler {
latest_connection: latest_out_connection_handle,
});
RSX_CONTEXT.provide_scheduler_channel(dom.get_scheduler_channel());
// connect to processes for incoming data
std::thread::spawn(move || {
if let Ok(listener) = LocalSocketListener::bind("@dioxusin") {
for conn in listener.incoming().filter_map(handle_error) {
*latest_in_connection_handle.lock().unwrap() =
Some(BufReader::new(conn));
}
}
});
// connect to processes for outgoing errors
std::thread::spawn(move || {
if let Ok(listener) = LocalSocketListener::bind("@dioxusout") {
for conn in listener.incoming().filter_map(handle_error) {
*latest_out_connection.lock().unwrap() = Some(BufReader::new(conn));
}
}
});
std::thread::spawn(move || {
loop {
if let Some(conn) = &mut *latest_in_connection.lock().unwrap() {
let mut buf = String::new();
match conn.read_line(&mut buf) {
Ok(_) => {
let msgs: SetManyRsxMessage =
serde_json::from_str(&buf).unwrap();
RSX_CONTEXT.extend(msgs);
}
Err(err) => {
if err.kind() != std::io::ErrorKind::WouldBlock {
break;
}
}
}
}
// give the error handler time to take the mutex
std::thread::sleep(Duration::from_millis(100));
}
});
}
crate::hot_reload::init(&dom);
let edits = dom.rebuild();
+80
View File
@@ -0,0 +1,80 @@
use dioxus_core::VirtualDom;
use dioxus_rsx_interpreter::{error::Error, ErrorHandler, SetManyRsxMessage, RSX_CONTEXT};
use interprocess::local_socket::{LocalSocketListener, LocalSocketStream};
use std::io::{BufRead, BufReader, Write};
use std::time::Duration;
use std::{sync::Arc, sync::Mutex};
fn handle_error(connection: std::io::Result<LocalSocketStream>) -> Option<LocalSocketStream> {
connection
.map_err(|error| eprintln!("Incoming connection failed: {}", error))
.ok()
}
pub(crate) fn init(dom: &VirtualDom) {
let latest_in_connection: Arc<Mutex<Option<BufReader<LocalSocketStream>>>> =
Arc::new(Mutex::new(None));
let latest_in_connection_handle = latest_in_connection.clone();
let latest_out_connection: Arc<Mutex<Option<BufReader<LocalSocketStream>>>> =
Arc::new(Mutex::new(None));
let latest_out_connection_handle = latest_out_connection.clone();
struct DesktopErrorHandler {
latest_connection: Arc<Mutex<Option<BufReader<LocalSocketStream>>>>,
}
impl ErrorHandler for DesktopErrorHandler {
fn handle_error(&self, err: Error) {
if let Some(conn) = &mut *self.latest_connection.lock().unwrap() {
conn.get_mut()
.write_all((serde_json::to_string(&err).unwrap() + "\n").as_bytes())
.unwrap();
} else {
panic!("{}", err);
}
}
}
RSX_CONTEXT.set_error_handler(DesktopErrorHandler {
latest_connection: latest_out_connection_handle,
});
RSX_CONTEXT.provide_scheduler_channel(dom.get_scheduler_channel());
// connect to processes for incoming data
std::thread::spawn(move || {
if let Ok(listener) = LocalSocketListener::bind("@dioxusin") {
for conn in listener.incoming().filter_map(handle_error) {
*latest_in_connection_handle.lock().unwrap() = Some(BufReader::new(conn));
}
}
});
// connect to processes for outgoing errors
std::thread::spawn(move || {
if let Ok(listener) = LocalSocketListener::bind("@dioxusout") {
for conn in listener.incoming().filter_map(handle_error) {
*latest_out_connection.lock().unwrap() = Some(BufReader::new(conn));
}
}
});
std::thread::spawn(move || {
loop {
if let Some(conn) = &mut *latest_in_connection.lock().unwrap() {
let mut buf = String::new();
match conn.read_line(&mut buf) {
Ok(_) => {
let msgs: SetManyRsxMessage = serde_json::from_str(&buf).unwrap();
RSX_CONTEXT.extend(msgs);
}
Err(err) => {
if err.kind() != std::io::ErrorKind::WouldBlock {
break;
}
}
}
}
// give the error handler time to take the mutex
std::thread::sleep(Duration::from_millis(100));
}
});
}
+2
View File
@@ -8,6 +8,8 @@ mod controller;
mod desktop_context;
mod escape;
mod events;
#[cfg(feature = "hot-reload")]
mod hot_reload;
mod protocol;
use desktop_context::UserWindowEvent;
+68
View File
@@ -0,0 +1,68 @@
use dioxus_core::VirtualDom;
use dioxus_rsx_interpreter::error::Error;
use dioxus_rsx_interpreter::{ErrorHandler, SetManyRsxMessage, RSX_CONTEXT};
use futures_channel::mpsc::unbounded;
use futures_channel::mpsc::UnboundedSender;
use futures_util::StreamExt;
use wasm_bindgen::closure::Closure;
use wasm_bindgen::JsCast;
use web_sys::{console, MessageEvent, WebSocket};
pub(crate) fn init(dom: &VirtualDom) {
let window = web_sys::window().unwrap();
let protocol = if window.location().protocol().unwrap() == "https:" {
"wss:"
} else {
"ws:"
};
let url = format!(
"{protocol}//{}/_dioxus/hot_reload",
window.location().host().unwrap()
);
let ws = WebSocket::new(&url).unwrap();
// change the rsx when new data is received
let cl = Closure::wrap(Box::new(|e: MessageEvent| {
if let Ok(text) = e.data().dyn_into::<js_sys::JsString>() {
let msgs: SetManyRsxMessage = serde_json::from_str(&format!("{text}")).unwrap();
RSX_CONTEXT.extend(msgs);
}
}) as Box<dyn FnMut(MessageEvent)>);
ws.set_onmessage(Some(cl.as_ref().unchecked_ref()));
cl.forget();
let (error_channel_sender, mut error_channel_receiver) = unbounded();
struct WebErrorHandler {
sender: UnboundedSender<Error>,
}
impl ErrorHandler for WebErrorHandler {
fn handle_error(&self, err: dioxus_rsx_interpreter::error::Error) {
self.sender.unbounded_send(err).unwrap();
}
}
RSX_CONTEXT.set_error_handler(WebErrorHandler {
sender: error_channel_sender,
});
RSX_CONTEXT.provide_scheduler_channel(dom.get_scheduler_channel());
// forward stream to the websocket
dom.base_scope().spawn_forever(async move {
while let Some(err) = error_channel_receiver.next().await {
if ws.ready_state() == WebSocket::OPEN {
ws.send_with_str(serde_json::to_string(&err).unwrap().as_str())
.unwrap();
} else {
console::warn_1(&"WebSocket is not open, cannot send error. Run with dioxus serve --hot-reload to enable hot reloading.".into());
panic!("{}", err);
}
}
});
}
+3 -68
View File
@@ -62,11 +62,12 @@ use dioxus_core::prelude::Component;
use dioxus_core::SchedulerMsg;
use dioxus_core::VirtualDom;
use futures_util::FutureExt;
use web_sys::console;
mod cache;
mod cfg;
mod dom;
#[cfg(feature = "hot-reload")]
mod hot_reload;
mod rehydrate;
mod ric_raf;
mod util;
@@ -174,73 +175,7 @@ pub async fn run_with_props<T: 'static + Send>(root: Component<T>, root_props: T
let mut dom = VirtualDom::new_with_props(root, root_props);
#[cfg(feature = "hot-reload")]
{
use dioxus_rsx_interpreter::error::Error;
use dioxus_rsx_interpreter::{ErrorHandler, SetManyRsxMessage, RSX_CONTEXT};
use futures_channel::mpsc::unbounded;
use futures_channel::mpsc::UnboundedSender;
use futures_util::StreamExt;
use wasm_bindgen::closure::Closure;
use wasm_bindgen::JsCast;
use web_sys::{MessageEvent, WebSocket};
let window = web_sys::window().unwrap();
let protocol = if window.location().protocol().unwrap() == "https:" {
"wss:"
} else {
"ws:"
};
let url = format!(
"{protocol}//{}/_dioxus/hot_reload",
window.location().host().unwrap()
);
let ws = WebSocket::new(&url).unwrap();
// change the rsx when new data is received
let cl = Closure::wrap(Box::new(|e: MessageEvent| {
if let Ok(text) = e.data().dyn_into::<js_sys::JsString>() {
let msgs: SetManyRsxMessage = serde_json::from_str(&format!("{text}")).unwrap();
RSX_CONTEXT.extend(msgs);
}
}) as Box<dyn FnMut(MessageEvent)>);
ws.set_onmessage(Some(cl.as_ref().unchecked_ref()));
cl.forget();
let (error_channel_sender, mut error_channel_receiver) = unbounded();
struct WebErrorHandler {
sender: UnboundedSender<Error>,
}
impl ErrorHandler for WebErrorHandler {
fn handle_error(&self, err: dioxus_rsx_interpreter::error::Error) {
self.sender.unbounded_send(err).unwrap();
}
}
RSX_CONTEXT.set_error_handler(WebErrorHandler {
sender: error_channel_sender,
});
RSX_CONTEXT.provide_scheduler_channel(dom.get_scheduler_channel());
// forward stream to the websocket
dom.base_scope().spawn_forever(async move {
while let Some(err) = error_channel_receiver.next().await {
if ws.ready_state() == WebSocket::OPEN {
ws.send_with_str(serde_json::to_string(&err).unwrap().as_str())
.unwrap();
} else {
console::warn_1(&"WebSocket is not open, cannot send error. Run with dioxus serve --hot-reload to enable hot reloading.".into());
panic!("{}", err);
}
}
});
}
hot_reload::init(&dom);
for s in crate::cache::BUILTIN_INTERNED_STRINGS {
wasm_bindgen::intern(s);