diff --git a/backend/src/handlers/mod.rs b/backend/src/handlers/mod.rs index 308df88..c410862 100644 --- a/backend/src/handlers/mod.rs +++ b/backend/src/handlers/mod.rs @@ -7,6 +7,7 @@ use rust_embed::RustEmbed; pub mod auth; pub mod setup; +pub mod notifications; #[derive(RustEmbed)] #[folder = "../frontend/dist"] diff --git a/backend/src/handlers/notifications.rs b/backend/src/handlers/notifications.rs new file mode 100644 index 0000000..e809ce7 --- /dev/null +++ b/backend/src/handlers/notifications.rs @@ -0,0 +1,44 @@ +use axum::{ + extract::{State, Query}, + http::StatusCode, +}; +use serde::Deserialize; +use shared::{AppEvent, SystemNotification, NotificationLevel}; +use crate::AppState; + +#[derive(Deserialize)] +pub struct TorrentFinishedQuery { + pub name: String, + pub hash: String, +} + +pub async fn torrent_finished_handler( + State(state): State, + Query(params): Query, +) -> StatusCode { + tracing::info!("Torrent finished notification received: {} ({})", params.name, params.hash); + + let message = format!("Torrent tamamlandı: {}", params.name); + + // 1. Send to active SSE clients (for Toast) + let notification = SystemNotification { + level: NotificationLevel::Success, + message: message.clone(), + }; + let _ = state.event_bus.send(AppEvent::Notification(notification)); + + // 2. Send Web Push Notification (for Background) + #[cfg(feature = "push-notifications")] + { + let push_store = state.push_store.clone(); + let title = "Torrent Tamamlandı".to_string(); + let body = message; + tokio::spawn(async move { + if let Err(e) = crate::push::send_push_notification(&push_store, &title, &body).await { + tracing::error!("Failed to send push notification from webhook: {}", e); + } + }); + } + + StatusCode::OK +} diff --git a/backend/src/main.rs b/backend/src/main.rs index dc826df..da23949 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -60,6 +60,7 @@ async fn auth_middleware( || path.starts_with("/api/server_fns/get_setup_status") || path.starts_with("/api/server_fns/Setup") || path.starts_with("/api/server_fns/setup") + || path.starts_with("/api/internal/") || path.starts_with("/swagger-ui") || path.starts_with("/api-docs") || !path.starts_with("/api/") @@ -434,6 +435,7 @@ async fn main() { let db_for_ctx = db.clone(); let app = app .route("/api/events", get(sse::sse_handler)) + .route("/api/internal/torrent-finished", post(handlers::notifications::torrent_finished_handler)) .route("/api/server_fns/{*fn_name}", post({ let scgi_path = scgi_path_for_ctx.clone(); let db = db_for_ctx.clone();