Skip to content

Commit

Permalink
feat: various fixes for writing actual projects with the framework
Browse files Browse the repository at this point in the history
This fixes a lot of stuff found when writing the documentation page:
* Add live reloading middleware
* Add support for response body-modifying middlewares
* Rename reverse_str!() to reverse!() and change param format a bit to
  be more intuitive
* Rename reverse!() to reverse_redirect!() since getting a URL as string
  is far more common than returning a redirect response
* Fixes around error handling, examples, documentation, etc.
* Updated year in LICENSE-MIT
  • Loading branch information
m4tx committed Jan 16, 2025
1 parent 2d9add6 commit 86e995a
Show file tree
Hide file tree
Showing 23 changed files with 345 additions and 71 deletions.
49 changes: 32 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ thiserror = "2"
time = { version = "0.3.35", default-features = false }
tokio = { version = "1.41", default-features = false }
tower = "0.5.2"
# TODO switch back to the published version when https://github.com/leotaku/tower-livereload/pull/24 is released
tower-livereload = { git = "https://github.com/leotaku/tower-livereload.git", rev = "106cc96f91b11a1eca6d3dfc86be4e766a90a415" }
tower-sessions = { version = "0.13", default-features = false }
tracing = { version = "0.1", default-features = false }
tracing-subscriber = "0.3"
Expand Down
2 changes: 1 addition & 1 deletion LICENSE-MIT
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 Cot Authors
Copyright (c) 2024-2025 Cot contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
3 changes: 3 additions & 0 deletions cot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ thiserror.workspace = true
time.workspace = true
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
tower = { workspace = true, features = ["util"] }
tower-livereload = { workspace = true, optional = true }
tower-sessions = { workspace = true, features = ["memory-store"] }
tracing.workspace = true

Expand All @@ -67,9 +68,11 @@ ignored = [

[features]
default = ["sqlite", "postgres", "mysql", "json"]
full = ["default", "fake", "live-reload"]
fake = ["dep:fake"]
db = []
sqlite = ["db", "sea-query/backend-sqlite", "sea-query-binder/sqlx-sqlite", "sqlx/sqlite"]
postgres = ["db", "sea-query/backend-postgres", "sea-query-binder/sqlx-postgres", "sqlx/postgres"]
mysql = ["db", "sea-query/backend-mysql", "sea-query-binder/sqlx-mysql", "sqlx/mysql"]
json = ["serde_json"]
live-reload = ["dep:tower-livereload"]
8 changes: 4 additions & 4 deletions cot/src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::forms::{
use crate::request::{Request, RequestExt};
use crate::response::{Response, ResponseExt};
use crate::router::Router;
use crate::{reverse, static_files, Body, CotApp, Render, StatusCode};
use crate::{reverse_redirect, static_files, Body, CotApp, Render, StatusCode};

#[derive(Debug, Form)]
struct LoginForm {
Expand Down Expand Up @@ -60,7 +60,7 @@ async fn index(mut request: Request) -> cot::Result<Response> {
Body::fixed(template.render()?),
))
} else {
Ok(reverse!(request, "login"))
Ok(reverse_redirect!(request, "login"))
}
}

Expand All @@ -72,7 +72,7 @@ async fn login(mut request: Request) -> cot::Result<Response> {
match login_form {
FormResult::Ok(login_form) => {
if authenticate(&mut request, login_form).await? {
return Ok(reverse!(request, "index"));
return Ok(reverse_redirect!(request, "index"));
}

let mut context = LoginForm::build_context(&mut request).await?;
Expand Down Expand Up @@ -139,7 +139,7 @@ async fn view_model(mut request: Request) -> cot::Result<Response> {
Body::fixed(template.render()?),
))
} else {
Ok(reverse!(request, "login"))
Ok(reverse_redirect!(request, "login"))
}
}

Expand Down
19 changes: 18 additions & 1 deletion cot/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ impl Error {
}
}

#[must_use]
pub fn custom<E>(error: E) -> Self
where
E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
{
Self::new(ErrorRepr::Custom(error.into()))
}

#[must_use]
pub(crate) fn backtrace(&self) -> &CotBacktrace {
&self.backtrace
Expand Down Expand Up @@ -78,13 +86,16 @@ impl_error_from_repr!(serde_json::Error);
#[derive(Debug, Error)]
#[non_exhaustive]
pub(crate) enum ErrorRepr {
/// A custom user error occurred.
#[error("{0}")]
Custom(#[source] Box<dyn std::error::Error + Send + Sync>),
/// An error occurred while trying to start the server.
#[error("Could not start server: {source}")]
StartServer { source: std::io::Error },
/// An error occurred while trying to read the request body.
#[error("Could not retrieve request body: {source}")]
ReadRequestBody {
#[from]
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
/// The request body had an invalid `Content-Type` header.
Expand Down Expand Up @@ -120,6 +131,12 @@ pub(crate) enum ErrorRepr {
#[error("JSON error: {0}")]
#[cfg(feature = "json")]
JsonError(#[from] serde_json::Error),
/// An error occurred inside a middleware-wrapped view.
#[error("{source}")]
MiddlewareWrapped {
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
}

#[cfg(test)]
Expand Down
3 changes: 1 addition & 2 deletions cot/src/error_page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ fn build_cot_failure_page() -> axum::response::Response {
axum::response::Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(axum::body::Body::from(FAILURE_PAGE))
.expect("Building the Cot failure page should not fail")
.expect("Building the Cot failure page should never fail")
}

thread_local! {
Expand All @@ -310,7 +310,6 @@ thread_local! {
}

pub(super) fn error_page_panic_hook(info: &PanicHookInfo<'_>) {
// TODO print out the panic as well
let location = info.location().map(|location| format!("{location}"));
PANIC_LOCATION.replace(location);

Expand Down
Loading

0 comments on commit 86e995a

Please sign in to comment.