Skip to main content

Mountain/Track/Effect/CreateEffectForRequest/
Commands.rs

1use std::sync::Arc;
2
3use CommonLibrary::{Command::CommandExecutor::CommandExecutor, Environment::Requires::Requires};
4use serde_json::{Value, json};
5use tauri::{Emitter, Runtime};
6
7use crate::Track::Effect::{
8	CreateEffectForRequest::Utilities::Params::{string_at, val_at},
9	MappedEffectType::MappedEffect,
10};
11
12pub fn CreateEffect<R:Runtime>(MethodName:&str, Parameters:Value) -> Option<Result<MappedEffect, String>> {
13	match MethodName {
14		"executeCommand" => {
15			crate::effect!(run_time, {
16				let command_executor:Arc<dyn CommandExecutor> = run_time.Environment.Require();
17
18				let (command_id, args) = if let Some(Object) = Parameters.as_object() {
19					let Id = Object
20						.get("command")
21						.or_else(|| Object.get("commandId"))
22						.and_then(Value::as_str)
23						.unwrap_or("")
24						.to_string();
25
26					let A = Object
27						.get("args")
28						.cloned()
29						.unwrap_or_else(|| Object.get("arguments").cloned().unwrap_or_default());
30
31					(Id, A)
32				} else {
33					let Id = string_at(&Parameters, 0);
34
35					let A = val_at(&Parameters, 1);
36
37					(Id, A)
38				};
39
40				command_executor
41					.ExecuteCommand(command_id, args)
42					.await
43					.map_err(|e| e.to_string())
44			})
45		},
46
47		"Command.Execute" => {
48			crate::effect!(run_time, {
49				let command_executor:Arc<dyn CommandExecutor> = run_time.Environment.Require();
50
51				let command_id = string_at(&Parameters, 0);
52
53				let args = val_at(&Parameters, 1);
54
55				// Capture before the move so the tier-gated dual-emit can
56				// reuse them. The executor consumes both by value.
57				let BroadcastId = command_id.clone();
58
59				let BroadcastArgs = args.clone();
60
61				let ExecResult = command_executor
62					.ExecuteCommand(command_id, args)
63					.await
64					.map_err(|e| e.to_string());
65
66				// `vscode.commands.onDidExecuteCommand` symmetry. The
67				// renderer-originated `commands:execute` Tauri-IPC arm
68				// (see WindServiceHandlers/Commands/Execute.rs) already
69				// dual-emits `$acceptCommandExecuted`. This arm is hit
70				// when an extension running in the Node.js host calls
71				// `vscode.commands.executeCommand(...)` and the command
72				// is NOT locally registered in Cocoon - the call goes
73				// through Mountain's gRPC `Command.Execute` arm instead.
74				//
75				// Off by default because every executeCommand from the
76				// extension host adds an extra Vine notification roundtrip.
77				// Flip `TierCommandEventBroadcast=On` to enable.
78				let BroadcastEnabled = std::env::var("TierCommandEventBroadcast")
79					.unwrap_or_else(|_| env!("TierCommandEventBroadcast", "Off").to_string());
80
81				if BroadcastEnabled == "On" {
82					let _ = ::Vine::Client::SendNotification::Fn(
83						"cocoon-main".to_string(),
84						"$acceptCommandExecuted".to_string(),
85						json!({
86							"command": BroadcastId,
87							"arguments": [BroadcastArgs],
88						}),
89					)
90					.await;
91				}
92
93				ExecResult
94			})
95		},
96
97		"Command.GetAll" => {
98			crate::effect!(run_time, {
99				let provider:Arc<dyn CommandExecutor> = run_time.Environment.Require();
100
101				provider
102					.GetAllCommands()
103					.await
104					.map(|cmds| json!(cmds))
105					.map_err(|e| e.to_string())
106			})
107		},
108
109		_ => None,
110	}
111}