attempt to reconnect to server after sever disconnects in debug mode

This commit is contained in:
Evan Almloff committed 2023-05-01 11:27:19 -05:00
1 parent 35dcacb956
commit 970d993758
5 files changed
+122 -21

No files matched your search

@@ -9,6 +9,7 @@
use dioxus::prelude::*;
use dioxus_router::*;
use dioxus_server::prelude::*;
use serde::{Deserialize, Serialize};
fn main() {
#[cfg(feature = "web")]
@@ -62,7 +63,7 @@ fn main() {
}
}
#[derive(Clone, Debug, Props, PartialEq)]
#[derive(Clone, Debug, Props, PartialEq, Serialize, Deserialize)]
struct AppProps {
route: Option<String>,
}
+34 -9
View File
@@ -267,6 +267,7 @@ where
.collect::<Vec<_>>()
.join("/");
let route = format!("/{}", route);
println!("Serving static asset at {}", route);
if path.is_dir() {
self = self.nest_service(&route, ServeDir::new(path));
} else {
@@ -275,20 +276,43 @@ where
}
// Add server functions and render index.html
self.connect_hot_reload()
.register_server_fns(server_fn_route)
.route(
"/",
get(render_handler).with_state((cfg, SSRState::default())),
)
self.route(
"/",
get(render_handler).with_state((cfg, SSRState::default())),
)
.connect_hot_reload()
.register_server_fns(server_fn_route)
}
fn connect_hot_reload(self) -> Self {
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
{
self.route(
"/_dioxus/hot_reload",
get(hot_reload_handler).with_state(crate::hot_reload::HotReloadState::default()),
self.nest(
"/_dioxus",
Router::new()
.route(
"/hot_reload",
get(hot_reload_handler)
.with_state(crate::hot_reload::HotReloadState::default()),
)
.route(
"/disconnect",
get(|ws: WebSocketUpgrade| async {
ws.on_failed_upgrade(|error| {
println!("failed to upgrade: {}", error);
todo!()
})
.on_upgrade(|mut ws| async move {
use axum::extract::ws::Message;
let _ = ws.send(Message::Text("connected".into())).await;
loop {
if ws.recv().await.is_none() {
break;
}
}
})
}),
),
)
}
#[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "ssr")))]
@@ -302,6 +326,7 @@ async fn render_handler<P: Clone + serde::Serialize + Send + Sync + 'static>(
State((cfg, ssr_state)): State<(ServeConfig<P>, SSRState)>,
request: Request<Body>,
) -> impl IntoResponse {
println!("Rendering");
let (parts, _) = request.into_parts();
let parts: Arc<RequestParts> = Arc::new(parts.into());
let server_context = DioxusServerContext::new(parts);
+24 -1
View File
@@ -261,7 +261,14 @@ impl DioxusRouterExt for Router {
}
fn connect_hot_reload(self) -> Self {
self.push(Router::with_path("/_dioxus/hot_reload").get(HotReloadHandler::default()))
let mut _dioxus_router = Router::with_path("_dioxus");
_dioxus_router = _dioxus_router
.push(Router::with_path("hot_reload").handle(HotReloadHandler::default()));
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
{
_dioxus_router = _dioxus_router.push(Router::with_path("disconnect").handle(ignore_ws));
}
self.push(_dioxus_router)
}
}
@@ -504,3 +511,19 @@ impl HotReloadHandler {
.await
}
}
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
#[handler]
async fn ignore_ws(req: &mut Request, res: &mut Response) -> Result<(), salvo::http::StatusError> {
use salvo::ws::WebSocketUpgrade;
WebSocketUpgrade::new()
.upgrade(req, res, |mut ws| async move {
let _ = dbg!(ws.send(salvo::ws::Message::text("connected")).await);
while let Some(msg) = ws.recv().await {
if msg.is_err() {
return;
};
}
})
.await
}
+26 -7
View File
@@ -360,7 +360,7 @@ pub fn connect_hot_reload() -> impl Filter<Extract = (impl Reply,), Error = warp
{
#[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "ssr")))]
{
warp::path("_dioxus/hot_reload")
warp::path!("_dioxus" / "hot_reload")
.and(warp::ws())
.map(warp::reply)
.map(|reply| warp::reply::with_status(reply, warp::http::StatusCode::NOT_FOUND));
@@ -368,20 +368,19 @@ pub fn connect_hot_reload() -> impl Filter<Extract = (impl Reply,), Error = warp
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
{
use crate::hot_reload::HotReloadState;
use futures_util::sink::SinkExt;
use futures_util::StreamExt;
use warp::ws::Message;
let state = HotReloadState::default();
warp::path("_dioxus")
.and(warp::path("hot_reload"))
warp::path!("_dioxus" / "hot_reload")
.and(warp::ws())
.and(warp::any().map(move || state.clone()))
.map(move |ws: warp::ws::Ws, state: HotReloadState| {
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
ws.on_upgrade(move |mut websocket| {
async move {
use futures_util::sink::SinkExt;
use futures_util::StreamExt;
use warp::ws::Message;
println!("🔥 Hot Reload WebSocket connected");
{
// update any rsx calls that changed before the websocket connected.
@@ -418,5 +417,25 @@ pub fn connect_hot_reload() -> impl Filter<Extract = (impl Reply,), Error = warp
}
})
})
.or(warp::path!("_dioxus" / "disconnect").and(warp::ws()).map(
move |ws: warp::ws::Ws| {
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
ws.on_upgrade(move |mut websocket| async move {
struct DisconnectOnDrop(Option<warp::ws::WebSocket>);
impl Drop for DisconnectOnDrop {
fn drop(&mut self) {
let _ = self.0.take().unwrap().close();
}
}
let _ = websocket.send(Message::text("connected")).await;
let mut ws = DisconnectOnDrop(Some(websocket));
loop {
ws.0.as_mut().unwrap().next().await;
}
})
},
))
}
}
+36 -3
View File
@@ -25,9 +25,7 @@ impl Default for SSRState {
impl SSRState {
/// Render the application to HTML.
pub fn render<P: 'static + Clone + serde::Serialize>(&self, cfg: &ServeConfig<P>) -> String {
let ServeConfig {
app, props, ..
} = cfg;
let ServeConfig { app, props, .. } = cfg;
let mut vdom = VirtualDom::new_with_props(*app, props.clone());
@@ -55,6 +53,41 @@ impl SSRState {
// serialize the props
let _ = crate::props_html::serialize_props::encode_in_element(&cfg.props, &mut html);
#[cfg(all(debug_assertions, feature = "hot-reload"))]
{
let disconnect_js = r#"(function () {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const url = protocol + '//' + window.location.host + '/_dioxus/disconnect';
const poll_interval = 1000;
const reload_upon_connect = () => {
console.log('Disconnected from server. Attempting to reconnect...');
window.setTimeout(
() => {
// Try to reconnect to the websocket
const ws = new WebSocket(url);
ws.onopen = () => {
// If we reconnect, reload the page
window.location.reload();
}
// Otherwise, try again in a second
reload_upon_connect();
},
poll_interval);
};
// on initial page load connect to the disconnect ws
const ws = new WebSocket(url);
ws.onopen = () => {
// if we disconnect, start polling
ws.onclose = reload_upon_connect;
};
})()"#;
html += r#"<script>"#;
html += disconnect_js;
html += r#"</script>"#;
}
html += &index.post_main;
html