#![warn(missing_docs)]
#![warn(clippy::all)]
#![warn(clippy::unwrap_used)]
#![warn(clippy::expect_used)]
pub mod api;
pub mod config;
pub mod db;
pub mod deobfuscation;
pub mod downloader;
pub mod error;
pub mod extraction;
pub mod folder_watcher;
pub mod parity;
pub mod post_processing;
pub mod retry;
pub mod rss_manager;
pub mod rss_scheduler;
pub mod scheduler;
pub mod scheduler_task;
pub mod speed_limiter;
pub mod types;
pub mod utils;
pub use config::{Config, DuplicateAction, ServerConfig};
pub use db::Database;
pub use downloader::UsenetDownloader;
pub use error::{
ApiError, DatabaseError, DownloadError, Error, ErrorDetail, PostProcessError, Result,
ToHttpStatus,
};
pub use parity::{
CliParityHandler, NoOpParityHandler, ParityCapabilities, ParityHandler, RepairResult,
VerifyResult,
};
pub use scheduler::{RuleId, ScheduleAction, ScheduleRule, Scheduler, Weekday};
pub use types::{
DownloadId, DownloadInfo, DownloadOptions, DuplicateInfo, Event, HistoryEntry, Priority,
QueueStats, ServerCapabilities, ServerTestResult, Stage, Status,
};
pub async fn run_with_shutdown(downloader: UsenetDownloader) -> Result<()> {
wait_for_signal().await;
downloader.shutdown().await
}
#[cfg(unix)]
async fn wait_for_signal() {
use tokio::signal::unix::{SignalKind, signal};
let sigterm_result = signal(SignalKind::terminate());
let sigint_result = signal(SignalKind::interrupt());
match (sigterm_result, sigint_result) {
(Ok(mut sigterm), Ok(mut sigint)) => {
tokio::select! {
_ = sigterm.recv() => {
tracing::info!("Received SIGTERM signal");
}
_ = sigint.recv() => {
tracing::info!("Received SIGINT signal (Ctrl+C)");
}
}
}
(Err(e), _) => {
tracing::warn!(error = %e, "Could not register SIGTERM handler, waiting for SIGINT only");
if let Ok(mut sigint) = signal(SignalKind::interrupt()) {
sigint.recv().await;
tracing::info!("Received SIGINT signal (Ctrl+C)");
} else {
tracing::error!("Could not register any signal handlers, using ctrl_c fallback");
tokio::signal::ctrl_c().await.ok();
}
}
(_, Err(e)) => {
tracing::warn!(error = %e, "Could not register SIGINT handler, waiting for SIGTERM only");
if let Ok(mut sigterm) = signal(SignalKind::terminate()) {
sigterm.recv().await;
tracing::info!("Received SIGTERM signal");
} else {
tracing::error!("Could not register any signal handlers, using ctrl_c fallback");
tokio::signal::ctrl_c().await.ok();
}
}
}
}
#[cfg(not(unix))]
async fn wait_for_signal() {
match tokio::signal::ctrl_c().await {
Ok(()) => {
tracing::info!("Received Ctrl+C signal");
}
Err(e) => {
tracing::error!(error = %e, "Failed to listen for Ctrl+C signal");
}
}
}