1+ import { spawn } from 'child_process' ;
2+ import { Observable , catchError , filter , lastValueFrom , map , of } from 'rxjs' ;
3+
4+ export async function getDriveList ( ) {
5+ // Determine the operating system
6+ switch ( process . platform ) {
7+ case 'win32' : {
8+ return await getWindowsDriveList ( ) ;
9+ }
10+ case 'linux' : {
11+ return await getLinuxDriveList ( ) ;
12+ }
13+ default : {
14+ console . warn ( 'Unsupported operating system:' , process . platform ) ;
15+ return [ ] ;
16+ }
17+ }
18+ }
19+
20+ async function getWindowsDriveList ( ) {
21+ return lastValueFrom (
22+ runCommand ( [
23+ 'wmic' ,
24+ 'logicaldisk' ,
25+ 'get' ,
26+ 'name,description,volumename' ,
27+ '/FORMAT:CSV' ,
28+ ] ) . pipe (
29+ filter ( ( result ) : result is string [ ] => ! ! result ) ,
30+ map ( ( [ headerLine , ...contentLines ] ) => {
31+ const headers = headerLine . split ( ',' ) . map ( ( s ) => s . toLocaleLowerCase ( ) ) ;
32+ const nameIndex = headers . indexOf ( 'name' ) ;
33+ const descriptionIndex = headers . indexOf ( 'description' ) ;
34+ const volumenameIndex = headers . indexOf ( 'volumename' ) ;
35+
36+ return contentLines . map ( ( line ) => {
37+ const parts = line . split ( ',' ) ;
38+ return {
39+ name : parts [ nameIndex ] ,
40+ description : parts [ descriptionIndex ] ,
41+ volumeName : parts [ volumenameIndex ] ,
42+ } as OSDrive ;
43+ } ) ;
44+ } ) ,
45+ catchError ( ( error ) => {
46+ console . error ( 'Error processing Windows drive list:' , error ) ;
47+ return of ( [ ] ) ;
48+ } )
49+ )
50+ ) ;
51+ }
52+
53+ async function getLinuxDriveList ( ) {
54+ return lastValueFrom (
55+ runCommand ( [ 'findmnt' , '--real' , '--output' , 'TARGET,SOURCE,FSTYPE,LABEL' , '--json' ] ) . pipe (
56+ filter ( ( result ) : result is string [ ] => ! ! result ) ,
57+ map ( ( lines ) => {
58+ const drives : OSDrive [ ] = [ ]
59+ const processFileSystems = ( filesystems : FileSystems [ ] ) => {
60+ filesystems
61+ . filter ( ( fs ) => {
62+ const target = fs . target ;
63+ return ( target === '/' ||
64+ target . startsWith ( '/mnt/' ) ||
65+ target . startsWith ( '/media/' ) ) ;
66+ } )
67+ . map ( ( fs ) => {
68+ drives . push ( {
69+ name : fs . target ,
70+ description : fs . source ,
71+ volumeName : fs . fstype ,
72+ } ) ;
73+ if ( fs . children ) {
74+ processFileSystems ( fs . children ) ;
75+ }
76+ } ) ;
77+ }
78+ try {
79+ const fsJson = JSON . parse ( lines . join ( '' ) ) as FindMountStructure ;
80+ if ( fsJson && fsJson . filesystems ) {
81+ processFileSystems ( fsJson . filesystems )
82+ }
83+ return drives ;
84+ } catch ( err ) {
85+ console . error ( 'Error parsing findmnt JSON output:' , err ) ;
86+ return [ ] ;
87+ }
88+ } ) ,
89+ catchError ( ( error ) => {
90+ console . error ( 'Error processing Linux mounts:' , error ) ;
91+ return of ( [ ] ) ;
92+ } )
93+ )
94+ ) ;
95+ }
96+
97+ function runCommand ( [ command , ...args ] : string [ ] ) {
98+ const observable = new Observable < string [ ] > ( ( subscriber ) => {
99+ const cmd = spawn ( command , args ) ;
100+ let stdoutData = '' ;
101+
102+ cmd . stdout . on ( 'data' , ( chunk ) => {
103+ stdoutData += String ( chunk ) ;
104+ } ) ;
105+
106+ cmd . stderr . once ( 'data' , ( data ) => {
107+ subscriber . error ( String ( data ) ) ;
108+ cmd . kill ( 'SIGINT' ) ;
109+ } ) ;
110+
111+ cmd . once ( 'exit' , ( code , signal ) => {
112+ console . log ( 'Child Process: ' , [ command , ...args ] . join ( ' ' ) ) ;
113+ console . log ( 'Exited with code' , code ) ;
114+ console . log ( 'Received termination signal' , signal ) ;
115+
116+ if ( stdoutData ) {
117+ const formattedData = stdoutData
118+ . trim ( )
119+ . split ( '\n' )
120+ . map ( ( line ) => line . trim ( ) )
121+ . filter ( ( line ) => line . length > 0 ) ;
122+
123+ subscriber . next ( formattedData ) ;
124+ } else {
125+ subscriber . next ( [ ] ) ;
126+ }
127+
128+ subscriber . complete ( ) ;
129+ } ) ;
130+
131+ process . once ( 'SIGINT' , ( ) => cmd . kill ( 'SIGINT' ) ) ;
132+ } ) . pipe (
133+ catchError ( ( err ) => {
134+ console . error ( `Error occurred while running ${ command } with args` , args ) ;
135+ console . error ( err ) ;
136+ return of ( null ) ;
137+ } )
138+ ) ;
139+
140+ return observable ;
141+ }
142+
143+ // Define the OSDrive interface
144+ interface OSDrive {
145+ name : string ;
146+ description : string ;
147+ volumeName : string ;
148+ }
149+
150+ interface FindMountStructure {
151+ filesystems : FileSystems [ ]
152+ }
153+
154+ interface FileSystems {
155+ source : string ;
156+ target : string ;
157+ fstype : string ;
158+ label : string | null ;
159+ children : FileSystems [ ] ;
160+ }
0 commit comments