Mountain/Vine/Server/Notification/
ProgressReport.rs1#![allow(non_snake_case)]
2use std::{
14 collections::HashMap,
15 sync::{
16 Arc,
17 Mutex,
18 OnceLock,
19 atomic::{AtomicBool, Ordering},
20 },
21 time::Duration,
22};
23
24use serde_json::{Value, json};
25use tauri::{AppHandle, Emitter};
26
27use crate::{Vine::Server::MountainVinegRPCService::MountainVinegRPCService, dev_log};
28
29#[derive(Default)]
30struct ProgressAccumulator {
31 Message:String,
32
33 Increment:f64,
34}
35
36struct ProgressEmitBatch {
37 Pending:Mutex<HashMap<String, ProgressAccumulator>>,
38
39 FlushScheduled:AtomicBool,
40}
41
42static PROGRESS_EMIT_BATCH:OnceLock<Arc<ProgressEmitBatch>> = OnceLock::new();
43
44fn EnqueueProgressEmit(Handle:&AppHandle, ProgressHandle:String, Message:String, Increment:f64) {
45 let Batch = PROGRESS_EMIT_BATCH.get_or_init(|| {
46 Arc::new(ProgressEmitBatch { Pending:Mutex::new(HashMap::new()), FlushScheduled:AtomicBool::new(false) })
47 });
48
49 {
50 let mut Guard = Batch.Pending.lock().unwrap();
51
52 let Entry = Guard.entry(ProgressHandle).or_default();
53
54 if !Message.is_empty() {
58 Entry.Message = Message;
59 }
60
61 Entry.Increment += Increment;
62 }
63
64 if !Batch.FlushScheduled.swap(true, Ordering::AcqRel) {
65 let BatchClone = Batch.clone();
66
67 let HandleClone = Handle.clone();
68
69 tokio::spawn(async move {
70 tokio::time::sleep(Duration::from_millis(16)).await;
71 let Drained:HashMap<String, ProgressAccumulator> = {
72 let mut Guard = BatchClone.Pending.lock().unwrap();
73 std::mem::take(&mut *Guard)
74 };
75 BatchClone.FlushScheduled.store(false, Ordering::Release);
76 for (ProgressHandleId, Accumulator) in Drained {
77 if let Err(Error) = HandleClone.emit(
78 "sky://notification/progress-update",
79 json!({
80 "id": ProgressHandleId,
81 "message": Accumulator.Message,
82 "increment": Accumulator.Increment,
83 }),
84 ) {
85 dev_log!(
86 "grpc",
87 "warn: [MountainVinegRPCService] sky://notification/progress-update emit failed: {}",
88 Error
89 );
90 }
91 }
92 });
93 }
94}
95
96pub async fn ProgressReport(Service:&MountainVinegRPCService, Parameter:&Value) {
97 let ProgressHandle = Parameter.get("handle").and_then(Value::as_str).unwrap_or("").to_string();
98
99 let Message = Parameter.get("message").and_then(Value::as_str).unwrap_or("").to_string();
100
101 let Increment = Parameter.get("increment").and_then(Value::as_f64).unwrap_or(0.0);
102
103 EnqueueProgressEmit(Service.ApplicationHandle(), ProgressHandle, Message, Increment);
104}