use crate::{distro::MetaDistroMgr, Config, Global}; use std::{io, path::PathBuf, sync::Arc}; use axum::Router; use clap::Parser; use sea_orm_migration::MigratorTrait; use tower_http::trace::TraceLayer; use tracing::debug; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; #[derive(Parser)] #[command(author, version, about, long_about = None)] pub struct Cli { /// Directory where repository metadata & SQLite database is stored #[arg(env = "RIETER_DATA_DIR")] pub data_dir: PathBuf, /// API key to authenticate private routes with #[arg(env = "RIETER_API_KEY")] pub api_key: String, #[arg( short, long, env = "RIETER_CONFIG_FILE", default_value = "./rieterd.toml" )] pub config_file: PathBuf, /// Database connection URL; either sqlite:// or postgres://. Defaults to rieter.sqlite in the /// data directory #[arg(short, long, env = "RIETER_DATABASE_URL")] pub database_url: Option, /// Port the server will listen on #[arg( short, long, value_name = "PORT", default_value_t = 8000, env = "RIETER_PORT" )] pub port: u16, /// Log levels for the tracing #[arg( long, value_name = "LOG_LEVEL", default_value = "tower_http=debug,rieterd=debug", env = "RIETER_LOG" )] pub log: String, } impl Cli { pub fn init_tracing(&self) { tracing_subscriber::registry() .with(tracing_subscriber::EnvFilter::new(self.log.clone())) .with(tracing_subscriber::fmt::layer()) .init(); } pub async fn run(&self) -> crate::Result<()> { self.init_tracing(); //tracing::debug!("{:?}", &self.config_file); //let new_config: crate::config::Config = crate::config::Config::figment(&self.config_file).extract().inspect_err( // |e| tracing::error!("{}", e) //)?; //tracing::debug!("{:?}", new_config); let db_url = if let Some(url) = &self.database_url { url.clone() } else { format!( "sqlite://{}?mode=rwc", self.data_dir.join("rieter.sqlite").to_string_lossy() ) }; debug!("Connecting to database with URL {}", db_url); let mut options = sea_orm::ConnectOptions::new(db_url); options.max_connections(16); let db = sea_orm::Database::connect(options).await?; crate::db::Migrator::up(&db, None).await?; debug!("Successfully applied migrations"); let config = Config { data_dir: self.data_dir.clone(), }; let mgr = Arc::new(crate::repo::RepoMgr::new(&self.data_dir.join("repos"), db.clone()).await?); for _ in 0..1 { let clone = Arc::clone(&mgr); tokio::spawn(async move { clone.pkg_parse_task().await }); } let global = Global { config, mgr, db }; // build our application with a single route let app = Router::new() .nest("/api", crate::api::router()) .merge(crate::repo::router(&self.api_key)) .with_state(global) .layer(TraceLayer::new_for_http()); let domain: String = format!("0.0.0.0:{}", self.port).parse().unwrap(); let listener = tokio::net::TcpListener::bind(domain).await?; // run it with hyper on localhost:3000 Ok(axum::serve(listener, app.into_make_service()) .await .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?) } }