WIP - add ActorContext, FidlHost loading

Change-Id: I61b3d4b1c9ab5c2f95d8b8fca00d89cce8093b25
diff --git a/bin/bluetooth/gap/src/actor.rs b/bin/bluetooth/gap/src/actor.rs
index 076bd83..5af26a56 100644
--- a/bin/bluetooth/gap/src/actor.rs
+++ b/bin/bluetooth/gap/src/actor.rs
@@ -7,7 +7,6 @@
 use futures::task::LocalWaker;
 use core::pin::Pin;
 use std::sync::Arc;
-//use std::sync::RwLock;
 use parking_lot::RwLock;
 use fuchsia_async as fasync;
 
@@ -20,17 +19,28 @@
    Could do it via message traits ala Actix What about types responders?
    What do I send as the message target? Perhaps just route via oneshot channels?
    */
-    fn update(&mut self, msg: Self::Message, system: System);
+    fn update(&mut self, msg: Self::Message, context: ActorContext<Self>);
     // TODO - handle errors by returning a result?
     // Then can terminate actors if they return an error?
     // Or terminate the whole system?
     // fn update(&mut self, msg: Message, system: System) -> Result<(),Error>;
 }
 
+pub struct ActorContext<A: Actor + ?Sized> {
+    system: System,
+    handle: ActorHandle<A::Message>,
+}
+
+impl<A: Actor + ?Sized> Clone for ActorContext<A> {
+    fn clone(&self) -> Self {
+        ActorContext{ system: self.system.clone(), handle: self.handle.clone() }
+    }
+}
+
 struct ActorCell<A: Actor> {
     actor: A,
     inbox: mpsc::UnboundedReceiver<A::Message>,
-    system: System
+    cx: ActorContext<A>
 }
 
 trait ActorProc {
@@ -52,7 +62,7 @@
     fn run_next(&mut self, lw: &LocalWaker) -> Poll<Option<()>> {
         let inbox = Pin::new(&mut self.inbox);
         match inbox.poll_next(lw) {
-            Poll::Ready(Some(msg)) => Poll::Ready(Some(self.actor.update(msg, self.system.clone()))),
+            Poll::Ready(Some(msg)) => Poll::Ready(Some(self.actor.update(msg, self.cx.clone()))),
             Poll::Ready(None) => Poll::Ready(None),
             Poll::Pending => Poll::Pending
         }
@@ -82,10 +92,11 @@
 }
 
 impl System {
-    pub fn spawn<A: Actor + 'static>(&mut self, a: A) -> ActorHandle<A::Message> {
-        let (sender, receiver) = mpsc::unbounded::<A::Message>();
-        let b: Box<dyn ActorProc> = Box::new(ActorCell{ actor: a, inbox: receiver, system: self.clone() });
-        self.inner.write().spawn(b);
+    pub fn spawn<A: Actor + 'static>(&mut self, actor: A) -> ActorHandle<A::Message> {
+        let (sender, inbox) = mpsc::unbounded::<A::Message>();
+        let cx = ActorContext{ system: self.clone(), handle: ActorHandle{ channel: sender.clone() }};
+        let dyn_actor: Box<dyn ActorProc> = Box::new(ActorCell{ actor, inbox, cx });
+        self.inner.write().spawn(dyn_actor);
         ActorHandle{ channel: sender }
     }
 
@@ -151,7 +162,7 @@
 impl Actor for Hello {
     type Message = String;
 
-    fn update(&mut self, msg: Self::Message, _system: System) {
+    fn update(&mut self, msg: Self::Message, _cx: ActorContext<Hello>) {
         println!("Hello, {}", msg);
     }
 }
diff --git a/bin/bluetooth/gap/src/adapters.rs b/bin/bluetooth/gap/src/adapters.rs
index bd2aae2..ba3ab20 100644
--- a/bin/bluetooth/gap/src/adapters.rs
+++ b/bin/bluetooth/gap/src/adapters.rs
@@ -1,12 +1,14 @@
-use fuchsia_syslog::fx_log_warn;
+use fuchsia_syslog::{fx_log_warn, fx_log_info};
 use fuchsia_vfs_watcher as vfs_watcher;
 use fuchsia_vfs_watcher::{WatchEvent, WatchMessage};
 use std::fs::File;
-use failure::Error;
+use failure::{Error, err_msg};
 use std::io;
 use std::path::{Path, PathBuf};
 use futures::{Stream, TryStreamExt};
 
+use crate::host::{FidlHost, open_host_fidl};
+
 // 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
@@ -43,4 +45,3 @@
         },
     })
 }
