blob: 1aa0d509090196199aa257ff3fda0ceec62db0cd [file] [log] [blame]
// Copyright 2018 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.
use {
anyhow::{format_err, Error},
fidl::endpoints::RequestStream,
fidl_fuchsia_bluetooth_control::{self as control, ControlRequest, ControlRequestStream},
fuchsia_bluetooth::{bt_fidl_status, types::PeerId},
fuchsia_syslog::fx_log_warn,
futures::prelude::*,
std::sync::Arc,
};
use crate::{host_dispatcher::*, types::status_response};
struct ControlSession {
discovery_token: Option<Arc<DiscoveryRequestToken>>,
discoverable_token: Option<Arc<DiscoverableRequestToken>>,
}
impl ControlSession {
fn new() -> ControlSession {
ControlSession { discovery_token: None, discoverable_token: None }
}
}
/// Build the ControlImpl to interact with fidl messages
/// State is stored in the HostDispatcher object
pub async fn start_control_service(
hd: HostDispatcher,
mut stream: ControlRequestStream,
) -> Result<(), Error> {
let event_listener = Arc::new(stream.control_handle());
hd.add_event_listener(Arc::downgrade(&event_listener));
let mut session = ControlSession::new();
while let Some(event) = stream.next().await {
handler(hd.clone(), &mut session, event?).await?;
}
// event_listener will now be dropped, closing the listener
Ok(())
}
async fn handler(
hd: HostDispatcher,
session: &mut ControlSession,
event: ControlRequest,
) -> fidl::Result<()> {
match event {
ControlRequest::Connect { device_id, responder } => {
let result = hd.connect(device_id).await;
responder.send(&mut status_response(result))
}
ControlRequest::Pair { id, options, responder } => {
let result = hd.pair(id, options).await;
responder.send(&mut status_response(result))
}
ControlRequest::SetDiscoverable { discoverable, responder } => {
let mut resp = if discoverable {
match hd.set_discoverable().await {
Ok(token) => {
session.discoverable_token = Some(token);
bt_fidl_status!()
}
Err(err) => err.as_status(),
}
} else {
session.discoverable_token = None;
bt_fidl_status!()
};
responder.send(&mut resp)
}
ControlRequest::SetIoCapabilities { input, output, control_handle: _ } => {
hd.set_io_capability(input, output);
Ok(())
}
ControlRequest::Forget { device_id, responder } => {
let peer_id = device_id
.parse::<PeerId>()
.map_err(|_| format_err!(format!("Invalid peer identifier: {}", device_id)));
let result = match peer_id {
Ok(peer_id) => hd.forget(peer_id).await,
Err(e) => Err(e.into()),
};
responder.send(&mut status_response(result))
}
ControlRequest::Disconnect { device_id, responder } => {
let result = hd.disconnect(device_id).await;
responder.send(&mut status_response(result))
}
ControlRequest::GetKnownRemoteDevices { responder } => {
let mut devices: Vec<_> =
hd.get_peers().into_iter().map(control::RemoteDevice::from).collect();
responder.send(&mut devices.iter_mut())
}
ControlRequest::IsBluetoothAvailable { responder } => {
let is_available = hd.get_active_host_info().is_some();
responder.send(is_available)
}
ControlRequest::SetPairingDelegate { delegate, responder } => {
let status = match delegate.map(|d| d.into_proxy()) {
Some(Ok(proxy)) => hd.set_pairing_delegate(Some(proxy)),
Some(Err(err)) => {
fx_log_warn!(
"Invalid Pairing Delegate passed to SetPairingDelegate - ignoring: {}",
err
);
false
}
None => hd.set_pairing_delegate(None),
};
responder.send(status)
}
ControlRequest::GetAdapters { responder } => {
let mut adapters: Vec<_> =
hd.get_adapters().await.into_iter().map(control::AdapterInfo::from).collect();
responder.send(Some(&mut adapters.iter_mut()))
}
ControlRequest::SetActiveAdapter { identifier, responder } => {
let result = hd.set_active_adapter(identifier.clone());
responder.send(&mut status_response(result))
}
ControlRequest::GetActiveAdapterInfo { responder } => {
let host_info = hd.get_active_host_info();
responder.send(host_info.map(control::AdapterInfo::from).as_mut())
}
ControlRequest::RequestDiscovery { discovery, responder } => {
let mut resp = if discovery {
match hd.start_discovery().await {
Ok(token) => {
session.discovery_token = Some(token);
bt_fidl_status!()
}
Err(err) => err.as_status(),
}
} else {
session.discovery_token = None;
bt_fidl_status!()
};
responder.send(&mut resp)
}
ControlRequest::SetName { name, responder } => {
let result = hd.set_name(name.unwrap_or("".to_string())).await;
responder.send(&mut status_response(result))
}
ControlRequest::SetDeviceClass { device_class, responder } => {
let device_class = fidl_fuchsia_bluetooth::DeviceClass { value: device_class.value };
let result = hd.set_device_class(device_class).await;
responder.send(&mut status_response(result))
}
}
}