Skip to main content

Mountain/RPC/CocoonService/TreeView/
EnqueueTreeViewEmit.rs

1#![allow(non_snake_case)]
2
3//! Coalesce 30+ Mountain → Sky `tree-view/create` emits at boot into a
4//! single batched payload per 16 ms window. SkyBridge's listener accepts
5//! both single `{ viewId, extensionId }` and batch `{ views: [...] }`
6//! shapes (mirrors the command-batch pattern from
7//! `Vine/Server/Notification/RegisterCommand.rs`).
8
9use std::{
10	sync::{
11		Arc,
12		Mutex,
13		OnceLock,
14		atomic::{AtomicBool, Ordering},
15	},
16	time::Duration,
17};
18
19use serde_json::{Value, json};
20use tauri::{AppHandle, Emitter};
21use CommonLibrary::IPC::SkyEvent::SkyEvent;
22
23use crate::dev_log;
24
25struct Batch {
26	Pending:Mutex<Vec<Value>>,
27
28	FlushScheduled:AtomicBool,
29}
30
31static BATCH:OnceLock<Arc<Batch>> = OnceLock::new();
32
33pub fn Fn(Handle:&AppHandle, Payload:Value) {
34	let Batch =
35		BATCH.get_or_init(|| Arc::new(Batch { Pending:Mutex::new(Vec::new()), FlushScheduled:AtomicBool::new(false) }));
36
37	{
38		let mut Pending = Batch.Pending.lock().unwrap();
39
40		Pending.push(Payload);
41	}
42
43	if !Batch.FlushScheduled.swap(true, Ordering::AcqRel) {
44		let Cloned = Batch.clone();
45
46		let HandleCloned = Handle.clone();
47
48		let Channel = SkyEvent::TreeViewCreate.AsStr().to_string();
49
50		tokio::spawn(async move {
51			tokio::time::sleep(Duration::from_millis(16)).await;
52			let Drained:Vec<Value> = {
53				let mut Pending = Cloned.Pending.lock().unwrap();
54				std::mem::take(&mut *Pending)
55			};
56			Cloned.FlushScheduled.store(false, Ordering::Release);
57			if Drained.is_empty() {
58				return;
59			}
60			let Count = Drained.len();
61			match HandleCloned.emit(&Channel, json!({ "views": Drained })) {
62				Ok(()) => dev_log!("sky-emit", "[SkyEmit] ok channel={} batch={}", Channel, Count),
63				Err(Error) => {
64					dev_log!("sky-emit", "[SkyEmit] fail channel={} batch={} error={}", Channel, Count, Error)
65				},
66			}
67		});
68	}
69}