yuki / okibi
焚き火の仲間だけの自前Gitホスティング(このサイト自身)
mod auth;
mod ci;
mod config;
mod db;
mod email;
mod git_http;
mod mcp;
mod repos;
mod util;
mod web;
use axum::routing::{get, post};
use axum::Router;
use config::Config;
use db::Db;
/// Shared application state.
#[derive(Clone)]
pub struct AppState {
pub db: Db,
pub cfg: Config,
}
async fn healthz() -> &'static str {
"ok\n"
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "okibi=info,tower_http=warn".into()),
)
.init();
let cfg = Config::from_env();
std::fs::create_dir_all(&cfg.repos_dir).ok();
let db = db::init(&cfg.db_path, &cfg.seed_members).await?;
tracing::info!("members seeded: {:?}", cfg.seed_members);
let state = AppState { db, cfg: cfg.clone() };
let app = Router::new()
.route("/", get(web::index))
.route("/about", get(web::about))
.route("/mcp", get(mcp::mcp_info).post(mcp::mcp_post))
.route("/healthz", get(healthz))
.route("/login", get(web::login_form).post(web::login_submit))
.route("/auth/verify", get(web::verify))
.route("/auth/bootstrap", get(web::bootstrap))
.route("/members", get(web::members_page))
.route("/members/invite", post(web::invite_submit))
.route("/admin/import", post(web::admin_import))
.route("/logout", post(web::logout))
.route("/new", get(web::new_repo_form).post(web::new_repo_submit))
.route("/settings", get(web::settings))
.route("/settings/tokens", post(web::new_token))
// git smart-HTTP (must come before the generic repo view)
.route("/{owner}/{repo}/info/refs", get(git_http::info_refs))
.route("/{owner}/{repo}/git-upload-pack", post(git_http::upload_pack))
.route("/{owner}/{repo}/git-receive-pack", post(git_http::receive_pack))
// web views
.route("/{owner}", get(web::user_view))
.route("/{owner}/{repo}", get(web::repo_view))
.with_state(state);
let listener = tokio::net::TcpListener::bind(&cfg.bind).await?;
tracing::info!("🔥 Okibi listening on {} (base {})", cfg.bind, cfg.base_url);
axum::serve(listener, app).await?;
Ok(())
}