mirror of
https://codeberg.org/icewind/shortcutd.git
synced 2026-06-03 17:24:08 +02:00
server: tokio/zbus/etc
This commit is contained in:
parent
a606af713b
commit
cea82db46b
10 changed files with 1602 additions and 396 deletions
|
|
@ -10,9 +10,13 @@ path = "src/server.rs"
|
|||
|
||||
[dependencies]
|
||||
main_error = "0.1.0"
|
||||
dbus = { version = "0.8.2", path = "../../dbus-rs/dbus" }
|
||||
glob = "0.3.0"
|
||||
evdev-shortcut = { version = "0.1", path = "../../evdev-shortcut" }
|
||||
evdev-shortcut = "0.1.1"
|
||||
tokio = { version = "1.28.2", features = ["macros", "rt-multi-thread"] }
|
||||
futures = "0.3.28"
|
||||
zbus = { version = "3.13.1", features = ["tokio"], default-features = false }
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = "0.3.17"
|
||||
|
||||
[dev-dependencies]
|
||||
test-case = "1.0.0"
|
||||
test-case = "3.1.0"
|
||||
|
|
@ -1,110 +1,71 @@
|
|||
use main_error::MainError;
|
||||
|
||||
use dbus::blocking::LocalConnection;
|
||||
use dbus::channel::Sender;
|
||||
|
||||
use dbus::tree::{Factory, MethodErr, Signal};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use evdev_shortcut::{Shortcut, ShortcutListener};
|
||||
use evdev_shortcut::{Shortcut, ShortcutEvent, ShortcutListener, ShortcutState};
|
||||
use glob::GlobError;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::mpsc::{channel, TryRecvError};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use futures::stream::StreamExt;
|
||||
use zbus::{ConnectionBuilder, dbus_interface, fdo, SignalContext, ObjectServer};
|
||||
use zbus::export::futures_util::pin_mut;
|
||||
|
||||
const INTERFACE: &'static str = "nl.icewind.shortcutd";
|
||||
struct Register {
|
||||
listener: ShortcutListener,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
let _ = std::panic::catch_unwind(|| {
|
||||
let _ = run();
|
||||
});
|
||||
#[dbus_interface(name = "nl.icewind.shortcutd")]
|
||||
impl Register {
|
||||
async fn register(&mut self, shortcut: &str, #[zbus(object_server)] server: &ObjectServer) -> Result<String, fdo::Error> {
|
||||
match shortcut.parse::<Shortcut>() {
|
||||
Ok(shortcut) => {
|
||||
self.listener.add(shortcut.clone());
|
||||
let path = format!("/{}", shortcut.identifier());
|
||||
if let Err(e) = server.at(path.as_str(), ShortcutSignal).await {
|
||||
eprintln!("{e:#}");
|
||||
}
|
||||
|
||||
eprintln!("crashed, restarting");
|
||||
|
||||
std::thread::sleep(Duration::from_secs(15));
|
||||
Ok(path)
|
||||
}
|
||||
Err(_) => Err(fdo::Error::InvalidArgs("Malformed shortcut".into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run() -> Result<(), MainError> {
|
||||
struct ShortcutSignal;
|
||||
|
||||
#[dbus_interface(name = "nl.icewind.shortcutd")]
|
||||
impl ShortcutSignal {
|
||||
#[dbus_interface(signal)]
|
||||
async fn triggered(signal_ctxt: &SignalContext<'_>, pressed: bool) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), MainError> {
|
||||
tracing_subscriber::fmt::init();
|
||||
let devices =
|
||||
glob::glob("/dev/input/by-id/*-kbd")?.collect::<Result<Vec<PathBuf>, GlobError>>()?;
|
||||
|
||||
let listener = Arc::new(ShortcutListener::new());
|
||||
let listener = ShortcutListener::new();
|
||||
let shortcut_events = listener.listen(&devices)?;
|
||||
|
||||
let mut signals: HashMap<String, Arc<Signal<()>>> = HashMap::default();
|
||||
let bus = Register {
|
||||
listener,
|
||||
};
|
||||
let conn = ConnectionBuilder::system()?
|
||||
.name("nl.icewind.shortcutd")?
|
||||
.serve_at("/register", bus)?
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
let shortcut_trigger_rx = listener.listen(&devices)?;
|
||||
let server = conn.object_server();
|
||||
|
||||
let mut connection = LocalConnection::new_system()?;
|
||||
connection.request_name(INTERFACE, false, true, false)?;
|
||||
|
||||
let (shortcut_register_tx, shortcut_register_rx) = channel();
|
||||
|
||||
let factory = Factory::new_fn::<()>();
|
||||
let mut tree = factory
|
||||
.tree(())
|
||||
.add(
|
||||
factory.object_path("/register", ()).introspectable().add(
|
||||
factory.interface(INTERFACE, ()).add_m(
|
||||
factory
|
||||
.method("Register", (), move |m| {
|
||||
let shortcut_str: &str = m.msg.read1()?;
|
||||
|
||||
match shortcut_str.parse::<Shortcut>() {
|
||||
Ok(shortcut) => {
|
||||
let path = shortcut.identifier();
|
||||
shortcut_register_tx.send(shortcut).unwrap();
|
||||
|
||||
Ok(vec![m.msg.method_return().append1(format!("/{}", path))])
|
||||
}
|
||||
Err(_) => Err(MethodErr::invalid_arg("Malformed shortcut")),
|
||||
}
|
||||
})
|
||||
.outarg::<&str, _>("path")
|
||||
.inarg::<&str, _>("shortcut"),
|
||||
),
|
||||
),
|
||||
)
|
||||
.add(factory.object_path("/", ()).introspectable());
|
||||
|
||||
// Serve clients forever.
|
||||
loop {
|
||||
connection.process_with_tree(&tree, Duration::from_millis(50))?;
|
||||
|
||||
while let Ok(shortcut) = shortcut_register_rx.try_recv() {
|
||||
let identifier = format!("/{}", shortcut.identifier());
|
||||
|
||||
listener.add(shortcut);
|
||||
|
||||
let signal = Arc::new(factory.signal("Triggered", ()));
|
||||
signals.insert(identifier.clone(), signal.clone());
|
||||
|
||||
tree = tree.add(
|
||||
factory
|
||||
.object_path(identifier, ())
|
||||
.introspectable()
|
||||
.add(factory.interface(INTERFACE, ()).add_s(signal)),
|
||||
);
|
||||
}
|
||||
|
||||
match shortcut_trigger_rx.try_recv() {
|
||||
Ok(shortcut) => {
|
||||
let identifier = format!("/{}", shortcut.identifier());
|
||||
if let Some(signal) = signals.get(&identifier) {
|
||||
connection
|
||||
.send(
|
||||
signal
|
||||
.clone()
|
||||
.msg(&identifier.into(), &INTERFACE.into())
|
||||
.append1(&format!("{}", shortcut)),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
pin_mut!(shortcut_events);
|
||||
while let Some(event) = shortcut_events.next().await {
|
||||
let event: ShortcutEvent = event;
|
||||
let identifier = format!("/{}", event.shortcut.identifier());
|
||||
if let Ok(signal_interface) = server.interface::<_, ShortcutSignal>(identifier).await {
|
||||
if let Err(e) = ShortcutSignal::triggered(signal_interface.signal_context(), event.state == ShortcutState::Pressed).await {
|
||||
eprintln!("{e:#}");
|
||||
}
|
||||
Err(TryRecvError::Disconnected) => panic!("keyboard listener crashed"),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue