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 ScanAndPopulateExtensions(
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 let ScanPaths:Vec<PathBuf> = _State.Registry.GetExtensionScanPaths();
21
22 dev_log!(
23 "extensions",
24 "[ExtensionScanner] Scanning {} paths in parallel",
25 ScanPaths.len()
26 );
27
28 let Futures:Vec<_> = ScanPaths
32 .into_iter()
33 .map(|Path| {
34 let Handle = ApplicationHandle.clone();
35
36 async move {
37 let Display = Path.display().to_string();
38
39 match ExtensionManagement::Scanner::ScanDirectoryForExtensions(Handle, Path).await {
40 Ok(Found) => {
41 dev_log!(
42 "extensions",
43 "[ExtensionScanner] Path '{}' → {} extensions",
44 Display,
45 Found.len()
46 );
47
48 (Display, Ok(Found))
49 },
50
51 Err(E) => {
52 dev_log!("extensions", "warn: [ExtensionScanner] Path '{}' failed: {}", Display, E);
53
54 (Display, Err(E))
55 },
56 }
57 }
58 })
59 .collect();
60
61 let Results = futures::future::join_all(Futures).await;
62
63 let mut All:HashMap<String, ExtensionDescriptionStateDTO> = HashMap::new();
64
65 let mut SuccessfulScans = 0usize;
66
67 let mut FailedScans = 0usize;
68
69 for (_Path, Result) in Results {
70 match Result {
71 Ok(Found) => {
72 SuccessfulScans += 1;
73
74 for Extension in Found {
75 let Identifier = Extension
76 .Identifier
77 .get("value")
78 .and_then(Value::as_str)
79 .unwrap_or_default()
80 .to_string();
81
82 if !Identifier.is_empty() {
83 All.insert(Identifier, Extension);
84 }
85 }
86 },
87
88 Err(_) => {
89 FailedScans += 1;
90 },
91 }
92 }
93
94 let PostWriteCount = {
95 let mut Guard = _State
96 .ScannedExtensions
97 .ScannedExtensions
98 .lock()
99 .map_err(|Error| CommonError::StateLockPoisoned { Context:Error.to_string() })?;
100
101 Guard.clear();
102
103 for (Key, Dto) in &All {
104 Guard.insert(Key.clone(), Dto.clone());
105 }
106
107 Guard.len()
108 };
109
110 dev_log!(
111 "extensions",
112 "[ExtensionScanner] Complete: {} extensions ({} paths ok, {} failed). State has {} entries.",
113 All.len(),
114 SuccessfulScans,
115 FailedScans,
116 PostWriteCount
117 );
118
119 _State.ScanReady.notify_waiters();
121
122 Ok(())
123}
124
125pub async fn ScanExtensionsWithRecovery(
127 ApplicationHandle:AppHandle,
128
129 State:&crate::ApplicationState::State::ExtensionState::State::State,
130) -> Result<(), CommonError> {
131 dev_log!("extensions", "[ExtensionScanner] Starting robust extension scan...");
132
133 match ScanAndPopulateExtensions(ApplicationHandle.clone(), State).await {
134 Ok(()) => {
135 dev_log!("extensions", "[ExtensionScanner] Robust scan completed successfully");
136
137 Ok(())
138 },
139
140 Err(Error) => {
141 dev_log!("extensions", "error: [ExtensionScanner] Scan failed: {}; retrying once", Error);
142
143 ScanAndPopulateExtensions(ApplicationHandle, State).await
144 },
145 }
146}