use std::net::SocketAddr;
use std::path::Path;
use axum::Router;
use tower_http::services::ServeDir;
pub struct ComponentServer {
addr: SocketAddr,
shutdown_tx: tokio::sync::oneshot::Sender<()>,
handle: tokio::task::JoinHandle<()>,
}
impl ComponentServer {
pub async fn start(root_dir: &Path) -> ferridriver::error::Result<Self> {
let service = ServeDir::new(root_dir).append_index_html_on_directories(true);
let app = Router::new().fallback_service(service);
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await?;
let addr = listener.local_addr()?;
let (shutdown_tx, shutdown_rx) = tokio::sync::oneshot::channel::<()>();
let handle = tokio::spawn(async move {
axum::serve(listener, app)
.with_graceful_shutdown(async {
let _ = shutdown_rx.await;
})
.await
.ok();
});
Ok(Self {
addr,
shutdown_tx,
handle,
})
}
#[must_use]
pub fn url(&self) -> String {
format!("http://{}", self.addr)
}
#[must_use]
pub fn port(&self) -> u16 {
self.addr.port()
}
pub async fn stop(self) {
let _ = self.shutdown_tx.send(());
let _ = self.handle.await;
}
}
pub fn wasm_html_wrapper(wasm_js_path: &str) -> String {
format!(
r#"<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"></head>
<body>
<div id="app"></div>
<script type="module">
import init from './{wasm_js_path}';
await init();
document.body.setAttribute('data-mounted', 'true');
</script>
</body>
</html>"#
)
}
pub fn vite_html_wrapper(entry_path: &str) -> String {
format!(
r#"<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"></head>
<body>
<div id="app"></div>
<script type="module" src="{entry_path}"></script>
</body>
</html>"#
)
}