Files
spacedrive/core/src/api/notifications.rs
Ericson "Fogo" Soares bdc242a852 [ENG-1775] Scan location using new jobs (#2476)
* First draft on task system usage, still missing job system

* Scan location roughly working, a ton of stuff to fix yet

* Updating some deps due to crashes and bugs

* Exposing non critical errors to frontend

* Getting active job reports from job system

* Using boxed opaque type to avoid a downcast issue with generics

* Task system issues discovered on race conditions

* Enable debug

* Fix job report in the job manager

* Fix race condition on steal tasks

* Fixed race condition on task suspend

* Some fixes on job progress reporting and save

* Fixed many race conditions and a hard deadlock
Also some progress report polishing

* Ignore .ts and .mts video files for now

* Some better logs

* bruh

* Internal deadlocks and excess of communication in the task system
- Also better logs

* Bunch of fixes and optimizations

* WIP at fixing file identifier

* Fixed file identifier job
- still need to work on its progress report frontend

* A bunch of polishing

* Fixed some bugs and did more polishing

* Cleanup

* Bridging old and new job systems

* A ton of fixes

* A bunch of bugs related to shutdown and resume

* Indexer and watcher bugs

* Log normalizing

* Fixing CI

* Change error! to warn! on non critical errors log

* Fix redirect to new location

* Type annotation

* Bogus merge resolution on cargo lock
2024-06-17 21:30:57 +00:00

168 lines
4.0 KiB
Rust

use sd_prisma::prisma::notification;
use crate::api::{Ctx, R};
use async_stream::stream;
use chrono::{DateTime, Utc};
use futures::future::join_all;
use rspc::{alpha::AlphaRouter, ErrorCode};
use serde::{Deserialize, Serialize};
use specta::Type;
use uuid::Uuid;
/// Represents a single notification.
#[derive(Debug, Clone, Serialize, Deserialize, Type)]
pub struct Notification {
#[serde(flatten)]
pub id: NotificationId,
pub data: NotificationData,
pub read: bool,
pub expires: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Type, PartialEq, Eq)]
#[serde(tag = "type", content = "id", rename_all = "camelCase")]
pub enum NotificationId {
Library(Uuid, u32),
Node(u32),
}
#[derive(Debug, Clone, Serialize, Deserialize, Type)]
#[serde(rename_all = "camelCase")]
pub enum NotificationKind {
Info,
Success,
Error,
Warning,
}
/// Represents the data of a single notification.
/// This data is used by the frontend to properly display the notification.
#[derive(Debug, Clone, Serialize, Deserialize, Type)]
pub struct NotificationData {
pub title: String,
pub content: String,
pub kind: NotificationKind,
}
pub(crate) fn mount() -> AlphaRouter<Ctx> {
R.router()
.procedure("get", {
R.query(|node, _: ()| async move {
let mut notifications = node.config.get().await.notifications;
for lib_notifications in join_all(node.libraries.get_all().await.into_iter().map(
|library| async move {
library
.db
.notification()
.find_many(vec![])
.exec()
.await
.map_err(|e| {
rspc::Error::new(
ErrorCode::InternalServerError,
format!(
"Failed to get notifications for library '{}': {}",
library.id, e
),
)
})?
.into_iter()
.map(|n| {
Ok(Notification {
id: NotificationId::Library(library.id, n.id as u32),
data: rmp_serde::from_slice(&n.data).map_err(|e| {
rspc::Error::new(
ErrorCode::InternalServerError,
format!(
"Failed to get notifications for library '{}': {}",
library.id, e
),
)
})?,
read: false,
expires: n.expires_at.map(Into::into),
})
})
.collect::<Result<Vec<Notification>, rspc::Error>>()
},
))
.await
{
notifications.extend(lib_notifications?);
}
Ok(notifications)
})
})
.procedure("dismiss", {
R.query(|node, id: NotificationId| async move {
match id {
NotificationId::Library(library_id, id) => {
node.libraries
.get_library(&library_id)
.await
.ok_or_else(|| {
rspc::Error::new(ErrorCode::NotFound, "Library not found".into())
})?
.db
.notification()
.delete_many(vec![notification::id::equals(id as i32)])
.exec()
.await
.map_err(|e| {
rspc::Error::new(ErrorCode::InternalServerError, e.to_string())
})?;
}
NotificationId::Node(id) => {
node.config
.write(|cfg| {
cfg.notifications
.retain(|n| n.id != NotificationId::Node(id));
})
.await
.map_err(|e| {
rspc::Error::new(ErrorCode::InternalServerError, e.to_string())
})?;
}
}
Ok(())
})
})
.procedure("dismissAll", {
R.query(|node, _: ()| async move {
node.config
.write(|cfg| {
cfg.notifications = vec![];
})
.await
.map_err(|e| rspc::Error::new(ErrorCode::InternalServerError, e.to_string()))?;
join_all(
node.libraries
.get_all()
.await
.into_iter()
.map(|library| async move {
library.db.notification().delete_many(vec![]).exec().await
}),
)
.await
.into_iter()
.collect::<Result<Vec<_>, _>>()?;
Ok(())
})
})
.procedure("listen", {
R.subscription(|node, _: ()| async move {
let mut sub = node.notifications.subscribe();
stream! {
while let Ok(notification) = sub.recv().await {
yield notification;
}
}
})
})
}