Mountain/Track/
DispatchLogic.rs

1// File: Mountain/Source/Track/DispatchLogic.rs
2// Role: Main dispatch functions for routing commands and RPC requests.
3// Responsibilities:
4//   - Route all incoming requests to the appropriate execution logic via the
5//     effect system.
6//   - Provide specific, high-performance Tauri command handlers for frequent UI
7//     interactions.
8
9//! # DispatchLogic
10//!
11//! Contains the main dispatch functions for routing all incoming commands and
12//! RPC requests to the appropriate execution logic via the effect system.
13
14use std::sync::Arc;
15
16use Common::{Environment::Requires::Requires, IPC::IPCProvider::IPCProvider};
17use log::{debug, error, warn};
18use serde_json::{Value, json};
19use tauri::{AppHandle, Manager, Runtime, State, command};
20
21use crate::{
22	ApplicationState::ApplicationState::ApplicationState,
23	RunTime::ApplicationRunTime::ApplicationRunTime,
24	Track::EffectCreation,
25};
26
27/// The primary Tauri command handler for requests originating from the `Sky`
28/// frontend. This is the general-purpose entry point for commands that are
29/// defined abstractly in the `Common` crate.
30#[command]
31pub async fn DispatchFrontendCommand<R:Runtime>(
32	ApplicationHandle:AppHandle<R>,
33
34	RunTime:State<'_, Arc<ApplicationRunTime>>,
35
36	Command:String,
37
38	Argument:Value,
39) -> Result<Value, String> {
40	debug!("[DispatchLogic] Dispatching frontend command: {}", Command);
41
42	match EffectCreation::CreateEffectForRequest(&ApplicationHandle, &Command, Argument) {
43		Ok(EffectFn) => {
44			let runtime_clone = RunTime.inner().clone();
45
46			EffectFn(runtime_clone).await
47		},
48
49		Err(Error) => {
50			error!("[DispatchLogic] Failed to create effect for command '{}': {}", Command, Error);
51
52			Err(Error)
53		},
54	}
55}
56
57/// The primary dispatcher for requests originating from a `Cocoon` sidecar via
58/// gRPC. This routes RPC calls to the correct effect-based implementation.
59pub async fn DispatchSideCarRequest<R:Runtime>(
60	ApplicationHandle:AppHandle<R>,
61
62	RunTime:Arc<ApplicationRunTime>,
63
64	SideCarIdentifier:String,
65
66	MethodName:String,
67
68	Parameters:Value,
69) -> Result<Value, String> {
70	debug!(
71		"[DispatchLogic] Dispatching sidecar request from '{}': {}",
72		SideCarIdentifier, MethodName
73	);
74
75	match EffectCreation::CreateEffectForRequest(&ApplicationHandle, &MethodName, Parameters) {
76		Ok(EffectFn) => EffectFn(RunTime).await,
77
78		Err(Error) => {
79			error!(
80				"[DispatchLogic] Failed to create effect for sidecar method '{}': {}",
81				MethodName, Error
82			);
83
84			Err(Error)
85		},
86	}
87}
88
89/// A specific Tauri command handler for the UI to send back the result of a
90/// request-response interaction (like a dialog or message box).
91#[command]
92pub async fn ResolveUIRequest(
93	State:State<'_, Arc<ApplicationState>>,
94
95	RequestID:String,
96
97	Result:Value,
98) -> Result<(), String> {
99	debug!("[DispatchLogic] Resolving UI request ID: {}", RequestID);
100
101	let Sender = {
102		let mut PendingRequests = State.PendingUserInterfaceRequests.lock().map_err(|Error| Error.to_string())?;
103
104		PendingRequests.remove(&RequestID)
105	};
106
107	if let Some(Sender) = Sender {
108		if Sender.send(Ok(Result)).is_err() {
109			let ErrorMessage = format!("Failed to send result for UI request '{}': receiver was dropped.", RequestID);
110
111			error!("{}", ErrorMessage);
112
113			return Err(ErrorMessage);
114		}
115	} else {
116		warn!(
117			"[DispatchLogic] Received a result for an unknown or timed-out UI request ID: {}",
118			RequestID
119		);
120	}
121
122	Ok(())
123}
124
125/// A specific Tauri command handler for a WebView guest to post a message back
126/// to the extension host.
127#[command]
128pub async fn MountainWebviewPostMessageFromGuest(
129	ApplicationHandle:AppHandle,
130
131	Handle:String,
132
133	Message:Value,
134) -> Result<(), String> {
135	let IPC:Arc<dyn IPCProvider> = {
136		let RunTime = ApplicationHandle.state::<Arc<ApplicationRunTime>>().inner().clone();
137
138		RunTime.Environment.Require()
139	};
140
141	let RPCResult = IPC
142		.SendNotificationToSideCar("cocoon-main".into(), "$onDidReceiveMessage".into(), json!([Handle, Message]))
143		.await;
144
145	if let Err(Error) = RPCResult {
146		error!("[DispatchLogic] Failed to forward webview message to Cocoon: {}", Error);
147
148		return Err(Error.to_string());
149	}
150
151	Ok(())
152}