Merge pull request #3076 from Kingtous/master
feat: add url scheme handler for macos
This commit is contained in:
commit
4b5724fa76
41
Cargo.lock
generated
41
Cargo.lock
generated
@ -1137,7 +1137,7 @@ checksum = "413487ef345ab5cdfbf23e66070741217a701bce70f2f397a54221b4f2b6056a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"dconf_rs",
|
"dconf_rs",
|
||||||
"detect-desktop-environment",
|
"detect-desktop-environment",
|
||||||
"dirs",
|
"dirs 4.0.0",
|
||||||
"objc",
|
"objc",
|
||||||
"rust-ini",
|
"rust-ini",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
@ -1401,6 +1401,16 @@ dependencies = [
|
|||||||
"dirs-sys-next",
|
"dirs-sys-next",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs"
|
||||||
|
version = "2.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10",
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "4.0.0"
|
version = "4.0.0"
|
||||||
@ -1873,6 +1883,19 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fruitbasket"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "898289b8e0528c84fb9b88f15ac9d5109bcaf23e0e49bb6f64deee0d86b6a351"
|
||||||
|
dependencies = [
|
||||||
|
"dirs 2.0.2",
|
||||||
|
"objc",
|
||||||
|
"objc-foundation",
|
||||||
|
"objc_id",
|
||||||
|
"time 0.1.45",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fuchsia-cprng"
|
name = "fuchsia-cprng"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -3657,6 +3680,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"malloc_buf",
|
"malloc_buf",
|
||||||
|
"objc_exception",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3670,6 +3694,15 @@ dependencies = [
|
|||||||
"objc_id",
|
"objc_id",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc_exception"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc_id"
|
name = "objc_id"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -4655,6 +4688,7 @@ dependencies = [
|
|||||||
"flexi_logger",
|
"flexi_logger",
|
||||||
"flutter_rust_bridge",
|
"flutter_rust_bridge",
|
||||||
"flutter_rust_bridge_codegen",
|
"flutter_rust_bridge_codegen",
|
||||||
|
"fruitbasket",
|
||||||
"glib 0.16.5",
|
"glib 0.16.5",
|
||||||
"gtk",
|
"gtk",
|
||||||
"hbb_common",
|
"hbb_common",
|
||||||
@ -4673,6 +4707,7 @@ dependencies = [
|
|||||||
"mouce",
|
"mouce",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"objc",
|
"objc",
|
||||||
|
"objc_id",
|
||||||
"parity-tokio-ipc",
|
"parity-tokio-ipc",
|
||||||
"rdev",
|
"rdev",
|
||||||
"repng",
|
"repng",
|
||||||
@ -4713,7 +4748,7 @@ name = "rustdesk-portable-packer"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"brotli",
|
"brotli",
|
||||||
"dirs",
|
"dirs 4.0.0",
|
||||||
"embed-resource",
|
"embed-resource",
|
||||||
"md5",
|
"md5",
|
||||||
]
|
]
|
||||||
@ -6591,7 +6626,7 @@ dependencies = [
|
|||||||
"async-trait",
|
"async-trait",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"derivative",
|
"derivative",
|
||||||
"dirs",
|
"dirs 4.0.0",
|
||||||
"enumflags2",
|
"enumflags2",
|
||||||
"event-listener",
|
"event-listener",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
@ -106,6 +106,8 @@ core-graphics = "0.22"
|
|||||||
include_dir = "0.7.2"
|
include_dir = "0.7.2"
|
||||||
tray-item = "0.7" # looks better than trayicon
|
tray-item = "0.7" # looks better than trayicon
|
||||||
dark-light = "0.2"
|
dark-light = "0.2"
|
||||||
|
fruitbasket = "0.10.0"
|
||||||
|
objc_id = "0.1.1"
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
psimple = { package = "libpulse-simple-binding", version = "2.25" }
|
psimple = { package = "libpulse-simple-binding", version = "2.25" }
|
||||||
|
@ -1315,6 +1315,12 @@ StreamSubscription? listenUniLinks() {
|
|||||||
///
|
///
|
||||||
/// * Returns true if we successfully handle the startup arguments.
|
/// * Returns true if we successfully handle the startup arguments.
|
||||||
bool checkArguments() {
|
bool checkArguments() {
|
||||||
|
if (kBootArgs.isNotEmpty) {
|
||||||
|
final ret = parseRustdeskUri(kBootArgs.first);
|
||||||
|
if (ret) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
// bootArgs:[--connect, 362587269, --switch_uuid, e3d531cc-5dce-41e0-bd06-5d4a2b1eec05]
|
// bootArgs:[--connect, 362587269, --switch_uuid, e3d531cc-5dce-41e0-bd06-5d4a2b1eec05]
|
||||||
// check connect args
|
// check connect args
|
||||||
var connectIndex = kBootArgs.indexOf("--connect");
|
var connectIndex = kBootArgs.indexOf("--connect");
|
||||||
@ -1352,7 +1358,7 @@ bool checkArguments() {
|
|||||||
bool parseRustdeskUri(String uriPath) {
|
bool parseRustdeskUri(String uriPath) {
|
||||||
final uri = Uri.tryParse(uriPath);
|
final uri = Uri.tryParse(uriPath);
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
print("uri is not valid: $uriPath");
|
debugPrint("uri is not valid: $uriPath");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return callUniLinksUriHandler(uri);
|
return callUniLinksUriHandler(uri);
|
||||||
|
@ -11,8 +11,9 @@ const String kPeerPlatformLinux = "Linux";
|
|||||||
const String kPeerPlatformMacOS = "Mac OS";
|
const String kPeerPlatformMacOS = "Mac OS";
|
||||||
const String kPeerPlatformAndroid = "Android";
|
const String kPeerPlatformAndroid = "Android";
|
||||||
|
|
||||||
/// [kAppTypeMain] used by 'Desktop Main Page' , 'Mobile (Client and Server)' , 'Desktop CM Page', "Install Page"
|
/// [kAppTypeMain] used by 'Desktop Main Page' , 'Mobile (Client and Server)', "Install Page"
|
||||||
const String kAppTypeMain = "main";
|
const String kAppTypeMain = "main";
|
||||||
|
const String kAppTypeConnectionManager = "cm";
|
||||||
const String kAppTypeDesktopRemote = "remote";
|
const String kAppTypeDesktopRemote = "remote";
|
||||||
const String kAppTypeDesktopFileTransfer = "file transfer";
|
const String kAppTypeDesktopFileTransfer = "file transfer";
|
||||||
const String kAppTypeDesktopPortForward = "port forward";
|
const String kAppTypeDesktopPortForward = "port forward";
|
||||||
|
@ -211,7 +211,7 @@ void runMultiWindow(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void runConnectionManagerScreen(bool hide) async {
|
void runConnectionManagerScreen(bool hide) async {
|
||||||
await initEnv(kAppTypeMain);
|
await initEnv(kAppTypeConnectionManager);
|
||||||
_runApp(
|
_runApp(
|
||||||
'',
|
'',
|
||||||
const DesktopServerPage(),
|
const DesktopServerPage(),
|
||||||
|
@ -199,6 +199,9 @@ class FfiModel with ChangeNotifier {
|
|||||||
final peer_id = evt['peer_id'].toString();
|
final peer_id = evt['peer_id'].toString();
|
||||||
await bind.sessionSwitchSides(id: peer_id);
|
await bind.sessionSwitchSides(id: peer_id);
|
||||||
closeConnection(id: peer_id);
|
closeConnection(id: peer_id);
|
||||||
|
} else if (name == "on_url_scheme_received") {
|
||||||
|
final url = evt['url'].toString();
|
||||||
|
parseRustdeskUri(url);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import 'package:external_path/external_path.dart';
|
|||||||
import 'package:ffi/ffi.dart';
|
import 'package:ffi/ffi.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_hbb/consts.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:win32/win32.dart' as win32;
|
import 'package:win32/win32.dart' as win32;
|
||||||
@ -46,6 +47,8 @@ class PlatformFFI {
|
|||||||
|
|
||||||
static get localeName => Platform.localeName;
|
static get localeName => Platform.localeName;
|
||||||
|
|
||||||
|
static get isMain => instance._appType == kAppTypeMain;
|
||||||
|
|
||||||
static Future<String> getVersion() async {
|
static Future<String> getVersion() async {
|
||||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||||
return packageInfo.version;
|
return packageInfo.version;
|
||||||
@ -112,8 +115,11 @@ class PlatformFFI {
|
|||||||
}
|
}
|
||||||
_ffiBind = RustdeskImpl(dylib);
|
_ffiBind = RustdeskImpl(dylib);
|
||||||
if (Platform.isLinux) {
|
if (Platform.isLinux) {
|
||||||
// start dbus service, no need to await
|
// Start a dbus service, no need to await
|
||||||
await _ffiBind.mainStartDbusServer();
|
_ffiBind.mainStartDbusServer();
|
||||||
|
} else if (Platform.isMacOS) {
|
||||||
|
// Start an ipc server for handling url schemes.
|
||||||
|
_ffiBind.mainStartIpcUrlServer();
|
||||||
}
|
}
|
||||||
_startListenEvent(_ffiBind); // global event
|
_startListenEvent(_ffiBind); // global event
|
||||||
try {
|
try {
|
||||||
|
@ -227,7 +227,7 @@
|
|||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
33CC10EC2044A3C60003C045 = {
|
33CC10EC2044A3C60003C045 = {
|
||||||
CreatedOnToolsVersion = 9.2;
|
CreatedOnToolsVersion = 9.2;
|
||||||
LastSwiftMigration = 1100;
|
LastSwiftMigration = 1420;
|
||||||
ProvisioningStyle = Automatic;
|
ProvisioningStyle = Automatic;
|
||||||
SystemCapabilities = {
|
SystemCapabilities = {
|
||||||
com.apple.Sandbox = {
|
com.apple.Sandbox = {
|
||||||
@ -463,6 +463,7 @@
|
|||||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk;
|
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
name = Profile;
|
name = Profile;
|
||||||
@ -607,6 +608,7 @@
|
|||||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk;
|
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
"SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = Runner/bridge_generated.h;
|
"SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = Runner/bridge_generated.h;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@ -643,6 +645,7 @@
|
|||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk;
|
PRODUCT_BUNDLE_IDENTIFIER = com.carriez.rustdesk;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
"SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = Runner/bridge_generated.h;
|
"SWIFT_OBJC_BRIDGING_HEADER[arch=*]" = Runner/bridge_generated.h;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
};
|
};
|
||||||
|
@ -87,4 +87,3 @@ class MainFlutterWindow: NSWindow {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use hbb_common::log;
|
use std::future::Future;
|
||||||
|
|
||||||
|
use hbb_common::{log, ResultType};
|
||||||
|
|
||||||
/// shared by flutter and sciter main function
|
/// 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()) };
|
return if res { None } else { Some(Vec::new()) };
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "macos")]
|
#[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::{
|
use std::{collections::HashMap, ffi::{CStr, CString}, os::raw::c_char, thread};
|
||||||
collections::HashMap,
|
use std::str::FromStr;
|
||||||
ffi::{CStr, CString},
|
|
||||||
os::raw::c_char,
|
|
||||||
};
|
|
||||||
|
|
||||||
use flutter_rust_bridge::{StreamSink, SyncReturn, ZeroCopyBuffer};
|
use flutter_rust_bridge::{StreamSink, SyncReturn, ZeroCopyBuffer};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use crate::common::is_keyboard_mode_supported;
|
|
||||||
use hbb_common::message_proto::KeyboardMode;
|
|
||||||
use hbb_common::ResultType;
|
|
||||||
use hbb_common::{
|
use hbb_common::{
|
||||||
config::{self, LocalConfig, PeerConfig, ONLINE},
|
config::{self, LocalConfig, ONLINE, PeerConfig},
|
||||||
fs, log,
|
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::{
|
use crate::{
|
||||||
client::file_trait::FileManager,
|
client::file_trait::FileManager,
|
||||||
common::make_fd_to_json,
|
common::make_fd_to_json,
|
||||||
flutter::{session_add, session_start_},
|
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) {
|
fn initialize(app_dir: &str) {
|
||||||
*config::APP_DIR.write().unwrap() = app_dir.to_owned();
|
*config::APP_DIR.write().unwrap() = app_dir.to_owned();
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
@ -1255,16 +1252,32 @@ pub fn main_hide_docker() -> SyncReturn<bool> {
|
|||||||
SyncReturn(true)
|
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")]
|
#[cfg(target_os = "android")]
|
||||||
pub mod server_side {
|
pub mod server_side {
|
||||||
|
use hbb_common::log;
|
||||||
use jni::{
|
use jni::{
|
||||||
|
JNIEnv,
|
||||||
objects::{JClass, JString},
|
objects::{JClass, JString},
|
||||||
sys::jstring,
|
sys::jstring,
|
||||||
JNIEnv,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use hbb_common::log;
|
|
||||||
|
|
||||||
use crate::start_server;
|
use crate::start_server;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
11
src/ipc.rs
11
src/ipc.rs
@ -16,10 +16,10 @@ use hbb_common::{
|
|||||||
config::{self, Config, Config2},
|
config::{self, Config, Config2},
|
||||||
futures::StreamExt as _,
|
futures::StreamExt as _,
|
||||||
futures_util::sink::SinkExt,
|
futures_util::sink::SinkExt,
|
||||||
log, password_security as password, timeout, tokio,
|
log, password_security as password, ResultType, timeout,
|
||||||
|
tokio,
|
||||||
tokio::io::{AsyncRead, AsyncWrite},
|
tokio::io::{AsyncRead, AsyncWrite},
|
||||||
tokio_util::codec::Framed,
|
tokio_util::codec::Framed,
|
||||||
ResultType,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::rendezvous_mediator::RendezvousMediator;
|
use crate::rendezvous_mediator::RendezvousMediator;
|
||||||
@ -210,6 +210,7 @@ pub enum Data {
|
|||||||
DataPortableService(DataPortableService),
|
DataPortableService(DataPortableService),
|
||||||
SwitchSidesRequest(String),
|
SwitchSidesRequest(String),
|
||||||
SwitchSidesBack,
|
SwitchSidesBack,
|
||||||
|
UrlLink(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
@ -832,3 +833,9 @@ pub async fn test_rendezvous_server() -> ResultType<()> {
|
|||||||
c.send(&Data::TestRendezvousServer).await?;
|
c.send(&Data::TestRendezvousServer).await?;
|
||||||
Ok(())
|
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;
|
use bytes::Bytes;
|
||||||
|
|
||||||
pub use connection::*;
|
pub use connection::*;
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
||||||
use hbb_common::config::Config2;
|
|
||||||
use hbb_common::{
|
use hbb_common::{
|
||||||
allow_err,
|
allow_err,
|
||||||
anyhow::{anyhow, Context},
|
anyhow::{anyhow, Context},
|
||||||
@ -12,19 +17,18 @@ use hbb_common::{
|
|||||||
message_proto::*,
|
message_proto::*,
|
||||||
protobuf::{Enum, Message as _},
|
protobuf::{Enum, Message as _},
|
||||||
rendezvous_proto::*,
|
rendezvous_proto::*,
|
||||||
|
ResultType,
|
||||||
socket_client,
|
socket_client,
|
||||||
sodiumoxide::crypto::{box_, secretbox, sign},
|
sodiumoxide::crypto::{box_, secretbox, sign}, Stream, timeout, tokio,
|
||||||
timeout, tokio, ResultType, Stream,
|
|
||||||
};
|
};
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[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 service::{GenericService, Service, Subscriber};
|
||||||
use std::{
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
collections::HashMap,
|
use service::ServiceTmpl;
|
||||||
net::SocketAddr,
|
|
||||||
sync::{Arc, Mutex, RwLock, Weak},
|
use crate::ipc::{connect, Data};
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub mod audio_service;
|
pub mod audio_service;
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
@ -55,8 +59,6 @@ mod service;
|
|||||||
mod video_qos;
|
mod video_qos;
|
||||||
pub mod video_service;
|
pub mod video_service;
|
||||||
|
|
||||||
use hbb_common::tcp::new_listener;
|
|
||||||
|
|
||||||
pub type Childs = Arc<Mutex<Vec<std::process::Child>>>;
|
pub type Childs = Arc<Mutex<Vec<std::process::Child>>>;
|
||||||
type ConnMap = HashMap<i32, ConnInner>;
|
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")]
|
#[cfg(target_os = "macos")]
|
||||||
async fn sync_and_watch_config_dir() {
|
async fn sync_and_watch_config_dir() {
|
||||||
if crate::platform::is_root() {
|
if crate::platform::is_root() {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::{ffi::c_void, rc::Rc};
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
appkit::{NSApp, NSApplication, NSApplicationActivationPolicy::*, NSMenu, NSMenuItem},
|
appkit::{NSApp, NSApplication, NSApplicationActivationPolicy::*, NSMenu, NSMenuItem},
|
||||||
@ -8,11 +10,16 @@ use objc::{
|
|||||||
class,
|
class,
|
||||||
declare::ClassDecl,
|
declare::ClassDecl,
|
||||||
msg_send,
|
msg_send,
|
||||||
runtime::{Object, Sel, BOOL},
|
runtime::{BOOL, Object, Sel},
|
||||||
sel, sel_impl,
|
sel, sel_impl,
|
||||||
};
|
};
|
||||||
use sciter::{make_args, Host};
|
use objc::runtime::Class;
|
||||||
use std::{ffi::c_void, rc::Rc};
|
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";
|
static APP_HANDLER_IVAR: &str = "GoDeskAppHandler";
|
||||||
|
|
||||||
@ -98,12 +105,21 @@ unsafe fn set_delegate(handler: Option<Box<dyn AppHandler>>) {
|
|||||||
sel!(handleMenuItem:),
|
sel!(handleMenuItem:),
|
||||||
handle_menu_item as extern "C" fn(&mut Object, Sel, id),
|
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 decl = decl.register();
|
||||||
let delegate: id = msg_send![decl, alloc];
|
let delegate: id = msg_send![decl, alloc];
|
||||||
let () = msg_send![delegate, init];
|
let () = msg_send![delegate, init];
|
||||||
let state = DelegateState { handler };
|
let state = DelegateState { handler };
|
||||||
let handler_ptr = Box::into_raw(Box::new(state));
|
let handler_ptr = Box::into_raw(Box::new(state));
|
||||||
(*delegate).set_ivar(APP_HANDLER_IVAR, handler_ptr as *mut c_void);
|
(*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];
|
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 {
|
unsafe fn make_menu_item(title: &str, key: &str, tag: u32) -> *mut Object {
|
||||||
let title = NSString::alloc(nil).init_str(title);
|
let title = NSString::alloc(nil).init_str(title);
|
||||||
let action = sel!(handleMenuItem:);
|
let action = sel!(handleMenuItem:);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user