]>
code.octet-stream.net Git - netwatcher/blob - src/watch_mac.rs
42e7217ad46a09f33c1ce9277da588ce6ac283e9
   3 use block2
::{Block
, RcBlock
}; 
   6 use crate::{Error
, List
, Update
}; 
   8 // The "objc2" project aims to provide bindings for all frameworks but Network.framework 
   9 // isn't ready yet so let's kick it old-school 
  12 struct NwPathMonitor([u8; 0]); 
  13 type NwPathMonitorT 
= *mut NwPathMonitor
; 
  15 struct NwPath([u8; 0]); 
  17 struct DispatchQueue([u8; 0]); 
  18 type DispatchQueueT 
= *mut DispatchQueue
; 
  19 const QOS_CLASS_BACKGROUND
: usize = 0x09; 
  21 unsafe impl objc2
::Encode 
for NwPath 
{ 
  22     const ENCODING
: Encoding 
= usize::ENCODING
; 
  25 #[link(name = "Network", kind = "framework")] 
  27     fn nw_path_monitor_create() -> NwPathMonitorT
; 
  28     fn nw_path_monitor_set_update_handler( 
  29         monitor
: NwPathMonitorT
, 
  30         update_handler
: &Block
<dyn 
Fn(NwPath
)>, 
  32     fn nw_path_monitor_set_queue(monitor
: NwPathMonitorT
, queue
: DispatchQueueT
); 
  33     fn nw_path_monitor_start(monitor
: NwPathMonitorT
); 
  34     fn nw_path_monitor_cancel(monitor
: NwPathMonitorT
); 
  36     fn dispatch_get_global_queue(identifier
: usize, flag
: usize) -> DispatchQueueT
; 
  39 pub(crate) struct WatchHandle 
{ 
  40     path_monitor
: NwPathMonitorT
, 
  43 impl Drop 
for WatchHandle 
{ 
  46             nw_path_monitor_cancel(self.path_monitor
); 
  51 struct CallbackState 
{ 
  53     callback
: Box
<dyn 
FnMut(Update
) + Send 
+ '
static>, 
  56 pub(crate) fn watch_interfaces
<F
: FnMut(Update
) + Send 
+ '
static>( 
  58 ) -> Result
<WatchHandle
, Error
> { 
  59     let state 
= CallbackState 
{ 
  60         prev_list
: List
::default(), 
  61         callback
: Box
::new(callback
), 
  63     // Blocks are Fn, not FnMut 
  64     let state 
= Mutex
::new(state
); 
  65     let block 
= RcBlock
::new(move |_
: NwPath
| { 
  66         let mut state 
= state
.lock().unwrap
(); 
  67         let Ok(new_list
) = crate::list
::list_interfaces() else { 
  70         if new_list 
== state
.prev_list 
{ 
  74             interfaces
: new_list
.0.clone(), 
  75             diff
: new_list
.diff_from(&state
.prev_list
), 
  77         (state
.callback
)(update
); 
  78         state
.prev_list 
= new_list
; 
  80     let path_monitor
: NwPathMonitorT
; 
  82         let queue 
= dispatch_get_global_queue(QOS_CLASS_BACKGROUND
, 0); 
  83         path_monitor 
= nw_path_monitor_create(); 
  84         nw_path_monitor_set_update_handler(path_monitor
, &block
); 
  85         nw_path_monitor_set_queue(path_monitor
, queue
); 
  86         nw_path_monitor_start(path_monitor
); 
  88     Ok(WatchHandle 
{ path_monitor 
})