Skip to main content

DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_Mountain/Environment/WebviewProvider/
Messaging.rs

1//! # WebviewProvider - Messaging Operations
2//!
3//! Implementation of webview message passing for
4//! [`MountainEnvironment`]
5//!
6//! Handles secure bidirectional communication between host and webview.
7
8use std::collections::HashMap;
9
10use CommonLibrary::{Error::CommonError::CommonError, IPC::SkyEvent::SkyEvent};
11use serde::{Deserialize, Serialize};
12use serde_json::Value;
13use tauri::{Emitter, Listener, Manager};
14use uuid::Uuid;
15
16use super::super::MountainEnvironment::MountainEnvironment;
17use crate::dev_log;
18
19/// Represents a Webview message
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct WebviewMessage {
22	pub MessageIdentifier:String,
23
24	pub MessageType:String,
25
26	pub Payload:Value,
27
28	pub Source:Option<String>,
29}
30
31/// Webview message handler context
32struct WebviewMessageContext {
33	Handle:String,
34
35	SideCarIdentifier:Option<String>,
36
37	PendingResponses:HashMap<String, tokio::sync::oneshot::Sender<Value>>,
38}
39
40/// Messaging operations implementation for MountainEnvironment
41pub(super) async fn post_message_to_webview_impl(
42	env:&MountainEnvironment,
43
44	handle:String,
45
46	message:Value,
47) -> Result<bool, CommonError> {
48	dev_log!("extensions", "[WebviewProvider] Posting message to Webview: {}", handle);
49
50	if let Some(webview_window) = env.ApplicationHandle.get_webview_window(&handle) {
51		let webview_message = WebviewMessage {
52			MessageIdentifier:Uuid::new_v4().to_string(),
53
54			MessageType:"request".to_string(),
55
56			Payload:message,
57
58			Source:Some("host".to_string()),
59		};
60
61		webview_window
62			.emit::<WebviewMessage>(SkyEvent::WebviewPostMessage.AsStr(), webview_message)
63			.map_err(|error| {
64				CommonError::IPCError { Description:format!("Failed to post message to Webview: {}", error) }
65			})?;
66
67		dev_log!(
68			"extensions",
69			"[WebviewProvider] Message sent successfully to Webview: {}",
70			handle
71		);
72
73		Ok(true)
74	} else {
75		dev_log!(
76			"extensions",
77			"warn: [WebviewProvider] Webview not found for message: {}",
78			handle
79		);
80
81		Ok(false)
82	}
83}
84
85/// Sets up a message listener for a specific Webview.
86///
87/// When an extension iframe calls `acquireVsCodeApi().postMessage(data)`,
88/// the iframe's `pre/index.html` shim fires a `webview-message` Tauri event
89/// on the webview window. We forward it to Cocoon via
90/// `SendNotificationToSideCar("cocoon-main", "webview.message", {handle,
91/// message})` so the extension host's `onDidReceiveMessage` subscriber fires.
92pub(super) async fn setup_webview_message_listener_impl(
93	env:&MountainEnvironment,
94
95	handle:String,
96) -> Result<(), CommonError> {
97	dev_log!(
98		"extensions",
99		"[WebviewProvider] Setting up message listener for Webview: {}",
100		handle
101	);
102
103	if let Some(WebviewWin) = env.ApplicationHandle.get_webview_window(&handle) {
104		let H = handle.clone();
105
106		WebviewWin.listen("webview-message", move |Event| {
107			let H2 = H.clone();
108
109			let RawPayload = Event.payload();
110
111			let Parsed:Value = serde_json::from_str(RawPayload).unwrap_or_else(|_| {
112				// If it's not valid JSON, wrap as a string value so Cocoon
113				// still receives something meaningful.
114				Value::String(RawPayload.to_string())
115			});
116
117			tokio::spawn(async move {
118				let Notification = serde_json::json!({
119					"handle": H2,
120					"message": Parsed,
121				});
122
123				if let Err(E) = crate::Vine::Client::SendNotification::Fn(
124					"cocoon-main".to_string(),
125					"webview.message".to_string(),
126					Notification,
127				)
128				.await
129				{
130					dev_log!(
131						"extensions",
132						"warn: [WebviewProvider] webview.message notify failed handle={}: {}",
133						H2,
134						E
135					);
136				}
137			});
138		});
139
140		dev_log!(
141			"extensions",
142			"[WebviewProvider] Message listener installed for handle={}",
143			handle
144		);
145	} else {
146		dev_log!(
147			"extensions",
148			"warn: [WebviewProvider] Webview window not found for handle={}, listener skipped",
149			handle
150		);
151	}
152
153	Ok(())
154}
155
156/// Removes a message listener for a specific Webview.
157/// Tauri's `listen` returns an unlisten closure; for simplicity we rely
158/// on the webview window being destroyed (which drops all its listeners)
159/// rather than storing the handle. Future work: store in a global map.
160pub(super) async fn remove_webview_message_listener_impl(_env:&MountainEnvironment, handle:&str) {
161	dev_log!(
162		"extensions",
163		"[WebviewProvider] Message listener unregistered for handle={}",
164		handle
165	);
166}