ferridriver_test/ct/
server.rs1use std::net::SocketAddr;
8use std::path::Path;
9
10use axum::Router;
11use tower_http::services::ServeDir;
12
13pub struct ComponentServer {
15 addr: SocketAddr,
16 shutdown_tx: tokio::sync::oneshot::Sender<()>,
17 handle: tokio::task::JoinHandle<()>,
18}
19
20impl ComponentServer {
21 pub async fn start(root_dir: &Path) -> ferridriver::error::Result<Self> {
27 let service = ServeDir::new(root_dir).append_index_html_on_directories(true);
28
29 let app = Router::new().fallback_service(service);
30
31 let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await?;
32
33 let addr = listener.local_addr()?;
34
35 let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel::<()>();
36
37 let handle = tokio::spawn(async move {
38 axum::serve(listener, app)
39 .with_graceful_shutdown(async {
40 let _ = shutdown_rx.await;
41 })
42 .await
43 .ok();
44 });
45
46 Ok(Self {
47 addr,
48 shutdown_tx,
49 handle,
50 })
51 }
52
53 #[must_use]
55 pub fn url(&self) -> String {
56 format!("http://{}", self.addr)
57 }
58
59 #[must_use]
61 pub fn port(&self) -> u16 {
62 self.addr.port()
63 }
64
65 pub async fn stop(self) {
67 let _ = self.shutdown_tx.send(());
68 let _ = self.handle.await;
69 }
70}
71
72pub fn wasm_html_wrapper(wasm_js_path: &str) -> String {
75 format!(
76 r#"<!DOCTYPE html>
77<html>
78<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"></head>
79<body>
80<div id="app"></div>
81<script type="module">
82import init from './{wasm_js_path}';
83await init();
84document.body.setAttribute('data-mounted', 'true');
85</script>
86</body>
87</html>"#
88 )
89}
90
91pub fn vite_html_wrapper(entry_path: &str) -> String {
94 format!(
95 r#"<!DOCTYPE html>
96<html>
97<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"></head>
98<body>
99<div id="app"></div>
100<script type="module" src="{entry_path}"></script>
101</body>
102</html>"#
103 )
104}