Skip to content

Commit 2ab109f

Browse files
committed
Initial commit with working implementation
1 parent 93e7aae commit 2ab109f

16 files changed

+325
-50
lines changed

Cargo.lock

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ members = [
1010
"ledmatrix",
1111
"fl16-inputmodules",
1212
"inputmodule-control",
13+
"dbus-monitor"
1314
]
1415
# Don't build all of them by default.
1516
# Because that'll lead to all features enabled in `fl16-inputmodules` and it

dbus-monitor/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
edition = "2021"
3+
name = "framework-inputmodule-dbus-monitor"
4+
version = "0.0.1"
5+
6+
[dependencies]
7+
dbus = { version = "0.9.7", features = ["vendored"] }
8+
clap = { version = "4.0", features = ["derive"] }
9+
10+
[dependencies.libdbus-sys]
11+
default-features = false
12+
features = ["vendored"]
13+
version = "0.2.5"
14+
15+
[dependencies.inputmodule-control]
16+
path = "../inputmodule-control"
Binary file not shown.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[Unit]
2+
Description=framework-inputmodule-dbus-monitor monitors dbus for messages and makes input modules react to them
3+
4+
[Service]
5+
ExecStart=/usr/bin/framework-inputmodule-dbus-monitor
6+
7+
[Install]
8+
WantedBy=graphical.target
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Package: framework-inputmodule-dbus-monitor
2+
Version: 0.0.1
3+
Maintainer: Zach Feldman <[email protected]>
4+
Architecture: all
5+
Description: Monitors dbus for messages and makes input modules react to them
Binary file not shown.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[Unit]
2+
Description=framework-inputmodule-dbus-monitor monitors dbus for messages and makes input modules react to them
3+
4+
[Service]
5+
ExecStart=/usr/bin/framework-inputmodule-dbus-monitor
6+
7+
[Install]
8+
WantedBy=graphical.target

dbus-monitor/release/release.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/bin/bash
2+
3+
set -euxo pipefail
4+
5+
: 'Checking for fpm Ruby gem, installing if not present'
6+
installed=`gem list -i fpm` || true
7+
8+
if [ $installed = 'false' ]; then
9+
gem install fpm
10+
fi
11+
12+
: 'Running the build'
13+
cargo build
14+
15+
cp -f target/debug/framework-inputmodule-dbus-monitor release/package/usr/bin/
16+
17+
: "Packaging"
18+
fpm \
19+
-s dir -t deb \
20+
-p release/framework-inputmodule-dbus-monitor-0.0.1.deb \
21+
--name framework-inputmodule-dbus-monitor\
22+
--version 0.0.1 \
23+
--architecture all \
24+
--description "framework-inputmodule-dbus-monitor monitors dbus for messages and makes input modules react to them" \
25+
--url "https://frame.work" \
26+
--maintainer "Framework <[email protected]>" \
27+
--deb-no-default-config-files \
28+
release/package/usr/bin/framework-inputmodule-dbus-monitor=/usr/bin/framework-inputmodule-dbus-monitor \
29+
release/package/usr/lib/systemd/user/framework-inputmodule-dbus-monitor.service=/lib/systemd/user/framework-inputmodule-dbus-monitor.service \
30+
release/package/DEBIAN/control
31+
32+
: 'Packaging successful, install with "sudo dpkg -i <pkg-name>.deb"'

