How can I detect application uniqueness using the dbus crate(https://crates.io/crates/dbus) in Rust?
So far I've tried the following but the the function always returns false.
pub fn detect_uniqueness() -> Result<bool, Box<dyn std::error::Error>> {
let conn = dbus::blocking::Connection::new_session()?;
match conn.request_name("com.localserver.myapp", false, false, false) {
Err(e) => Err(Box::new(e)),
Ok(dbus::blocking::stdintf::org_freedesktop_dbus::RequestNameReply::Exists) => Ok(true),
_ => Ok(false)
}
}
Changing the function to the following indicates that the function always reaches RequestReply::PrimaryOwner
.
pub fn detect_uniqueness() -> Result<bool, Box<dyn std::error::Error>> {
let conn = dbus::blocking::Connection::new_session()?;
match conn.request_name("com.localserver.myapp", false, false, false) {
Err(e) => Err(Box::new(e)),
Ok(dbus::blocking::stdintf::org_freedesktop_dbus::RequestNameReply::PrimaryOwner) => {
log::info!("PrimaryOwner");
Ok(true)
},
Ok(dbus::blocking::stdintf::org_freedesktop_dbus::RequestNameReply::InQueue) => {
log::info!("InQueue");
Ok(false)
},
Ok(dbus::blocking::stdintf::org_freedesktop_dbus::RequestNameReply::Exists) => {
log::info!("Exists");
Ok(false)
},
Ok(dbus::blocking::stdintf::org_freedesktop_dbus::RequestNameReply::AlreadyOwner) => {
log::info!("AlreadyOwner");
Ok(false)
},
}
}
I am not sure which of these implies application uniqueness.
I have tried holding off the first instance of the program if the function reaches PrimaryOwner
and launch another instance, but even the second instance seems to reach PrimaryOwner
too.
// main.rs
fn main() {
aux::logger::init();
if app::manually_invoked() {
match app::unique_instance() {
Ok(unique) => {
if unique {
log::info!("Unique instance detected.");
loop {
std::thread::sleep_ms(999999);
}
} else {
log::info!("Duplicate instance detected.")
}
},
Err(e) => {
log::error!("Error detecting uniqueness: {}.", e);
app::exit();
}
}
} else {
//
}
}
// app.rs
pub fn manually_invoked() -> bool {
std::env::args().len() == 1
}
pub fn unique_instance() -> Result<bool, Box<dyn std::error::Error>> {
crate::aux::ipc::detect_uniqueness()
}
pub fn exit() {
std::process::exit(1);
}
Resulting into the program thinking that it's always unique.
When a dbus::blocking::Connection
goes out of scope, it will be dropped and result in the underlying dbus
connection being dropped too.
In order to do anything meaningful with the connection, you need to keep it alive. One way to do that is to create connection once and pass the reference around:
//# dbus = "0.7.1"
use dbus;
use dbus::blocking::Connection;
use dbus::blocking::stdintf::org_freedesktop_dbus::RequestNameReply;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let conn = Connection::new_session()?;
match is_unique(&conn) {
Ok(true) => loop {},
_ => Ok(()),
}
}
pub fn is_unique(conn: &Connection) -> Result<bool, dbus::Error> {
match conn.request_name("com.localserver.myapp", false, false, false) {
Ok(RequestNameReply::PrimaryOwner) => Ok(true),
Ok(_) => Ok(false),
Err(e) => Err(e),
}
}
Try run the program twice and the second instance will terminate immediately.