// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! This module defines a watcher that subscribes to the device filesystem and
//! produces a stream of messages when bt-host devices are added or removed from
//! the system

use {
    fuchsia_bluetooth::constants::HOST_DEVICE_DIR,
    fuchsia_vfs_watcher::{self as vfs_watcher, WatchEvent, WatchMessage},
    futures::{future, FutureExt, Stream, TryStreamExt},
    io_util::{open_directory_in_namespace, OPEN_RIGHT_READABLE},
    log::warn,
    std::{
        io,
        path::{Path, PathBuf},
    },
};

pub enum HostEvent {
    HostAdded(PathBuf),
    HostRemoved(PathBuf),
}

/// Watch the VFS for host devices being added or removed, and produce a stream of HostEvent messages
pub fn watch_hosts() -> impl Stream<Item = Result<HostEvent, io::Error>> {
    async {
        let directory = open_directory_in_namespace(HOST_DEVICE_DIR, OPEN_RIGHT_READABLE).unwrap();
        let watcher = vfs_watcher::Watcher::new(directory)
            .await
            .expect("Cannot open vfs watcher for bt-host device path");
        watcher.try_filter_map(|msg| future::ok(as_host_event(msg)))
    }
    .flatten_stream()
}

fn as_host_event(msg: WatchMessage) -> Option<HostEvent> {
    let path = Path::new(HOST_DEVICE_DIR).join(&msg.filename);
    match msg.event {
        WatchEvent::EXISTING | WatchEvent::ADD_FILE => Some(HostEvent::HostAdded(path)),
        WatchEvent::REMOVE_FILE => Some(HostEvent::HostRemoved(path)),
        WatchEvent::IDLE => None,
        e => {
            warn!("Unrecognized host watch event: {:?}", e);
            None
        }
    }
}
