Implémentation d'une première approche de gestion des erreurs #52
@ -10,6 +10,7 @@ axum = "0.7.5"
|
|||||||
listenfd = "1.0.1"
|
listenfd = "1.0.1"
|
||||||
notify = "6.1.1"
|
notify = "6.1.1"
|
||||||
serde = { version = "1.0.204", features = ["derive"] }
|
serde = { version = "1.0.204", features = ["derive"] }
|
||||||
|
thiserror = "1.0.63"
|
||||||
tokio = { version = "1.39.1", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.39.1", features = ["macros", "rt-multi-thread"] }
|
||||||
tower-http = { version = "0.5.2", features = ["fs"] }
|
tower-http = { version = "0.5.2", features = ["fs"] }
|
||||||
tower-livereload = "0.9.3"
|
tower-livereload = "0.9.3"
|
||||||
|
@ -3,12 +3,23 @@ use axum::body::Body;
|
|||||||
use axum::http::Request;
|
use axum::http::Request;
|
||||||
use listenfd::ListenFd;
|
use listenfd::ListenFd;
|
||||||
use notify::Watcher;
|
use notify::Watcher;
|
||||||
use std::env;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::{env, io};
|
||||||
|
use thiserror::Error;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tower_livereload::predicate::Predicate;
|
use tower_livereload::predicate::Predicate;
|
||||||
use tower_livereload::LiveReloadLayer;
|
use tower_livereload::LiveReloadLayer;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum AppError {
|
||||||
|
#[error("Unable to bind to TCP listener")]
|
||||||
|
TCPListener(#[from] std::io::Error),
|
||||||
|
#[error("Error with the notify watcher")]
|
||||||
|
NotifyWatcher(#[from] notify::Error),
|
||||||
|
#[error("Missing environment variable {var}")]
|
||||||
|
MissingEnvVar { var: &'static str },
|
||||||
|
}
|
||||||
|
|
||||||
/// Nous filtrons les requêtes de `htmx` pour ne pas inclure le script _JS_ qui gère le rechargement
|
/// Nous filtrons les requêtes de `htmx` pour ne pas inclure le script _JS_ qui gère le rechargement
|
||||||
/// Voir https://github.com/leotaku/tower-livereload/pull/3
|
/// Voir https://github.com/leotaku/tower-livereload/pull/3
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
@ -20,44 +31,47 @@ impl<T> Predicate<Request<T>> for NotHtmxPredicate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_LISTENER: &str = "localhost:3000";
|
const DEFAULT_LISTENER: &str = "localhost:3000";
|
||||||
async fn get_tcp_listener() -> TcpListener {
|
async fn get_tcp_listener() -> Result<TcpListener, io::Error> {
|
||||||
let mut listenfd = ListenFd::from_env();
|
let mut listenfd = ListenFd::from_env();
|
||||||
|
|
||||||
match listenfd.take_tcp_listener(0).unwrap() {
|
match listenfd.take_tcp_listener(0)? {
|
||||||
// if we are given a tcp listener on listen fd 0, we use that one
|
// if we are given a tcp listener on listen fd 0, we use that one
|
||||||
Some(listener) => {
|
Some(listener) => {
|
||||||
listener.set_nonblocking(true).unwrap();
|
listener.set_nonblocking(true)?;
|
||||||
TcpListener::from_std(listener).unwrap()
|
Ok(TcpListener::from_std(listener)?)
|
||||||
}
|
}
|
||||||
// otherwise fall back to local listening
|
// otherwise fall back to local listening
|
||||||
None => TcpListener::bind(DEFAULT_LISTENER).await.unwrap(),
|
None => Ok(TcpListener::bind(DEFAULT_LISTENER).await?),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_livereload_layer(templates_path: &Path) -> LiveReloadLayer<NotHtmxPredicate> {
|
fn get_livereload_layer(
|
||||||
|
templates_path: &Path,
|
||||||
|
) -> Result<LiveReloadLayer<NotHtmxPredicate>, notify::Error> {
|
||||||
let livereload = LiveReloadLayer::new();
|
let livereload = LiveReloadLayer::new();
|
||||||
let reloader = livereload.reloader();
|
let reloader = livereload.reloader();
|
||||||
let mut watcher = notify::recommended_watcher(move |_| reloader.reload()).unwrap();
|
let mut watcher = notify::recommended_watcher(move |_| reloader.reload())?;
|
||||||
watcher
|
watcher.watch(templates_path, notify::RecursiveMode::Recursive)?;
|
||||||
.watch(templates_path, notify::RecursiveMode::Recursive)
|
Ok(livereload.request_predicate::<Body, NotHtmxPredicate>(NotHtmxPredicate))
|
||||||
.unwrap();
|
|
||||||
livereload.request_predicate::<Body, NotHtmxPredicate>(NotHtmxPredicate)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() -> Result<(), AppError> {
|
||||||
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
let manifest_dir = env::var("CARGO_MANIFEST_DIR").map_err(|_| AppError::MissingEnvVar {
|
||||||
|
var: "CARGO_MANIFEST_DIR",
|
||||||
|
})?;
|
||||||
let assets_path = Path::new(&manifest_dir).join("assets");
|
let assets_path = Path::new(&manifest_dir).join("assets");
|
||||||
let templates_path = Path::new(&manifest_dir).join("templates");
|
let templates_path = Path::new(&manifest_dir).join("templates");
|
||||||
|
|
||||||
let livereload_layer = get_livereload_layer(&templates_path);
|
let livereload_layer =
|
||||||
|
get_livereload_layer(&templates_path).map_err(AppError::NotifyWatcher)?;
|
||||||
let router = get_router(assets_path.as_path()).layer(livereload_layer);
|
let router = get_router(assets_path.as_path()).layer(livereload_layer);
|
||||||
|
|
||||||
let listener: TcpListener = get_tcp_listener().await;
|
let listener: TcpListener = get_tcp_listener().await.map_err(AppError::TCPListener)?;
|
||||||
println!("Listening on: http://{}", listener.local_addr().unwrap());
|
let local_addr = listener.local_addr().map_err(AppError::TCPListener)?;
|
||||||
|
println!("Listening on: http://{}", local_addr);
|
||||||
|
|
||||||
// Run the server with the router
|
// Run the server with the router
|
||||||
axum::serve(listener, router.into_make_service())
|
axum::serve(listener, router.into_make_service()).await?;
|
||||||
.await
|
Ok(())
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user