gitscope
← rgit / Diff · a254a4a → a254a4a
Changes a254a4a..a254a4a
Patch commit
diff --git a/src/layers/logger.rs b/src/layers/logger.rs
index 5ccdc3e..0affeea 100644
--- a/src/layers/logger.rs
+++ b/src/layers/logger.rs
@@ -12,6 +12,7 @@ use axum::{
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 @@ where
type Response = S::Response;
type Error = S::Error;
type Future = Map<
- Join<Instrumented<S::Future>, Ready<PendingLogMessage>>,
+ Join<TaskLocalFuture<Instant, Instrumented<S::Future>>, Ready<PendingLogMessage>>,
fn((<S::Future as Future>::Output, PendingLogMessage)) -> <S::Future as Future>::Output,
>;
@@ -63,7 +64,7 @@ where
};
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)| {
@@ -78,6 +79,10 @@ where
}
}
+tokio::task_local! {
+ pub static REQ_TIMESTAMP: Instant;
+}
+
pub struct PendingLogMessage {
span: Span,
request_id: Uuid,
diff --git a/src/main.rs b/src/main.rs
index ee61a4c..fb55d94 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -315,17 +315,41 @@ pub fn build_asset_hash(v: &[u8]) -> Box<str> {
Box::from(out)
}
-#[instrument(skip(t))]
-pub fn into_response<T: Template>(t: &T) -> Response {
- match t.render() {
- Ok(body) => {
- let headers = [(
- http::header::CONTENT_TYPE,
- HeaderValue::from_static(T::MIME_TYPE),
- )];
+pub struct TemplateResponse<T> {
+ template: T,
+}
+
+impl<T: Template> IntoResponse for TemplateResponse<T> {
+ #[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<T: Template>(template: T) -> impl IntoResponse {
+ TemplateResponse { template }
+}
- (headers, body).into_response()
+pub enum ResponseEither<A, B> {
+ Left(A),
+ Right(B),
+}
+
+impl<A: IntoResponse, B: IntoResponse> IntoResponse for ResponseEither<A, B> {
+ 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/src/methods/filters.rs b/src/methods/filters.rs
index f6d6f6b..273bb7e 100644
--- a/src/methods/filters.rs
+++ b/src/methods/filters.rs
@@ -2,6 +2,13 @@
#![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<String, askama::Error> {
+ s.format(&Rfc3339)
+ .map_err(Box::from)
+ .map_err(askama::Error::Custom)
+}
pub fn timeago(s: impl Borrow<time::OffsetDateTime>) -> Result<String, askama::Error> {
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
+++ b/src/methods/index.rs
@@ -2,34 +2,37 @@ 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<Option<String>, Vec<&'a Repository<'a>>>,
+pub struct View {
+ pub repositories: BTreeMap<Option<String>, Vec<YokedRepository>>,
}
pub async fn handle(
Extension(db): Extension<Arc<rocksdb::DB>>,
-) -> Result<Response, super::repo::Error> {
- let mut repositories: BTreeMap<Option<String>, Vec<&Repository<'_>>> = BTreeMap::new();
+) -> Result<impl IntoResponse, super::repo::Error> {
+ let mut repositories: BTreeMap<Option<String>, Vec<YokedRepository>> = 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
+++ b/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 @@ pub async fn handle(
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
Query(query): Query<UriQuery>,
-) -> Result<Response> {
+) -> Result<impl IntoResponse> {
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
+++ b/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 @@ pub async fn handle(
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
Query(query): Query<UriQuery>,
-) -> Result<Response> {
+) -> Result<impl IntoResponse> {
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 @@ pub async fn handle(
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
+++ b/src/methods/repo/diff.rs
@@ -11,7 +11,10 @@ use axum::{
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 @@ pub async fn handle(
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
Query(query): Query<UriQuery>,
-) -> Result<Response> {
+) -> Result<impl IntoResponse> {
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 @@ pub async fn handle(
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
+++ b/src/methods/repo/log.rs
@@ -2,9 +2,8 @@ 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 @@ pub struct UriQuery {
#[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<YokedCommit>,
next_offset: Option<u64>,
branch: Option<String>,
}
@@ -36,7 +35,7 @@ pub async fn handle(
Extension(repo): Extension<Repository>,
Extension(db): Extension<Arc<rocksdb::DB>>,
Query(query): Query<UriQuery>,
-) -> Result<Response> {
+) -> Result<impl IntoResponse> {
tokio::task::spawn_blocking(move || {
let offset = query.offset.unwrap_or(0);
@@ -52,9 +51,7 @@ pub async fn handle(
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
+++ b/src/methods/repo/refs.rs
@@ -2,7 +2,7 @@ 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 struct View {
pub async fn handle(
Extension(repo): Extension<Repository>,
Extension(db): Extension<Arc<rocksdb::DB>>,
-) -> Result<Response> {
+) -> Result<impl IntoResponse> {
tokio::task::spawn_blocking(move || {
let repository = crate::database::schema::repository::Repository::open(&db, &*repo)?
.context("Repository does not exist")?;
@@ -40,7 +40,7 @@ pub async fn handle(
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
+++ b/src/methods/repo/summary.rs
@@ -2,8 +2,7 @@ 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 @@ use crate::{
#[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<YokedCommit>,
branch: Option<Arc<str>>,
}
pub async fn handle(
Extension(repo): Extension<Repository>,
Extension(db): Extension<Arc<rocksdb::DB>>,
-) -> Result<Response> {
+) -> Result<impl IntoResponse> {
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 @@ pub async fn handle(
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
+++ b/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 @@ pub async fn handle(
Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
Extension(git): Extension<Arc<Git>>,
Query(query): Query<UriQuery>,
-) -> Result<Response> {
+) -> Result<impl IntoResponse> {
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
+++ b/src/methods/repo/tree.rs
@@ -4,11 +4,7 @@ use std::{
};
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 @@ use crate::{
filters,
repo::{ChildPath, Repository, RepositoryPath, Result},
},
- Git,
+ Git, ResponseEither,
};
#[derive(Deserialize)]
@@ -71,7 +67,7 @@ pub async fn handle(
Extension(ChildPath(child_path)): Extension<ChildPath>,
Extension(git): Extension<Arc<Git>>,
Query(query): Query<UriQuery>,
-) -> Result<Response> {
+) -> Result<impl IntoResponse> {
let open_repo = git.repo(repository_path, query.branch.clone()).await?;
Ok(
@@ -79,18 +75,22 @@ pub async fn handle(
.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/base.html b/templates/base.html
index 3000365..34eef63 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -35,7 +35,9 @@
</main>
<footer>
- generated by <a href="https://git.inept.dev/~doyle/rgit.git/about" target="_blank">rgit</a> v{{ crate::CRATE_VERSION }} at {{ time::OffsetDateTime::now_utc().to_string() }}
+ generated by <a href="https://git.inept.dev/~doyle/rgit.git/about" target="_blank">rgit</a> v{{ crate::CRATE_VERSION }}
+ at {{ time::OffsetDateTime::now_utc()|format_time }}
+ in {{ "{:?}"|format(crate::layers::logger::REQ_TIMESTAMP.get().elapsed()) }}
</footer>
</body>
</html>
diff --git a/templates/index.html b/templates/index.html
index 2544395..a15551e 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -12,12 +12,13 @@
</thead>
<tbody>
- {%- for (path, repositories) in repositories.iter() %}
+ {%- for (path, repositories) in repositories %}
{%- if let Some(path) = path %}
<tr><td class="repo-section" colspan="4">{{ path }}</td></tr>
{%- endif -%}
{%- for repository in repositories %}
+ {% set repository = repository.get() %}
<tr class="{% if path.is_some() %}has-parent{% endif %}">
<td>
<a href="/{% if let Some(path) = path %}{{ path }}/{% endif %}{{ repository.name }}">
diff --git a/templates/repo/macros/refs.html b/templates/repo/macros/refs.html
index 705697f..e802355 100644
--- a/templates/repo/macros/refs.html
+++ b/templates/repo/macros/refs.html
@@ -71,6 +71,7 @@
<tbody>
{% for commit in commits -%}
+ {% set commit = commit.get() %}
<tr>
<td>
<time datetime="{{ commit.committer.time }}" title="{{ commit.committer.time }}">