feat: add indexer and torrent REST controllers with service layer

- Add config module for yaml config (database, indexers, torrent)
- Add indexer module with Torznab protocol support
- Add IndexerService and TorrentService for business logic
- Add REST controllers for indexer search and torrent management
- Add Docker Compose for PostgreSQL and Jackett
- Add ERD documentation for database schema
This commit is contained in:
Alexander
2026-04-28 18:53:50 +02:00
parent f77806ba46
commit 1aaaab4640
23 changed files with 1841 additions and 51 deletions
+51 -10
View File
@@ -1,20 +1,16 @@
mod api;
mod models;
mod services;
mod torrent;
use std::sync::Arc;
use tokio::sync::RwLock;
use axum::Router;
use music_agregator::{
api, config,
services::{IndexerService, TorrentService},
AppServices, AppState,
};
use tower_http::cors::{Any, CorsLayer};
use tower_http::trace::TraceLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use crate::services::Aggregator;
pub type AppState = Arc<RwLock<Aggregator>>;
#[tokio::main]
async fn main() {
tracing_subscriber::registry()
@@ -22,7 +18,52 @@ async fn main() {
.with(tracing_subscriber::EnvFilter::from_default_env())
.init();
let state: AppState = Arc::new(RwLock::new(Aggregator::new()));
let config_path = std::env::var("CONFIG_PATH").unwrap_or_else(|_| "config.yaml".to_string());
let config = match config::Config::load(&config_path) {
Ok(cfg) => {
tracing::info!("loaded config from {}", config_path);
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 = if let Some(qbit_config) = &config.torrent.qbittorrent {
match TorrentService::from_qbittorrent_config(qbit_config).await {
Ok(svc) => {
tracing::info!("connected to qBittorrent at {}", qbit_config.url);
svc
}
Err(e) => {
tracing::warn!(
"failed to connect to qBittorrent: {} (continuing without torrent client)",
e
);
TorrentService::new()
}
}
} else {
tracing::info!("no torrent client configured");
TorrentService::new()
};
let state: AppState = Arc::new(RwLock::new(AppServices::new(
indexer_service,
torrent_service,
)));
let cors = CorsLayer::new()
.allow_origin(Any)