From d44c56142745269112ccf072d0354c169bac7334 Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Wed, 14 Aug 2024 10:40:41 +0200 Subject: [PATCH] feat: [app] Use thiserror to properly handle errors instead of unwrap --- crates/app/Cargo.toml | 1 + crates/app/src/main.rs | 54 ++++++++++++++++++++++++++---------------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/crates/app/Cargo.toml b/crates/app/Cargo.toml index c837783..e095c3a 100644 --- a/crates/app/Cargo.toml +++ b/crates/app/Cargo.toml @@ -10,6 +10,7 @@ axum = "0.7.5" listenfd = "1.0.1" notify = "6.1.1" serde = { version = "1.0.204", features = ["derive"] } +thiserror = "1.0.63" tokio = { version = "1.39.1", features = ["macros", "rt-multi-thread"] } tower-http = { version = "0.5.2", features = ["fs"] } tower-livereload = "0.9.3" diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index bf3cea0..98f0882 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -3,12 +3,23 @@ use axum::body::Body; use axum::http::Request; use listenfd::ListenFd; use notify::Watcher; -use std::env; use std::path::Path; +use std::{env, io}; +use thiserror::Error; use tokio::net::TcpListener; use tower_livereload::predicate::Predicate; 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 /// Voir https://github.com/leotaku/tower-livereload/pull/3 #[derive(Copy, Clone)] @@ -20,44 +31,47 @@ impl Predicate> for NotHtmxPredicate { } const DEFAULT_LISTENER: &str = "localhost:3000"; -async fn get_tcp_listener() -> TcpListener { +async fn get_tcp_listener() -> Result { 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 Some(listener) => { - listener.set_nonblocking(true).unwrap(); - TcpListener::from_std(listener).unwrap() + listener.set_nonblocking(true)?; + Ok(TcpListener::from_std(listener)?) } // 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 { +fn get_livereload_layer( + templates_path: &Path, +) -> Result, notify::Error> { let livereload = LiveReloadLayer::new(); let reloader = livereload.reloader(); - let mut watcher = notify::recommended_watcher(move |_| reloader.reload()).unwrap(); - watcher - .watch(templates_path, notify::RecursiveMode::Recursive) - .unwrap(); - livereload.request_predicate::(NotHtmxPredicate) + let mut watcher = notify::recommended_watcher(move |_| reloader.reload())?; + watcher.watch(templates_path, notify::RecursiveMode::Recursive)?; + Ok(livereload.request_predicate::(NotHtmxPredicate)) } #[tokio::main] -async fn main() { - let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); +async fn main() -> Result<(), AppError> { + 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 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 listener: TcpListener = get_tcp_listener().await; - println!("Listening on: http://{}", listener.local_addr().unwrap()); + let listener: TcpListener = get_tcp_listener().await.map_err(AppError::TCPListener)?; + let local_addr = listener.local_addr().map_err(AppError::TCPListener)?; + println!("Listening on: http://{}", local_addr); // Run the server with the router - axum::serve(listener, router.into_make_service()) - .await - .unwrap(); + axum::serve(listener, router.into_make_service()).await?; + Ok(()) }