Skip to content

Commit 6ee2bc7

Browse files
committed
basic repo support
1 parent 84db28a commit 6ee2bc7

File tree

6 files changed

+180
-86
lines changed

6 files changed

+180
-86
lines changed

.cargo/config.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
[target.aarch64-unknown-linux-gnu]
22
linker = "aarch64-linux-gnu-gcc"
3+
4+
[build]
5+
rustflags = ["--remap-path-prefix", "${CARGO_HOME:-$HOME/.cargo/registry/src}=registry/src"]

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ Cargo.lock
2323
# Added by cargo
2424

2525
/target
26+
27+
repos/**

Cargo.toml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@ edition = "2021"
55

66
[dependencies]
77
axum = "0.8.1"
8-
tokio = { version = "1.43.0", features = ["rt-multi-thread", "signal"] }
8+
axum-server = { version = "0.7.1" }
9+
git2 = "0.20.0"
10+
gix = "0.70.0"
11+
tokio = { version = "1.43.0", features = ["fs", "rt-multi-thread", "signal"] }
912
tracing = "0.1.41"
1013
tracing-appender = "0.2.3"
1114
tracing-subscriber = "0.3.19"
15+
log = "0.4.25"
1216

1317
[dev-dependencies]
1418
rusty-hook = "^0.11.2"
@@ -26,3 +30,10 @@ variant_size_differences = "warn"
2630

2731
[profile.dev]
2832
debug-assertions = true
33+
rpath = false
34+
35+
36+
37+
38+
[features]
39+
https = ["axum-server/tls-rustls","axum-server/tls-rustls-no-provider"]

logs/app.log.2025-02-05

Lines changed: 0 additions & 75 deletions
This file was deleted.

logs/app.log.2025-02-06

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2025-02-06T18:19:51.524807Z INFO hydroxide: Server listening on 0.0.0.0:80
2+
2025-02-06T18:19:52.280569Z INFO hydroxide: Shutting down server...
3+
2025-02-06T18:19:52.280670Z TRACE axum::serve: received graceful shutdown signal. Telling tasks to shutdown
4+
2025-02-06T18:19:52.280727Z TRACE axum::serve: signal received, not accepting new connections
5+
2025-02-06T18:19:52.280832Z TRACE axum::serve: waiting for 0 task(s) to finish
6+
2025-02-06T18:20:15.938027Z INFO hydroxide: Server listening on 0.0.0.0:80
7+
2025-02-06T18:20:28.948739Z INFO hydroxide: Shutting down server...
8+
2025-02-06T18:20:28.948884Z TRACE axum::serve: received graceful shutdown signal. Telling tasks to shutdown
9+
2025-02-06T18:20:28.948968Z TRACE axum::serve: signal received, not accepting new connections
10+
2025-02-06T18:20:28.949551Z TRACE axum::serve: waiting for 0 task(s) to finish
11+
2025-02-06T18:21:24.519436Z INFO hydroxide: Server listening on 0.0.0.0:80
12+
2025-02-06T18:21:34.697504Z INFO hydroxide: Shutting down server...
13+
2025-02-06T18:21:34.697547Z TRACE axum::serve: received graceful shutdown signal. Telling tasks to shutdown
14+
2025-02-06T18:21:34.697594Z TRACE axum::serve: signal received, not accepting new connections
15+
2025-02-06T18:21:34.697692Z TRACE axum::serve: waiting for 0 task(s) to finish
16+
2025-02-06T18:22:32.250257Z INFO hydroxide: Server listening on 0.0.0.0:80
17+
2025-02-06T18:22:33.262470Z INFO hydroxide: Shutting down server...
18+
2025-02-06T18:22:33.262533Z TRACE axum::serve: received graceful shutdown signal. Telling tasks to shutdown
19+
2025-02-06T18:22:33.262605Z TRACE axum::serve: signal received, not accepting new connections
20+
2025-02-06T18:22:33.262691Z TRACE axum::serve: waiting for 0 task(s) to finish
21+
2025-02-06T18:24:16.416246Z INFO hydroxide: Server listening on 0.0.0.0:80
22+
2025-02-06T18:25:01.192377Z TRACE axum::serve: connection 127.0.0.1:56408 accepted
23+
2025-02-06T18:25:01.425670Z TRACE axum::serve: connection 127.0.0.1:56410 accepted
24+
2025-02-06T18:25:01.427012Z ERROR hydroxide: 404 - Not Found: PROPFIND /u/Caznix/Harbr/
25+
2025-02-06T18:25:01.427483Z ERROR hydroxide: 404 - Not Found: PROPFIND /u/Caznix/Harbr/
26+
2025-02-06T18:25:52.921497Z INFO hydroxide: Shutting down server...
27+
2025-02-06T18:25:52.921540Z TRACE axum::serve: received graceful shutdown signal. Telling tasks to shutdown
28+
2025-02-06T18:25:52.921592Z TRACE axum::serve: signal received, not accepting new connections
29+
2025-02-06T18:25:52.921673Z TRACE axum::serve: waiting for 0 task(s) to finish

src/main.rs

Lines changed: 134 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,169 @@
11
#![allow(unused_imports)]
2-
use axum::{http::StatusCode, response::IntoResponse, Router};
2+
use axum::extract::State;
3+
use axum::http::{Method, Uri};
4+
use axum::routing::{get, post};
5+
use axum::{http::StatusCode, response::IntoResponse, Router, ServiceExt};
6+
#[cfg(feature = "https")]
7+
use axum_server::tls_rustls::RustlsConfig;
38
use std::io;
9+
use std::net::SocketAddr;
410
use tokio::net::TcpListener;
5-
use tracing::{error, info};
11+
use tracing::{error, info, Level};
612
use tracing_appender::rolling::{RollingFileAppender, Rotation};
13+
use tracing_subscriber::fmt::format;
14+
use tracing_subscriber::layer::Filter;
715
use tracing_subscriber::{fmt, prelude::*, Registry};
816

17+
#[derive(Clone)]
18+
struct GitServer {
19+
instance_url: String,
20+
router: Router<GitServer>,
21+
addr: SocketAddr,
22+
}
923
#[tokio::main]
1024
async fn main() {
1125
let file_appender = RollingFileAppender::new(Rotation::DAILY, "logs", "app.log");
1226

13-
let stdout_layer = fmt::layer().with_writer(io::stdout).with_ansi(true);
27+
let stdout_layer = fmt::layer()
28+
.with_writer(io::stdout)
29+
.with_ansi(true)
30+
.pretty()
31+
.without_time()
32+
.with_filter(tracing_subscriber::filter::LevelFilter::DEBUG);
1433

1534
let file_layer = fmt::layer().with_writer(file_appender).with_ansi(false);
1635

1736
let subscriber = Registry::default().with(stdout_layer).with(file_layer);
1837

1938
tracing::subscriber::set_global_default(subscriber).expect("Failed to set global subscriber");
2039

21-
let app = Router::new().fallback(fallback);
22-
2340
let listener = TcpListener::bind("0.0.0.0:80").await.unwrap();
2441
let addr = listener.local_addr().unwrap();
2542

43+
let router = Router::new()
44+
.route("/init/{user}/{repo_name}", post(init))
45+
.route("/u/{user}/{repo_name}/{*path}", get(handle_repo))
46+
.fallback(fallback);
47+
let state = GitServer {
48+
addr: addr.clone(),
49+
instance_url: format!("http://{}", addr),
50+
router: router.clone(),
51+
};
52+
let router = router.with_state(state);
53+
2654
info!("Server listening on {}", addr);
2755

28-
axum::serve(listener, app)
56+
if cfg!(feature = "https") {
57+
#[cfg(feature = "https")]
58+
{
59+
serve_tls(addr, router).await;
60+
}
61+
} else {
62+
axum::serve(listener, router)
63+
.with_graceful_shutdown(shutdown_signal())
64+
.await
65+
.unwrap();
66+
}
67+
}
68+
#[cfg(feature = "https")]
69+
async fn serve_tls(addr: std::net::SocketAddr, app: Router<GitServer>) {
70+
let config = RustlsConfig::from_pem_file(
71+
"examples/self-signed-certs/cert.pem",
72+
"examples/self-signed-certs/key.pem",
73+
)
74+
.await
75+
.unwrap();
76+
axum_server::bind_rustls(addr, config)
77+
.serve(app.into_make_service())
2978
.with_graceful_shutdown(shutdown_signal())
3079
.await
3180
.unwrap();
3281
}
3382

34-
// Graceful shutdown handler.
3583
async fn shutdown_signal() {
3684
tokio::signal::ctrl_c()
3785
.await
3886
.expect("Failed to install CTRL+C signal handler");
3987
info!("Shutting down server...");
4088
}
4189

42-
async fn fallback(uri: axum::http::Uri) -> impl IntoResponse {
43-
error!("404 - Not Found: {}", uri);
44-
(StatusCode::NOT_FOUND, "404 - Not Found")
90+
async fn init(
91+
axum::extract::Path((user, repo_name)): axum::extract::Path<(String, String)>,
92+
) -> impl IntoResponse {
93+
let repo_path = format!("repos/{}/{}", user, repo_name);
94+
let repo = git2::Repository::init_bare(&repo_path)
95+
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR.into_response());
96+
match repo {
97+
Ok(repo) => {
98+
// Create the info/refs file
99+
let refs_path = format!("{}/info/refs", repo_path);
100+
if let Err(e) = std::fs::File::create(&refs_path) {
101+
error!("Failed to create info/refs file: {:#?}", e);
102+
return (
103+
StatusCode::INTERNAL_SERVER_ERROR,
104+
"Failed to initialize repository".to_string(),
105+
)
106+
.into_response();
107+
}
108+
info!("Initialized repository: {}", repo.path().display());
109+
(
110+
StatusCode::CREATED,
111+
format!("Initialized repository: {}", repo.path().display()),
112+
)
113+
.into_response()
114+
}
115+
Err(e) => {
116+
error!("Failed to initialize repository: {:#?}", e);
117+
(
118+
StatusCode::INTERNAL_SERVER_ERROR,
119+
"Failed to initialize repository".to_string(),
120+
)
121+
.into_response()
122+
}
123+
}
124+
}
125+
async fn handle_repo(
126+
axum::extract::Path((user, repo_name, path)): axum::extract::Path<(String, String, String)>,
127+
) -> impl IntoResponse {
128+
let repo_path = format!("repos/{}/{}", user, repo_name);
129+
let file_path = format!("{}/{}", repo_path, path);
130+
131+
match tokio::fs::metadata(&file_path).await {
132+
Ok(metadata) => {
133+
if metadata.is_dir() {
134+
info!("Directory: {}", file_path);
135+
(StatusCode::OK, format!("Directory: {}", file_path)).into_response()
136+
} else {
137+
match tokio::fs::read(&file_path).await {
138+
Ok(contents) => (StatusCode::OK, contents).into_response(),
139+
Err(_) => (
140+
StatusCode::NOT_FOUND,
141+
format!("File not found: {}", file_path),
142+
)
143+
.into_response(),
144+
}
145+
}
146+
}
147+
Err(_) => (
148+
StatusCode::NOT_FOUND,
149+
format!("Path not found: {}", file_path),
150+
)
151+
.into_response(),
152+
}
153+
}
154+
async fn fallback(
155+
uri: axum::http::Uri,
156+
State(state): State<GitServer>,
157+
method: axum::http::Method,
158+
) -> impl IntoResponse {
159+
let mut msg = format!("404 - Not Found: {} {}", method, uri);
160+
error!("{}", msg);
161+
if let Some(uri) = uri.query() {
162+
let uri = uri.to_string();
163+
if uri.contains("service=git") {
164+
let instance_url = state.instance_url;
165+
}
166+
}
167+
error!("{}", msg);
168+
(StatusCode::NOT_FOUND, msg)
45169
}

0 commit comments

Comments
 (0)