1 mod state_machine;
2
3 use dbus::channel::MatchingReceiver;
4 use dbus::message::MatchRule;
5 use dbus_crossroads::Crossroads;
6 use dbus_tokio::connection;
7
8 #[tokio::main]
main() -> Result<(), Box<dyn std::error::Error>>9 pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
10 let context = state_machine::start_new_state_machine_context();
11 let proxy = context.get_proxy();
12
13 // Connect to the D-Bus system bus (this is blocking, unfortunately).
14 let (resource, c) = connection::new_system_sync()?;
15
16 // The resource is a task that should be spawned onto a tokio compatible
17 // reactor ASAP. If the resource ever finishes, you lost connection to D-Bus.
18 tokio::spawn(async {
19 let err = resource.await;
20 panic!("Lost connection to D-Bus: {}", err);
21 });
22
23 // Let's request a name on the bus, so that clients can find us.
24 c.request_name("org.chromium.bluetooth.Manager", false, true, false).await?;
25
26 // Create a new crossroads instance.
27 // The instance is configured so that introspection and properties interfaces
28 // are added by default on object path additions.
29 let mut cr = Crossroads::new();
30
31 // Enable async support for the crossroads instance.
32 cr.set_async_support(Some((
33 c.clone(),
34 Box::new(|x| {
35 tokio::spawn(x);
36 }),
37 )));
38
39 let iface_token = cr.register("org.chromium.bluetooth.Manager", |b| {
40 b.method_with_cr_async(
41 "Start",
42 ("hci_interface",),
43 (),
44 |mut ctx, cr, (hci_interface,): (i32,)| {
45 let proxy =
46 cr.data_mut::<state_machine::StateMachineProxy>(ctx.path()).unwrap().clone();
47 println!("Incoming Start call for hci {}!", hci_interface);
48 async move {
49 let result = proxy.start_bluetooth(hci_interface).await;
50 match result {
51 Ok(()) => ctx.reply(Ok(())),
52 Err(_) => ctx.reply(Err(dbus_crossroads::MethodErr::failed(
53 "cannot start Bluetooth",
54 ))),
55 }
56 }
57 },
58 );
59 b.method_with_cr_async("Stop", ("hci_interface",), (), |mut ctx, cr, (hci_interface,) : (i32,)| {
60 let proxy =
61 cr.data_mut::<state_machine::StateMachineProxy>(ctx.path()).unwrap().clone();
62 println!("Incoming Stop call!");
63 async move {
64 let result = proxy.stop_bluetooth(hci_interface).await;
65 match result {
66 Ok(()) => ctx.reply(Ok(())),
67 Err(_) => {
68 ctx.reply(Err(dbus_crossroads::MethodErr::failed("cannot stop Bluetooth")))
69 }
70 }
71 }
72 });
73 b.method_with_cr_async("GetState", (), ("result",), |mut ctx, cr, ()| {
74 let proxy =
75 cr.data_mut::<state_machine::StateMachineProxy>(ctx.path()).unwrap().clone();
76 async move {
77 let state = proxy.get_state().await;
78 let result = match state {
79 state_machine::State::Off => 0,
80 state_machine::State::TurningOn => 1,
81 state_machine::State::On => 2,
82 state_machine::State::TurningOff => 3,
83 };
84 ctx.reply(Ok((result,)))
85 }
86 });
87 b.method_with_cr_async(
88 "RegisterStateChangeObserver",
89 ("object_path",),
90 (),
91 |mut ctx, cr, (object_path,): (String,)| {
92 let proxy =
93 cr.data_mut::<state_machine::StateMachineProxy>(ctx.path()).unwrap().clone();
94 async move {
95 let result = proxy.register_state_change_observer(object_path.clone()).await;
96 match result {
97 Ok(()) => ctx.reply(Ok(())),
98 Err(_) => ctx.reply(Err(dbus_crossroads::MethodErr::failed(&format!(
99 "cannot register {}",
100 object_path
101 )))),
102 }
103 }
104 },
105 );
106 b.method_with_cr_async(
107 "UnregisterStateChangeObserver",
108 ("object_path",),
109 (),
110 |mut ctx, cr, (object_path,): (String,)| {
111 let proxy =
112 cr.data_mut::<state_machine::StateMachineProxy>(ctx.path()).unwrap().clone();
113 async move {
114 let result = proxy.unregister_state_change_observer(object_path.clone()).await;
115 match result {
116 Ok(()) => ctx.reply(Ok(())),
117 Err(_) => ctx.reply(Err(dbus_crossroads::MethodErr::failed(&format!(
118 "cannot unregister {}",
119 object_path
120 )))),
121 }
122 }
123 },
124 );
125 });
126
127 // Let's add the "/org/chromium/bluetooth/Manager" path, which implements the org.chromium.bluetooth.Manager interface,
128 // to the crossroads instance.
129 cr.insert("/org/chromium/bluetooth/Manager", &[iface_token], proxy);
130
131 // We add the Crossroads instance to the connection so that incoming method calls will be handled.
132 c.start_receive(
133 MatchRule::new_method_call(),
134 Box::new(move |msg, conn| {
135 cr.handle_message(msg, conn).unwrap();
136 true
137 }),
138 );
139
140 tokio::spawn(async move {
141 state_machine::mainloop(context).await;
142 });
143
144 loop {}
145
146 // Run forever.
147 unreachable!()
148 }
149