feat: add dbus and cli connect support

This commit is contained in:
Kingtous
2022-10-11 19:52:03 +08:00
parent 5756bee266
commit 3d7736836f
18 changed files with 219 additions and 9 deletions

View File

@@ -1,3 +1,5 @@
use std::env::Args;
use hbb_common::log;
// shared by flutter and sciter main function
@@ -11,6 +13,7 @@ pub fn core_main() -> Option<Vec<String>> {
let mut is_setup = false;
let mut _is_elevate = false;
let mut _is_run_as_system = false;
let mut _is_connect = false;
for arg in std::env::args() {
// to-do: how to pass to flutter?
if i == 0 && crate::common::is_setup(&arg) {
@@ -20,14 +23,16 @@ pub fn core_main() -> Option<Vec<String>> {
_is_elevate = true;
} else if arg == "--run-as-system" {
_is_run_as_system = true;
} else if arg == "--connect" {
_is_connect = true;
} else {
args.push(arg);
}
}
i += 1;
}
if args.contains(&"--install".to_string()) {
is_setup = true;
if _is_connect {
return core_main_invoke_new_connection(std::env::args());
}
if is_setup {
if args.is_empty() {
@@ -208,3 +213,36 @@ fn import_config(path: &str) {
}
}
}
/// invoke a new connection
///
/// [Note]
/// this is for invoke new connection from dbus
fn core_main_invoke_new_connection(mut args: Args) -> Option<Vec<String>> {
args
.position(|element| {
return element == "--connect";
})
.unwrap();
let peer_id = args.next().unwrap_or("".to_string());
if peer_id.is_empty() {
eprintln!("please provide a valid peer id");
return None;
}
#[cfg(target_os = "linux")]
{
use crate::dbus::invoke_new_connection;
match invoke_new_connection(peer_id) {
Ok(()) => {
return None;
}
Err(err) => {
log::error!("{}", err.as_ref());
// return Some to invoke this new connection by self
return Some(Vec::new());
}
}
}
return None;
}

View File

@@ -801,6 +801,17 @@ pub fn main_is_release() -> bool {
is_release()
}
pub fn main_start_dbus_server() {
#[cfg(target_os = "linux")]
{
use crate::dbus::start_dbus_server;
// spawn new thread to start dbus server
std::thread::spawn(|| {
let _ = start_dbus_server();
});
}
}
pub fn session_send_mouse(id: String, msg: String) {
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(&msg) {
let alt = m.get("alt").is_some();

View File

@@ -30,6 +30,8 @@ mod clipboard_service;
mod wayland;
#[cfg(target_os = "linux")]
pub mod uinput;
#[cfg(target_os = "linux")]
pub mod dbus;
pub mod input_service;
} else {
mod clipboard_service {

92
src/server/dbus.rs Normal file
View File

@@ -0,0 +1,92 @@
/// Url handler based on dbus
///
/// Note:
/// On linux, we use dbus to communicate multiple rustdesk process.
/// [Flutter]: handle uni links for linux
use dbus::blocking::Connection;
use dbus_crossroads::{Crossroads, IfaceBuilder};
use hbb_common::{log};
use std::{error::Error, fmt, time::Duration, collections::HashMap};
const DBUS_NAME: &str = "org.rustdesk.rustdesk";
const DBUS_PREFIX: &str = "/dbus";
const DBUS_METHOD_NEW_CONNECTION: &str = "NewConnection";
const DBUS_METHOD_NEW_CONNECTION_ID: &str = "id";
const DBUS_METHOD_RETURN: &str = "ret";
const DBUS_METHOD_RETURN_SUCCESS: &str = "ok";
const DBUS_TIMEOUT: Duration = Duration::from_secs(5);
#[derive(Debug)]
struct DbusError(String);
impl fmt::Display for DbusError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RustDesk DBus Error: {}", self.0)
}
}
impl Error for DbusError {}
/// invoke new connection from dbus
///
/// [Tips]:
/// How to test by CLI:
/// - use dbus-send command:
/// `dbus-send --session --print-reply --dest=org.rustdesk.rustdesk /dbus org.rustdesk.rustdesk.NewConnection string:'PEER_ID'`
pub fn invoke_new_connection(peer_id: String) -> Result<(), Box<dyn Error>> {
let conn = Connection::new_session()?;
let proxy = conn.with_proxy(DBUS_NAME, DBUS_PREFIX, DBUS_TIMEOUT);
let (ret,): (String,) = proxy.method_call(DBUS_NAME, DBUS_METHOD_NEW_CONNECTION, (peer_id,))?;
if ret != DBUS_METHOD_RETURN_SUCCESS {
log::error!("error on call new connection to dbus server");
return Err(Box::new(DbusError("not success".to_string())));
}
Ok(())
}
/// start dbus server
///
/// [Blocking]:
/// The function will block current thread to serve dbus server.
/// So it's suitable to spawn a new thread dedicated to dbus server.
pub fn start_dbus_server() -> Result<(), Box<dyn Error>> {
let conn: Connection = Connection::new_session()?;
let _ = conn.request_name(DBUS_NAME, false, true, false)?;
let mut cr = Crossroads::new();
let token = cr.register(DBUS_NAME, handle_client_message);
cr.insert(DBUS_PREFIX, &[token], ());
cr.serve(&conn)?;
Ok(())
}
fn handle_client_message(builder: &mut IfaceBuilder<()>) {
// register new connection dbus
builder.method(
DBUS_METHOD_NEW_CONNECTION,
(DBUS_METHOD_NEW_CONNECTION_ID,),
(DBUS_METHOD_RETURN,),
move |_, _, (peer_id,): (String,)| {
#[cfg(feature = "flutter")]
{
use crate::flutter::{self, APP_TYPE_MAIN};
if let Some(stream) = flutter::GLOBAL_EVENT_STREAM
.write()
.unwrap()
.get(APP_TYPE_MAIN)
{
let data = HashMap::from([
("name", "new_connection"),
("peer_id", peer_id.as_str())
]);
if !stream.add(serde_json::ser::to_string(&data).unwrap_or("".to_string())) {
log::error!("failed to add dbus message to flutter global dbus stream.");
}
} else {
log::error!("failed to find main event stream");
}
}
return Ok((DBUS_METHOD_RETURN_SUCCESS.to_string(),));
},
);
}