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

11
Cargo.lock generated
View File

@ -1229,6 +1229,15 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "dbus-crossroads"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "554114296d012b33fdaf362a733db6dc5f73c4c9348b8b620ddd42e61b406e30"
dependencies = [
"dbus",
]
[[package]]
name = "dconf_rs"
version = "0.3.0"
@ -4361,6 +4370,8 @@ dependencies = [
"ctrlc",
"dark-light",
"dasp",
"dbus",
"dbus-crossroads",
"default-net",
"dispatch",
"enigo",

View File

@ -110,6 +110,8 @@ rust-pulsectl = { git = "https://github.com/open-trade/pulsectl" }
async-process = "1.3"
mouce = { git="https://github.com/fufesou/mouce.git" }
evdev = { git="https://github.com/fufesou/evdev" }
dbus = "0.9"
dbus-crossroads = "0.5"
[target.'cfg(target_os = "android")'.dependencies]

View File

@ -165,6 +165,8 @@ def build_flutter_deb(version):
'cp ../res/128x128@2x.png tmpdeb/usr/share/rustdesk/files/rustdesk.png')
os.system(
'cp ../res/rustdesk.desktop tmpdeb/usr/share/applications/rustdesk.desktop')
os.system(
'cp ../res/rustdesk-link.desktop tmpdeb/usr/share/applications/rustdesk-link.desktop')
os.system(
'cp ../res/com.rustdesk.RustDesk.policy tmpdeb/usr/share/polkit-1/actions/')
os.system("echo \"#!/bin/sh\" >> tmpdeb/usr/share/rustdesk/files/polkit && chmod a+x tmpdeb/usr/share/rustdesk/files/polkit")
@ -333,6 +335,8 @@ def main():
'cp res/128x128@2x.png tmpdeb/usr/share/rustdesk/files/rustdesk.png')
os.system(
'cp res/rustdesk.desktop tmpdeb/usr/share/applications/rustdesk.desktop')
os.system(
'cp res/rustdesk-link.desktop tmpdeb/usr/share/applications/rustdesk-link.desktop')
os.system('cp -a res/DEBIAN/* tmpdeb/DEBIAN/')
os.system('strip tmpdeb/usr/bin/rustdesk')
os.system('mkdir -p tmpdeb/usr/lib/rustdesk')

View File

@ -10,6 +10,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
import 'package:flutter_hbb/main.dart';
import 'package:flutter_hbb/models/peer_model.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:get/get.dart';
@ -1128,6 +1129,19 @@ Future<bool> restoreWindowPosition(WindowType type, {int? windowId}) async {
return false;
}
void checkArguments() {
// check connect args
final connectIndex = bootArgs.indexOf("--connect");
if (connectIndex == -1) {
return;
}
String? peerId = bootArgs.length < connectIndex + 1 ? null: bootArgs[connectIndex + 1];
if (peerId != null) {
rustDeskWinManager.newRemoteDesktop(peerId);
bootArgs.removeAt(connectIndex); bootArgs.removeAt(connectIndex);
}
}
/// Connect to a peer with [id].
/// If [isFileTransfer], starts a session only for file transfer.
/// If [isTcpTunneling], starts a session only for tcp tunneling.

View File

@ -452,6 +452,9 @@ class _DesktopHomePageState extends State<DesktopHomePage>
}
}
});
Future.delayed(Duration.zero, () {
checkArguments();
});
}
@override

View File

