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")]
54pub(super) fn insert(id: String, kind: TaskKind) {
55 TASKS.insert(
56 id.clone(),
57 TaskProgress {
58 id,
59 kind,
60 stage: "排队中".to_string(),
61 percent: 0,
62 detail: None,
63 status: TaskStatus::Running,
64 error: None,
65 created_at: Utc::now(),
66 result_filename: None,
67 },
68 );
69}
70
71#[cfg(feature = "server")]
73pub(super) fn update(
74 id: &str,
75 stage: &str,
76 percent: u8,
77 status: TaskStatus,
78 detail: Option<String>,
79 error: Option<String>,
80 result_filename: Option<String>,
81) {
82 if let Some(mut p) = TASKS.get_mut(id) {
83 p.stage = stage.to_string();
84 p.percent = percent;
85 p.status = status;
86 p.detail = detail;
87 p.error = error;
88 p.result_filename = result_filename;
89 }
90}
91
92#[cfg(feature = "server")]
94fn gc_old() {
95 let cutoff = Utc::now() - chrono::Duration::hours(1);
96 TASKS.retain(|_, p| {
97 !(matches!(p.status, TaskStatus::Done | TaskStatus::Failed) && p.created_at < cutoff)
98 });
99}
100
101#[server(GetTaskProgress, "/api")]
103pub async fn get_task_progress(task_id: String) -> Result<TaskProgress, ServerFnError> {
104 let _user = get_current_admin_user().await?;
105 #[cfg(feature = "server")]
106 {
107 gc_old();
108 TASKS
109 .get(&task_id)
110 .map(|p| p.clone())
111 .ok_or_else(|| crate::api::error::AppError::NotFound("任务不存在").into())
112 }
113 #[cfg(not(feature = "server"))]
114 {
115 Ok(TaskProgress {
116 id: task_id,
117 kind: TaskKind::Backup,
118 stage: String::new(),
119 percent: 0,
120 detail: None,
121 status: TaskStatus::Done,
122 error: None,
123 created_at: Utc::now(),
124 result_filename: None,
125 })
126 }
127}