@@ -50,7 +50,10 @@ use log::{info, warn};
5050use serde_json:: Value ;
5151use tauri:: { AppHandle , Manager , Wry } ;
5252
53- use crate :: ApplicationState :: ApplicationState :: ApplicationState ;
53+ use crate :: {
54+ ApplicationState :: ApplicationState :: ApplicationState ,
55+ ApplicationState :: DTO :: ExtensionDescriptionStateDTO :: ExtensionDescriptionStateDTO ,
56+ } ;
5457
5558/// The concrete `Environment` for the Mountain application.
5659#[ derive( Clone ) ]
@@ -146,16 +149,123 @@ impl MountainEnvironment {
146149 pub async fn IsAirAvailable ( & self ) -> bool {
147150 false
148151 }
152+
153+ /// Scans a directory for extensions and returns their package.json data
154+ async fn ScanExtensionDirectory ( & self , path : & std:: path:: PathBuf ) -> Result < Vec < serde_json:: Value > , CommonError > {
155+ use std:: fs;
156+ use serde_json:: Value ;
157+
158+ let mut extensions = Vec :: new ( ) ;
159+
160+ // Check if directory exists
161+ if !path. exists ( ) || !path. is_dir ( ) {
162+ warn ! ( "[ExtensionManagementService] Extension directory does not exist: {:?}" , path) ;
163+ return Ok ( extensions) ;
164+ }
165+
166+ // Read directory contents
167+ let entries = fs:: read_dir ( path) . map_err ( |error| CommonError :: FileSystemError {
168+ Description : format ! ( "Failed to read extension directory: {}" , error) ,
169+ } ) ?;
170+
171+ for entry in entries {
172+ let entry = entry. map_err ( |error| CommonError :: FileSystemError {
173+ Description : format ! ( "Failed to read directory entry: {}" , error) ,
174+ } ) ?;
175+
176+ let entry_path = entry. path ( ) ;
177+ if entry_path. is_dir ( ) {
178+ // Look for package.json in the extension directory
179+ let package_json_path = entry_path. join ( "package.json" ) ;
180+ if package_json_path. exists ( ) {
181+ match fs:: read_to_string ( & package_json_path) {
182+ Ok ( content) => {
183+ match serde_json:: from_str :: < Value > ( & content) {
184+ Ok ( mut package_json) => {
185+ // Add extension location information
186+ if let Some ( obj) = package_json. as_object_mut ( ) {
187+ obj. insert ( "ExtensionLocation" . to_string ( ) , Value :: String ( entry_path. to_string_lossy ( ) . to_string ( ) ) ) ;
188+ }
189+ extensions. push ( package_json) ;
190+ info ! ( "[ExtensionManagementService] Found extension at: {:?}" , entry_path) ;
191+ }
192+ Err ( error) => {
193+ warn ! ( "[ExtensionManagementService] Failed to parse package.json at {:?}: {}" , package_json_path, error) ;
194+ }
195+ }
196+ }
197+ Err ( error) => {
198+ warn ! ( "[ExtensionManagementService] Failed to read package.json at {:?}: {}" , package_json_path, error) ;
199+ }
200+ }
201+ }
202+ }
203+ }
204+
205+ Ok ( extensions)
206+ }
149207}
150208
151209impl Environment for MountainEnvironment { }
152210
153211#[ async_trait]
154212impl ExtensionManagementService for MountainEnvironment {
155213 async fn ScanForExtensions ( & self ) -> Result < ( ) , CommonError > {
156- warn ! ( "[ExtensionManagementService] ScanForExtensions is a stub." ) ;
214+ info ! ( "[ExtensionManagementService] Scanning for extensions..." ) ;
215+
216+ // Get the extension scan paths from ApplicationState
217+ let ScanPaths : Vec < std:: path:: PathBuf > = {
218+ let ScanPathsGuard = self
219+ . ApplicationState
220+ . ExtensionScanPaths
221+ . lock ( )
222+ . map_err ( |Error | CommonError :: StateLockPoisoned { Context : Error . to_string ( ) } ) ?;
223+ ScanPathsGuard . clone ( )
224+ } ;
225+
226+ let mut extensions = Vec :: new ( ) ;
227+
228+ // Scan each extension directory
229+ for path in ScanPaths {
230+ if let Ok ( mut scan_result) = self . ScanExtensionDirectory ( & path) . await {
231+ extensions. append ( & mut scan_result) ;
232+ }
233+ }
234+
235+ // Update ApplicationState with scanned extensions
236+ let mut ScannedExtensionsGuard = self
237+ . ApplicationState
238+ . ScannedExtensions
239+ . lock ( )
240+ . map_err ( |Error | CommonError :: StateLockPoisoned { Context : Error . to_string ( ) } ) ?;
157241
158- Err ( CommonError :: NotImplemented { FeatureName : "ScanForExtensions" . into ( ) } )
242+ ScannedExtensionsGuard . clear ( ) ;
243+
244+ for extension in extensions {
245+ if let Some ( identifier) = extension. get ( "Identifier" ) . and_then ( |v| v. as_str ( ) ) {
246+ // Convert the extension DTO to ExtensionDescriptionStateDTO
247+ let extension_dto = ExtensionDescriptionStateDTO {
248+ Identifier : serde_json:: Value :: String ( identifier. to_string ( ) ) ,
249+ Name : extension. get ( "Name" ) . and_then ( |v| v. as_str ( ) ) . unwrap_or ( "Unknown" ) . to_string ( ) ,
250+ Version : extension. get ( "Version" ) . and_then ( |v| v. as_str ( ) ) . unwrap_or ( "0.0.0" ) . to_string ( ) ,
251+ Publisher : extension. get ( "Publisher" ) . and_then ( |v| v. as_str ( ) ) . unwrap_or ( "Unknown" ) . to_string ( ) ,
252+ Engines : extension. get ( "Engines" ) . cloned ( ) . unwrap_or ( serde_json:: Value :: Null ) ,
253+ Main : extension. get ( "Main" ) . and_then ( |v| v. as_str ( ) ) . map ( |s| s. to_string ( ) ) ,
254+ Browser : extension. get ( "Browser" ) . and_then ( |v| v. as_str ( ) ) . map ( |s| s. to_string ( ) ) ,
255+ ModuleType : extension. get ( "ModuleType" ) . and_then ( |v| v. as_str ( ) ) . map ( |s| s. to_string ( ) ) ,
256+ IsBuiltin : extension. get ( "IsBuiltin" ) . and_then ( |v| v. as_bool ( ) ) . unwrap_or ( false ) ,
257+ IsUnderDevelopment : extension. get ( "IsUnderDevelopment" ) . and_then ( |v| v. as_bool ( ) ) . unwrap_or ( false ) ,
258+ ExtensionLocation : extension. get ( "ExtensionLocation" ) . cloned ( ) . unwrap_or ( serde_json:: Value :: Null ) ,
259+ ActivationEvents : extension. get ( "ActivationEvents" ) . and_then ( |v| v. as_array ( ) ) . map ( |arr| arr. iter ( ) . filter_map ( |v| v. as_str ( ) . map ( |s| s. to_string ( ) ) ) . collect ( ) ) ,
260+ Contributes : extension. get ( "Contributes" ) . cloned ( ) ,
261+ } ;
262+
263+ ScannedExtensionsGuard . insert ( identifier. to_string ( ) , extension_dto) ;
264+ }
265+ }
266+
267+ info ! ( "[ExtensionManagementService] Found {} extensions" , ScannedExtensionsGuard . len( ) ) ;
268+ Ok ( ( ) )
159269 }
160270
161271 async fn GetExtensions ( & self ) -> Result < Vec < Value > , CommonError > {
@@ -173,10 +283,51 @@ impl ExtensionManagementService for MountainEnvironment {
173283 Ok ( Extensions )
174284 }
175285
176- async fn GetExtension ( & self , _id : String ) -> Result < Option < Value > , CommonError > {
177- warn ! ( "[ExtensionManagementService] GetExtension is a stub." ) ;
286+ async fn GetExtension ( & self , id : String ) -> Result < Option < Value > , CommonError > {
287+ let ScannedExtensionsGuard = self
288+ . ApplicationState
289+ . ScannedExtensions
290+ . lock ( )
291+ . map_err ( |Error | CommonError :: StateLockPoisoned { Context : Error . to_string ( ) } ) ?;
292+
293+ if let Some ( extension_dto) = ScannedExtensionsGuard . get ( & id) {
294+ // Convert ExtensionDescriptionStateDTO back to JSON Value
295+ let mut extension_value = serde_json:: Map :: new ( ) ;
296+ extension_value. insert ( "Identifier" . to_string ( ) , extension_dto. Identifier . clone ( ) ) ;
297+ extension_value. insert ( "Name" . to_string ( ) , Value :: String ( extension_dto. Name . clone ( ) ) ) ;
298+ extension_value. insert ( "Version" . to_string ( ) , Value :: String ( extension_dto. Version . clone ( ) ) ) ;
299+ extension_value. insert ( "Publisher" . to_string ( ) , Value :: String ( extension_dto. Publisher . clone ( ) ) ) ;
300+ extension_value. insert ( "Engines" . to_string ( ) , extension_dto. Engines . clone ( ) ) ;
301+
302+ if let Some ( main) = & extension_dto. Main {
303+ extension_value. insert ( "Main" . to_string ( ) , Value :: String ( main. clone ( ) ) ) ;
304+ }
305+
306+ if let Some ( browser) = & extension_dto. Browser {
307+ extension_value. insert ( "Browser" . to_string ( ) , Value :: String ( browser. clone ( ) ) ) ;
308+ }
178309
179- Err ( CommonError :: NotImplemented { FeatureName : "GetExtension" . into ( ) } )
310+ if let Some ( module_type) = & extension_dto. ModuleType {
311+ extension_value. insert ( "ModuleType" . to_string ( ) , Value :: String ( module_type. clone ( ) ) ) ;
312+ }
313+
314+ extension_value. insert ( "IsBuiltin" . to_string ( ) , Value :: Bool ( extension_dto. IsBuiltin ) ) ;
315+ extension_value. insert ( "IsUnderDevelopment" . to_string ( ) , Value :: Bool ( extension_dto. IsUnderDevelopment ) ) ;
316+ extension_value. insert ( "ExtensionLocation" . to_string ( ) , extension_dto. ExtensionLocation . clone ( ) ) ;
317+
318+ if let Some ( activation_events) = & extension_dto. ActivationEvents {
319+ let events: Vec < Value > = activation_events. iter ( ) . map ( |e| Value :: String ( e. clone ( ) ) ) . collect ( ) ;
320+ extension_value. insert ( "ActivationEvents" . to_string ( ) , Value :: Array ( events) ) ;
321+ }
322+
323+ if let Some ( contributes) = & extension_dto. Contributes {
324+ extension_value. insert ( "Contributes" . to_string ( ) , contributes. clone ( ) ) ;
325+ }
326+
327+ Ok ( Some ( Value :: Object ( extension_value) ) )
328+ } else {
329+ Ok ( None )
330+ }
180331 }
181332}
182333
0 commit comments