Files
music-agregator/src/main.rs
T
Alexander 3aaeade4d3 feat: add artist sync flow and stub torrent client
- Add DownloadService to orchestrate metadata → indexer → torrent flow
- Add POST /api/sync/artist endpoint for syncing artist albums
- Add StubTorrentClient for testing (logs requests to file)
- Refactor TorrentConfig to tagged enum (client_type: qbittorrent|stub|none)
- Add POST /api/reload endpoint for hot config reload
- Add chrono dependency for timestamps
2026-04-28 21:40:11 +02:00

117 lines
3.5 KiB
Rust

use std::sync::Arc;
use tokio::sync::RwLock;
use axum::Router;
use clap::Parser;
use music_agregator::{
api, config,
services::{IndexerService, MetadataService, TorrentService},
AppServices, AppState,
};
use tower_http::cors::{Any, CorsLayer};
use tower_http::trace::TraceLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[derive(Parser)]
#[command(name = "music-agregator")]
#[command(about = "Music aggregation service with torrent and metadata integration")]
struct Args {
#[arg(short, long, default_value = "config.yaml")]
config: String,
#[arg(short, long)]
port: Option<u16>,
}
#[tokio::main]
async fn main() {
tracing_subscriber::registry()
.with(tracing_subscriber::fmt::layer())
.with(tracing_subscriber::EnvFilter::from_default_env())
.init();
let args = Args::parse();
let config = match config::Config::load(&args.config) {
Ok(cfg) => {
tracing::info!("loaded config from {}", args.config);
cfg
}
Err(e) => {
tracing::error!("failed to load config: {}", e);
std::process::exit(1);
}
};
let indexer_service = match IndexerService::from_config(&config.indexers) {
Ok(svc) => {
tracing::info!("initialized {} indexer(s)", config.indexers.len());
svc
}
Err(e) => {
tracing::error!("failed to initialize indexer service: {}", e);
std::process::exit(1);
}
};
let torrent_service = match TorrentService::from_config(&config.torrent).await {
Ok(svc) => {
match &config.torrent {
config::TorrentConfig::QBittorrent { url, .. } => {
tracing::info!("connected to qBittorrent at {}", url);
}
config::TorrentConfig::Stub { log_path, .. } => {
tracing::info!("using stub torrent client, logging to {}", log_path);
}
config::TorrentConfig::None => {
tracing::info!("no torrent client configured");
}
}
svc
}
Err(e) => {
tracing::warn!("failed to init torrent client: {} (continuing without)", e);
TorrentService::new()
}
};
let mut metadata_service = MetadataService::new(&config.metadata.endpoint);
match metadata_service.connect().await {
Ok(()) => {
tracing::info!(
"connected to metadata service at {}",
config.metadata.endpoint
);
}
Err(e) => {
tracing::warn!(
"failed to connect to metadata service: {} (continuing without metadata)",
e
);
}
}
let state: AppState = Arc::new(RwLock::new(AppServices::new(
indexer_service,
torrent_service,
metadata_service,
args.config.clone(),
)));
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any);
let app = Router::new()
.nest("/api", api::routes(state))
.layer(cors)
.layer(TraceLayer::new_for_http());
let port = args.port.unwrap_or(config.app.port);
let addr = format!("0.0.0.0:{}", port);
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
tracing::info!("listening on {}", listener.local_addr().unwrap());
axum::serve(listener, app).await.unwrap();
}