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	FlushScheduled:AtomicBool,
28}
29
30static BATCH:OnceLock<Arc<Batch>> = OnceLock::new();
31
32pub fn Fn(Handle:&AppHandle, Payload:Value) {
33	let Batch =
34		BATCH.get_or_init(|| Arc::new(Batch { Pending:Mutex::new(Vec::new()), FlushScheduled:AtomicBool::new(false) }));
35
36	{
37		let mut Pending = Batch.Pending.lock().unwrap();
38		Pending.push(Payload);
39	}
40
41	if !Batch.FlushScheduled.swap(true, Ordering::AcqRel) {
42		let Cloned = Batch.clone();
43		let HandleCloned = Handle.clone();
44		let Channel = SkyEvent::TreeViewCreate.AsStr().to_string();
45		tokio::spawn(async move {
46			tokio::time::sleep(Duration::from_millis(16)).await;
47			let Drained:Vec<Value> = {
48				let mut Pending = Cloned.Pending.lock().unwrap();
49				std::mem::take(&mut *Pending)
50			};
51			Cloned.FlushScheduled.store(false, Ordering::Release);
52			if Drained.is_empty() {
53				return;
54			}
55			let Count = Drained.len();
56			match HandleCloned.emit(&Channel, json!({ "views": Drained })) {
57				Ok(()) => dev_log!("sky-emit", "[SkyEmit] ok channel={} batch={}", Channel, Count),
58				Err(Error) => {
59					dev_log!("sky-emit", "[SkyEmit] fail channel={} batch={} error={}", Channel, Count, Error)
60				},
61			}
62		});
63	}
64}