yggdrasil/api/database/
tasks.rs1#![allow(clippy::unused_unit, deprecated)]
2
3use chrono::{DateTime, Utc};
10use dioxus::prelude::*;
11use serde::{Deserialize, Serialize};
12
13#[cfg(feature = "server")]
15use crate::api::auth::get_current_admin_user;
16#[cfg(feature = "server")]
18use dashmap::DashMap;
19#[cfg(feature = "server")]
20use std::sync::LazyLock;
21
22#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
23pub enum TaskKind {
24 Backup,
25 Restore,
26}
27
28#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
29pub enum TaskStatus {
30 Running,
31 Done,
32 Failed,
33}
34
35#[derive(Clone, Serialize, Deserialize, Debug)]
36pub struct TaskProgress {
37 pub id: String,
38 pub kind: TaskKind,
39 pub stage: String,
40 pub percent: u8,
41 pub detail: Option<String>,
42 pub status: TaskStatus,
43 pub error: Option<String>,
44 pub created_at: DateTime<Utc>,
45 pub result_filename: Option<String>,
47}
48
49#[cfg(feature = "server")]
50static TASKS: LazyLock<DashMap<String, TaskProgress>> = LazyLock::new(DashMap::new);
51
52#[cfg(feature = "server")]
57pub(crate) fn insert(id: String, kind: TaskKind) {
58 TASKS.insert(
59 id.clone(),
60 TaskProgress {
61 id,
62 kind,
63 stage: "排队中".to_string(),
64 percent: 0,
65 detail: None,
66 status: TaskStatus::Running,
67 error: None,
68 created_at: Utc::now(),
69 result_filename: None,
70 },
71 );
72}
73
74#[cfg(feature = "server")]
76pub(super) fn update(
77 id: &str,
78 stage: &str,
79 percent: u8,
80 status: TaskStatus,
81 detail: Option<String>,
82 error: Option<String>,
83 result_filename: Option<String>,
84) {
85 if let Some(mut p) = TASKS.get_mut(id) {
86 p.stage = stage.to_string();
87 p.percent = percent;
88 p.status = status;
89 p.detail = detail;
90 p.error = error;
91 p.result_filename = result_filename;
92 }
93}
94
95#[cfg(feature = "server")]
97fn gc_old() {
98 let cutoff = Utc::now() - chrono::Duration::hours(1);
99 TASKS.retain(|_, p| {
100 !(matches!(p.status, TaskStatus::Done | TaskStatus::Failed) && p.created_at < cutoff)
101 });
102}
103
104#[server(GetTaskProgress, "/api")]
106pub async fn get_task_progress(task_id: String) -> Result<TaskProgress, ServerFnError> {
107 let _user = get_current_admin_user().await?;
108 #[cfg(feature = "server")]
109 {
110 gc_old();
111 TASKS
112 .get(&task_id)
113 .map(|p| p.clone())
114 .ok_or_else(|| crate::api::error::AppError::NotFound("任务不存在").into())
115 }
116 #[cfg(not(feature = "server"))]
117 {
118 Ok(TaskProgress {
119 id: task_id,
120 kind: TaskKind::Backup,
121 stage: String::new(),
122 percent: 0,
123 detail: None,
124 status: TaskStatus::Done,
125 error: None,
126 created_at: Utc::now(),
127 result_filename: None,
128 })
129 }
130}