80 lines
2.6 KiB
Rust
80 lines
2.6 KiB
Rust
use crate::push::{PushPayload, WebPushService};
|
|
use db::database::AppDatabase;
|
|
use models::users::user_notification;
|
|
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
|
|
use std::sync::Arc;
|
|
use uuid::Uuid;
|
|
|
|
/// Helper function to send push notification to a user.
|
|
/// Reads the user's push subscription from `user_notification` table.
|
|
/// Non-blocking: failures are logged but don't affect the caller.
|
|
pub async fn send_push_notification(
|
|
push: &WebPushService,
|
|
db: &AppDatabase,
|
|
user_id: Uuid,
|
|
payload: &PushPayload,
|
|
) -> Result<(), String> {
|
|
let prefs = user_notification::Entity::find()
|
|
.filter(user_notification::Column::User.eq(user_id))
|
|
.one(db)
|
|
.await
|
|
.map_err(|e| format!("Failed to read push subscription: {}", e))?;
|
|
|
|
if let Some(prefs) = prefs {
|
|
if prefs.push_enabled {
|
|
if let Some(endpoint) = &prefs.push_subscription_endpoint {
|
|
if let Some(p256dh) = &prefs.push_subscription_keys_p256dh {
|
|
if let Some(auth) = &prefs.push_subscription_keys_auth {
|
|
push.send(endpoint, p256dh, auth, payload)
|
|
.await
|
|
.map_err(|e| format!("WebPush send failed: {}", e))?;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Spawn a background task to send push notification.
|
|
/// Failures are logged but don't affect the caller.
|
|
pub fn spawn_push_notification(
|
|
push: Option<Arc<WebPushService>>,
|
|
db: AppDatabase,
|
|
user_id: Uuid,
|
|
payload: PushPayload,
|
|
) {
|
|
tokio::spawn(async move {
|
|
if let Some(push) = push {
|
|
if let Err(e) = send_push_notification(&push, &db, user_id, &payload).await {
|
|
tracing::warn!(user_id = %user_id, error = %e, "Push notification failed");
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/// Create a push notification callback for RoomService.
|
|
pub fn create_push_notification_fn(
|
|
push: Arc<WebPushService>,
|
|
db: AppDatabase,
|
|
) -> room::PushNotificationFn {
|
|
Arc::new(
|
|
move |user_id: Uuid, title: String, body: Option<String>, url: Option<String>| {
|
|
let push = push.clone();
|
|
let db = db.clone();
|
|
let payload = PushPayload {
|
|
title,
|
|
body: body.unwrap_or_default(),
|
|
url,
|
|
icon: None,
|
|
};
|
|
tokio::spawn(async move {
|
|
if let Err(e) = send_push_notification(&push, &db, user_id, &payload).await {
|
|
tracing::warn!(user_id = %user_id, error = %e, "Push notification failed");
|
|
}
|
|
});
|
|
},
|
|
)
|
|
}
|