DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_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 let UserScanPaths:Vec<PathBuf> = _State
69 .Registry
70 .GetExtensionScanPaths()
71 .into_iter()
72 .filter(|P| ExtensionManagement::Scanner::IsUserExtensionScanPath(P))
73 .collect();
74
75 if !UserScanPaths.is_empty() {
76 dev_log!(
77 "extensions",
78 "[ExtensionScanner] Cache hit supplement: live-scanning {} user-writable path(s)",
79 UserScanPaths.len()
80 );
81
82 let UserFutures:Vec<_> = UserScanPaths
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] User path '{}' → {} extensions (supplement)",
95 Display,
96 Found.len()
97 );
98
99 Found
100 },
101
102 Err(E) => {
103 dev_log!(
104 "extensions",
105 "warn: [ExtensionScanner] User path '{}' failed (supplement): {}",
106 Display,
107 E
108 );
109
110 Vec::new()
111 },
112 }
113 }
114 })
115 .collect();
116
117 let UserResults = futures::future::join_all(UserFutures).await;
118
119 let mut UserMerged = 0usize;
120
121 {
122 let mut Guard = _State
123 .ScannedExtensions
124 .ScannedExtensions
125 .lock()
126 .map_err(|Error| CommonError::StateLockPoisoned { Context:Error.to_string() })?;
127
128 for Found in UserResults {
129 for Extension in Found {
130 let Identifier = Extension
131 .Identifier
132 .get("value")
133 .and_then(Value::as_str)
134 .unwrap_or_default()
135 .to_string();
136
137 if !Identifier.is_empty() {
138 Guard.insert(Identifier, Extension);
139
140 UserMerged += 1;
141 }
142 }
143 }
144 }
145
146 dev_log!(
147 "extensions",
148 "[ExtensionScanner] Cache hit supplement: merged {} user extension(s) into state",
149 UserMerged
150 );
151 }
152
153 _State.ScanReady.notify_waiters();
155
156 return Ok(());
157 },
158
159 Ok(None) => {
160 dev_log!("extensions", "[ExtensionScanner] Cache miss - falling back to live disk scan");
161 },
162
163 Err(E) => {
164 dev_log!(
165 "extensions",
166 "warn: [ExtensionScanner] Cache load error: {}; continuing with live scan",
167 E
168 );
169 },
170 }
171 }
172 }
173
174 let ScanPaths:Vec<PathBuf> = _State.Registry.GetExtensionScanPaths();
175
176 dev_log!(
177 "extensions",
178 "[ExtensionScanner] Scanning {} paths in parallel",
179 ScanPaths.len()
180 );
181
182 let Futures:Vec<_> = ScanPaths
186 .into_iter()
187 .map(|Path| {
188 let Handle = ApplicationHandle.clone();
189
190 async move {
191 let Display = Path.display().to_string();
192
193 match ExtensionManagement::Scanner::ScanDirectoryForExtensions(Handle, Path).await {
194 Ok(Found) => {
195 dev_log!(
196 "extensions",
197 "[ExtensionScanner] Path '{}' → {} extensions",
198 Display,
199 Found.len()
200 );
201
202 (Display, Ok(Found))
203 },
204
205 Err(E) => {
206 dev_log!("extensions", "warn: [ExtensionScanner] Path '{}' failed: {}", Display, E);
207
208 (Display, Err(E))
209 },
210 }
211 }
212 })
213 .collect();
214
215 let Results = futures::future::join_all(Futures).await;
216
217 let mut All:HashMap<String, ExtensionDescriptionStateDTO> = HashMap::new();
218
219 let mut SuccessfulScans = 0usize;
220
221 let mut FailedScans = 0usize;
222
223 for (_Path, Result) in Results {
224 match Result {
225 Ok(Found) => {
226 SuccessfulScans += 1;
227
228 for Extension in Found {
229 let Identifier = Extension
230 .Identifier
231 .get("value")
232 .and_then(Value::as_str)
233 .unwrap_or_default()
234 .to_string();
235
236 if !Identifier.is_empty() {
237 All.insert(Identifier, Extension);
238 }
239 }
240 },
241
242 Err(_) => {
243 FailedScans += 1;
244 },
245 }
246 }
247
248 let AllLen = All.len();
253
254 let PostWriteCount = {
255 let mut Guard = _State
256 .ScannedExtensions
257 .ScannedExtensions
258 .lock()
259 .map_err(|Error| CommonError::StateLockPoisoned { Context:Error.to_string() })?;
260
261 *Guard = All; Guard.len()
264 };
265
266 dev_log!(
267 "extensions",
268 "[ExtensionScanner] Complete: {} extensions ({} paths ok, {} failed). State has {} entries.",
269 AllLen,
270 SuccessfulScans,
271 FailedScans,
272 PostWriteCount
273 );
274
275 _State.ScanReady.notify_waiters();
277
278 Ok(())
279}
280
281pub(crate) async fn ScanExtensionsWithRecovery(
283 ApplicationHandle:AppHandle,
284
285 State:&crate::ApplicationState::State::ExtensionState::State::State,
286) -> Result<(), CommonError> {
287 dev_log!("extensions", "[ExtensionScanner] Starting robust extension scan...");
288
289 match Fn(ApplicationHandle.clone(), State).await {
290 Ok(()) => {
291 dev_log!("extensions", "[ExtensionScanner] Robust scan completed successfully");
292
293 Ok(())
294 },
295
296 Err(Error) => {
297 dev_log!("extensions", "error: [ExtensionScanner] Scan failed: {}; retrying once", Error);
298
299 Fn(ApplicationHandle, State).await
300 },
301 }
302}