blob: be7e6a017ff32042ee4d3aa06ae347c5a3cb9be3 [file] [log] [blame]
use bt_topshim::topstack;
use dbus::channel::MatchingReceiver;
use dbus::message::MatchRule;
use dbus::nonblock::SyncConnection;
use manager_service::iface_bluetooth_manager::{IBluetoothManager, IBluetoothManagerCallback};
use std::sync::{Arc, Mutex};
use crate::command_handler::CommandHandler;
use crate::dbus_iface::{BluetoothDBus, BluetoothManagerDBus};
use crate::editor::AsyncEditor;
use dbus_crossroads::Crossroads;
mod command_handler;
mod console;
mod dbus_arg;
mod dbus_iface;
mod editor;
struct BtManagerCallback {
objpath: String,
}
impl IBluetoothManagerCallback for BtManagerCallback {
fn on_hci_device_changed(&self, hci_interface: i32, present: bool) {
print_info!("hci{} present = {}", hci_interface, present);
}
fn on_hci_enabled_changed(&self, hci_interface: i32, enabled: bool) {
print_info!("hci{} enabled = {}", hci_interface, enabled);
}
}
impl manager_service::RPCProxy for BtManagerCallback {
fn register_disconnect(&mut self, _f: Box<dyn Fn() + Send>) {}
fn get_object_id(&self) -> String {
self.objpath.clone()
}
}
struct API {
bluetooth_manager: Arc<Mutex<Box<BluetoothManagerDBus>>>,
bluetooth: Arc<Mutex<Box<BluetoothDBus>>>,
}
// This creates the API implementations over D-Bus.
fn create_api_dbus(conn: Arc<SyncConnection>, cr: Arc<Mutex<Crossroads>>) -> API {
let bluetooth = Arc::new(Mutex::new(Box::new(BluetoothDBus::new(conn.clone(), cr.clone()))));
let bluetooth_manager =
Arc::new(Mutex::new(Box::new(BluetoothManagerDBus::new(conn.clone(), cr.clone()))));
API { bluetooth_manager, bluetooth }
}
/// Runs a command line program that interacts with a Bluetooth stack.
fn main() -> Result<(), Box<dyn std::error::Error>> {
// TODO: Process command line arguments.
topstack::get_runtime().block_on(async move {
// Connect to D-Bus system bus.
let (resource, conn) = dbus_tokio::connection::new_system_sync()?;
// The `resource` is a task that should be spawned onto a tokio compatible
// reactor ASAP. If the resource ever finishes, we lost connection to D-Bus.
tokio::spawn(async {
let err = resource.await;
panic!("Lost connection to D-Bus: {}", err);
});
// Sets up Crossroads for receiving callbacks.
let cr = Arc::new(Mutex::new(Crossroads::new()));
cr.lock().unwrap().set_async_support(Some((
conn.clone(),
Box::new(|x| {
tokio::spawn(x);
}),
)));
let cr_clone = cr.clone();
conn.start_receive(
MatchRule::new_method_call(),
Box::new(move |msg, conn| {
cr_clone.lock().unwrap().handle_message(msg, conn).unwrap();
true
}),
);
let api = create_api_dbus(conn, cr);
// TODO: Registering the callback should be done when btmanagerd is ready (detect with
// ObjectManager).
api.bluetooth_manager.lock().unwrap().register_callback(Box::new(BtManagerCallback {
objpath: String::from("/org/chromium/bluetooth/client/bluetooth_manager_callback"),
}));
let mut handler = CommandHandler::new(api.bluetooth_manager.clone(), api.bluetooth.clone());
let mut handle_cmd = move |cmd: String| match cmd.split(' ').collect::<Vec<&str>>()[0] {
"enable" => handler.cmd_enable(cmd),
"disable" => handler.cmd_disable(cmd),
"get_address" => handler.cmd_get_address(cmd),
"start_discovery" => handler.cmd_start_discovery(cmd),
"cancel_discovery" => handler.cmd_cancel_discovery(cmd),
"create_bond" => handler.cmd_create_bond(cmd),
// Ignore empty commands.
"" => {}
// TODO: Print help.
_ => print_info!("Command \"{}\" not recognized", cmd),
};
let editor = AsyncEditor::new();
loop {
let result = editor.readline().await;
match result {
Err(_err) => break,
Ok(line) => {
if line.eq("quit") {
break;
}
handle_cmd(line.clone());
}
}
}
print_info!("Client exiting");
Result::Ok(())
})
}