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