add functionality for BlockNotifier to unregister a previously registered listener, in order to no longer receive events

This commit is contained in:
Ryan Loomba 2020-02-15 00:04:09 -08:00
parent fc03ab1534
commit 7d6234662c
2 changed files with 88 additions and 2 deletions

View file

@ -19,6 +19,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::collections::HashSet;
use std::ops::Deref;
use std::marker::PhantomData;
use std::ptr;
/// Used to give chain error details upstream
pub enum ChainError {
@ -252,11 +253,22 @@ impl<'a, CL: Deref<Target = ChainListener + 'a> + 'a> BlockNotifier<'a, CL> {
}
/// Register the given listener to receive events.
// TODO: unregister
pub fn register_listener(&self, listener: CL) {
let mut vec = self.listeners.lock().unwrap();
vec.push(listener);
}
/// Unregister the given listener to no longer
/// receive events.
///
/// If the same listener is registered multiple times, unregistering
/// will remove ALL occurrences of that listener. Comparison is done using
/// the pointer returned by the Deref trait implementation.
pub fn unregister_listener(&self, listener: CL) {
let mut vec = self.listeners.lock().unwrap();
// item is a ref to an abstract thing that dereferences to a ChainListener,
// so dereference it twice to get the ChainListener itself
vec.retain(|item | !ptr::eq(&(**item), &(*listener)));
}
/// Notify listeners that a block was connected given a full, unfiltered block.
///
@ -376,3 +388,76 @@ impl ChainWatchInterfaceUtil {
watched.does_match_tx(tx)
}
}
#[cfg(test)]
mod tests {
use ln::functional_test_utils::{create_node_cfgs};
use super::{BlockNotifier, ChainListener};
use std::ptr;
#[test]
fn register_listener_test() {
let node_cfgs = create_node_cfgs(1);
let block_notifier = BlockNotifier::new(node_cfgs[0].chain_monitor.clone());
assert_eq!(block_notifier.listeners.lock().unwrap().len(), 0);
let listener = &node_cfgs[0].chan_monitor.simple_monitor as &ChainListener;
block_notifier.register_listener(listener);
let vec = block_notifier.listeners.lock().unwrap();
assert_eq!(vec.len(), 1);
let item = vec.first().clone().unwrap();
assert!(ptr::eq(&(**item), &(*listener)));
}
#[test]
fn unregister_single_listener_test() {
let node_cfgs = create_node_cfgs(2);
let block_notifier = BlockNotifier::new(node_cfgs[0].chain_monitor.clone());
let listener1 = &node_cfgs[0].chan_monitor.simple_monitor as &ChainListener;
let listener2 = &node_cfgs[1].chan_monitor.simple_monitor as &ChainListener;
block_notifier.register_listener(listener1);
block_notifier.register_listener(listener2);
let vec = block_notifier.listeners.lock().unwrap();
assert_eq!(vec.len(), 2);
drop(vec);
block_notifier.unregister_listener(listener1);
let vec = block_notifier.listeners.lock().unwrap();
assert_eq!(vec.len(), 1);
let item = vec.first().clone().unwrap();
assert!(ptr::eq(&(**item), &(*listener2)));
}
#[test]
fn unregister_single_listener_ref_test() {
let node_cfgs = create_node_cfgs(2);
let block_notifier = BlockNotifier::new(node_cfgs[0].chain_monitor.clone());
block_notifier.register_listener(&node_cfgs[0].chan_monitor.simple_monitor as &ChainListener);
block_notifier.register_listener(&node_cfgs[1].chan_monitor.simple_monitor as &ChainListener);
let vec = block_notifier.listeners.lock().unwrap();
assert_eq!(vec.len(), 2);
drop(vec);
block_notifier.unregister_listener(&node_cfgs[0].chan_monitor.simple_monitor);
let vec = block_notifier.listeners.lock().unwrap();
assert_eq!(vec.len(), 1);
let item = vec.first().clone().unwrap();
assert!(ptr::eq(&(**item), &(*&node_cfgs[1].chan_monitor.simple_monitor)));
}
#[test]
fn unregister_multiple_of_the_same_listeners_test() {
let node_cfgs = create_node_cfgs(2);
let block_notifier = BlockNotifier::new(node_cfgs[0].chain_monitor.clone());
let listener1 = &node_cfgs[0].chan_monitor.simple_monitor as &ChainListener;
let listener2 = &node_cfgs[1].chan_monitor.simple_monitor as &ChainListener;
block_notifier.register_listener(listener1);
block_notifier.register_listener(listener1);
block_notifier.register_listener(listener2);
let vec = block_notifier.listeners.lock().unwrap();
assert_eq!(vec.len(), 3);
drop(vec);
block_notifier.unregister_listener(listener1);
let vec = block_notifier.listeners.lock().unwrap();
assert_eq!(vec.len(), 1);
let item = vec.first().clone().unwrap();
assert!(ptr::eq(&(**item), &(*listener2)));
}
}

View file

@ -27,7 +27,8 @@ mod onion_utils;
mod wire;
#[cfg(test)]
#[macro_use] mod functional_test_utils;
#[macro_use]
pub(crate) mod functional_test_utils;
#[cfg(test)]
mod functional_tests;
#[cfg(test)]