-
diff --git a/bin/bluetooth/gap/src/host.rs b/bin/bluetooth/gap/src/host.rs
index 017e26b..36fd332 100644
--- a/bin/bluetooth/gap/src/host.rs
+++ b/bin/bluetooth/gap/src/host.rs
@@ -2,13 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+use failure::{Error, err_msg};
 use fuchsia_async as fasync;
+use fuchsia_bluetooth::host::open_host_channel;
+use fuchsia_bluetooth::util::clone_host_info;
 use fidl_fuchsia_bluetooth_control::AdapterInfo;
 use fidl_fuchsia_bluetooth_host::HostProxy;
 //use fidl_fuchsia_bluetooth_control::PairingDelegateMarker;
 //use fidl_fuchsia_bluetooth_control::{InputCapabilityType, OutputCapabilityType};
 //use fuchsia_syslog::{fx_log, fx_log_err, fx_log_info};
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 
 //use fidl_fuchsia_bluetooth_host::HostEvent::*;
 //use fidl_fuchsia_bluetooth_host::HostEvent;
@@ -16,6 +19,7 @@
 use futures::future::FutureExt;
 use futures::channel::oneshot;
 use futures::channel::oneshot::Receiver;
+use std::fs::File;
 
 //use crate::host_dispatcher::*;
 use crate::types::bt;
@@ -33,9 +37,29 @@
 
 /// Type representing a BT Adapter with a loaded Host Device Driver
 pub struct FidlHost {
-    _device_path: PathBuf,
+    device_path: PathBuf,
     proxy: HostProxy,
-    _info: AdapterInfo
+    info: AdapterInfo
+}
+
+impl FidlHost {
+    pub fn get_info(&self) -> AdapterInfo { clone_host_info(&self.info) }
+    pub fn path(&self) -> &Path { &self.device_path }
+}
+
+/// Initialize a HostDevice
+pub async fn open_host_fidl(device_path: PathBuf) -> Result<FidlHost, Error> {
+    // Connect to the host device.
+    let host = File::open(device_path.clone())
+                .map_err(|_| err_msg("failed to open bt-host device"))?;
+    let handle = open_host_channel(&host)?;
+    let handle = fasync::Channel::from_channel(handle.into())?;
+    let proxy = HostProxy::new(handle);
+
+    // Obtain basic information and create and entry in the disptacher's map.
+    let info = await!(proxy.get_info())
+        .map_err(|_| err_msg("failed to obtain bt-host information"))?;
+    Ok(FidlHost{ device_path, proxy, info })
 }
 
 //struct HostListener {}
diff --git a/bin/bluetooth/gap/src/host_dispatcher.rs b/bin/bluetooth/gap/src/host_dispatcher.rs
index 5f886a5..c452570 100644
--- a/bin/bluetooth/gap/src/host_dispatcher.rs
+++ b/bin/bluetooth/gap/src/host_dispatcher.rs
@@ -3,11 +3,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+use failure::Error;
 use fidl_fuchsia_bluetooth_control::ControlRequest;
 use fidl_fuchsia_bluetooth_host::HostEvent;
 //use failure::Error;
 //use fuchsia_async::{self as fasync, TimeoutExt};
 //use fuchsia_syslog::{fx_log, fx_log_err, fx_log_info, fx_log_warn};
+use fuchsia_syslog::fx_log_info;
 //use fuchsia_vfs_watcher as vfs_watcher;
 //use fuchsia_vfs_watcher::{WatchEvent, WatchMessage};
 //use fuchsia_zircon as zx;
@@ -18,13 +20,13 @@
 use std::collections::HashMap;
 //use std::marker::Unpin;
 //use std::sync::{Arc, Weak};
-use futures::channel::mpsc;
+//use futures::channel::mpsc;
 
-use crate::actor::{Actor, ActorHandle, System};
+use crate::actor::{Actor, ActorHandle, ActorContext};
 use crate::adapters::AdapterEvent;
 use crate::adapters::AdapterEvent::*;
 //use crate::host::*;
