diff options
Diffstat (limited to 'src/cli.rs')
| -rw-r--r-- | src/cli.rs | 62 |
1 files changed, 30 insertions, 32 deletions
@@ -3,7 +3,7 @@ //! This module supports running `pilcrow` as a freestanding program, via the //! [`Args`] struct. -use std::{future, io, str}; +use std::{future, str}; use axum::{ http::header, @@ -15,10 +15,13 @@ use sqlx::sqlite::SqlitePool; use tokio::net; use web_push::{IsahcWebPushClient, WebPushClient}; +pub use crate::exit::Exit; use crate::{ app::App, - clock, db, routes, - umask::{self, Umask}, + clock, db, + error::failed::{Failed, ResultExt as _}, + routes, + umask::Umask, }; /// Command-line entry point for running the `pilcrow` server. @@ -96,20 +99,24 @@ impl Args { /// of the failure. pub async fn run(self) -> Result<(), impl std::error::Error> { self.umask.set(); - let pool = self.pool().await?; + let pool = self.pool().await.fail("Failed to create database pool")?; - let webpush = IsahcWebPushClient::new()?; + let webpush = IsahcWebPushClient::new().fail("Failed to create web push publisher")?; let app = App::from(pool, webpush); match self.command { None => self.serve(app).await?, - Some(Command::RotateVapidKey) => app.vapid().rotate_key().await?, + Some(Command::RotateVapidKey) => app + .vapid() + .rotate_key() + .await + .fail("Failed to rotate VAPID key")?, } - Result::<_, Error>::Ok(()) + Result::<_, Failed>::Ok(()) } - async fn serve<P>(self, app: App<P>) -> Result<(), Error> + async fn serve<P>(self, app: App<P>) -> Result<(), Failed> where P: WebPushClient + Clone + Send + Sync + 'static, { @@ -118,24 +125,25 @@ impl Args { .route_layer(middleware::map_response(Self::server_info())) .with_state(app); - let listener = self.listener().await?; - let started_msg = started_msg(&listener)?; + let listen_addr = self.listen_addr(); + let listener = net::TcpListener::bind(&listen_addr).await.fail_with(|| { + format!( + "Failed to bind to {host}:{port}", + host = listen_addr.0, + port = listen_addr.1 + ) + })?; + let started_msg = started_msg(&listen_addr); let serve = axum::serve(listener, app); println!("{started_msg}"); - serve.await?; + serve.await.fail("Failed to serve application")?; Ok(()) } - async fn listener(&self) -> io::Result<net::TcpListener> { - let listen_addr = self.listen_addr(); - let listener = tokio::net::TcpListener::bind(listen_addr).await?; - Ok(listener) - } - - fn listen_addr(&self) -> impl net::ToSocketAddrs + '_ { - (self.address.as_str(), self.port) + fn listen_addr(&self) -> (String, u16) { + (self.address.clone(), self.port) } async fn pool(&self) -> Result<SqlitePool, db::Error> { @@ -154,17 +162,7 @@ impl Args { } } -fn started_msg(listener: &net::TcpListener) -> io::Result<String> { - let local_addr = listener.local_addr()?; - Ok(format!("listening on http://{local_addr}/")) -} - -#[derive(Debug, thiserror::Error)] -#[error(transparent)] -enum Error { - Io(#[from] io::Error), - Database(#[from] db::Error), - Sqlx(#[from] sqlx::Error), - Umask(#[from] umask::Error), - Webpush(#[from] web_push::WebPushError), +fn started_msg(listen_addr: &(String, u16)) -> String { + let (host, port) = listen_addr; + format!("Listening on http://{host}:{port}/") } |
