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 Increment:f64,
33}
34
35struct ProgressEmitBatch {
36 Pending:Mutex<HashMap<String, ProgressAccumulator>>,
37 FlushScheduled:AtomicBool,
38}
39
40static PROGRESS_EMIT_BATCH:OnceLock<Arc<ProgressEmitBatch>> = OnceLock::new();
41
42fn EnqueueProgressEmit(Handle:&AppHandle, ProgressHandle:String, Message:String, Increment:f64) {
43 let Batch = PROGRESS_EMIT_BATCH.get_or_init(|| {
44 Arc::new(ProgressEmitBatch { Pending:Mutex::new(HashMap::new()), FlushScheduled:AtomicBool::new(false) })
45 });
46
47 {
48 let mut Guard = Batch.Pending.lock().unwrap();
49 let Entry = Guard.entry(ProgressHandle).or_default();
50 if !Message.is_empty() {
54 Entry.Message = Message;
55 }
56 Entry.Increment += Increment;
57 }
58
59 if !Batch.FlushScheduled.swap(true, Ordering::AcqRel) {
60 let BatchClone = Batch.clone();
61 let HandleClone = Handle.clone();
62 tokio::spawn(async move {
63 tokio::time::sleep(Duration::from_millis(16)).await;
64 let Drained:HashMap<String, ProgressAccumulator> = {
65 let mut Guard = BatchClone.Pending.lock().unwrap();
66 std::mem::take(&mut *Guard)
67 };
68 BatchClone.FlushScheduled.store(false, Ordering::Release);
69 for (ProgressHandleId, Accumulator) in Drained {
70 if let Err(Error) = HandleClone.emit(
71 "sky://notification/progress-update",
72 json!({
73 "id": ProgressHandleId,
74 "message": Accumulator.Message,
75 "increment": Accumulator.Increment,
76 }),
77 ) {
78 dev_log!(
79 "grpc",
80 "warn: [MountainVinegRPCService] sky://notification/progress-update emit failed: {}",
81 Error
82 );
83 }
84 }
85 });
86 }
87}
88
89pub async fn ProgressReport(Service:&MountainVinegRPCService, Parameter:&Value) {
90 let ProgressHandle = Parameter.get("handle").and_then(Value::as_str).unwrap_or("").to_string();
91 let Message = Parameter.get("message").and_then(Value::as_str).unwrap_or("").to_string();
92 let Increment = Parameter.get("increment").and_then(Value::as_f64).unwrap_or(0.0);
93 EnqueueProgressEmit(Service.ApplicationHandle(), ProgressHandle, Message, Increment);
94}