gitdataai/libs/service/push_helper.rs

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");
}
});
},
)
}