dbus-monitor/src/dbus_monitor.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Mostly taken from https://github.com/diwic/dbus-rs/blob/366a6dca3d20745f5dcfa006b1b1311c376d420e/dbus/examples/monitor.rs
2+
3+
// This programs implements the equivalent of running the "dbus-monitor" tool
4+
// modified to only search for messages in the org.freedesktop.Notifications interface
5+
use dbus::blocking::Connection;
6+
use dbus::channel::MatchingReceiver;
7+
use dbus::message::MatchRule;
8+
9+
use dbus::Message;
10+
use dbus::MessageType;
11+
12+
use std::process::Command;
13+
use std::time::Duration;
14+
15+
use crate::utils;
16+
17+
use inputmodule_control::inputmodule::find_serialdevs;
18+
use inputmodule_control::commands::ClapCli;
19+
use inputmodule_control::inputmodule::{serial_commands};
20+
use clap::{Parser, Subcommand};
21+
22+
fn handle_message(msg: &Message) {
23+
println!("Got message from DBus: {:?}", msg);
24+
25+
run_inputmodule_command(vec!["led-matrix", "--pattern", "all-on", "--blinking"]);
26+
// Can't seem to get to this second command
27+
run_inputmodule_command(vec!["led-matrix", "--brightness", "0"]);
28+
29+
println!("Message handled");
30+
}
31+
32+
pub fn run_inputmodule_command(args: Vec<&str>){
33+
let bin_placeholder = vec!["bin-placeholder"];
34+
let full_args = [&bin_placeholder[..], &args[..]].concat();
35+
let args = ClapCli::parse_from(full_args);
36+
37+
serial_commands(&args);
38+
}
39+
40+
pub fn run_dbus_monitor() {
41+
// First open up a connection to the desired bus.
42+
let conn = Connection::new_session().expect("D-Bus connection failed");
43+
println!("Connection to DBus session monitor opened");
44+
45+
// Second create a rule to match messages we want to receive; in this example we add no
46+
// further requirements, so all messages will match
47+
let rule = MatchRule::new()
48+
.with_type(MessageType::MethodCall)
49+
.with_interface("org.freedesktop.Notifications")
50+
.with_member("Notify");
51+
52+
// Try matching using new scheme
53+
let proxy = conn.with_proxy(
54+
"org.freedesktop.DBus",
55+
"/org/freedesktop/DBus",
56+
Duration::from_millis(5000),
57+
);
58+
let result: Result<(), dbus::Error> = proxy.method_call(
59+
"org.freedesktop.DBus.Monitoring",
60+
"BecomeMonitor",
61+
(vec![rule.match_str()], 0u32),
62+
);
63+
println!("Monitoring DBus channel...");
64+
65+
match result {
66+
// BecomeMonitor was successful, start listening for messages
67+
Ok(_) => {
68+
conn.start_receive(
69+
rule,
70+
Box::new(|msg, _| {
71+
println!("Start listening");
72+
handle_message(&msg);
73+
true
74+
}),
75+
);
76+
}
77+
// BecomeMonitor failed, fallback to using the old scheme
78+
Err(e) => {
79+
eprintln!(
80+
"Failed to BecomeMonitor: '{}', falling back to eavesdrop",
81+
e
82+
);
83+
84+
// First, we'll try "eavesdrop", which as the name implies lets us receive
85+
// *all* messages, not just ours.
86+
let rule_with_eavesdrop = {
87+
let mut rule = rule.clone();
88+
rule.eavesdrop = true;
89+
rule
90+
};
91+
92+
let result = conn.add_match(rule_with_eavesdrop, |_: (), _, msg| {
93+
handle_message(&msg);
94+
true
95+
});
96+
97+
match result {
98+
Ok(_) => {
99+
// success, we're now listening
100+
}
101+
// This can sometimes fail, for example when listening to the system bus as a non-root user.
102+
// So, just like `dbus-monitor`, we attempt to fallback without `eavesdrop=true`:
103+
Err(e) => {
104+
eprintln!("Failed to eavesdrop: '{}', trying without it", e);
105+
conn.add_match(rule, |_: (), _, msg| {
106+
handle_message(&msg);
107+
true
108+
})
109+
.expect("add_match failed");
110+
}
111+
}
112+
}
113+
}
114+
115+
// Loop and print out all messages received (using handle_message()) as they come.
116+
// Some can be quite large, e.g. if they contain embedded images..
117+
loop {
118+
conn.process(Duration::from_millis(1000)).unwrap();
119+
}
120+
}

0 commit comments

Comments
 (0)