]> code.octet-stream.net Git - netwatcher/commitdiff
Mac watching working
authorThomas Karpiniec <tom.karpiniec@outlook.com>
Sat, 15 Jun 2024 22:48:14 +0000 (08:48 +1000)
committerThomas Karpiniec <tom.karpiniec@outlook.com>
Sat, 15 Jun 2024 22:48:14 +0000 (08:48 +1000)
Cargo.lock
Cargo.toml
src/list_win.rs
src/watch_mac.rs

index 632fe83357c6bc9605e9524740110903ae196e12..b24c7bfd70a489b2e9722e35bc3029b4bdce485c 100644 (file)
@@ -56,6 +56,7 @@ version = "0.1.0"
 dependencies = [
  "block2",
  "nix",
+ "objc2",
  "windows",
 ]
 
index 45cff205d21bf16c5288a7decbff325a7554d008..78a17e682527061e0e5a83c0c0c06cbbf1987e5b 100644 (file)
@@ -10,6 +10,7 @@ nix = { version = "0.29.0", features = ["net"] }
 
 [target.'cfg(target_vendor = "apple")'.dependencies]
 block2 = "0.5.1"
+objc2 = "0.5.2"
 
 [target.'cfg(windows)'.dependencies.windows]
 version = "0.56.0"
index 2ae79a66e9dd2dcab0bb3bd0f6eaf95b524367d1..8f0b7833d5d1a2a57782d55bc38f3533dd9181d6 100644 (file)
@@ -105,14 +105,3 @@ pub(crate) fn list_interfaces() -> Result<List, Error> {
 
     Ok(List(ifs))
 }
-
-#[cfg(test)]
-mod test {
-    use super::list_interfaces;
-
-    #[test]
-    fn list() {
-        let ifaces = list_interfaces().unwrap().0;
-        println!("{:?}", ifaces);
-    }
-}
index ed2879c6feff85a0c57c5fb9c08c3f2e48068df3..7a984e5185c79d6379b4b7e1fd9589ca1c56f5ca 100644 (file)
@@ -1,4 +1,9 @@
-use crate::Update;
+use std::sync::Mutex;
+
+use block2::{Block, RcBlock};
+use objc2::Encoding;
+
+use crate::{Error, List, Update};
 
 // The "objc2" project aims to provide bindings for all frameworks but Network.framework
 // isn't ready yet so let's kick it old-school
@@ -6,17 +11,20 @@ use crate::Update;
 struct nw_path_monitor;
 type nw_path_monitor_t = *mut nw_path_monitor;
 struct nw_path;
-type nw_path_t = *mut nw_path;
 struct dispatch_queue;
 type dispatch_queue_t = *mut dispatch_queue;
 const QOS_CLASS_BACKGROUND: usize = 0x09;
 
+unsafe impl objc2::Encode for nw_path {
+    const ENCODING: Encoding = usize::ENCODING;
+}
+
 #[link(name = "Network", kind = "framework")]
 extern "C" {
     fn nw_path_monitor_create() -> nw_path_monitor_t;
     fn nw_path_monitor_set_update_handler(
         monitor: nw_path_monitor_t,
-        update_handler: &Block<dyn Fn(nw_path_t)>,
+        update_handler: &Block<dyn Fn(nw_path)>,
     );
     fn nw_path_monitor_set_queue(monitor: nw_path_monitor_t, queue: dispatch_queue_t);
     fn nw_path_monitor_start(monitor: nw_path_monitor_t);
@@ -25,24 +33,54 @@ extern "C" {
     fn dispatch_get_global_queue(identifier: usize, flag: usize) -> dispatch_queue_t;
 }
 
-#[cfg(test)]
-mod test {
-    use super::list_interfaces;
+pub(crate) struct WatchHandle {
+    path_monitor: nw_path_monitor_t,
+}
 
-    #[test]
-    fn list() {
-        let ifaces = list_interfaces().unwrap();
-        println!("{:?}", ifaces);
+impl Drop for WatchHandle {
+    fn drop(&mut self) {
+        unsafe { nw_path_monitor_cancel(self.path_monitor); }
     }
 }
 
-pub(crate) struct WatchHandle;
+struct CallbackState {
+    prev_list: List,
+    callback: Box<dyn FnMut(Update) + Send + 'static>,
+}
 
-pub(crate) fn watch_interfaces<F: FnMut(Update) + 'static>(
+pub(crate) fn watch_interfaces<F: FnMut(Update) + Send + 'static>(
     callback: F,
 ) -> Result<WatchHandle, Error> {
-    // stop current worker thread
-    // post this into a thread that will use it
-    drop(callback);
-    Ok(WatchHandle)
+    let state = CallbackState {
+        prev_list: List::default(),
+        callback: Box::new(callback),
+    };
+    // Blocks are Fn, not FnMut
+    let state = Mutex::new(state);
+    let block = RcBlock::new(move |_: nw_path| {
+        let mut state = state.lock().unwrap();
+        let Ok(new_list) = crate::list::list_interfaces() else {
+            return;
+        };
+        if new_list == state.prev_list {
+            return;
+        }
+        let update = Update {
+            interfaces: new_list.0.clone(),
+            diff: new_list.diff_from(&state.prev_list),
+        };
+        (state.callback)(update);
+        state.prev_list = new_list;
+    });
+    let path_monitor: nw_path_monitor_t;
+    unsafe {
+        let queue = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0);
+        path_monitor = nw_path_monitor_create();
+        nw_path_monitor_set_update_handler(path_monitor, &block);
+        nw_path_monitor_set_queue(path_monitor, queue);
+        nw_path_monitor_start(path_monitor);
+    }
+    Ok(WatchHandle {
+        path_monitor,
+    })
 }