Vine/Server/Notification/
RegisterCommand.rs1use std::sync::{Arc, OnceLock};
14
15use serde_json::{Value, json};
16use tokio::sync::mpsc::{UnboundedSender, unbounded_channel};
17
18use crate::{
19 Host::{RendererEmitter, VineHost},
20 dev_log,
21};
22
23struct CommandBatchChannel {
24 Sender:UnboundedSender<Value>,
25}
26
27static CMD_CHANNEL:OnceLock<CommandBatchChannel> = OnceLock::new();
28
29fn GetOrInitChannel(Emitter:Arc<dyn RendererEmitter>) -> &'static CommandBatchChannel {
30 CMD_CHANNEL.get_or_init(|| {
31 let (Tx, mut Rx) = unbounded_channel::<Value>();
32
33 tokio::spawn(async move {
34 let mut Buf:Vec<Value> = Vec::with_capacity(128);
35
36 loop {
37 match Rx.recv().await {
39 None => break,
40 Some(V) => Buf.push(V),
41 }
42
43 Rx.recv_many(&mut Buf, 4096).await;
45
46 tokio::time::sleep(std::time::Duration::from_millis(16)).await;
48
49 Rx.recv_many(&mut Buf, 4096).await;
51
52 if Buf.is_empty() {
53 continue;
54 }
55
56 let Count = Buf.len();
57
58 let Commands:Vec<Value> = Buf.drain(..).collect();
59
60 Emitter.Emit("sky://command/register", json!({ "commands": Commands }));
61
62 dev_log!("commands", "[RegisterCommand] batch={}", Count);
63 }
64 });
65
66 CommandBatchChannel { Sender:Tx }
67 })
68}
69
70pub async fn RegisterCommand(Host:&dyn VineHost, Parameter:&Value) {
71 let CommandId = Parameter.get("commandId").and_then(Value::as_str).unwrap_or("");
72
73 dev_log!("command-register", "[RegisterCommand] id={}", CommandId);
74
75 if CommandId.is_empty() {
76 return;
77 }
78
79 let Kind = Parameter.get("kind").and_then(Value::as_str).unwrap_or("command").to_string();
80
81 Host.RegisterCommandInRegistry(CommandId, "cocoon-main");
83
84 let Ch = GetOrInitChannel(Host.RendererEmitter());
86
87 let _ = Ch.Sender.send(json!({ "id": CommandId, "commandId": CommandId, "kind": Kind }));
88}