mod cli; mod config; pub mod db; mod error; mod repo; mod util; mod web; pub use config::{Config, DbConfig, FsConfig}; pub use error::{Result, ServerError}; use std::{io, path::PathBuf}; use clap::Parser; use migration::MigratorTrait; use tokio::runtime; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; pub const ANY_ARCH: &str = "any"; pub const PKG_FILENAME_REGEX: &str = "^([a-z0-9@._+-]+)-((?:[0-9]+:)?[a-zA-Z0-9@._+]+-[0-9]+)-([a-zA-z0-9_]+).pkg.tar.([a-zA-Z0-9]+)$"; #[derive(Clone)] pub struct Global { config: crate::config::Config, repo: repo::Handle, db: sea_orm::DbConn, pkg_filename_re: regex::Regex, } fn main() -> crate::Result<()> { let rt = tokio::runtime::Builder::new_multi_thread() .enable_all() .build() .unwrap(); let handle = rt.handle(); let cli = cli::Cli::parse(); let global = setup(handle, cli.config_file)?; handle.block_on(run(global)) } fn setup(rt: &runtime::Handle, config_file: PathBuf) -> crate::Result { let config: Config = Config::figment(config_file) .extract() .inspect_err(|e| tracing::error!("{}", e))?; tracing_subscriber::registry() .with(tracing_subscriber::EnvFilter::new(config.log_level.clone())) .with(tracing_subscriber::fmt::layer()) .init(); tracing::info!("Connecting to database"); let db = rt.block_on(crate::db::connect(&config.db))?; rt.block_on(migration::Migrator::up(&db, None))?; let repo = match &config.fs { FsConfig::Local { data_dir } => { crate::repo::start( data_dir.join("repos"), db.clone(), rt.clone(), config.repo.sync_workers, config.repo.async_workers, )? //rt.block_on(crate::repo::RepoMgr::new( // data_dir.join("repos"), // db.clone(), //))? //RepoHandle::start(data_dir.join("repos"), db.clone(), config.pkg_workers, rt.clone())? } }; //let mgr = Arc::new(mgr); // //for _ in 0..config.pkg_workers { // let clone = Arc::clone(&mgr); // // rt.spawn(async move { clone.pkg_parse_task().await }); //} Ok(Global { config: config.clone(), repo, db, pkg_filename_re: regex::Regex::new(PKG_FILENAME_REGEX).unwrap(), }) } async fn run(global: Global) -> crate::Result<()> { let domain: String = format!("{}:{}", &global.config.domain, global.config.port) .parse() .unwrap(); let listener = tokio::net::TcpListener::bind(domain).await?; let app = web::router(global); // 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))?) }