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