/<repo>.git/<path> in a browser: the code, browsed. A directory lists
its entries and shows its README; a file is shown with numbered lines, or
rendered if it is markdown; ?raw serves it as it is.
Everything comes from GitHub's contents API with the clone proxy's read-only token, at most once a minute per isolate for a given path. jevcrates is browsed on its own and where each project pins it: a path under a project's jevcrates submodule is read from jevcrates at the pinned commit.
11use std::cell::RefCell;
13use axum::body::Body; 14use axum::extract::{Path, Query, State}; 15use axum::http::{HeaderMap, Response, StatusCode, header}; 16use serde::Deserialize; 17use tree::{Contents, Kind}; 18 19use super::App; 20use crate::clone::{self, Repo}; 21use crate::host::{GitRedirect, Host}; 22use crate::view::code::{self, Doc, Docs, Shown, View};
How long an isolate keeps what GitHub said about a path.
25const KEPT_MS: f64 = 60_000.0;
How many paths an isolate keeps at once; the oldest goes first.
27const KEPT: usize = 64;
29thread_local! {
What GitHub said, by (repository, ref, path), and when.
31 static READ: RefCell<Vec<((Repo, String, String), f64, Read)>> = const { RefCell::new(Vec::new()) };
Each repository's whole tree at main, submodules mounted, and when.
The whole tree of repo at main for the explorer, each submodule's tree
mounted where it is pinned: two calls to GitHub at most, kept a minute.
Empty if GitHub cannot be read; the pages still work without it.
39pub async fn explorer(env: &worker::Env, repo: Repo) -> tree::Tree { 40 let now = js_sys::Date::now(); 41 let kept = TREES.with(|trees| trees.borrow().iter().find(|(seen, at, _)| *seen == repo && now - at < KEPT_MS).map(|(_, _, tree)| tree.clone())); 42 if let Some(tree) = kept { 43 return tree; 44 } 45 let Some(mut whole) = git_tree(env, repo, repo.branch()).await else { return tree::Tree::default() }; 46 for (mount, inner) in repo.submodules() { 47 let pin = whole.pins.iter().find(|(path, _)| path == mount).map(|(_, sha)| sha.clone()); 48 if let Some(inner_tree) = match pin { Some(sha) => git_tree(env, *inner, &sha).await, None => None } { 49 whole.mount(mount, inner_tree); 50 } 51 } 52 TREES.with(|trees| { 53 let mut trees = trees.borrow_mut(); 54 trees.retain(|(seen, _, _)| *seen != repo); 55 trees.push((repo, now, whole.clone())); 56 }); 57 whole 58}
60async fn git_tree(env: &worker::Env, repo: Repo, reference: &str) -> Option<tree::Tree> { 61 let url = format!("https://api.github.com/repos/{}/git/trees/{}?recursive=1", repo.github(), tree::encoded(&[reference])); 62 match clone::github(env, &url).await? { 63 (200, body, _) => tree::parse_tree(&body), 64 _ => None, 65 } 66}
GitHub said there is nothing there.
73 Missing,
?raw serves a file as it is; ?view=agents shows a directory's
CLAUDE.md in place of its README.
GET /<repo>/<path>.
88#[worker::send] 89pub async fn path( 90 State(app): State<App>, 91 Path((segment, path)): Path<(String, String)>, 92 Query(asked): Query<Asked>, 93 headers: HeaderMap, 94) -> Response<Body> { 95 let origin = super::origin(&headers); 96 let Some(repo) = Repo::named(&segment) else { return clone::refused(StatusCode::NOT_FOUND, "No such page.") }; 97 let Some(segments) = tree::segments(&path) else { return clone::refused(StatusCode::NOT_FOUND, "No such page.") }; 98 let served = segments.join("/"); 99 let read = resolve(&app.env, repo, &segments).await; 100 if asked.raw.is_some() 101 && let Read::Found(Contents::File { path, body, .. }) = &read 102 { 103 return raw_file(path, body); 104 } 105 let view = View::asked(asked.view.as_deref()); 106 let (status, shown) = match &read { 107 Read::Found(Contents::Dir(entries)) => { 108 let entries = mounted(repo, &served, entries); 109 let docs = docs(&app.env, repo, &segments, &entries, view).await; 110 (StatusCode::OK, Shown::Dir { docs }) 111 } 112 Read::Found(Contents::File { size, body, .. }) => (StatusCode::OK, Shown::File { size: *size, body, view }), 113 // A submodule's own path resolves to its root, so this is not seen. 114 Read::Found(Contents::Submodule { .. }) | Read::Missing => (StatusCode::NOT_FOUND, Shown::Missing), 115 Read::Unreachable => (StatusCode::BAD_GATEWAY, Shown::Unreachable), 116 }; 117 let whole = explorer(&app.env, repo).await; 118 let latest = clone::latest(&app.env, repo).await; 119 let metas = clone::metas(&app.env).await; 120 let frame = frame(&origin, super::host_of(&headers), super::git_redirect(&app.env), repo, &served, &whole, latest.as_ref(), metas); 121 let page = code::page(&frame, shown); 122 Response::builder() 123 .status(status) 124 .header(header::CONTENT_TYPE, "text/html; charset=utf-8") 125 .header(header::CACHE_CONTROL, "no-cache") 126 .body(Body::from(page.into_string())) 127 .expect("static headers are valid") 128}
Everything around a code page's main pane, for repo. metas is what
GitHub says about each repository, in the order of Repo::ALL.
132#[allow(clippy::too_many_arguments)] 133pub fn frame<'a>( 134 origin: &'a str, 135 host: Host, 136 redirect: GitRedirect, 137 repo: Repo, 138 path: &'a str, 139 tree: &'a tree::Tree, 140 latest: Option<&'a card::Commit>, 141 metas: Vec<Option<code::Meta>>, 142) -> code::Frame<'a> { 143 let at = Repo::ALL.iter().position(|each| *each == repo); 144 let meta = at.and_then(|at| metas.get(at).cloned().flatten()); 145 code::Frame { 146 origin, 147 host, 148 project: repo.project(), 149 path, 150 tree, 151 latest, 152 clone: repo.command(&host.code_origin(origin, redirect)), 153 projects: Repo::ALL.iter().map(|repo| repo.project()).zip(metas.into_iter().chain(std::iter::repeat(None))).collect(), 154 meta, 155 } 156}
The root of a repository's documents, for the front page.
What is at a served path: in the repository itself, or under one of its submodules, in the submodule at the commit it is pinned at.
168async fn resolve(env: &worker::Env, repo: Repo, segments: &[&str]) -> Read { 169 for (mount, inner) in repo.submodules() { 170 let mount_segments: Vec<&str> = mount.split('/').collect(); 171 if segments.starts_with(&mount_segments) { 172 let pin = match read(env, repo, repo.branch(), &mount_segments).await { 173 Read::Found(Contents::Submodule { sha, .. }) => sha, 174 Read::Found(_) | Read::Missing => return Read::Missing, 175 Read::Unreachable => return Read::Unreachable, 176 }; 177 return read(env, *inner, &pin, &segments[mount_segments.len()..]).await; 178 } 179 } 180 read(env, repo, repo.branch(), segments).await 181}
A directory's entries with their paths as served: a submodule's entries are under its mount.
185fn mounted(repo: Repo, served: &str, entries: &[tree::Entry]) -> Vec<tree::Entry> { 186 let mount = repo.submodules().iter().map(|(mount, _)| *mount).find(|mount| served == *mount || served.starts_with(&format!("{mount}/"))); 187 entries 188 .iter() 189 .map(|entry| tree::Entry { 190 path: match mount { 191 Some(mount) => format!("{mount}/{}", entry.path), 192 None => entry.path.clone(), 193 }, 194 ..entry.clone() 195 }) 196 .collect() 197}
The directory's README and CLAUDE.md, rendered.
208async fn doc(env: &worker::Env, repo: Repo, segments: &[&str], entries: &[tree::Entry], name: &str) -> Option<Doc> { 209 let found = entries.iter().find(|entry| entry.kind == Kind::File && entry.name.eq_ignore_ascii_case(name))?; 210 let mut path = segments.to_vec(); 211 path.push(&found.name); 212 match resolve(env, repo, &path).await { 213 Read::Found(Contents::File { body: tree::Body::Text(text), .. }) => Some(Doc::new(&path.join("/"), &text, &repo.project().base())), 214 _ => None, 215 } 216}
One path of one repository at one ref, from this isolate's memory or from GitHub.
220async fn read(env: &worker::Env, repo: Repo, reference: &str, segments: &[&str]) -> Read { 221 let key = (repo, reference.to_owned(), segments.join("/")); 222 let now = js_sys::Date::now(); 223 let kept = READ.with(|read| { 224 read.borrow().iter().find(|(seen, at, _)| *seen == key && now - at < KEPT_MS).map(|(_, _, read)| read.clone()) 225 }); 226 if let Some(read) = kept { 227 return read; 228 } 229 let url = format!("https://api.github.com/repos/{}/contents/{}?ref={}", repo.github(), tree::encoded(segments), tree::encoded(&[reference])); 230 let read = match clone::github(env, &url).await { 231 Some((200, body, _)) => tree::parse(&body).map_or(Read::Unreachable, Read::Found), 232 Some((404, _, _)) => Read::Missing, 233 _ => Read::Unreachable, 234 }; 235 // Only answers are kept: an outage is asked about again next time. 236 if !matches!(read, Read::Unreachable) { 237 READ.with(|kept| { 238 let mut kept = kept.borrow_mut(); 239 kept.retain(|(seen, at, _)| *seen != key && now - at < KEPT_MS); 240 if kept.len() >= KEPT { 241 kept.remove(0); 242 } 243 kept.push((key, now, read.clone())); 244 }); 245 } 246 read 247}
A file as it is. A sandbox keeps anything in it from running as this site.
251fn raw_file(path: &str, body: &tree::Body) -> Response<Body> { 252 let bytes = match body { 253 tree::Body::Text(text) => text.clone().into_bytes(), 254 tree::Body::Binary(bytes) => bytes.clone(), 255 tree::Body::TooLarge => return clone::refused(StatusCode::PAYLOAD_TOO_LARGE, "Too large to show here. Clone it."), 256 }; 257 Response::builder() 258 .header(header::CONTENT_TYPE, tree::media_type(path, body)) 259 .header(header::CACHE_CONTROL, "public, max-age=60") 260 .header("content-security-policy", "sandbox") 261 .header("x-content-type-options", "nosniff") 262 .body(Body::from(bytes)) 263 .expect("static headers are valid") 264}