better error handling using anyhow
This commit is contained in:
parent
425ec50a5f
commit
ad3a235982
4 changed files with 66 additions and 51 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -20,6 +20,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "askama"
|
name = "askama"
|
||||||
version = "0.14.0"
|
version = "0.14.0"
|
||||||
|
|
@ -812,6 +818,7 @@ checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
||||||
name = "task_counter"
|
name = "task_counter"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"askama",
|
"askama",
|
||||||
"axum",
|
"axum",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anyhow = "1.0.100"
|
||||||
askama = "0.14.0"
|
askama = "0.14.0"
|
||||||
axum = "0.8.6"
|
axum = "0.8.6"
|
||||||
chrono = "0.4.42"
|
chrono = "0.4.42"
|
||||||
|
|
|
||||||
BIN
foods.db
BIN
foods.db
Binary file not shown.
109
src/main.rs
109
src/main.rs
|
|
@ -5,7 +5,7 @@ use axum::{
|
||||||
Router,
|
Router,
|
||||||
extract::{MatchedPath, Path, State},
|
extract::{MatchedPath, Path, State},
|
||||||
http::{Request, StatusCode},
|
http::{Request, StatusCode},
|
||||||
response::Html,
|
response::{Html, IntoResponse, Response},
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
@ -80,7 +80,7 @@ impl Food {
|
||||||
struct PreparedStatements {}
|
struct PreparedStatements {}
|
||||||
|
|
||||||
impl<'conn> PreparedStatements {
|
impl<'conn> PreparedStatements {
|
||||||
fn check(conn: &Connection) -> rusqlite::Result<Self> {
|
fn check(conn: &Connection) -> anyhow::Result<Self> {
|
||||||
conn.prepare_cached(include_str!("increase.sql"))?;
|
conn.prepare_cached(include_str!("increase.sql"))?;
|
||||||
conn.prepare_cached(include_str!("decrease.sql"))?;
|
conn.prepare_cached(include_str!("decrease.sql"))?;
|
||||||
conn.prepare_cached(include_str!("get_food.sql"))?;
|
conn.prepare_cached(include_str!("get_food.sql"))?;
|
||||||
|
|
@ -121,10 +121,35 @@ impl<'conn> PreparedStatements {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make our own error that wraps `anyhow::Error`.
|
||||||
|
struct AppError(anyhow::Error);
|
||||||
|
|
||||||
|
// Tell axum how to convert `AppError` into a response.
|
||||||
|
impl IntoResponse for AppError {
|
||||||
|
fn into_response(self) -> Response {
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
format!("Something went wrong: {}", self.0),
|
||||||
|
)
|
||||||
|
.into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into
|
||||||
|
// `Result<_, AppError>`. That way you don't need to do that manually.
|
||||||
|
impl<E> From<E> for AppError
|
||||||
|
where
|
||||||
|
E: Into<anyhow::Error>,
|
||||||
|
{
|
||||||
|
fn from(err: E) -> Self {
|
||||||
|
Self(err.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ConnState = Arc<Mutex<Connection>>;
|
type ConnState = Arc<Mutex<Connection>>;
|
||||||
|
|
||||||
fn get_version(tx: &Transaction) -> rusqlite::Result<usize> {
|
fn get_version(tx: &Transaction) -> anyhow::Result<usize> {
|
||||||
tx.query_one(include_str!("get_version.sql"), (), |row| row.get(0))
|
Ok(tx.query_one(include_str!("get_version.sql"), (), |row| row.get(0))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_migrations() -> [&'static str; 4] {
|
fn get_migrations() -> [&'static str; 4] {
|
||||||
|
|
@ -136,7 +161,7 @@ fn get_migrations() -> [&'static str; 4] {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_migrations(conn: &mut Connection) -> rusqlite::Result<()> {
|
fn do_migrations(conn: &mut Connection) -> anyhow::Result<()> {
|
||||||
let migrations = get_migrations();
|
let migrations = get_migrations();
|
||||||
let num_migrations = migrations.len();
|
let num_migrations = migrations.len();
|
||||||
let tx = conn.transaction()?;
|
let tx = conn.transaction()?;
|
||||||
|
|
@ -198,7 +223,7 @@ fn app(conn: Connection) -> axum::Router {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), std::io::Error> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
tracing_subscriber::registry()
|
tracing_subscriber::registry()
|
||||||
.with(
|
.with(
|
||||||
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
|
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
|
||||||
|
|
@ -239,10 +264,11 @@ async fn main() -> Result<(), std::io::Error> {
|
||||||
.local_addr()
|
.local_addr()
|
||||||
.expect("failed to get local listening address")
|
.expect("failed to get local listening address")
|
||||||
);
|
);
|
||||||
axum::serve(listener, app).await
|
axum::serve(listener, app).await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_foods(conn: &ConnState) -> rusqlite::Result<Vec<Food>> {
|
fn get_foods(conn: &ConnState) -> anyhow::Result<Vec<Food>> {
|
||||||
let conn = conn.lock();
|
let conn = conn.lock();
|
||||||
let mut stmt = PreparedStatements::get_foods(&conn);
|
let mut stmt = PreparedStatements::get_foods(&conn);
|
||||||
let foods: Vec<_> = stmt
|
let foods: Vec<_> = stmt
|
||||||
|
|
@ -252,7 +278,7 @@ fn get_foods(conn: &ConnState) -> rusqlite::Result<Vec<Food>> {
|
||||||
Ok(foods)
|
Ok(foods)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_sum(conn: &Arc<Mutex<Connection>>) -> rusqlite::Result<Sum> {
|
fn get_sum(conn: &Arc<Mutex<Connection>>) -> anyhow::Result<Sum> {
|
||||||
let conn = conn.lock();
|
let conn = conn.lock();
|
||||||
let mut stmt = PreparedStatements::get_sum(&conn);
|
let mut stmt = PreparedStatements::get_sum(&conn);
|
||||||
let sum = stmt.query_one((), |row| {
|
let sum = stmt.query_one((), |row| {
|
||||||
|
|
@ -272,22 +298,15 @@ fn get_date() -> String {
|
||||||
date
|
date
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn root(State(conn): State<ConnState>) -> Result<Html<String>, StatusCode> {
|
async fn root(State(conn): State<ConnState>) -> Result<Html<String>, AppError> {
|
||||||
let foods = get_foods(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
let foods = get_foods(&conn)?;
|
||||||
let sum = get_sum(&conn).map_err(|e| {
|
let sum = get_sum(&conn)?;
|
||||||
error!(?e);
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR
|
|
||||||
})?;
|
|
||||||
let date = get_date();
|
let date = get_date();
|
||||||
let index = IndexTemplate { foods, sum, date };
|
let index = IndexTemplate { foods, sum, date };
|
||||||
Ok(Html(
|
Ok(Html(index.render()?))
|
||||||
index
|
|
||||||
.render()
|
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_increase(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<()> {
|
fn do_increase(conn: &Arc<Mutex<Connection>>, id: i32) -> anyhow::Result<()> {
|
||||||
let conn = conn.lock();
|
let conn = conn.lock();
|
||||||
let mut stmt = PreparedStatements::increase(&conn);
|
let mut stmt = PreparedStatements::increase(&conn);
|
||||||
let new: i32 = stmt.query_one((id,), |row| row.get(0))?;
|
let new: i32 = stmt.query_one((id,), |row| row.get(0))?;
|
||||||
|
|
@ -295,7 +314,7 @@ fn do_increase(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_food(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<Food> {
|
fn get_food(conn: &Arc<Mutex<Connection>>, id: i32) -> anyhow::Result<Food> {
|
||||||
let conn = conn.lock();
|
let conn = conn.lock();
|
||||||
let mut stmt = PreparedStatements::get_food(&conn);
|
let mut stmt = PreparedStatements::get_food(&conn);
|
||||||
let food = stmt.query_one((id,), Food::from_row)?;
|
let food = stmt.query_one((id,), Food::from_row)?;
|
||||||
|
|
@ -306,20 +325,16 @@ fn get_food(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<Food> {
|
||||||
async fn increase(
|
async fn increase(
|
||||||
State(conn): State<Arc<Mutex<Connection>>>,
|
State(conn): State<Arc<Mutex<Connection>>>,
|
||||||
Path(id): Path<i32>,
|
Path(id): Path<i32>,
|
||||||
) -> Result<Html<String>, StatusCode> {
|
) -> Result<Html<String>, AppError> {
|
||||||
do_increase(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
do_increase(&conn, id)?;
|
||||||
let food = get_food(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
let food = get_food(&conn, id)?;
|
||||||
let sum = get_sum(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
let sum = get_sum(&conn)?;
|
||||||
let date = get_date();
|
let date = get_date();
|
||||||
let update = FoodUpdateTemplate { food, sum, date };
|
let update = FoodUpdateTemplate { food, sum, date };
|
||||||
Ok(Html(
|
Ok(Html(update.render()?))
|
||||||
update
|
|
||||||
.render()
|
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_decrease(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<()> {
|
fn do_decrease(conn: &Arc<Mutex<Connection>>, id: i32) -> anyhow::Result<()> {
|
||||||
let conn = conn.lock();
|
let conn = conn.lock();
|
||||||
let mut stmt = PreparedStatements::decrease(&conn);
|
let mut stmt = PreparedStatements::decrease(&conn);
|
||||||
let new: i32 = stmt.query_one((id,), |row| row.get(0))?;
|
let new: i32 = stmt.query_one((id,), |row| row.get(0))?;
|
||||||
|
|
@ -330,20 +345,16 @@ fn do_decrease(conn: &Arc<Mutex<Connection>>, id: i32) -> rusqlite::Result<()> {
|
||||||
async fn decrease(
|
async fn decrease(
|
||||||
State(conn): State<Arc<Mutex<Connection>>>,
|
State(conn): State<Arc<Mutex<Connection>>>,
|
||||||
Path(id): Path<i32>,
|
Path(id): Path<i32>,
|
||||||
) -> Result<Html<String>, StatusCode> {
|
) -> Result<Html<String>, AppError> {
|
||||||
do_decrease(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
do_decrease(&conn, id)?;
|
||||||
let food = get_food(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
let food = get_food(&conn, id)?;
|
||||||
let sum = get_sum(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
let sum = get_sum(&conn)?;
|
||||||
let date = get_date();
|
let date = get_date();
|
||||||
let update = FoodUpdateTemplate { food, sum, date };
|
let update = FoodUpdateTemplate { food, sum, date };
|
||||||
Ok(Html(
|
Ok(Html(update.render()?))
|
||||||
update
|
|
||||||
.render()
|
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_set(conn: &Arc<Mutex<Connection>>, id: i32, amount: i32) -> rusqlite::Result<()> {
|
fn do_set(conn: &Arc<Mutex<Connection>>, id: i32, amount: i32) -> anyhow::Result<()> {
|
||||||
let conn = conn.lock();
|
let conn = conn.lock();
|
||||||
let mut stmt = PreparedStatements::set(&conn);
|
let mut stmt = PreparedStatements::set(&conn);
|
||||||
let new: i32 = stmt.query_one((id, amount), |row| row.get(0))?;
|
let new: i32 = stmt.query_one((id, amount), |row| row.get(0))?;
|
||||||
|
|
@ -354,15 +365,11 @@ fn do_set(conn: &Arc<Mutex<Connection>>, id: i32, amount: i32) -> rusqlite::Resu
|
||||||
async fn set(
|
async fn set(
|
||||||
State(conn): State<Arc<Mutex<Connection>>>,
|
State(conn): State<Arc<Mutex<Connection>>>,
|
||||||
Path((id, amount)): Path<(i32, i32)>,
|
Path((id, amount)): Path<(i32, i32)>,
|
||||||
) -> Result<Html<String>, StatusCode> {
|
) -> Result<Html<String>, AppError> {
|
||||||
do_set(&conn, id, amount).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
do_set(&conn, id, amount)?;
|
||||||
let food = get_food(&conn, id).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
let food = get_food(&conn, id)?;
|
||||||
let sum = get_sum(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
let sum = get_sum(&conn)?;
|
||||||
let date = get_date();
|
let date = get_date();
|
||||||
let update = FoodUpdateTemplate { food, sum, date };
|
let update = FoodUpdateTemplate { food, sum, date };
|
||||||
Ok(Html(
|
Ok(Html(update.render()?))
|
||||||
update
|
|
||||||
.render()
|
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue