From a254a4a08146cca551382da78032e58dfc302b3d Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sun, 21 Jan 2024 11:43:11 +0000 Subject: [PATCH] Expose page generation time --- src/main.rs | 46 ++++++++++++++++++++++++++++++++++++++++++---- templates/base.html | 4 +++- templates/index.html | 3 ++- src/layers/logger.rs | 9 +++++++-- src/methods/filters.rs | 7 +++++++ src/methods/index.rs | 21 +++++++++++++-------- src/methods/repo/about.rs | 11 +++++++---- src/methods/repo/commit.rs | 11 +++++++---- src/methods/repo/diff.rs | 9 ++++++--- src/methods/repo/log.rs | 13 +++++-------- src/methods/repo/refs.rs | 6 +++--- src/methods/repo/summary.rs | 14 ++++++-------- src/methods/repo/tag.rs | 11 +++++++---- src/methods/repo/tree.rs | 38 ++++++++++++++++++++++---------------- templates/repo/macros/refs.html | 1 + 15 files changed, 127 insertions(+), 77 deletions(-) diff --git a/src/main.rs b/src/main.rs index ee61a4c..fb55d94 100644 --- a/src/main.rs +++ a/src/main.rs @@ -315,17 +315,41 @@ Box::from(out) } -#[instrument(skip(t))] -pub fn into_response(t: &T) -> Response { - match t.render() { - Ok(body) => { - let headers = [( - http::header::CONTENT_TYPE, - HeaderValue::from_static(T::MIME_TYPE), - )]; - - (headers, body).into_response() +pub struct TemplateResponse { + template: T, +} + +impl IntoResponse for TemplateResponse { + #[instrument(skip_all)] + fn into_response(self) -> Response { + match self.template.render() { + Ok(body) => { + let headers = [( + http::header::CONTENT_TYPE, + HeaderValue::from_static(T::MIME_TYPE), + )]; + + (headers, body).into_response() + } + Err(_) => StatusCode::INTERNAL_SERVER_ERROR.into_response(), + } + } +} + +pub fn into_response(template: T) -> impl IntoResponse { + TemplateResponse { template } +} + +pub enum ResponseEither { + Left(A), + Right(B), +} + +impl IntoResponse for ResponseEither { + fn into_response(self) -> Response { + match self { + Self::Left(a) => a.into_response(), + Self::Right(b) => b.into_response(), } - Err(_) => StatusCode::INTERNAL_SERVER_ERROR.into_response(), } } diff --git a/templates/base.html b/templates/base.html index 3000365..34eef63 100644 --- a/templates/base.html +++ a/templates/base.html @@ -35,7 +35,9 @@
- generated by rgit v{{ crate::CRATE_VERSION }} at {{ time::OffsetDateTime::now_utc().to_string() }} + generated by rgit v{{ crate::CRATE_VERSION }} + at {{ time::OffsetDateTime::now_utc()|format_time }} + in {{ "{:?}"|format(crate::layers::logger::REQ_TIMESTAMP.get().elapsed()) }}
diff --git a/templates/index.html b/templates/index.html index 2544395..a15551e 100644 --- a/templates/index.html +++ a/templates/index.html @@ -12,12 +12,13 @@ - {%- for (path, repositories) in repositories.iter() %} + {%- for (path, repositories) in repositories %} {%- if let Some(path) = path %} {{ path }} {%- endif -%} {%- for repository in repositories %} + {% set repository = repository.get() %} diff --git a/src/layers/logger.rs b/src/layers/logger.rs index 5ccdc3e..0affeea 100644 --- a/src/layers/logger.rs +++ a/src/layers/logger.rs @@ -12,6 +12,7 @@ http::{HeaderValue, Method, Request, Response}, }; use futures::future::{Future, FutureExt, Join, Map, Ready}; +use tokio::task::futures::TaskLocalFuture; use tower_service::Service; use tracing::{error, info, instrument::Instrumented, Instrument, Span}; use uuid::Uuid; @@ -37,7 +38,7 @@ type Response = S::Response; type Error = S::Error; type Future = Map< - Join, Ready>, + Join>, Ready>, fn((::Output, PendingLogMessage)) -> ::Output, >; @@ -63,7 +64,7 @@ }; futures::future::join( - self.0.call(req).instrument(span), + REQ_TIMESTAMP.scope(log_message.start, self.0.call(req).instrument(span)), futures::future::ready(log_message), ) .map(|(response, pending_log_message)| { @@ -76,6 +77,10 @@ Ok(response) }) } +} + +tokio::task_local! { + pub static REQ_TIMESTAMP: Instant; } pub struct PendingLogMessage { diff --git a/src/methods/filters.rs b/src/methods/filters.rs index f6d6f6b..273bb7e 100644 --- a/src/methods/filters.rs +++ a/src/methods/filters.rs @@ -1,7 +1,14 @@ // sorry clippy, we don't have a choice. askama forces this on us #![allow(clippy::unnecessary_wraps, clippy::trivially_copy_pass_by_ref)] use std::borrow::Borrow; +use time::format_description::well_known::Rfc3339; + +pub fn format_time(s: time::OffsetDateTime) -> Result { + s.format(&Rfc3339) + .map_err(Box::from) + .map_err(askama::Error::Custom) +} pub fn timeago(s: impl Borrow) -> Result { Ok(timeago::Formatter::new() diff --git a/src/methods/index.rs b/src/methods/index.rs index 40a8b8c..ed10048 100644 --- a/src/methods/index.rs +++ a/src/methods/index.rs @@ -1,35 +1,38 @@ use std::{collections::BTreeMap, sync::Arc}; use anyhow::Context; use askama::Template; -use axum::{response::Response, Extension}; +use axum::{response::IntoResponse, Extension}; use super::filters; -use crate::{database::schema::repository::Repository, into_response}; +use crate::{ + database::schema::repository::{Repository, YokedRepository}, + into_response, +}; #[derive(Template)] #[template(path = "index.html")] -pub struct View<'a> { - pub repositories: BTreeMap, Vec<&'a Repository<'a>>>, +pub struct View { + pub repositories: BTreeMap, Vec>, } pub async fn handle( Extension(db): Extension>, -) -> Result { - let mut repositories: BTreeMap, Vec<&Repository<'_>>> = BTreeMap::new(); +) -> Result { + let mut repositories: BTreeMap, Vec> = BTreeMap::new(); let fetched = tokio::task::spawn_blocking(move || Repository::fetch_all(&db)) .await .context("Failed to join Tokio task")??; - for (k, v) in &fetched { + for (k, v) in fetched { // TODO: fixme let mut split: Vec<_> = k.split('/').collect(); split.pop(); let key = Some(split.join("/")).filter(|v| !v.is_empty()); let k = repositories.entry(key).or_default(); - k.push(v.get()); + k.push(v); } - Ok(into_response(&View { repositories })) + Ok(into_response(View { repositories })) } diff --git a/src/methods/repo/about.rs b/src/methods/repo/about.rs index f8e86cf..b597f31 100644 --- a/src/methods/repo/about.rs +++ a/src/methods/repo/about.rs @@ -1,13 +1,16 @@ use std::sync::Arc; use askama::Template; -use axum::{extract::Query, response::Response, Extension}; +use axum::{extract::Query, response::IntoResponse, Extension}; use serde::Deserialize; use crate::{ git::ReadmeFormat, into_response, - methods::repo::{Repository, RepositoryPath, Result}, + methods::{ + filters, + repo::{Repository, RepositoryPath, Result}, + }, Git, }; @@ -30,14 +33,14 @@ Extension(RepositoryPath(repository_path)): Extension, Extension(git): Extension>, Query(query): Query, -) -> Result { +) -> Result { let open_repo = git .clone() .repo(repository_path, query.branch.clone()) .await?; let readme = open_repo.readme().await?; - Ok(into_response(&View { + Ok(into_response(View { repo, readme, branch: query.branch, diff --git a/src/methods/repo/commit.rs b/src/methods/repo/commit.rs index b339ff8..e089ab7 100644 --- a/src/methods/repo/commit.rs +++ a/src/methods/repo/commit.rs @@ -1,13 +1,16 @@ use std::sync::Arc; use askama::Template; -use axum::{extract::Query, response::Response, Extension}; +use axum::{extract::Query, response::IntoResponse, Extension}; use serde::Deserialize; use crate::{ git::Commit, into_response, - methods::repo::{Repository, RepositoryPath, Result}, + methods::{ + filters, + repo::{Repository, RepositoryPath, Result}, + }, Git, }; @@ -33,7 +36,7 @@ Extension(RepositoryPath(repository_path)): Extension, Extension(git): Extension>, Query(query): Query, -) -> Result { +) -> Result { let open_repo = git.repo(repository_path, query.branch.clone()).await?; let dl_branch = if let Some(branch) = query.branch.clone() { @@ -56,7 +59,7 @@ Arc::new(open_repo.latest_commit().await?) }; - Ok(into_response(&View { + Ok(into_response(View { repo, commit, branch: query.branch, diff --git a/src/methods/repo/diff.rs b/src/methods/repo/diff.rs index ebc7e25..0a6a6c6 100644 --- a/src/methods/repo/diff.rs +++ a/src/methods/repo/diff.rs @@ -11,7 +11,10 @@ use crate::{ git::Commit, http, into_response, - methods::repo::{commit::UriQuery, Repository, RepositoryPath, Result}, + methods::{ + filters, + repo::{commit::UriQuery, Repository, RepositoryPath, Result}, + }, Git, }; @@ -28,7 +31,7 @@ Extension(RepositoryPath(repository_path)): Extension, Extension(git): Extension>, Query(query): Query, -) -> Result { +) -> Result { let open_repo = git.repo(repository_path, query.branch.clone()).await?; let commit = if let Some(commit) = query.id { open_repo.commit(&commit).await? @@ -36,7 +39,7 @@ Arc::new(open_repo.latest_commit().await?) }; - Ok(into_response(&View { + Ok(into_response(View { repo, commit, branch: query.branch, diff --git a/src/methods/repo/log.rs b/src/methods/repo/log.rs index 80f4b1e..1882317 100644 --- a/src/methods/repo/log.rs +++ a/src/methods/repo/log.rs @@ -1,10 +1,9 @@ use std::sync::Arc; use anyhow::Context; use askama::Template; -use axum::{extract::Query, response::Response, Extension}; +use axum::{extract::Query, response::IntoResponse, Extension}; use serde::Deserialize; -use yoke::Yoke; use crate::{ database::schema::{commit::YokedCommit, repository::YokedRepository}, @@ -25,9 +24,9 @@ #[derive(Template)] #[template(path = "repo/log.html")] -pub struct View<'a> { +pub struct View { repo: Repository, - commits: Vec<&'a crate::database::schema::commit::Commit<'a>>, + commits: Vec, next_offset: Option, branch: Option, } @@ -36,7 +35,7 @@ Extension(repo): Extension, Extension(db): Extension>, Query(query): Query, -) -> Result { +) -> Result { tokio::task::spawn_blocking(move || { let offset = query.offset.unwrap_or(0); @@ -52,9 +51,7 @@ None }; - let commits = commits.iter().map(Yoke::get).collect(); - - Ok(into_response(&View { + Ok(into_response(View { repo, commits, next_offset, diff --git a/src/methods/repo/refs.rs b/src/methods/repo/refs.rs index 660065b..9ed2814 100644 --- a/src/methods/repo/refs.rs +++ a/src/methods/repo/refs.rs @@ -1,8 +1,8 @@ use std::{collections::BTreeMap, sync::Arc}; use anyhow::Context; use askama::Template; -use axum::{response::Response, Extension}; +use axum::{response::IntoResponse, Extension}; use crate::{ into_response, @@ -23,7 +23,7 @@ pub async fn handle( Extension(repo): Extension, Extension(db): Extension>, -) -> Result { +) -> Result { tokio::task::spawn_blocking(move || { let repository = crate::database::schema::repository::Repository::open(&db, &*repo)? .context("Repository does not exist")?; @@ -40,7 +40,7 @@ let tags = repository.get().tag_tree(db).fetch_all()?; - Ok(into_response(&View { + Ok(into_response(View { repo, refs: Refs { heads, tags }, branch: None, diff --git a/src/methods/repo/summary.rs b/src/methods/repo/summary.rs index 3d6d5b4..d5cd176 100644 --- a/src/methods/repo/summary.rs +++ a/src/methods/repo/summary.rs @@ -1,9 +1,8 @@ use std::{collections::BTreeMap, sync::Arc}; use anyhow::Context; use askama::Template; -use axum::{response::Response, Extension}; -use yoke::Yoke; +use axum::{response::IntoResponse, Extension}; use crate::{ database::schema::{commit::YokedCommit, repository::YokedRepository}, @@ -16,22 +15,21 @@ #[derive(Template)] #[template(path = "repo/summary.html")] -pub struct View<'a> { +pub struct View { repo: Repository, refs: Refs, - commit_list: Vec<&'a crate::database::schema::commit::Commit<'a>>, + commit_list: Vec, branch: Option>, } pub async fn handle( Extension(repo): Extension, Extension(db): Extension>, -) -> Result { +) -> Result { tokio::task::spawn_blocking(move || { let repository = crate::database::schema::repository::Repository::open(&db, &*repo)? .context("Repository does not exist")?; let commits = get_default_branch_commits(&repository, &db)?; - let commit_list = commits.iter().map(Yoke::get).collect(); let mut heads = BTreeMap::new(); for head in repository.get().heads(&db)?.get() { @@ -45,10 +43,10 @@ let tags = repository.get().tag_tree(db).fetch_all()?; - Ok(into_response(&View { + Ok(into_response(View { repo, refs: Refs { heads, tags }, - commit_list, + commit_list: commits, branch: None, })) }) diff --git a/src/methods/repo/tag.rs b/src/methods/repo/tag.rs index e337d6b..0b7dab4 100644 --- a/src/methods/repo/tag.rs +++ a/src/methods/repo/tag.rs @@ -1,13 +1,16 @@ use std::sync::Arc; use askama::Template; -use axum::{extract::Query, response::Response, Extension}; +use axum::{extract::Query, response::IntoResponse, Extension}; use serde::Deserialize; use crate::{ git::DetailedTag, into_response, - methods::repo::{Repository, RepositoryPath, Result}, + methods::{ + filters, + repo::{Repository, RepositoryPath, Result}, + }, Git, }; @@ -30,11 +33,11 @@ Extension(RepositoryPath(repository_path)): Extension, Extension(git): Extension>, Query(query): Query, -) -> Result { +) -> Result { let open_repo = git.repo(repository_path, Some(query.name.clone())).await?; let tag = open_repo.tag_info().await?; - Ok(into_response(&View { + Ok(into_response(View { repo, tag, branch: Some(query.name), diff --git a/src/methods/repo/tree.rs b/src/methods/repo/tree.rs index 1f1ba6c..485c2da 100644 --- a/src/methods/repo/tree.rs +++ a/src/methods/repo/tree.rs @@ -1,14 +1,10 @@ use std::{ fmt::{Display, Formatter}, sync::Arc, }; use askama::Template; -use axum::{ - extract::Query, - response::{IntoResponse, Response}, - Extension, -}; +use axum::{extract::Query, response::IntoResponse, Extension}; use serde::Deserialize; use crate::{ @@ -18,7 +14,7 @@ filters, repo::{ChildPath, Repository, RepositoryPath, Result}, }, - Git, + Git, ResponseEither, }; #[derive(Deserialize)] @@ -71,7 +67,7 @@ Extension(ChildPath(child_path)): Extension, Extension(git): Extension>, Query(query): Query, -) -> Result { +) -> Result { let open_repo = git.repo(repository_path, query.branch.clone()).await?; Ok( @@ -79,18 +75,22 @@ .path(child_path, query.id.as_deref(), !query.raw) .await? { - PathDestination::Tree(items) => into_response(&TreeView { - repo, - items, - branch: query.branch.clone(), - query, - }), - PathDestination::File(file) if query.raw => file.content.into_response(), - PathDestination::File(file) => into_response(&FileView { - repo, - file, - branch: query.branch, - }), + PathDestination::Tree(items) => { + ResponseEither::Left(ResponseEither::Left(into_response(TreeView { + repo, + items, + branch: query.branch.clone(), + query, + }))) + } + PathDestination::File(file) if query.raw => ResponseEither::Right(file.content), + PathDestination::File(file) => { + ResponseEither::Left(ResponseEither::Right(into_response(FileView { + repo, + file, + branch: query.branch, + }))) + } }, ) } diff --git a/templates/repo/macros/refs.html b/templates/repo/macros/refs.html index 705697f..e802355 100644 --- a/templates/repo/macros/refs.html +++ a/templates/repo/macros/refs.html @@ -71,6 +71,7 @@ {% for commit in commits -%} + {% set commit = commit.get() %}