mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Merge pull request #3076 from Kingtous/master
feat: add url scheme handler for macos
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
use hbb_common::log;
|
||||
use std::future::Future;
|
||||
|
||||
use hbb_common::{log, ResultType};
|
||||
|
||||
/// shared by flutter and sciter main function
|
||||
///
|
||||
@@ -346,5 +348,11 @@ fn core_main_invoke_new_connection(mut args: std::env::Args) -> Option<Vec<Strin
|
||||
return if res { None } else { Some(Vec::new()) };
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
return Some(Vec::new());
|
||||
{
|
||||
return if let Err(_) = crate::ipc::send_url_scheme(uni_links) {
|
||||
Some(Vec::new())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,27 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::{CStr, CString},
|
||||
os::raw::c_char,
|
||||
};
|
||||
use std::{collections::HashMap, ffi::{CStr, CString}, os::raw::c_char, thread};
|
||||
use std::str::FromStr;
|
||||
|
||||
use flutter_rust_bridge::{StreamSink, SyncReturn, ZeroCopyBuffer};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::common::is_keyboard_mode_supported;
|
||||
use hbb_common::message_proto::KeyboardMode;
|
||||
use hbb_common::ResultType;
|
||||
use hbb_common::{
|
||||
config::{self, LocalConfig, PeerConfig, ONLINE},
|
||||
config::{self, LocalConfig, ONLINE, PeerConfig},
|
||||
fs, log,
|
||||
};
|
||||
use std::str::FromStr;
|
||||
use hbb_common::message_proto::KeyboardMode;
|
||||
use hbb_common::ResultType;
|
||||
|
||||
// use crate::hbbs_http::account::AuthResult;
|
||||
|
||||
use crate::flutter::{self, SESSIONS};
|
||||
use crate::ui_interface::{self, *};
|
||||
use crate::{
|
||||
client::file_trait::FileManager,
|
||||
common::make_fd_to_json,
|
||||
flutter::{session_add, session_start_},
|
||||
};
|
||||
use crate::common::is_keyboard_mode_supported;
|
||||
use crate::flutter::{self, SESSIONS};
|
||||
use crate::ui_interface::{self, *};
|
||||
|
||||
// use crate::hbbs_http::account::AuthResult;
|
||||
|
||||
fn initialize(app_dir: &str) {
|
||||
*config::APP_DIR.write().unwrap() = app_dir.to_owned();
|
||||
#[cfg(target_os = "android")]
|
||||
@@ -1255,16 +1252,32 @@ pub fn main_hide_docker() -> SyncReturn<bool> {
|
||||
SyncReturn(true)
|
||||
}
|
||||
|
||||
/// Start an ipc server for receiving the url scheme.
|
||||
///
|
||||
/// * Should only be called in the main flutter window.
|
||||
/// * macOS only
|
||||
pub fn main_start_ipc_url_server() {
|
||||
#[cfg(target_os = "macos")]
|
||||
thread::spawn(move || crate::server::start_ipc_url_server());
|
||||
}
|
||||
|
||||
/// Send a url scheme throught the ipc.
|
||||
///
|
||||
/// * macOS only
|
||||
pub fn send_url_scheme(url: String) {
|
||||
#[cfg(target_os = "macos")]
|
||||
thread::spawn(move || crate::ui::macos::handle_url_scheme(url));
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub mod server_side {
|
||||
use hbb_common::log;
|
||||
use jni::{
|
||||
JNIEnv,
|
||||
objects::{JClass, JString},
|
||||
sys::jstring,
|
||||
JNIEnv,
|
||||
};
|
||||
|
||||
use hbb_common::log;
|
||||
|
||||
use crate::start_server;
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
11
src/ipc.rs
11
src/ipc.rs
@@ -16,10 +16,10 @@ use hbb_common::{
|
||||
config::{self, Config, Config2},
|
||||
futures::StreamExt as _,
|
||||
futures_util::sink::SinkExt,
|
||||
log, password_security as password, timeout, tokio,
|
||||
log, password_security as password, ResultType, timeout,
|
||||
tokio,
|
||||
tokio::io::{AsyncRead, AsyncWrite},
|
||||
tokio_util::codec::Framed,
|
||||
ResultType,
|
||||
};
|
||||
|
||||
use crate::rendezvous_mediator::RendezvousMediator;
|
||||
@@ -210,6 +210,7 @@ pub enum Data {
|
||||
DataPortableService(DataPortableService),
|
||||
SwitchSidesRequest(String),
|
||||
SwitchSidesBack,
|
||||
UrlLink(String)
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
@@ -832,3 +833,9 @@ pub async fn test_rendezvous_server() -> ResultType<()> {
|
||||
c.send(&Data::TestRendezvousServer).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
pub async fn send_url_scheme(url: String) -> ResultType<()> {
|
||||
connect(1_000, "_url").await?.send(&Data::UrlLink(url)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
use crate::ipc::Data;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
net::SocketAddr,
|
||||
sync::{Arc, Mutex, RwLock, Weak},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
|
||||
pub use connection::*;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use hbb_common::config::Config2;
|
||||
use hbb_common::{
|
||||
allow_err,
|
||||
anyhow::{anyhow, Context},
|
||||
@@ -12,19 +17,18 @@ use hbb_common::{
|
||||
message_proto::*,
|
||||
protobuf::{Enum, Message as _},
|
||||
rendezvous_proto::*,
|
||||
ResultType,
|
||||
socket_client,
|
||||
sodiumoxide::crypto::{box_, secretbox, sign},
|
||||
timeout, tokio, ResultType, Stream,
|
||||
sodiumoxide::crypto::{box_, secretbox, sign}, Stream, timeout, tokio,
|
||||
};
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use service::ServiceTmpl;
|
||||
use hbb_common::config::Config2;
|
||||
use hbb_common::tcp::new_listener;
|
||||
use service::{GenericService, Service, Subscriber};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
net::SocketAddr,
|
||||
sync::{Arc, Mutex, RwLock, Weak},
|
||||
time::Duration,
|
||||
};
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use service::ServiceTmpl;
|
||||
|
||||
use crate::ipc::{connect, Data};
|
||||
|
||||
pub mod audio_service;
|
||||
cfg_if::cfg_if! {
|
||||
@@ -55,8 +59,6 @@ mod service;
|
||||
mod video_qos;
|
||||
pub mod video_service;
|
||||
|
||||
use hbb_common::tcp::new_listener;
|
||||
|
||||
pub type Childs = Arc<Mutex<Vec<std::process::Child>>>;
|
||||
type ConnMap = HashMap<i32, ConnInner>;
|
||||
|
||||
@@ -425,6 +427,50 @@ pub async fn start_server(is_server: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
pub async fn start_ipc_url_server() {
|
||||
log::debug!("Start an ipc server for listening to url schemes");
|
||||
match crate::ipc::new_listener("_url").await {
|
||||
Ok(mut incoming) => {
|
||||
while let Some(Ok(conn)) = incoming.next().await {
|
||||
let mut conn = crate::ipc::Connection::new(conn);
|
||||
match conn.next_timeout(1000).await {
|
||||
Ok(Some(data)) => {
|
||||
match data {
|
||||
Data::UrlLink(url) => {
|
||||
#[cfg(feature = "flutter")]
|
||||
{
|
||||
if let Some(stream) = crate::flutter::GLOBAL_EVENT_STREAM.read().unwrap().get(
|
||||
crate::flutter::APP_TYPE_MAIN
|
||||
) {
|
||||
let mut m = HashMap::new();
|
||||
m.insert("name", "on_url_scheme_received");
|
||||
m.insert("url", url.as_str());
|
||||
stream.add(serde_json::to_string(&m).unwrap());
|
||||
} else {
|
||||
log::warn!("No main window app found!");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
log::warn!("An unexpected data was sent to the ipc url server.")
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("{}", err);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("{}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
async fn sync_and_watch_config_dir() {
|
||||
if crate::platform::is_root() {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::{ffi::c_void, rc::Rc};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
use cocoa::{
|
||||
appkit::{NSApp, NSApplication, NSApplicationActivationPolicy::*, NSMenu, NSMenuItem},
|
||||
@@ -8,11 +10,16 @@ use objc::{
|
||||
class,
|
||||
declare::ClassDecl,
|
||||
msg_send,
|
||||
runtime::{Object, Sel, BOOL},
|
||||
runtime::{BOOL, Object, Sel},
|
||||
sel, sel_impl,
|
||||
};
|
||||
use sciter::{make_args, Host};
|
||||
use std::{ffi::c_void, rc::Rc};
|
||||
use objc::runtime::Class;
|
||||
use objc_id::WeakId;
|
||||
use sciter::{Host, make_args};
|
||||
|
||||
use hbb_common::{log, tokio};
|
||||
|
||||
use crate::ui_cm_interface::start_ipc;
|
||||
|
||||
static APP_HANDLER_IVAR: &str = "GoDeskAppHandler";
|
||||
|
||||
@@ -98,12 +105,21 @@ unsafe fn set_delegate(handler: Option<Box<dyn AppHandler>>) {
|
||||
sel!(handleMenuItem:),
|
||||
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
|
||||
);
|
||||
decl.add_method(sel!(handleEvent:withReplyEvent:), handle_apple_event as extern fn(&Object, Sel, u64, u64));
|
||||
let decl = decl.register();
|
||||
let delegate: id = msg_send![decl, alloc];
|
||||
let () = msg_send![delegate, init];
|
||||
let state = DelegateState { handler };
|
||||
let handler_ptr = Box::into_raw(Box::new(state));
|
||||
(*delegate).set_ivar(APP_HANDLER_IVAR, handler_ptr as *mut c_void);
|
||||
// Set the url scheme handler
|
||||
let cls = Class::get("NSAppleEventManager").unwrap();
|
||||
let manager: *mut Object = msg_send![cls, sharedAppleEventManager];
|
||||
let _: () = msg_send![manager,
|
||||
setEventHandler: delegate
|
||||
andSelector: sel!(handleEvent:withReplyEvent:)
|
||||
forEventClass: fruitbasket::kInternetEventClass
|
||||
andEventID: fruitbasket::kAEGetURL];
|
||||
let () = msg_send![NSApp(), setDelegate: delegate];
|
||||
}
|
||||
|
||||
@@ -167,6 +183,24 @@ extern "C" fn handle_menu_item(this: &mut Object, _: Sel, item: id) {
|
||||
}
|
||||
}
|
||||
|
||||
/// The function to handle the url scheme sent by the system.
|
||||
///
|
||||
/// 1. Try to send the url scheme from ipc.
|
||||
/// 2. If failed to send the url scheme, we open a new main window to handle this url scheme.
|
||||
pub fn handle_url_scheme(url: String) {
|
||||
if let Err(err) = crate::ipc::send_url_scheme(url.clone()) {
|
||||
log::debug!("Send the url to the existing flutter process failed, {}. Let's open a new program to handle this.", err);
|
||||
let _ = crate::run_me(vec![url]);
|
||||
}
|
||||
}
|
||||
|
||||
extern fn handle_apple_event(_this: &Object, _cmd: Sel, event: u64, _reply: u64) {
|
||||
let event = event as *mut Object;
|
||||
let url = fruitbasket::parse_url_event(event);
|
||||
log::debug!("an event was received: {}", url);
|
||||
std::thread::spawn(move || handle_url_scheme(url));
|
||||
}
|
||||
|
||||
unsafe fn make_menu_item(title: &str, key: &str, tag: u32) -> *mut Object {
|
||||
let title = NSString::alloc(nil).init_str(title);
|
||||
let action = sel!(handleMenuItem:);
|
||||
|
||||
Reference in New Issue
Block a user