+/// Utility for notifying listeners about new blocks, and handling block rescans if new watch
+/// data is registered.
+pub struct BlockNotifier<'a> {
+ listeners: Mutex<Vec<Weak<ChainListener + 'a>>>, //TODO(vmw): try removing Weak
+ chain_monitor: Arc<ChainWatchInterface>,
+}
+
+impl<'a> BlockNotifier<'a> {
+ /// Constructs a new BlockNotifier without any listeners.
+ pub fn new(chain_monitor: Arc<ChainWatchInterface>) -> BlockNotifier<'a> {
+ BlockNotifier {
+ listeners: Mutex::new(Vec::new()),
+ chain_monitor,
+ }
+ }
+
+ /// Register the given listener to receive events. Only a weak pointer is provided and
+ /// the registration should be freed once that pointer expires.
+ // TODO: unregister
+ pub fn register_listener(&self, listener: Weak<ChainListener + 'a>) {
+ let mut vec = self.listeners.lock().unwrap();
+ vec.push(listener);
+ }
+
+ /// Notify listeners that a block was connected given a full, unfiltered block.
+ ///
+ /// Handles re-scanning the block and calling block_connected again if listeners register new
+ /// watch data during the callbacks for you (see ChainListener::block_connected for more info).
+ pub fn block_connected<'b>(&self, block: &'b Block, height: u32) {
+ let mut reentered = true;
+ while reentered {
+ let (matched, matched_index) = self.chain_monitor.filter_block(block);
+ reentered = self.block_connected_checked(&block.header, height, matched.as_slice(), matched_index.as_slice());
+ }
+ }
+
+ /// Notify listeners that a block was connected, given pre-filtered list of transactions in the
+ /// block which matched the filter (probably using does_match_tx).
+ ///
+ /// Returns true if notified listeners registered additional watch data (implying that the
+ /// block must be re-scanned and this function called again prior to further block_connected
+ /// calls, see ChainListener::block_connected for more info).
+ pub fn block_connected_checked(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> bool {
+ let last_seen = self.chain_monitor.reentered();
+
+ let listeners = self.listeners.lock().unwrap().clone();
+ for listener in listeners.iter() {
+ match listener.upgrade() {
+ Some(arc) => arc.block_connected(header, height, txn_matched, indexes_of_txn_matched),
+ None => ()
+ }
+ }
+ return last_seen != self.chain_monitor.reentered();
+ }
+
+
+ /// Notify listeners that a block was disconnected.
+ pub fn block_disconnected(&self, header: &BlockHeader, disconnected_height: u32) {
+ let listeners = self.listeners.lock().unwrap().clone();
+ for listener in listeners.iter() {
+ match listener.upgrade() {
+ Some(arc) => arc.block_disconnected(&header, disconnected_height),
+ None => ()
+ }
+ }
+ }
+
+}
+