gitscope
← rgit / main / src/methods/index.rs
https://dev.kronoz.win/r/rgit.git
src/methods/index.rs · Rust
Blame Raw
 1use std::{cell::RefCell, sync::Arc};
 2
 3use anyhow::Context;
 4use askama::Template;
 5use axum::{
 6    Extension,
 7    response::{IntoResponse, Response},
 8};
 9use itertools::{Either, Itertools};
10
11use super::filters;
12use crate::{
13    database::schema::repository::{Repository, YokedRepository},
14    into_response,
15};
16
17#[derive(Template)]
18#[template(path = "index.html")]
19pub struct View<
20    'a,
21    Group: Iterator<Item = (&'a String, &'a YokedRepository)>,
22    GroupIter: Iterator<Item = (&'a str, Group)>,
23> {
24    // this type sig is a necessary evil unfortunately, because askama takes a reference
25    // to the data for rendering.
26    pub repositories: RefCell<Either<GroupIter, std::iter::Empty<(&'a str, Group)>>>,
27}
28
29impl<'a, Group, GroupIter> View<'a, Group, GroupIter>
30where
31    Group: Iterator<Item = (&'a String, &'a YokedRepository)>,
32    GroupIter: Iterator<Item = (&'a str, Group)>,
33{
34    fn take_iter(&self) -> Either<GroupIter, std::iter::Empty<(&'a str, Group)>> {
35        self.repositories.replace(Either::Right(std::iter::empty()))
36    }
37}
38
39pub async fn handle(
40    Extension(db): Extension<Arc<rocksdb::DB>>,
41) -> Result<Response, super::repo::Error> {
42    let fetched = tokio::task::spawn_blocking(move || Repository::fetch_all(&db))
43        .await
44        .context("Failed to join Tokio task")??;
45
46    // rocksdb returned the keys already ordered for us so group_by is a nice
47    // operation we can use here to avoid writing into a map to group. though,
48    // now that i think about it it might act a little bit strangely when mixing
49    // root repositories and nested repositories. we're going to have to prefix
50    // root repositories with a null byte or something. i'll just leave this here
51    // as a TODO.
52    let repositories = fetched
53        .iter()
54        .group_by(|(k, _)| memchr::memrchr(b'/', k.as_bytes()).map_or("", |idx| &k[..idx]));
55
56    Ok(into_response(View {
57        repositories: Either::Left(repositories.into_iter()).into(),
58    })
59    .into_response())
60}