Mountain/Environment/
DiagnosticProvider.rs

1// File: Mountain/Source/Environment/DiagnosticProvider.rs
2// Role: Implements the `DiagnosticManager` trait for the `MountainEnvironment`.
3// Responsibilities:
4//   - Manage diagnostic collections in the central `ApplicationState`.
5//   - Store diagnostics from various sources (owners).
6//   - Notify the UI (`Sky`) of changes to diagnostics.
7//   - Provide an aggregated view of all diagnostics.
8
9//! # DiagnosticProvider Implementation
10//!
11//! Implements the `DiagnosticManager` trait for the `MountainEnvironment`. This
12//! provider contains the core logic for managing diagnostic collections,
13//! including storing diagnostics from various sources and notifying the UI of
14//! changes.
15
16#![allow(non_snake_case, non_camel_case_types)]
17
18use Common::{Diagnostic::DiagnosticManager::DiagnosticManager, Error::CommonError::CommonError};
19use async_trait::async_trait;
20use log::{debug, error, info};
21use serde_json::{Value, json};
22use tauri::Emitter;
23
24use super::{MountainEnvironment::MountainEnvironment, Utility};
25use crate::ApplicationState::DTO::MarkerDataDTO::MarkerDataDTO;
26
27#[async_trait]
28impl DiagnosticManager for MountainEnvironment {
29	/// Sets or updates diagnostics for multiple resources from a specific
30	/// owner.
31	async fn SetDiagnostics(&self, Owner:String, EntriesDTOValue:Value) -> Result<(), CommonError> {
32		info!("[DiagnosticProvider] Setting diagnostics for owner: {}", Owner);
33
34		let DeserializedEntries:Vec<(Value, Option<Vec<MarkerDataDTO>>)> = serde_json::from_value(EntriesDTOValue)
35			.map_err(|Error| {
36				CommonError::InvalidArgument {
37					ArgumentName:"EntriesDTOValue".to_string(),
38					Reason:format!("Failed to deserialize diagnostic entries: {}", Error),
39				}
40			})?;
41
42		let mut DiagnosticsMapGuard = self
43			.ApplicationState
44			.DiagnosticsMap
45			.lock()
46			.map_err(Utility::MapApplicationStateLockErrorToCommonError)?;
47
48		let OwnerMap = DiagnosticsMapGuard.entry(Owner.clone()).or_default();
49
50		let mut ChangedURIKeys = Vec::new();
51
52		for (URIComponentsValue, MarkersOption) in DeserializedEntries {
53			let URIKey = Utility::GetURLFromURIComponentsDTO(&URIComponentsValue)?.to_string();
54
55			ChangedURIKeys.push(URIKey.clone());
56
57			if let Some(Markers) = MarkersOption {
58				if Markers.is_empty() {
59					OwnerMap.remove(&URIKey);
60				} else {
61					OwnerMap.insert(URIKey, Markers);
62				}
63			} else {
64				OwnerMap.remove(&URIKey);
65			}
66		}
67
68		drop(DiagnosticsMapGuard);
69
70		// Notify the frontend that diagnostics have changed for specific URIs.
71		let EventPayload = json!({ "Owner": Owner, "Uris": ChangedURIKeys });
72
73		if let Err(Error) = self.ApplicationHandle.emit("sky://diagnostics/changed", EventPayload) {
74			error!("[DiagnosticProvider] Failed to emit 'diagnostics_changed': {}", Error);
75		}
76
77		Ok(())
78	}
79
80	/// Clears all diagnostics from a specific owner.
81	async fn ClearDiagnostics(&self, Owner:String) -> Result<(), CommonError> {
82		info!("[DiagnosticProvider] Clearing all diagnostics for owner: {}", Owner);
83
84		let ChangedURIKeys:Vec<String> = {
85			let mut DiagnosticsMapGuard = self
86				.ApplicationState
87				.DiagnosticsMap
88				.lock()
89				.map_err(Utility::MapApplicationStateLockErrorToCommonError)?;
90
91			DiagnosticsMapGuard
92				.remove(&Owner)
93				.map_or(vec![], |OwnerMap| OwnerMap.keys().cloned().collect())
94		};
95
96		if !ChangedURIKeys.is_empty() {
97			let EventPayload = json!({ "Owner": Owner, "Uris": ChangedURIKeys });
98
99			if let Err(Error) = self.ApplicationHandle.emit("sky://diagnostics/changed", EventPayload) {
100				error!("[DiagnosticProvider] Failed to emit 'diagnostics_changed' on clear: {}", Error);
101			}
102		}
103
104		Ok(())
105	}
106
107	/// Retrieves all diagnostics, optionally filtered by a resource URI.
108	async fn GetAllDiagnostics(&self, ResourceURIFilterOption:Option<Value>) -> Result<Value, CommonError> {
109		debug!(
110			"[DiagnosticProvider] Getting all diagnostics with filter: {:?}",
111			ResourceURIFilterOption
112		);
113
114		let DiagnosticsMapGuard = self
115			.ApplicationState
116			.DiagnosticsMap
117			.lock()
118			.map_err(Utility::MapApplicationStateLockErrorToCommonError)?;
119
120		let mut ResultMap:std::collections::HashMap<String, Vec<MarkerDataDTO>> = std::collections::HashMap::new();
121
122		if let Some(FilterURIValue) = ResourceURIFilterOption {
123			let FilterURIKey = Utility::GetURLFromURIComponentsDTO(&FilterURIValue)?.to_string();
124
125			for OwnerMap in DiagnosticsMapGuard.values() {
126				if let Some(Markers) = OwnerMap.get(&FilterURIKey) {
127					ResultMap.entry(FilterURIKey.clone()).or_default().extend(Markers.clone());
128				}
129			}
130		} else {
131			// Aggregate all diagnostics from all owners for all files.
132			for OwnerMap in DiagnosticsMapGuard.values() {
133				for (URIKey, Markers) in OwnerMap.iter() {
134					ResultMap.entry(URIKey.clone()).or_default().extend(Markers.clone());
135				}
136			}
137		}
138
139		let ResultList:Vec<(String, Vec<MarkerDataDTO>)> = ResultMap.into_iter().collect();
140
141		serde_json::to_value(ResultList).map_err(|Error| CommonError::from(Error))
142	}
143}