use crate::List;
use crate::Update;
-pub struct WatchState {
+struct WatchState {
/// The last result that we captured, for diffing
prev_list: List,
/// User's callback
- cb: Box<dyn FnMut(Update) + 'static>,
+ cb: Box<dyn FnMut(Update) + Send + 'static>,
}
-pub struct WatchHandle {
+pub(crate) struct WatchHandle {
hnd: HANDLE,
_state: Pin<Box<Mutex<WatchState>>>,
}
}
}
-pub(crate) fn watch_interfaces<F: FnMut(Update) + 'static>(
- mut callback: F,
+pub(crate) fn watch_interfaces<F: FnMut(Update) + Send + 'static>(
+ callback: F,
) -> Result<WatchHandle, Error> {
- let null_list = List::default();
- let prev_list = crate::list::list_interfaces()?;
- callback(Update {
- interfaces: prev_list.0.clone(),
- diff: prev_list.diff_from(&null_list),
- });
-
- // TODO: Can wo do something about the race condition?
let state = Box::pin(Mutex::new(WatchState {
- prev_list,
+ prev_list: List::default(),
cb: Box::new(callback),
}));
let state_ctx = &*state.as_ref() as *const _ as *const c_void;
)
};
match res {
- NO_ERROR => Ok(WatchHandle { hnd, _state: state }),
- ERROR_INVALID_HANDLE => Err(Error::Internal),
- ERROR_INVALID_PARAMETER => Err(Error::Internal),
- ERROR_NOT_ENOUGH_MEMORY => Err(Error::Internal),
- _ => Err(Error::Internal), // TODO: Use FormatMessage and get real error
+ NO_ERROR => {
+ // Trigger an initial update
+ handle_notif(&mut state.lock().unwrap(), crate::list::list_interfaces()?);
+ // Then return the handle
+ Ok(WatchHandle { hnd, _state: state })
+ }
+ ERROR_INVALID_HANDLE => Err(Error::InvalidHandle),
+ ERROR_INVALID_PARAMETER => Err(Error::InvalidParameter),
+ ERROR_NOT_ENOUGH_MEMORY => Err(Error::NotEnoughMemory),
+ _ => Err(Error::UnexpectedWindowsResult(res.0)),
}
}
_row: *const MIB_UNICASTIPADDRESS_ROW,
_notification_type: MIB_NOTIFICATION_TYPE,
) {
- println!("There was a change!");
- let Ok(new_list) = crate::list::list_interfaces() else {
- println!("Failed to get list of interfaces on change");
- return;
- };
let state_ptr = ctx as *const Mutex<WatchState>;
unsafe {
- let state_guard = &mut *state_ptr.as_ref().unwrap().lock().unwrap();
- if new_list == state_guard.prev_list {
- // TODO: Hitting this a lot, is it true?
- println!("Interfaces seem to be the same, ignoring");
+ let state_guard = &mut *state_ptr
+ .as_ref()
+ .expect("callback ctx should never be null")
+ .lock()
+ .unwrap();
+ let Ok(new_list) = crate::list::list_interfaces() else {
return;
- }
- let update = Update {
- interfaces: new_list.0.clone(),
- diff: new_list.diff_from(&state_guard.prev_list),
};
- (state_guard.cb)(update);
- state_guard.prev_list = new_list;
+ handle_notif(state_guard, new_list);
}
}
+
+fn handle_notif(state: &mut WatchState, new_list: List) {
+ if new_list == state.prev_list {
+ return;
+ }
+ let update = Update {
+ interfaces: new_list.0.clone(),
+ diff: new_list.diff_from(&state.prev_list),
+ };
+ (state.cb)(update);
+ state.prev_list = new_list;
+}