Mountain/Vine/Server/Notification/
RegisterCommand.rs1#![allow(non_snake_case)]
2use 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};
21
22use crate::{
23 Environment::CommandProvider::CommandHandler,
24 Vine::Server::MountainVinegRPCService::MountainVinegRPCService,
25 dev_log,
26};
27
28struct CommandEmitBatch {
38 Pending:Mutex<Vec<Value>>,
39
40 FlushScheduled:AtomicBool,
41}
42
43static COMMAND_EMIT_BATCH:OnceLock<Arc<CommandEmitBatch>> = OnceLock::new();
44
45fn EnqueueCommandEmit(Handle:&AppHandle, Payload:Value) {
46 let Batch = COMMAND_EMIT_BATCH.get_or_init(|| {
47 Arc::new(CommandEmitBatch { Pending:Mutex::new(Vec::new()), FlushScheduled:AtomicBool::new(false) })
48 });
49
50 {
51 let mut Pending = Batch.Pending.lock().unwrap();
52
53 Pending.push(Payload);
54 }
55
56 if !Batch.FlushScheduled.swap(true, Ordering::AcqRel) {
57 let BatchClone = Batch.clone();
58
59 let HandleClone = Handle.clone();
60
61 tokio::spawn(async move {
62 tokio::time::sleep(Duration::from_millis(16)).await;
63 let Drained:Vec<Value> = {
64 let mut Pending = BatchClone.Pending.lock().unwrap();
65 std::mem::take(&mut *Pending)
66 };
67 BatchClone.FlushScheduled.store(false, Ordering::Release);
68 if Drained.is_empty() {
69 return;
70 }
71 let Count = Drained.len();
72 match HandleClone.emit("sky://command/register", json!({ "commands": Drained })) {
73 Ok(()) => {
74 dev_log!("sky-emit", "[SkyEmit] ok channel=sky://command/register batch={}", Count);
75 },
76 Err(Error) => {
77 dev_log!(
78 "sky-emit",
79 "[SkyEmit] fail channel=sky://command/register batch={} error={}",
80 Count,
81 Error
82 );
83 },
84 }
85 });
86 }
87}
88
89pub async fn RegisterCommand(Service:&MountainVinegRPCService, Parameter:&Value) {
90 let CommandId = Parameter.get("commandId").and_then(Value::as_str).unwrap_or("");
91
92 dev_log!(
97 "command-register",
98 "[MountainVinegRPCService] Cocoon registered command: {}",
99 CommandId
100 );
101
102 if CommandId.is_empty() {
103 return;
104 }
105
106 let Kind = Parameter.get("kind").and_then(Value::as_str).unwrap_or("command").to_string();
107
108 if let Ok(mut Registry) = Service
109 .RunTime()
110 .Environment
111 .ApplicationState
112 .Extension
113 .Registry
114 .CommandRegistry
115 .lock()
116 {
117 Registry.insert(
118 CommandId.to_string(),
119 CommandHandler::Proxied {
120 SideCarIdentifier:"cocoon-main".to_string(),
121 CommandIdentifier:CommandId.to_string(),
122 },
123 );
124 }
125
126 EnqueueCommandEmit(
132 Service.ApplicationHandle(),
133 json!({ "id": CommandId, "commandId": CommandId, "kind": Kind }),
134 );
135}