@@ -15,6 +15,12 @@ pub struct SSHConnection {
1515 sftp : Option < Sftp > ,
1616}
1717
18+ #[ derive( Debug , Clone ) ]
19+ pub struct ServerStats {
20+ pub cpu_usage : String ,
21+ pub memory_usage : String ,
22+ pub disk_usage : String ,
23+ }
1824impl SSHConnection {
1925 pub fn new ( hostname : & str , username : & str , password : & str , port : u16 ) -> Self {
2026 Self {
@@ -214,4 +220,67 @@ impl SSHConnection {
214220 Err ( "SFTP subsystem not initialized." . to_string ( ) )
215221 }
216222 }
223+
224+ fn run_command ( session : & Session , cmd : & str ) -> Result < String , String > {
225+ let mut channel = session
226+ . channel_session ( )
227+ . map_err ( |e| format ! ( "Failed to open channel: {}" , e) ) ?;
228+ channel
229+ . exec ( cmd)
230+ . map_err ( |e| format ! ( "Failed to exec command {}: {}" , cmd, e) ) ?;
231+
232+ let mut stdout = String :: new ( ) ;
233+ channel
234+ . read_to_string ( & mut stdout)
235+ . map_err ( |e| format ! ( "Failed to read command output: {}" , e) ) ?;
236+
237+ channel
238+ . wait_close ( )
239+ . map_err ( |e| format ! ( "Failed to close channel: {}" , e) ) ?;
240+
241+ Ok ( stdout)
242+ }
243+
244+ pub fn fetch_stats ( & self ) -> Result < ServerStats , String > {
245+ let session = self
246+ . session
247+ . as_ref ( )
248+ . ok_or_else ( || "Session not initialized." . to_string ( ) ) ?;
249+
250+ let cpu_cmd = r#"top -bn1 | grep "Cpu(s)""# ;
251+ let mem_cmd = r#"free -h | grep "Mem:""# ;
252+ let disk_cmd = r#"df -h / | tail -1"# ;
253+
254+ let raw_cpu = Self :: run_command ( session, cpu_cmd) ?;
255+ let raw_mem = Self :: run_command ( session, mem_cmd) ?;
256+ let raw_disk = Self :: run_command ( session, disk_cmd) ?;
257+
258+ Ok ( Self :: process_stats ( & raw_cpu, & raw_mem, & raw_disk) )
259+ }
260+
261+ fn process_stats ( raw_cpu : & str , raw_mem : & str , raw_disk : & str ) -> ServerStats {
262+ let cpu_parts: Vec < & str > = raw_cpu. split_whitespace ( ) . collect ( ) ;
263+ let cpu_usage = format ! (
264+ "User: {}%, System: {}%, Idle: {}%, Steal: {}%" ,
265+ cpu_parts[ 1 ] , cpu_parts[ 3 ] , cpu_parts[ 7 ] , cpu_parts[ 15 ]
266+ ) ;
267+
268+ let mem_parts: Vec < & str > = raw_mem. split_whitespace ( ) . collect ( ) ;
269+ let memory_usage = format ! (
270+ "Total: {}, Used: {}, Free: {}, Buffers/Cache: {}" ,
271+ mem_parts[ 1 ] , mem_parts[ 2 ] , mem_parts[ 3 ] , mem_parts[ 5 ]
272+ ) ;
273+
274+ let disk_parts: Vec < & str > = raw_disk. split_whitespace ( ) . collect ( ) ;
275+ let disk_usage = format ! (
276+ "Filesystem: {}, Total: {}, Used: {}, Available: {}, Usage: {}" ,
277+ disk_parts[ 0 ] , disk_parts[ 1 ] , disk_parts[ 2 ] , disk_parts[ 3 ] , disk_parts[ 4 ]
278+ ) ;
279+
280+ ServerStats {
281+ cpu_usage,
282+ memory_usage,
283+ disk_usage,
284+ }
285+ }
217286}
0 commit comments