commit - 87e1be84a219cdfabd7d13aa98d7fd66b0d05704
commit + abbece2d4cffddf1a71d31ee715695610cb7871a
blob - 01cf8463955196baf438637f59a5c99f10403f6b
blob + 2f76393a844b9b813e9f3bcf92349060066b6dff
--- web/README.md
+++ web/README.md
# web template
-* Axum
-* Graceful Shutdown
-* Minijinja
-* Prometheus
-* Middleware Ip
-* Config
-* Tracing
-* 404
+* [x] Axum
+* [x] Graceful Shutdown
+* [x] Minijinja
+* [x] Prometheus
+* [ ] Middleware Ip
+* [x] Request Id Header
+* [x] Static files
+* [ ] Config
+* [x] Tracing
+* [ ] Messages (like flask)
+* [x] Sessions
+* [ ] CSRF
+* [ ] 404
blob - 4d421e1712dc62ac0ea7b179ab8e26577ac21756
blob + 63bc87a3e2c89cdd680f8aca850f0d59da2837e6
--- web/template/Cargo.toml
+++ web/template/Cargo.toml
metrics-exporter-prometheus = { version = "=0.17.2", default-features = false }
minijinja = "=2.12.0"
serde = { version = "=1.0.228", features = ["derive"] }
+time = "=0.3.44"
tokio = { version = "=1.48.0", features = ["macros", "rt-multi-thread", "signal"] }
tower-http = { version = "=0.6.6", features = ["timeout", "trace", "fs", "request-id"] }
+tower-sessions = "=0.14.0"
tracing = "=0.1.41"
tracing-subscriber = { version = "=0.3.20", features = ["env-filter"] }
blob - 1e002169f79037057ca3631f69e2749b83251b4b
blob + 45112a324af8f1f02f41c7c4107e474bff1580c8
--- web/template/src/router.rs
+++ web/template/src/router.rs
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
-use std::{sync::Arc, time::Duration};
+use std::sync::Arc;
use axum::{
Router,
routing::get,
};
use minijinja::context;
+use serde::{Deserialize, Serialize};
+use time::Duration;
use tower_http::{
request_id::{
MakeRequestUuid, PropagateRequestIdLayer, SetRequestIdLayer,
timeout::TimeoutLayer,
trace::TraceLayer,
};
+use tower_sessions::{Expiry, MemoryStore, Session, SessionManagerLayer};
use tracing::{error, info_span};
use crate::metric::track_metrics;
use crate::state::AppState;
+const COUNTER_KEY: &str = "counter";
const REQUEST_ID_HEADER: &str = "x-request-id";
+#[derive(Default, Deserialize, Serialize)]
+struct Counter(usize);
+
pub(crate) fn route(app_state: Arc<AppState>) -> Router {
let x_request_id = HeaderName::from_static(REQUEST_ID_HEADER);
+ let session_store = MemoryStore::default();
+
Router::new()
.route("/", get(handler_home))
.route("/content", get(handler_content))
.route("/about", get(handler_about))
+ .route("/session", get(handler_session))
// TODO(msi): from config folder asssets
.nest_service("/assets", ServeDir::new("assets"))
.layer((
}
},
),
+ SessionManagerLayer::new(session_store)
+ .with_secure(false)
+ .with_expiry(Expiry::OnInactivity(Duration::seconds(10))),
// TODO(msi): from config
- TimeoutLayer::new(Duration::from_secs(10)),
+ TimeoutLayer::new(std::time::Duration::from_secs(10)),
PropagateRequestIdLayer::new(x_request_id),
))
.route_layer(middleware::from_fn(track_metrics))
.with_state(app_state)
}
+async fn handler_session(session: Session) -> impl IntoResponse {
+ let counter: Counter =
+ session.get(COUNTER_KEY).await.unwrap().unwrap_or_default();
+ session.insert(COUNTER_KEY, counter.0 + 1).await.unwrap();
+ format!("Current count: {}", counter.0)
+}
+
async fn healthz() -> impl IntoResponse {
StatusCode::OK
}
blob - 02232bcc6116173cbbcaab69161cdd4ea05e4b02
blob + 1ee943a0a2f2c1fcc1d56825bb7277c0189a2817
--- web/template/templates/layout.jinja
+++ web/template/templates/layout.jinja
<li><a href="/">Home</a></li>
<li><a href="/content">Content</a></li>
<li><a href="/about">About</a></li>
+ <li><a href="/session">Session</a></li>
</ul>
</nav>
<h1><h1>Hello, World web =]</h1>