-use crate::host::Host;
+use crate::host::{Host, FidlHost};
 use crate::types::bt;
 use crate::types::*;
 use crate::types::DiscoveryState::*;
@@ -56,16 +58,16 @@
 //}
 
 pub struct DiscoveryClient {}
-pub struct HostDispatcherHandle {}
+//pub struct HostDispatcherHandle {}
 
 /// A token returned to someone who has requested discovery
 pub struct DiscoverySession<H: Host> {
-    dispatcher: mpsc::UnboundedSender<HostDispatcherMsg<H>>
+    dispatcher: ActorHandle<HostDispatcherMsg<H>>
 }
 
 impl<H: Host> Drop for DiscoverySession<H> {
     fn drop(&mut self) {
-        self.dispatcher.unbounded_send(HostDispatcherMsg::StopDiscovery);
+        self.dispatcher.send(HostDispatcherMsg::StopDiscovery);
     }
 }
 
@@ -79,10 +81,18 @@
         }
     }
 
-    fn handle(&self) -> mpsc::UnboundedSender<HostDispatcherMsg<H>> {
+    fn handle(&self) -> ActorHandle<HostDispatcherMsg<H>> {
         unreachable!()
     }
 
+    //fn add_host(&mut self, id: HostId, host: AdapterInfo) {
+        //panic!("NYI");
+    //}
+
+    //fn rm_host(&mut self, id: HostId, host: H) {
+        //panic!("NYI");
+    //}
+
     // TODO - what should this type signature be
     //   pub fn start_discovery(&mut self) -> bt::Result<DiscoverySession> {
     //
@@ -124,6 +134,33 @@
     }
 }
 
+impl HostDispatcher<FidlHost> {
+    /// Adds an adapter to the host dispatcher. Called by the watch_hosts device watcher
+    pub async fn add_adapter(hd: HostDispatcher<FidlHost>, host: FidlHost) -> Result<(), Error> {
+        fx_log_info!("Adding Host Device: {:?}", host.path());
+        //let info = host.get_info();
+        // TODO
+        //await!(try_restore_bonds(host.clone(), self.clone(), &info.address.clone()))?;
+
+        //hd.adapters.push(info.identifier, host);
+
+        // Start listening to Host interface events.
+        //fasync::spawn(host::run(self.clone(), host.clone()).map(|_| ()));
+
+        Ok(())
+    }
+
+    //fn activate_host(host) {
+    //    // Initialize bt-gap as this host's pairing delegate.
+    //    start_pairing_delegate(self.clone(), host.clone())?;
+    //    // TODO(NET-1445): Only the active host should be made connectable and scanning in the background.
+    //    await!(host.read().set_connectable(true)).map_err(|_| err_msg("failed to set connectable"))?;
+    //    host.read().enable_background_scan(true).map_err(|_| err_msg("failed to enable background scan"))?;
+    //}
+}
+
+
+
 pub enum HostDispatcherMsg<H: Host> {
     StartDiscovery(ActorHandle<bt::Result<DiscoverySession<H>>>),
     StopDiscovery,
@@ -135,7 +172,7 @@
 impl<H: Host + Send + Sync> Actor for HostDispatcher<H> {
     type Message = HostDispatcherMsg<H>;
 
-    fn update(&mut self, msg: Self::Message, _system: System) {
+    fn update(&mut self, msg: Self::Message, _cx: ActorContext<HostDispatcher<H>>) {
         match msg {
             HostDispatcherMsg::StartDiscovery(mut sender) => {
                 let session = self.start_discovery();
diff --git a/bin/bluetooth/gap/src/main.rs b/bin/bluetooth/gap/src/main.rs
index 75892ac..9476005 100644
--- a/bin/bluetooth/gap/src/main.rs
+++ b/bin/bluetooth/gap/src/main.rs
@@ -55,7 +55,7 @@
     fasync::spawn({
         let hd_ = hd.clone();
         async {
-        let r = await!(control_service(hd_, chan));
-        r.unwrap_or_else(|e| eprintln!("Failed to spawn {:?}", e))
+            let r = await!(control_service(hd_, chan));
+            r.unwrap_or_else(|e| eprintln!("Failed to spawn {:?}", e))
     }})
 }