@ -24,10 +24,12 @@ import 'mobile/pages/server_page.dart';
import 'models/platform_model.dart';
int? windowId;
late List<String> bootArgs;
Future<void> main(List<String> args) async {
WidgetsFlutterBinding.ensureInitialized();
debugPrint("launch args: $args");
bootArgs = args;
if (!isDesktop) {
runMobileApp();

View File

@ -14,6 +14,7 @@ import 'package:flutter_hbb/models/chat_model.dart';
import 'package:flutter_hbb/models/file_model.dart';
import 'package:flutter_hbb/models/server_model.dart';
import 'package:flutter_hbb/models/user_model.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tuple/tuple.dart';
import 'package:flutter_custom_cursor/flutter_custom_cursor.dart';
@ -176,6 +177,9 @@ class FfiModel with ChangeNotifier {
updateBlockInputState(evt, peerId);
} else if (name == 'update_privacy_mode') {
updatePrivacyMode(evt, peerId);
} else if (name == 'new_connection') {
final remoteId = evt['peer_id'];
rustDeskWinManager.newRemoteDesktop(remoteId);
}
};
}

View File

@ -113,6 +113,10 @@ class PlatformFFI {
debugPrint('Failed to get documents directory: $e');
}
_ffiBind = RustdeskImpl(dylib);
if (Platform.isLinux) {
// start dbus service, no need to await
await _ffiBind.mainStartDbusServer();
}
_startListenEvent(_ffiBind); // global event
try {
if (isAndroid) {

View File

@ -140,7 +140,7 @@ packages:
name: characters
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0"
version: "1.2.1"
charcode:
dependency: transitive
description:
@ -161,7 +161,7 @@ packages:
name: clock
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
version: "1.1.1"
code_builder:
dependency: transitive
description:
@ -369,8 +369,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: "4a950fd3a5a228bf5381070a4c803919d5787c07"
resolved-ref: "4a950fd3a5a228bf5381070a4c803919d5787c07"
ref: dec2166e881c47d922e1edc484d10d2cd5c2103b
resolved-ref: dec2166e881c47d922e1edc484d10d2cd5c2103b
url: "https://github.com/Kingtous/rustdesk_flutter_custom_cursor"
source: git
version: "0.0.1"
@ -602,7 +602,7 @@ packages:
name: material_color_utilities
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.1.4"
version: "0.1.5"
menu_base:
dependency: transitive
description:
@ -616,7 +616,7 @@ packages:
name: meta
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.7.0"
version: "1.8.0"
mime:
dependency: transitive
description:
@ -693,7 +693,7 @@ packages:
name: path
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.8.1"
version: "1.8.2"
path_drawing:
dependency: transitive
description:

View File

@ -30,5 +30,6 @@ package() {
pushd ${pkgdir} && ln -s /usr/lib/rustdesk/rustdesk usr/bin/rustdesk && popd
install -Dm 644 $HBB/res/rustdesk.service -t "${pkgdir}/usr/share/rustdesk/files"
install -Dm 644 $HBB/res/rustdesk.desktop -t "${pkgdir}/usr/share/rustdesk/files"
install -Dm 644 $HBB/res/rustdesk-link.desktop -t "${pkgdir}/usr/share/rustdesk/files"
install -Dm 644 $HBB/res/128x128@2x.png "${pkgdir}/usr/share/rustdesk/files/rustdesk.png"
}

View File

@ -7,6 +7,7 @@ post_install() {
# do something here
cp /usr/share/rustdesk/files/rustdesk.service /etc/systemd/system/rustdesk.service
cp /usr/share/rustdesk/files/rustdesk.desktop /usr/share/applications/
cp /usr/share/rustdesk/files/rustdesk-link.desktop /usr/share/applications/
systemctl daemon-reload
systemctl enable rustdesk
systemctl start rustdesk
@ -24,6 +25,7 @@ pre_upgrade() {
post_upgrade() {
cp /usr/share/rustdesk/files/rustdesk.service /etc/systemd/system/rustdesk.service
cp /usr/share/rustdesk/files/rustdesk.desktop /usr/share/applications/
cp /usr/share/rustdesk/files/rustdesk-link.desktop /usr/share/applications/
systemctl daemon-reload
systemctl enable rustdesk
systemctl start rustdesk
@ -40,5 +42,6 @@ pre_remove() {
# arg 1: the old package version
post_remove() {
rm /usr/share/applications/rustdesk.desktop || true
rm /usr/share/applications/rustdesk-link.desktop || true
update-desktop-database
}

View File

@ -25,6 +25,7 @@ install $HBB/libsciter-gtk.so %{buildroot}/usr/lib/rustdesk/libsciter-gtk.so
install $HBB/res/rustdesk.service %{buildroot}/usr/share/rustdesk/files/
install $HBB/res/128x128@2x.png %{buildroot}/usr/share/rustdesk/files/rustdesk.png
install $HBB/res/rustdesk.desktop %{buildroot}/usr/share/rustdesk/files/
install $HBB/res/rustdesk-link.desktop %{buildroot}/usr/share/rustdesk/files/
%files
/usr/bin/rustdesk
@ -32,6 +33,7 @@ install $HBB/res/rustdesk.desktop %{buildroot}/usr/share/rustdesk/files/
/usr/share/rustdesk/files/rustdesk.service
/usr/share/rustdesk/files/rustdesk.png
/usr/share/rustdesk/files/rustdesk.desktop
/usr/share/rustdesk/files/rustdesk-link.desktop
%changelog
# let's skip this for now
@ -52,6 +54,7 @@ esac
%post
cp /usr/share/rustdesk/files/rustdesk.service /etc/systemd/system/rustdesk.service
cp /usr/share/rustdesk/files/rustdesk.desktop /usr/share/applications/
cp /usr/share/rustdesk/files/rustdesk-link.desktop /usr/share/applications/
systemctl daemon-reload
systemctl enable rustdesk
systemctl start rustdesk
@ -75,6 +78,7 @@ case "$1" in
0)
# for uninstall
rm /usr/share/applications/rustdesk.desktop || true
rm /usr/share/applications/rustdesk-link.desktop || true
update-desktop-database
;;
1)

View File

@ -25,6 +25,7 @@ install $HBB/libsciter-gtk.so %{buildroot}/usr/lib/rustdesk/libsciter-gtk.so
install $HBB/res/rustdesk.service %{buildroot}/usr/share/rustdesk/files/
install $HBB/res/128x128@2x.png %{buildroot}/usr/share/rustdesk/files/rustdesk.png
install $HBB/res/rustdesk.desktop %{buildroot}/usr/share/rustdesk/files/
install $HBB/res/rustdesk-link.desktop %{buildroot}/usr/share/rustdesk/files/
%files
/usr/bin/rustdesk
@ -32,6 +33,7 @@ install $HBB/res/rustdesk.desktop %{buildroot}/usr/share/rustdesk/files/
/usr/share/rustdesk/files/rustdesk.service
/usr/share/rustdesk/files/rustdesk.png
/usr/share/rustdesk/files/rustdesk.desktop
/usr/share/rustdesk/files/rustdesk-link.desktop
/usr/share/rustdesk/files/__pycache__/*
%changelog
@ -53,6 +55,7 @@ esac
%post
cp /usr/share/rustdesk/files/rustdesk.service /etc/systemd/system/rustdesk.service
cp /usr/share/rustdesk/files/rustdesk.desktop /usr/share/applications/
cp /usr/share/rustdesk/files/rustdesk-link.desktop /usr/share/applications/
systemctl daemon-reload
systemctl enable rustdesk
systemctl start rustdesk
@ -76,6 +79,7 @@ case "$1" in
0)
# for uninstall
rm /usr/share/applications/rustdesk.desktop || true
rm /usr/share/applications/rustdesk-link.desktop || true
update-desktop-database
;;
1)

11
res/rustdesk-link.desktop Normal file
View File

@ -0,0 +1,11 @@
[Desktop Entry]
Name=RustDeskURL Scheme Handler
NoDisplay=true
MimeType=x-scheme-handler/rustdesk;
TryExec=rustdesk
Exec=rustdesk --connect "%u"
Icon=rustdesk
Terminal=false
Type=Application
StartupNotify=false
Version=1.5

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(),));
},
);
}