Mountain/ApplicationState/Internal/ExtensionScanner/
ScanAndPopulateExtensions.rs1use std::{collections::HashMap, path::PathBuf};
2
3use CommonLibrary::Error::CommonError::CommonError;
4use serde_json::Value;
5use tauri::AppHandle;
6
7use crate::{
8 ApplicationState::DTO::ExtensionDescriptionStateDTO::ExtensionDescriptionStateDTO,
9 ExtensionManagement,
10 dev_log,
11};
12
13pub async fn Fn(
14 ApplicationHandle:AppHandle,
15
16 _State:&crate::ApplicationState::State::ExtensionState::State::State,
17) -> Result<(), CommonError> {
18 dev_log!("extensions", "[ExtensionScanner] Starting extension scan...");
19
20 if let Ok(ExecutablePath) = std::env::current_exe() {
25 if let Some(BinaryDir) = ExecutablePath.parent() {
26 match super::LoadFromCache::Fn(&BinaryDir.to_path_buf()).await {
27 Ok(Some(CachedMap)) => {
28 let CachedLen = CachedMap.len();
29
30 let PostWriteCount = {
31 let mut Guard = _State
32 .ScannedExtensions
33 .ScannedExtensions
34 .lock()
35 .map_err(|Error| CommonError::StateLockPoisoned { Context:Error.to_string() })?;
36
37 *Guard = CachedMap;
38
39 Guard.len()
40 };
41
42 dev_log!(
43 "extensions",
44 "[ExtensionScanner] Cache hit: {} extensions loaded in <50ms (live scan skipped). State has \
45 {} entries.",
46 CachedLen,
47 PostWriteCount
48 );
49
50 _State.ScanReady.notify_waiters();
52
53 return Ok(());
54 },
55
56 Ok(None) => {
57 dev_log!("extensions", "[ExtensionScanner] Cache miss - falling back to live disk scan");
58 },
59
60 Err(E) => {
61 dev_log!(
62 "extensions",
63 "warn: [ExtensionScanner] Cache load error: {}; continuing with live scan",
64 E
65 );
66 },
67 }
68 }
69 }
70
71 let ScanPaths:Vec<PathBuf> = _State.Registry.GetExtensionScanPaths();
72
73 dev_log!(
74 "extensions",
75 "[ExtensionScanner] Scanning {} paths in parallel",
76 ScanPaths.len()
77 );
78
79 let Futures:Vec<_> = ScanPaths
83 .into_iter()
84 .map(|Path| {
85 let Handle = ApplicationHandle.clone();
86
87 async move {
88 let Display = Path.display().to_string();
89
90 match ExtensionManagement::Scanner::ScanDirectoryForExtensions(Handle, Path).await {
91 Ok(Found) => {
92 dev_log!(
93 "extensions",
94 "[ExtensionScanner] Path '{}' → {} extensions",
95 Display,
96 Found.len()
97 );
98
99 (Display, Ok(Found))
100 },
101
102 Err(E) => {
103 dev_log!("extensions", "warn: [ExtensionScanner] Path '{}' failed: {}", Display, E);
104
105 (Display, Err(E))
106 },
107 }
108 }
109 })
110 .collect();
111
112 let Results = futures::future::join_all(Futures).await;
113
114 let mut All:HashMap<String, ExtensionDescriptionStateDTO> = HashMap::new();
115
116 let mut SuccessfulScans = 0usize;
117
118 let mut FailedScans = 0usize;
119
120 for (_Path, Result) in Results {
121 match Result {
122 Ok(Found) => {
123 SuccessfulScans += 1;
124
125 for Extension in Found {
126 let Identifier = Extension
127 .Identifier
128 .get("value")
129 .and_then(Value::as_str)
130 .unwrap_or_default()
131 .to_string();
132
133 if !Identifier.is_empty() {
134 All.insert(Identifier, Extension);
135 }
136 }
137 },
138
139 Err(_) => {
140 FailedScans += 1;
141 },
142 }
143 }
144
145 let AllLen = All.len();
150
151 let PostWriteCount = {
152 let mut Guard = _State
153 .ScannedExtensions
154 .ScannedExtensions
155 .lock()
156 .map_err(|Error| CommonError::StateLockPoisoned { Context:Error.to_string() })?;
157
158 *Guard = All; Guard.len()
161 };
162
163 dev_log!(
164 "extensions",
165 "[ExtensionScanner] Complete: {} extensions ({} paths ok, {} failed). State has {} entries.",
166 AllLen,
167 SuccessfulScans,
168 FailedScans,
169 PostWriteCount
170 );
171
172 _State.ScanReady.notify_waiters();
174
175 Ok(())
176}
177
178pub(crate) async fn ScanExtensionsWithRecovery(
180 ApplicationHandle:AppHandle,
181
182 State:&crate::ApplicationState::State::ExtensionState::State::State,
183) -> Result<(), CommonError> {
184 dev_log!("extensions", "[ExtensionScanner] Starting robust extension scan...");
185
186 match Fn(ApplicationHandle.clone(), State).await {
187 Ok(()) => {
188 dev_log!("extensions", "[ExtensionScanner] Robust scan completed successfully");
189
190 Ok(())
191 },
192
193 Err(Error) => {
194 dev_log!("extensions", "error: [ExtensionScanner] Scan failed: {}; retrying once", Error);
195
196 Fn(ApplicationHandle, State).await
197 },
198 }
199}