-
-
Notifications
You must be signed in to change notification settings - Fork 960
/
Copy pathaxum_adapter.rs
89 lines (78 loc) · 2.52 KB
/
axum_adapter.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use std::sync::Arc;
use crate::{interpreter_glue, LiveViewError, LiveViewSocket, LiveviewRouter};
use axum::{
extract::{
ws::{Message, WebSocket},
WebSocketUpgrade,
},
response::Html,
routing::*,
Router,
};
use futures_util::{SinkExt, StreamExt};
/// Convert an Axum WebSocket into a `LiveViewSocket`.
///
/// This is required to launch a LiveView app using the Axum web framework.
pub fn axum_socket(ws: WebSocket) -> impl LiveViewSocket {
ws.map(transform_rx)
.with(transform_tx)
.sink_map_err(|_| LiveViewError::SendingFailed)
}
fn transform_rx(message: Result<Message, axum::Error>) -> Result<Vec<u8>, LiveViewError> {
message
.map_err(|_| LiveViewError::SendingFailed)?
.into_text()
.map(|s| s.into_bytes())
.map_err(|_| LiveViewError::SendingFailed)
}
async fn transform_tx(message: Vec<u8>) -> Result<Message, axum::Error> {
Ok(Message::Binary(message))
}
impl LiveviewRouter for Router {
fn create_default_liveview_router() -> Self {
Router::new()
}
fn with_virtual_dom(
self,
route: &str,
app: impl Fn() -> dioxus_core::prelude::VirtualDom + Send + Sync + 'static,
) -> Self {
let view = crate::LiveViewPool::new();
let ws_path = format!("{}/ws", route.trim_start_matches('/'));
let title = crate::app_title();
let index_page_with_glue = move |glue: &str| {
Html(format!(
r#"
<!DOCTYPE html>
<html>
<head><title>{title}</title></head>
<body><div id="main"></div></body>
{glue}
</html>
"#,
))
};
let app = Arc::new(app);
self.route(
&ws_path,
get(move |ws: WebSocketUpgrade| async move {
let app = app.clone();
ws.on_upgrade(move |socket| async move {
_ = view
.launch_virtualdom(axum_socket(socket), move || app())
.await;
})
}),
)
.route(
route,
get(move || async move { index_page_with_glue(&interpreter_glue(&ws_path)) }),
)
}
async fn start(self, address: impl Into<std::net::SocketAddr>) {
let listener = tokio::net::TcpListener::bind(address.into()).await.unwrap();
if let Err(err) = axum::serve(listener, self.into_make_service()).await {
eprintln!("Failed to start axum server: {}", err);
}
}
}