mod config;
mod handlers;
mod network;
use config::*;
use network::error::Error as NetworkError;
use windmark::{context::RouteContext, response::Response};
#[windmark::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cfg: &Config = config();
let kind = cfg.forge_api().kind().to_string();
match cfg.forge_api().get_version() {
Ok(server_version) => {
let version = server_version.version;
println!("{kind} {version}");
}
Err(NetworkError::Unauthorized) => {
println!("Warning: We are not authorized to query metadata of this {kind} instance. Some routes may return errors.");
},
Err(err) => Err(err)?, };
return windmark::router::Router::new()
.set_private_key_file(format!("{}/key.pem", cfg.certs_dir))
.set_certificate_file(format!("{}/cert.pem", cfg.certs_dir))
.add_header(move |_| format!("# {kind} Proxy"))
.add_footer(|ctx: RouteContext| {
let base: &str = ctx.url.path().split("/").collect::<Vec<&str>>()[1];
let mode_dest: &str;
if base == "users" {
mode_dest = "/ Recent Activity";
} else {
mode_dest = "/users Users";
}
let version = cfg.crate_version;
return format!("\n==========================\n=> {mode_dest}\n\nPowered by git-gemini-forge v{version}\n=> gemini://git.average.name/AverageHelper/git-gemini-forge View source")
})
.mount("/", |_| {
route(handlers::root::handler(cfg))
})
.mount("/users", |_| {
route(handlers::users::handler(cfg))
})
.mount("/:user", |ctx| {
let user: &str = ctx.url.path().split("/").last().unwrap_or("");
route(handlers::user::handler(cfg, user))
})
.mount("/:user/:repo", |ctx| {
let path_segments = ctx.url.path().split("/").collect::<Vec<&str>>();
let user: &str = path_segments[1];
let repo: &str = path_segments[2];
route(handlers::repo::handler(cfg, user, repo))
})
.mount("/:user/:repo/src/branch/:branch", |ctx| {
let path_segments = ctx.url.path().split("/").collect::<Vec<&str>>();
let _user: &str = path_segments[1];
let _repo: &str = path_segments[2];
let _branch: &str = path_segments[5];
return Response::temporary_failure("That route is not implemented yet");
})
.mount("/:user/:repo/src/branch/:branch/:filename", |ctx| {
let path_segments = ctx.url.path().split("/").collect::<Vec<&str>>();
let _user: &str = path_segments[1];
let _repo: &str = path_segments[2];
let _branch: &str = path_segments[5];
let _filename: &str = path_segments[6];
return Response::temporary_failure("That route is not implemented yet");
})
.set_error_handler(|error| {
let failure_addr = error.url;
println!("Failed to serve {failure_addr}");
return Response::temporary_failure("Something went wrong!");
})
.run()
.await
}
fn route(res: Result<Response, NetworkError>) -> Response {
return match res {
Ok(res) => res,
Err(NetworkError::NetworkFailure) => Response::proxy_error("Couldn't communicate with the forge"),
Err(NetworkError::ResourceNotFound) => Response::not_found("Not found"),
Err(NetworkError::Unauthorized) => Response::proxy_error("We aren't authorized to communicate with the forge on this route"),
Err(NetworkError::UnexpectedResponse) => Response::temporary_failure("The upstream gave us a response we don't understand"),
}
}