Mountain/ExtensionManagement/
Scanner.rs1#![allow(non_snake_case, non_camel_case_types)]
14
15use std::{path::PathBuf, sync::Arc};
16
17use Common::{
18 Effect::ApplicationRunTime::ApplicationRunTime as _,
19 Error::CommonError::CommonError,
20 FileSystem::{DTO::FileTypeDTO::FileTypeDTO, ReadDirectory::ReadDirectory, ReadFile::ReadFile},
21};
22use log::{trace, warn};
23use serde_json::{Map, Value};
24use tauri::Manager;
25
26use crate::{
27 ApplicationState::{
28 ApplicationState::ApplicationState,
29 DTO::ExtensionDescriptionStateDTO::ExtensionDescriptionStateDTO,
30 },
31 Environment::Utility,
32 RunTime::ApplicationRunTime::ApplicationRunTime,
33};
34
35pub async fn ScanDirectoryForExtensions(
41 ApplicationHandle:tauri::AppHandle,
42
43 DirectoryPath:PathBuf,
44) -> Result<Vec<ExtensionDescriptionStateDTO>, CommonError> {
45 let RunTime = ApplicationHandle.state::<Arc<ApplicationRunTime>>().inner().clone();
46
47 let mut FoundExtensions = Vec::new();
48
49 let TopLevelEntries = match RunTime.Run(ReadDirectory(DirectoryPath.clone())).await {
50 Ok(entries) => entries,
51
52 Err(error) => {
53 warn!(
54 "[ExtensionScanner] Could not read extension directory '{}': {}. Skipping.",
55 DirectoryPath.display(),
56 error
57 );
58
59 return Ok(Vec::new());
60 },
61 };
62
63 for (EntryName, FileType) in TopLevelEntries {
64 if FileType == FileTypeDTO::Directory {
65 let PotentialExtensionPath = DirectoryPath.join(EntryName);
66
67 let PackageJsonPath = PotentialExtensionPath.join("package.json");
68
69 trace!(
70 "[ExtensionScanner] Checking for package.json in: {}",
71 PotentialExtensionPath.display()
72 );
73
74 if let Ok(PackageJsonContent) = RunTime.Run(ReadFile(PackageJsonPath)).await {
75 match serde_json::from_slice::<ExtensionDescriptionStateDTO>(&PackageJsonContent) {
76 Ok(mut Description) => {
77 Description.ExtensionLocation =
79 serde_json::to_value(url::Url::from_directory_path(PotentialExtensionPath).unwrap())
80 .unwrap_or(Value::Null);
81
82 FoundExtensions.push(Description);
83 },
84
85 Err(error) => {
86 warn!(
87 "[ExtensionScanner] Failed to parse package.json for extension at '{}': {}",
88 PotentialExtensionPath.display(),
89 error
90 );
91 },
92 }
93 }
94 }
95 }
96
97 Ok(FoundExtensions)
98}
99
100pub fn CollectDefaultConfigurations(State:&ApplicationState) -> Result<Value, CommonError> {
103 let mut MergedDefaults = Map::new();
104
105 let Extensions = State
106 .ScannedExtensions
107 .lock()
108 .map_err(Utility::MapApplicationStateLockErrorToCommonError)?;
109
110 for Extension in Extensions.values() {
111 if let Some(contributes) = Extension.Contributes.as_ref().and_then(|v| v.as_object()) {
112 if let Some(configuration) = contributes.get("configuration").and_then(|v| v.as_object()) {
113 if let Some(properties) = configuration.get("properties").and_then(|v| v.as_object()) {
114 for (key, value) in properties {
115 if let Some(prop_details) = value.as_object() {
116 if let Some(default_value) = prop_details.get("default") {
117 MergedDefaults.insert(key.clone(), default_value.clone());
119 }
120 }
121 }
122 }
123 }
124 }
125 }
126
127 Ok(Value::Object(MergedDefaults))
128}