@@ -25,6 +25,8 @@ use iced::widget::image::Handle;
2525use image:: { GenericImageView , RgbaImage } ;
2626use objc:: { class, msg_send, sel, sel_impl} ;
2727use std:: fmt:: Write ;
28+ use std:: path:: Path ;
29+ use std:: process:: Command ;
2830
2931include ! ( concat!( env!( "OUT_DIR" ) , "/services.rs" ) ) ;
3032
@@ -266,7 +268,7 @@ pub fn modify_or_insert_in_map(
266268) -> ( TrafficDirection , Service , String , Option < Handle > ) {
267269 let mut traffic_direction = TrafficDirection :: default ( ) ;
268270 let mut service = Service :: Unknown ;
269- let mut process = "- " . to_string ( ) ;
271+ let mut process = "? " . to_string ( ) ;
270272 let mut picon = None ;
271273
272274 if !info_traffic_msg. map . contains_key ( key) {
@@ -287,43 +289,40 @@ pub fn modify_or_insert_in_map(
287289 service = get_service ( key, traffic_direction, my_interface_addresses) ;
288290 // determine process
289291 if let Some ( local_port) = get_local_port ( key, traffic_direction) {
290- let processes = listeners:: get_processes_by_port ( local_port) ;
291- process = processes
292- . into_iter ( )
293- . flatten ( )
294- . next ( )
295- . map_or ( "?" . to_string ( ) , |p| {
296- let path = get_executable_path ( p. pid as i32 ) ;
297- let mut image: Option < iced:: widget:: Image > = None ;
298- println ! ( "Process: {} (PID: {})" , p. name, p. pid) ;
299- if let Some ( app_path) = path {
300- println ! ( "--> Exe path: {}" , app_path) ;
301- if let Some ( bundle_path) = find_app_bundle_path ( & app_path) {
302- println ! ( "--> Bundle path: {}" , bundle_path) ;
303- if let Some ( tiff) = get_icon_tiff_bytes ( & bundle_path) {
304- let img =
305- image:: load_from_memory ( & tiff) . expect ( "Failed to decode image" ) ;
306- // resize the image
307- let resized =
308- img. resize_exact ( 64 , 64 , image:: imageops:: FilterType :: Lanczos3 ) ;
309- let ( width, height) = resized. dimensions ( ) ;
310- println ! ( "--> Icon size: {}x{}" , width, height) ;
311- // crop the image
312- let sub =
313- image:: imageops:: crop_imm ( & resized, 6 , 6 , 52 , 52 ) . to_image ( ) ;
314- let ( width, height) = sub. dimensions ( ) ;
315- println ! ( "--> Cropped icon size: {}x{}" , width, height) ;
316-
317- picon = Some ( iced:: widget:: image:: Handle :: from_rgba (
318- width,
319- height,
320- sub. into_raw ( ) ,
321- ) ) ;
322- }
323- }
292+ let processes = get_processes ( ) ;
293+ let pid = processes. get ( & local_port) . unwrap_or ( & 0 ) ;
294+ let path = get_executable_path ( * pid as i32 ) ;
295+ let mut image: Option < iced:: widget:: Image > = None ;
296+ // println!("Process: {} (PID: {})", path, p.pid);
297+ if let Some ( app_path) = path {
298+ process = Path :: new ( & app_path)
299+ . file_name ( )
300+ . unwrap_or_default ( )
301+ . to_string_lossy ( )
302+ . to_string ( ) ;
303+ // println!("--> Exe path: {}", app_path);
304+ if let Some ( bundle_path) = find_app_bundle_path ( & app_path) {
305+ // println!("--> Bundle path: {}", bundle_path);
306+ if let Some ( tiff) = get_icon_tiff_bytes ( & bundle_path) {
307+ let img = image:: load_from_memory ( & tiff) . expect ( "Failed to decode image" ) ;
308+ // resize the image
309+ let resized =
310+ img. resize_exact ( 64 , 64 , image:: imageops:: FilterType :: Lanczos3 ) ;
311+ let ( width, height) = resized. dimensions ( ) ;
312+ // println!("--> Icon size: {}x{}", width, height);
313+ // crop the image
314+ let sub = image:: imageops:: crop_imm ( & resized, 6 , 6 , 52 , 52 ) . to_image ( ) ;
315+ let ( width, height) = sub. dimensions ( ) ;
316+ // println!("--> Cropped icon size: {}x{}", width, height);
317+
318+ picon = Some ( iced:: widget:: image:: Handle :: from_rgba (
319+ width,
320+ height,
321+ sub. into_raw ( ) ,
322+ ) ) ;
324323 }
325- p . name
326- } ) ;
324+ }
325+ }
327326 }
328327 }
329328
@@ -378,6 +377,59 @@ pub fn modify_or_insert_in_map(
378377 )
379378}
380379
380+ fn get_processes ( ) -> HashMap < u16 , u32 > {
381+ let output = Command :: new ( "nettop" )
382+ . args ( & [ "-n" , "-L" , "1" , "-J" , "" ] )
383+ . output ( )
384+ . unwrap ( ) ;
385+
386+ if !output. status . success ( ) {
387+ return HashMap :: new ( ) ;
388+ }
389+
390+ let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
391+
392+ let mut map = HashMap :: new ( ) ;
393+ let mut current_pid: Option < u32 > = None ;
394+
395+ for line in stdout. lines ( ) {
396+ let line = line. trim ( ) . trim_end_matches ( ',' ) ;
397+
398+ if line. is_empty ( ) {
399+ continue ;
400+ }
401+
402+ // Detect process line: processName.PID
403+ if let Some ( dot_pos) = line. rfind ( '.' ) {
404+ let pid_str = & line[ dot_pos + 1 ..] ;
405+ if let Ok ( pid) = pid_str. parse :: < u32 > ( ) {
406+ current_pid = Some ( pid) ;
407+ continue ;
408+ }
409+ }
410+
411+ // Parse connection line
412+ if let Some ( pid) = current_pid {
413+ // Expect format like: tcp4 192.168.1.102:64694<->172.64.155.209:443
414+ if let Some ( space_pos) = line. find ( ' ' ) {
415+ let addr = & line[ space_pos + 1 ..] ;
416+ if let Some ( ( local, _remote) ) = addr. split_once ( "<->" ) {
417+ // Extract port from local address (skip if wildcard)
418+ if let Some ( ( _ip, port_str) ) = local. rsplit_once ( ':' ) {
419+ if port_str != "*" {
420+ if let Ok ( port) = port_str. parse :: < u16 > ( ) {
421+ map. insert ( port, pid) ;
422+ }
423+ }
424+ }
425+ }
426+ }
427+ }
428+ }
429+
430+ map
431+ }
432+
381433unsafe extern "C" {
382434 fn proc_pidpath ( pid : c_int , buffer : * mut libc:: c_void , buffersize : u32 ) -> c_int ;
383435}
0 commit comments