Added config stuff

This commit is contained in:
Connor Johnstone
2026-03-18 15:14:45 -04:00
parent edcc5cb110
commit b8f178ae08
6 changed files with 461 additions and 1 deletions
+134
View File
@@ -0,0 +1,134 @@
use actix_cors::Cors;
use actix_web::{web, App, HttpServer};
use clap::Parser;
use tracing_actix_web::TracingLogger;
use tracing_subscriber::EnvFilter;
use shanty_config::AppConfig;
use shanty_db::Database;
use shanty_search::MusicBrainzSearch;
use shanty_tag::MusicBrainzClient;
use shanty_web::routes;
use shanty_web::state::AppState;
use shanty_web::tasks::TaskManager;
#[derive(Parser)]
#[command(name = "shanty", about = "Shanty — self-hosted music management")]
struct Cli {
/// Path to config file.
#[arg(long, env = "SHANTY_CONFIG")]
config: Option<String>,
/// Override the port.
#[arg(long)]
port: Option<u16>,
/// Increase verbosity (-v info, -vv debug, -vvv trace).
#[arg(short, long, action = clap::ArgAction::Count)]
verbose: u8,
}
#[actix_web::main]
async fn main() -> anyhow::Result<()> {
let cli = Cli::parse();
let filter = match cli.verbose {
0 => "info,shanty=info,shanty_web=info",
1 => "info,shanty=debug,shanty_web=debug",
_ => "debug,shanty=trace,shanty_web=trace",
};
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(filter)),
)
.init();
let mut config = AppConfig::load(cli.config.as_deref());
if let Some(port) = cli.port {
config.web.port = port;
}
tracing::info!(url = %config.database_url, "connecting to database");
let db = Database::new(&config.database_url).await?;
let mb_client = MusicBrainzClient::new()?;
let search = MusicBrainzSearch::new()?;
let bind = format!("{}:{}", config.web.bind, config.web.port);
tracing::info!(bind = %bind, "starting server");
let config_path = cli.config.clone();
let state = web::Data::new(AppState {
db,
mb_client,
search,
config: std::sync::Arc::new(tokio::sync::RwLock::new(config)),
config_path,
tasks: TaskManager::new(),
});
// Resolve static files directory
let static_dir = std::env::current_exe()
.ok()
.and_then(|exe| exe.parent().map(|p| p.to_owned()))
.map(|p| p.join("static"))
.unwrap_or_else(|| std::path::PathBuf::from("static"));
let static_dir = if static_dir.is_dir() {
static_dir
} else {
// Check next to shanty-web crate root (for development)
let dev_path = std::path::PathBuf::from(
concat!(env!("CARGO_MANIFEST_DIR"), "/shanty-web/static"),
);
if dev_path.is_dir() {
dev_path
} else {
tracing::warn!("static directory not found — frontend will not be served");
static_dir
}
};
tracing::info!(path = %static_dir.display(), "serving static files");
let server = HttpServer::new(move || {
let cors = Cors::permissive();
let static_dir = static_dir.clone();
App::new()
.wrap(cors)
.wrap(TracingLogger::default())
.app_data(state.clone())
.configure(routes::configure)
.service(
actix_files::Files::new("/", static_dir.clone())
.index_file("index.html")
.prefer_utf8(true),
)
.default_service(web::to({
let index_path = static_dir.join("index.html");
move |req: actix_web::HttpRequest| {
let index_path = index_path.clone();
async move {
actix_files::NamedFile::open_async(index_path)
.await
.map(|f| f.into_response(&req))
}
}
}))
})
.bind(&bind)?
.run();
// Graceful shutdown on Ctrl+C / SIGTERM
let handle = server.handle();
tokio::spawn(async move {
tokio::signal::ctrl_c().await.ok();
tracing::info!("shutdown signal received, stopping server");
handle.stop(true).await;
});
server.await?;
tracing::info!("server stopped");
Ok(())
}