diff --git a/.github/workflows/bridge.yml b/.github/workflows/bridge.yml index 873cf008b..6d99a24b2 100644 --- a/.github/workflows/bridge.yml +++ b/.github/workflows/bridge.yml @@ -61,7 +61,7 @@ jobs: - name: Install flutter rust bridge deps shell: bash run: | - cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} + cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid" pushd flutter && flutter pub get && popd - name: Run flutter rust bridge diff --git a/.github/workflows/flutter-build.yml b/.github/workflows/flutter-build.yml index 0c5bb7f08..35a4191f0 100644 --- a/.github/workflows/flutter-build.yml +++ b/.github/workflows/flutter-build.yml @@ -79,7 +79,7 @@ jobs: - name: Install flutter rust bridge deps run: | - cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} + cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid" Push-Location flutter ; flutter pub get ; Pop-Location ~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart @@ -312,7 +312,7 @@ jobs: - name: Install flutter rust bridge deps shell: bash run: | - cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} + cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid" pushd flutter && flutter pub get && popd ~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart diff --git a/Cargo.lock b/Cargo.lock index 41064be33..030a380a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,6 +58,7 @@ dependencies = [ "anyhow", "atomic", "chrono", + "uuid", ] [[package]] @@ -2103,6 +2104,7 @@ dependencies = [ "log", "parking_lot", "threadpool", + "uuid", "wasm-bindgen", "web-sys", ] @@ -2878,6 +2880,7 @@ dependencies = [ "tokio-socks", "tokio-util", "toml 0.7.3", + "uuid", "winapi 0.3.9", "zstd 0.12.3+zstd.1.5.2", ] diff --git a/Cargo.toml b/Cargo.toml index a1717a6de..cc72bf48f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,7 @@ num_cpus = "1.15" bytes = { version = "1.4", features = ["serde"] } default-net = "0.14" wol-rs = "1.0" -flutter_rust_bridge = { version = "1.75", optional = true } +flutter_rust_bridge = { version = "1.75", features = ["uuid"], optional = true} errno = "0.3" rdev = { git = "https://github.com/fufesou/rdev" } url = { version = "2.3", features = ["serde"] } diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 7468bdf35..a78af2a94 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -23,6 +23,7 @@ import 'package:texture_rgba_renderer/texture_rgba_renderer.dart'; import 'package:uni_links/uni_links.dart'; import 'package:uni_links_desktop/uni_links_desktop.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:uuid/uuid.dart'; import 'package:win32/win32.dart' as win32; import 'package:window_manager/window_manager.dart'; import 'package:window_size/window_size.dart' as window_size; @@ -68,6 +69,7 @@ typedef F = String Function(String); typedef FMethod = String Function(String, dynamic); typedef StreamEventHandler = Future Function(Map); +typedef SessionID = UuidValue; final iconHardDrive = MemoryImage(Uint8List.fromList(base64Decode( 'iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAmVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjHWqVAAAAMnRSTlMAv0BmzLJNXlhiUu2fxXDgu7WuSUUe29LJvpqUjX53VTstD7ilNujCqTEk5IYH+vEoFjKvAagAAAPpSURBVHja7d0JbhpBEIXhB3jYzb5vBgzYgO04df/DJXGUKMwU9ECmZ6pQfSfw028LCXW3YYwxxhhjjDHGGGOM0eZ9VV1MckdKWLM1bRQ/35GW/WxHHu1me6ShuyHvNl34VhlTKsYVeDWj1EzgUZ1S1DrAk/UDparZgxd9Sl0BHnxSBhpI3jfKQG2FpLUpE69I2ILikv1nsvygjBwPSNKYMlNHggqUoSKS80AZCnwHqQ1zCRvW+CRegwRFeFAMKKrtM8gTPJlzSfwFgT9dJom3IDN4VGaSeAryAK8m0SSeghTg1ZYiql6CjBDhO8mzlyAVhKhIwgXxrh5NojGIhyRckEdwpCdhgpSQgiWTRGMQNonGIGySp0SDvMDBX5KWxiB8Eo1BgE00SYJBykhNnkmSWJAcLpGaJNMgfJKyxiDAK4WNEwryhMtkJsk8CJtEYxA+icYgQIfCcgkEqcJNXhIRQdgkGoPwSTQG+e8khdu/7JOVREwQIKCwF41B2CQljUH4JLcH6SI+OUlEBQHa0SQag/BJNAbhkjxqDMIn0RgEeI4muSlID9eSkERgEKAVTaIxCJ9EYxA2ydVB8hCASVLRGAQYR5NoDMIn0RgEyFHYSGMQPonGII4kziCNvBgNJonEk4u3GAk8Sprk6eYaqbMDY0oKvUm5jfC/viGiSypV7+M3i2iDsAGpNEDYjlTa3W8RdR/r544g50ilnA0RxoZIE2NIXqQbhkAkGyKNDZHGhkhjQ6SxIdLYEGlsiDQ2JGTVeD0264U9zipPh7XOooffpA6pfNCXjxl4/c3pUzlChwzor53zwYYVfpI5pOV6LWFF/2jiJ5FDSs5jdY/0rwUAkUMeXWdBqnSqD0DikBqdqCHsjTvELm9In0IOri/0pwAEDtlSyNaRjAIAAoesKWTtuusxByBwCJp0oomwBXcYUuCQgE50ENajE4OvZAKHLB1/68Br5NqiyCGYOY8YRd77kTkEb64n7lZN+mOIX4QOwb5FX0ZVx3uOxwW+SB0CbBubemWP8/rlaaeRX+M3uUOuZENsiA25zIbYkPsZElBIHwL13U/PTjJ/cyOOEoVM3I+hziDQlELm7pPxw3eI8/7gPh1fpLA6xGnEeDDgO0UcIAzzM35HxLPIq5SXe9BLzOsj9eUaQqyXzxS1QFSfWM2cCANiHcAISJ0AnCKpUwTuIkkA3EeSInAXSQKcs1V18e24wlllUmQp9v9zXKeHi+akRAMOPVKhAqdPBZeUmnnEsO6QcJ0+4qmOSbBxFfGVRiTUqITrdKcCbyYO3/K4wX4+aQ+FfNjXhu3JfAVjjDHGGGOMMcYYY4xIPwCgfqT6TbhCLAAAAABJRU5ErkJggg=='))); @@ -890,8 +892,8 @@ class CustomAlertDialog extends StatelessWidget { } } -void msgBox(String id, String type, String title, String text, String link, - OverlayDialogManager dialogManager, +void msgBox(SessionID sessionId, String type, String title, String text, + String link, OverlayDialogManager dialogManager, {bool? hasCancel, ReconnectHandle? reconnect}) { dialogManager.dismissAll(); List buttons = []; @@ -936,7 +938,7 @@ void msgBox(String id, String type, String title, String text, String link, buttons.insert( 0, dialogButton('Reconnect', isOutline: true, onPressed: () { - reconnect(dialogManager, id, false); + reconnect(dialogManager, sessionId, false); })); } if (link.isNotEmpty) { @@ -950,7 +952,7 @@ void msgBox(String id, String type, String title, String text, String link, onSubmit: hasOk ? submit : null, onCancel: hasCancel == true ? cancel : null, ), - tag: '$id-$type-$title-$text-$link', + tag: '$sessionId-$type-$title-$text-$link', ); } diff --git a/flutter/lib/common/widgets/dialog.dart b/flutter/lib/common/widgets/dialog.dart index 486b16b6d..5f9205fdc 100644 --- a/flutter/lib/common/widgets/dialog.dart +++ b/flutter/lib/common/widgets/dialog.dart @@ -10,9 +10,9 @@ import '../../common.dart'; import '../../models/model.dart'; import '../../models/platform_model.dart'; -void clientClose(String id, OverlayDialogManager dialogManager) { - msgBox(id, 'info', 'Close', 'Are you sure to close the connection?', '', - dialogManager); +void clientClose(SessionID sessionId, OverlayDialogManager dialogManager) { + msgBox(sessionId, 'info', 'Close', 'Are you sure to close the connection?', + '', dialogManager); } abstract class ValidationRule { @@ -423,8 +423,8 @@ class _PasswordWidgetState extends State { } } -void wrongPasswordDialog( - String id, OverlayDialogManager dialogManager, type, title, text) { +void wrongPasswordDialog(SessionID sessionId, + OverlayDialogManager dialogManager, type, title, text) { dialogManager.dismissAll(); dialogManager.show((setState, close, context) { cancel() { @@ -433,7 +433,7 @@ void wrongPasswordDialog( } submit() { - enterPasswordDialog(id, dialogManager); + enterPasswordDialog(sessionId, dialogManager); } return CustomAlertDialog( @@ -455,17 +455,19 @@ void wrongPasswordDialog( }); } -void enterPasswordDialog(String id, OverlayDialogManager dialogManager) async { +void enterPasswordDialog( + SessionID sessionId, OverlayDialogManager dialogManager) async { await _connectDialog( - id, + sessionId, dialogManager, passwordController: TextEditingController(), ); } -void enterUserLoginDialog(String id, OverlayDialogManager dialogManager) async { +void enterUserLoginDialog( + SessionID sessionId, OverlayDialogManager dialogManager) async { await _connectDialog( - id, + sessionId, dialogManager, osUsernameController: TextEditingController(), osPasswordController: TextEditingController(), @@ -473,9 +475,9 @@ void enterUserLoginDialog(String id, OverlayDialogManager dialogManager) async { } void enterUserLoginAndPasswordDialog( - String id, OverlayDialogManager dialogManager) async { + SessionID sessionId, OverlayDialogManager dialogManager) async { await _connectDialog( - id, + sessionId, dialogManager, osUsernameController: TextEditingController(), osPasswordController: TextEditingController(), @@ -484,7 +486,7 @@ void enterUserLoginAndPasswordDialog( } _connectDialog( - String id, + SessionID sessionId, OverlayDialogManager dialogManager, { TextEditingController? osUsernameController, TextEditingController? osPasswordController, @@ -492,11 +494,13 @@ _connectDialog( }) async { var rememberPassword = false; if (passwordController != null) { - rememberPassword = await bind.sessionGetRemember(id: id) ?? false; + rememberPassword = + await bind.sessionGetRemember(sessionId: sessionId) ?? false; } var rememberAccount = false; if (osUsernameController != null) { - rememberAccount = await bind.sessionGetRemember(id: id) ?? false; + rememberAccount = + await bind.sessionGetRemember(sessionId: sessionId) ?? false; } dialogManager.dismissAll(); dialogManager.show((setState, close, context) { @@ -511,13 +515,15 @@ _connectDialog( final password = passwordController?.text.trim() ?? ''; if (passwordController != null && password.isEmpty) return; if (rememberAccount) { - bind.sessionPeerOption(id: id, name: 'os-username', value: osUsername); - bind.sessionPeerOption(id: id, name: 'os-password', value: osPassword); + bind.sessionPeerOption( + sessionId: sessionId, name: 'os-username', value: osUsername); + bind.sessionPeerOption( + sessionId: sessionId, name: 'os-password', value: osPassword); } gFFI.login( osUsername, osPassword, - id, + sessionId, password, rememberPassword, ); @@ -650,10 +656,10 @@ _connectDialog( } void showWaitUacDialog( - String id, OverlayDialogManager dialogManager, String type) { + SessionID sessionId, OverlayDialogManager dialogManager, String type) { dialogManager.dismissAll(); dialogManager.show( - tag: '$id-wait-uac', + tag: '$sessionId-wait-uac', (setState, close, context) => CustomAlertDialog( title: null, content: msgboxContent(type, 'Wait', 'wait_accept_uac_tip'), @@ -661,7 +667,8 @@ void showWaitUacDialog( } // Another username && password dialog? -void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) { +void showRequestElevationDialog( + SessionID sessionId, OverlayDialogManager dialogManager) { RxString groupValue = ''.obs; RxString errUser = ''.obs; RxString errPwd = ''.obs; @@ -785,7 +792,8 @@ void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) { ); dialogManager.dismissAll(); - dialogManager.show(tag: '$id-request-elevation', (setState, close, context) { + dialogManager.show(tag: '$sessionId-request-elevation', + (setState, close, context) { void submit() { if (groupValue.value == 'logon') { if (userController.text.isEmpty) { @@ -797,11 +805,11 @@ void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) { return; } bind.sessionElevateWithLogon( - id: id, + sessionId: sessionId, username: userController.text, password: pwdController.text); } else { - bind.sessionElevateDirect(id: id); + bind.sessionElevateDirect(sessionId: sessionId); } } @@ -828,20 +836,20 @@ void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) { } void showOnBlockDialog( - String id, + SessionID sessionId, String type, String title, String text, OverlayDialogManager dialogManager, ) { - if (dialogManager.existing('$id-wait-uac') || - dialogManager.existing('$id-request-elevation')) { + if (dialogManager.existing('$sessionId-wait-uac') || + dialogManager.existing('$sessionId-request-elevation')) { return; } - dialogManager.show(tag: '$id-$type', (setState, close, context) { + dialogManager.show(tag: '$sessionId-$type', (setState, close, context) { void submit() { close(); - showRequestElevationDialog(id, dialogManager); + showRequestElevationDialog(sessionId, dialogManager); } return CustomAlertDialog( @@ -858,12 +866,12 @@ void showOnBlockDialog( }); } -void showElevationError(String id, String type, String title, String text, - OverlayDialogManager dialogManager) { - dialogManager.show(tag: '$id-$type', (setState, close, context) { +void showElevationError(SessionID sessionId, String type, String title, + String text, OverlayDialogManager dialogManager) { + dialogManager.show(tag: '$sessionId-$type', (setState, close, context) { void submit() { close(); - showRequestElevationDialog(id, dialogManager); + showRequestElevationDialog(sessionId, dialogManager); } return CustomAlertDialog( @@ -881,8 +889,8 @@ void showElevationError(String id, String type, String title, String text, }); } -void showWaitAcceptDialog(String id, String type, String title, String text, - OverlayDialogManager dialogManager) { +void showWaitAcceptDialog(SessionID sessionId, String type, String title, + String text, OverlayDialogManager dialogManager) { dialogManager.dismissAll(); dialogManager.show((setState, close, context) { onCancel() { @@ -900,8 +908,8 @@ void showWaitAcceptDialog(String id, String type, String title, String text, }); } -void showRestartRemoteDevice( - PeerInfo pi, String id, OverlayDialogManager dialogManager) async { +void showRestartRemoteDevice(PeerInfo pi, String id, SessionID sessionId, + OverlayDialogManager dialogManager) async { final res = await dialogManager .show((setState, close, context) => CustomAlertDialog( title: Row(children: [ @@ -928,26 +936,33 @@ void showRestartRemoteDevice( onCancel: close, onSubmit: () => close(true), )); - if (res == true) bind.sessionRestartRemoteDevice(id: id); + if (res == true) bind.sessionRestartRemoteDevice(sessionId: sessionId); } showSetOSPassword( - String id, + SessionID sessionId, bool login, OverlayDialogManager dialogManager, ) async { final controller = TextEditingController(); - var password = await bind.sessionGetOption(id: id, arg: 'os-password') ?? ''; - var autoLogin = await bind.sessionGetOption(id: id, arg: 'auto-login') != ''; + var password = + await bind.sessionGetOption(sessionId: sessionId, arg: 'os-password') ?? + ''; + var autoLogin = + await bind.sessionGetOption(sessionId: sessionId, arg: 'auto-login') != + ''; controller.text = password; dialogManager.show((setState, close, context) { submit() { var text = controller.text.trim(); - bind.sessionPeerOption(id: id, name: 'os-password', value: text); bind.sessionPeerOption( - id: id, name: 'auto-login', value: autoLogin ? 'Y' : ''); + sessionId: sessionId, name: 'os-password', value: text); + bind.sessionPeerOption( + sessionId: sessionId, + name: 'auto-login', + value: autoLogin ? 'Y' : ''); if (text != '' && login) { - bind.sessionInputOsPassword(id: id, value: text); + bind.sessionInputOsPassword(sessionId: sessionId, value: text); } close(); } @@ -999,21 +1014,27 @@ showSetOSPassword( } showSetOSAccount( - String id, + SessionID sessionId, OverlayDialogManager dialogManager, ) async { final usernameController = TextEditingController(); final passwdController = TextEditingController(); - var username = await bind.sessionGetOption(id: id, arg: 'os-username') ?? ''; - var password = await bind.sessionGetOption(id: id, arg: 'os-password') ?? ''; + var username = + await bind.sessionGetOption(sessionId: sessionId, arg: 'os-username') ?? + ''; + var password = + await bind.sessionGetOption(sessionId: sessionId, arg: 'os-password') ?? + ''; usernameController.text = username; passwdController.text = password; dialogManager.show((setState, close, context) { submit() { final username = usernameController.text.trim(); final password = usernameController.text.trim(); - bind.sessionPeerOption(id: id, name: 'os-username', value: username); - bind.sessionPeerOption(id: id, name: 'os-password', value: password); + bind.sessionPeerOption( + sessionId: sessionId, name: 'os-username', value: username); + bind.sessionPeerOption( + sessionId: sessionId, name: 'os-password', value: password); close(); } @@ -1077,13 +1098,13 @@ showSetOSAccount( }); } -showAuditDialog(String id, dialogManager) async { +showAuditDialog(SessionID sessionId, dialogManager) async { final controller = TextEditingController(); dialogManager.show((setState, close) { submit() { var text = controller.text.trim(); if (text != '') { - bind.sessionSendNote(id: id, note: text); + bind.sessionSendNote(sessionId: sessionId, note: text); } close(); } @@ -1139,10 +1160,10 @@ showAuditDialog(String id, dialogManager) async { } void showConfirmSwitchSidesDialog( - String id, OverlayDialogManager dialogManager) async { + SessionID sessionId, String id, OverlayDialogManager dialogManager) async { dialogManager.show((setState, close, context) { submit() async { - await bind.sessionSwitchSides(id: id); + await bind.sessionSwitchSides(sessionId: sessionId); closeConnection(id: id); } @@ -1159,7 +1180,7 @@ void showConfirmSwitchSidesDialog( }); } -customImageQualityDialog(String id, FFI ffi) async { +customImageQualityDialog(SessionID sessionId, String id, FFI ffi) async { double qualityInitValue = 50; double fpsInitValue = 30; bool qualitySet = false; @@ -1167,20 +1188,22 @@ customImageQualityDialog(String id, FFI ffi) async { setCustomValues({double? quality, double? fps}) async { if (quality != null) { qualitySet = true; - await bind.sessionSetCustomImageQuality(id: id, value: quality.toInt()); + await bind.sessionSetCustomImageQuality( + sessionId: sessionId, value: quality.toInt()); } if (fps != null) { fpsSet = true; - await bind.sessionSetCustomFps(id: id, fps: fps.toInt()); + await bind.sessionSetCustomFps(sessionId: sessionId, fps: fps.toInt()); } if (!qualitySet) { qualitySet = true; await bind.sessionSetCustomImageQuality( - id: id, value: qualityInitValue.toInt()); + sessionId: sessionId, value: qualityInitValue.toInt()); } if (!fpsSet) { fpsSet = true; - await bind.sessionSetCustomFps(id: id, fps: fpsInitValue.toInt()); + await bind.sessionSetCustomFps( + sessionId: sessionId, fps: fpsInitValue.toInt()); } } @@ -1190,7 +1213,7 @@ customImageQualityDialog(String id, FFI ffi) async { }); // quality - final quality = await bind.sessionGetCustomImageQuality(id: id); + final quality = await bind.sessionGetCustomImageQuality(sessionId: sessionId); qualityInitValue = quality != null && quality.isNotEmpty ? quality[0].toDouble() : 50.0; const qualityMinValue = 10.0; @@ -1238,7 +1261,8 @@ customImageQualityDialog(String id, FFI ffi) async { ], )); // fps - final fpsOption = await bind.sessionGetOption(id: id, arg: 'custom-fps'); + final fpsOption = + await bind.sessionGetOption(sessionId: sessionId, arg: 'custom-fps'); fpsInitValue = fpsOption == null ? 30 : double.tryParse(fpsOption) ?? 30; if (fpsInitValue < 5 || fpsInitValue > 120) { fpsInitValue = 30; diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index ab8fd9fea..ccc9014d6 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -735,7 +735,6 @@ abstract class BasePeerCard extends StatelessWidget { } await bind.mainRemovePeer(id: id); } - removePreference(id); await reloadFunc(); close(); } diff --git a/flutter/lib/common/widgets/toolbar.dart b/flutter/lib/common/widgets/toolbar.dart index 32522fb66..21af68097 100644 --- a/flutter/lib/common/widgets/toolbar.dart +++ b/flutter/lib/common/widgets/toolbar.dart @@ -48,6 +48,7 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { final ffiModel = ffi.ffiModel; final pi = ffiModel.pi; final perms = ffiModel.permissions; + final sessionId = ffi.sessionId; List v = []; // elevation @@ -55,7 +56,8 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { v.add( TTextMenu( child: Text(translate('Request Elevation')), - onPressed: () => showRequestElevationDialog(id, ffi.dialogManager)), + onPressed: () => + showRequestElevationDialog(sessionId, ffi.dialogManager)), ); } // osAccount / osPassword @@ -70,8 +72,8 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { ]), trailingIcon: Transform.scale(scale: 0.8, child: Icon(Icons.edit)), onPressed: () => pi.is_headless - ? showSetOSAccount(id, ffi.dialogManager) - : showSetOSPassword(id, false, ffi.dialogManager)), + ? showSetOSAccount(sessionId, ffi.dialogManager) + : showSetOSPassword(sessionId, false, ffi.dialogManager)), ); // paste if (isMobile && perms['keyboard'] != false && perms['clipboard'] != false) { @@ -80,7 +82,8 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { onPressed: () async { ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); if (data != null && data.text != null) { - bind.sessionInputString(id: id, value: data.text ?? ""); + bind.sessionInputString( + sessionId: sessionId, value: data.text ?? ""); } })); } @@ -107,11 +110,13 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { ); } // note - if (bind.sessionGetAuditServerSync(id: id, typ: "conn").isNotEmpty) { + if (bind + .sessionGetAuditServerSync(sessionId: sessionId, typ: "conn") + .isNotEmpty) { v.add( TTextMenu( child: Text(translate('Note')), - onPressed: () => showAuditDialog(id, ffi.dialogManager)), + onPressed: () => showAuditDialog(sessionId, ffi.dialogManager)), ); } // divider @@ -125,7 +130,7 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { v.add( TTextMenu( child: Text('${translate("Insert")} Ctrl + Alt + Del'), - onPressed: () => bind.sessionCtrlAltDel(id: id)), + onPressed: () => bind.sessionCtrlAltDel(sessionId: sessionId)), ); } // restart @@ -136,7 +141,8 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { v.add( TTextMenu( child: Text(translate('Restart Remote Device')), - onPressed: () => showRestartRemoteDevice(pi, id, ffi.dialogManager)), + onPressed: () => + showRestartRemoteDevice(pi, id, sessionId, ffi.dialogManager)), ); } // insertLock @@ -144,7 +150,7 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { v.add( TTextMenu( child: Text(translate('Insert Lock')), - onPressed: () => bind.sessionLockScreen(id: id)), + onPressed: () => bind.sessionLockScreen(sessionId: sessionId)), ); } // blockUserInput @@ -157,7 +163,8 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { onPressed: () { RxBool blockInput = BlockInputState.find(id); bind.sessionToggleOption( - id: id, value: '${blockInput.value ? 'un' : ''}block-input'); + sessionId: sessionId, + value: '${blockInput.value ? 'un' : ''}block-input'); blockInput.value = !blockInput.value; })); } @@ -169,13 +176,14 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { version_cmp(pi.version, '1.2.0') >= 0) { v.add(TTextMenu( child: Text(translate('Switch Sides')), - onPressed: () => showConfirmSwitchSidesDialog(id, ffi.dialogManager))); + onPressed: () => + showConfirmSwitchSidesDialog(sessionId, id, ffi.dialogManager))); } // refresh if (pi.version.isNotEmpty) { v.add(TTextMenu( child: Text(translate('Refresh')), - onPressed: () => bind.sessionRefresh(id: id))); + onPressed: () => bind.sessionRefresh(sessionId: sessionId))); } // record var codecFormat = ffi.qualityMonitorModel.data.codecFormat; @@ -213,11 +221,12 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { Future>> toolbarViewStyle( BuildContext context, String id, FFI ffi) async { - final groupValue = await bind.sessionGetViewStyle(id: id) ?? ''; + final groupValue = + await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? ''; void onChanged(String? value) async { if (value == null) return; bind - .sessionSetViewStyle(id: id, value: value) + .sessionSetViewStyle(sessionId: ffi.sessionId, value: value) .then((_) => ffi.canvasModel.updateViewStyle()); } @@ -237,10 +246,11 @@ Future>> toolbarViewStyle( Future>> toolbarImageQuality( BuildContext context, String id, FFI ffi) async { - final groupValue = await bind.sessionGetImageQuality(id: id) ?? ''; + final groupValue = + await bind.sessionGetImageQuality(sessionId: ffi.sessionId) ?? ''; onChanged(String? value) async { if (value == null) return; - await bind.sessionSetImageQuality(id: id, value: value); + await bind.sessionSetImageQuality(sessionId: ffi.sessionId, value: value); } return [ @@ -265,7 +275,7 @@ Future>> toolbarImageQuality( groupValue: groupValue, onChanged: (value) { onChanged(value); - customImageQualityDialog(id, ffi); + customImageQualityDialog(ffi.sessionId, id, ffi); }, ), ]; @@ -273,9 +283,12 @@ Future>> toolbarImageQuality( Future>> toolbarCodec( BuildContext context, String id, FFI ffi) async { - final alternativeCodecs = await bind.sessionAlternativeCodecs(id: id); - final groupValue = - await bind.sessionGetOption(id: id, arg: 'codec-preference') ?? ''; + final sessionId = ffi.sessionId; + final alternativeCodecs = + await bind.sessionAlternativeCodecs(sessionId: sessionId); + final groupValue = await bind.sessionGetOption( + sessionId: sessionId, arg: 'codec-preference') ?? + ''; final List codecs = []; try { final Map codecsJson = jsonDecode(alternativeCodecs); @@ -296,8 +309,8 @@ Future>> toolbarCodec( onChanged(String? value) async { if (value == null) return; await bind.sessionPeerOption( - id: id, name: 'codec-preference', value: value); - bind.sessionChangePreferCodec(id: id); + sessionId: sessionId, name: 'codec-preference', value: value); + bind.sessionChangePreferCodec(sessionId: sessionId); } TRadioMenu radio(String label, String value, bool enabled) { @@ -324,6 +337,7 @@ Future> toolbarDisplayToggle( final ffiModel = ffi.ffiModel; final pi = ffiModel.pi; final perms = ffiModel.permissions; + final sessionId = ffi.sessionId; // show remote cursor if (pi.platform != kPeerPlatformAndroid && @@ -338,14 +352,15 @@ Future> toolbarDisplayToggle( onChanged: enabled ? (value) async { if (value == null) return; - await bind.sessionToggleOption(id: id, value: option); - state.value = - bind.sessionGetToggleOptionSync(id: id, arg: option); + await bind.sessionToggleOption( + sessionId: sessionId, value: option); + state.value = bind.sessionGetToggleOptionSync( + sessionId: sessionId, arg: option); } : null)); } // zoom cursor - final viewStyle = await bind.sessionGetViewStyle(id: id) ?? ''; + final viewStyle = await bind.sessionGetViewStyle(sessionId: sessionId) ?? ''; if (!isMobile && pi.platform != kPeerPlatformAndroid && viewStyle != kRemoteViewStyleOriginal) { @@ -356,30 +371,32 @@ Future> toolbarDisplayToggle( value: peerState.value, onChanged: (value) async { if (value == null) return; - await bind.sessionToggleOption(id: id, value: option); - peerState.value = bind.sessionGetToggleOptionSync(id: id, arg: option); + await bind.sessionToggleOption(sessionId: sessionId, value: option); + peerState.value = + bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option); }, )); } // show quality monitor final option = 'show-quality-monitor'; v.add(TToggleMenu( - value: bind.sessionGetToggleOptionSync(id: id, arg: option), + value: bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option), onChanged: (value) async { if (value == null) return; - await bind.sessionToggleOption(id: id, value: option); - ffi.qualityMonitorModel.checkShowQualityMonitor(id); + await bind.sessionToggleOption(sessionId: sessionId, value: option); + ffi.qualityMonitorModel.checkShowQualityMonitor(sessionId); }, child: Text(translate('Show quality monitor')))); // mute if (perms['audio'] != false) { final option = 'disable-audio'; - final value = bind.sessionGetToggleOptionSync(id: id, arg: option); + final value = + bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option); v.add(TToggleMenu( value: value, onChanged: (value) { if (value == null) return; - bind.sessionToggleOption(id: id, value: option); + bind.sessionToggleOption(sessionId: sessionId, value: option); }, child: Text(translate('Mute')))); } @@ -388,12 +405,13 @@ Future> toolbarDisplayToggle( pi.platform == kPeerPlatformWindows && perms['file'] != false) { final option = 'enable-file-transfer'; - final value = bind.sessionGetToggleOptionSync(id: id, arg: option); + final value = + bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option); v.add(TToggleMenu( value: value, onChanged: (value) { if (value == null) return; - bind.sessionToggleOption(id: id, value: option); + bind.sessionToggleOption(sessionId: sessionId, value: option); }, child: Text(translate('Allow file copy and paste')))); } @@ -401,14 +419,15 @@ Future> toolbarDisplayToggle( if (ffiModel.keyboard && perms['clipboard'] != false) { final enabled = !ffiModel.viewOnly; final option = 'disable-clipboard'; - var value = bind.sessionGetToggleOptionSync(id: id, arg: option); + var value = + bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option); if (ffiModel.viewOnly) value = true; v.add(TToggleMenu( value: value, onChanged: enabled ? (value) { if (value == null) return; - bind.sessionToggleOption(id: id, value: option); + bind.sessionToggleOption(sessionId: sessionId, value: option); } : null, child: Text(translate('Disable clipboard')))); @@ -416,12 +435,13 @@ Future> toolbarDisplayToggle( // lock after session end if (ffiModel.keyboard) { final option = 'lock-after-session-end'; - final value = bind.sessionGetToggleOptionSync(id: id, arg: option); + final value = + bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option); v.add(TToggleMenu( value: value, onChanged: (value) { if (value == null) return; - bind.sessionToggleOption(id: id, value: option); + bind.sessionToggleOption(sessionId: sessionId, value: option); }, child: Text(translate('Lock after session end')))); } @@ -434,11 +454,11 @@ Future> toolbarDisplayToggle( onChanged: (value) { if (value == null) return; if (ffiModel.pi.currentDisplay != 0) { - msgBox(id, 'custom-nook-nocancel-hasclose', 'info', + msgBox(sessionId, 'custom-nook-nocancel-hasclose', 'info', 'Please switch to Display 1 first', '', ffi.dialogManager); return; } - bind.sessionToggleOption(id: id, value: option); + bind.sessionToggleOption(sessionId: sessionId, value: option); }, child: Text(translate('Privacy mode')))); } @@ -447,12 +467,13 @@ Future> toolbarDisplayToggle( ((Platform.isMacOS && pi.platform != kPeerPlatformMacOS) || (!Platform.isMacOS && pi.platform == kPeerPlatformMacOS))) { final option = 'allow_swap_key'; - final value = bind.sessionGetToggleOptionSync(id: id, arg: option); + final value = + bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option); v.add(TToggleMenu( value: value, onChanged: (value) { if (value == null) return; - bind.sessionToggleOption(id: id, value: option); + bind.sessionToggleOption(sessionId: sessionId, value: option); }, child: Text(translate('Swap control-command key')))); } diff --git a/flutter/lib/desktop/pages/file_manager_page.dart b/flutter/lib/desktop/pages/file_manager_page.dart index 68d198750..2c1746bd1 100644 --- a/flutter/lib/desktop/pages/file_manager_page.dart +++ b/flutter/lib/desktop/pages/file_manager_page.dart @@ -449,7 +449,8 @@ class _FileManagerViewState extends State { padding: EdgeInsets.all(8.0), child: FutureBuilder( future: bind.sessionGetPlatform( - id: _ffi.id, isRemote: !isLocal), + sessionId: _ffi.sessionId, + isRemote: !isLocal), builder: (context, snapshot) { if (snapshot.hasData && snapshot.data!.isNotEmpty) { diff --git a/flutter/lib/desktop/pages/port_forward_page.dart b/flutter/lib/desktop/pages/port_forward_page.dart index 167c2b20c..bb4965b13 100644 --- a/flutter/lib/desktop/pages/port_forward_page.dart +++ b/flutter/lib/desktop/pages/port_forward_page.dart @@ -194,7 +194,7 @@ class _PortForwardPageState extends State (remoteHostController.text.isEmpty || remoteHostController.text.trim().isNotEmpty)) { await bind.sessionAddPortForward( - id: 'pf_${widget.id}', + sessionId: _ffi.sessionId, localPort: localPort, remoteHost: remoteHostController.text.trim().isEmpty ? 'localhost' @@ -254,7 +254,7 @@ class _PortForwardPageState extends State icon: const Icon(Icons.close), onPressed: () async { await bind.sessionRemovePortForward( - id: 'pf_${widget.id}', localPort: pf.localPort); + sessionId: _ffi.sessionId, localPort: pf.localPort); refreshTunnelConfig(); }, ), @@ -313,7 +313,7 @@ class _PortForwardPageState extends State width: 120, child: ElevatedButton( onPressed: () => - bind.sessionNewRdp(id: "pf_${widget.id}"), + bind.sessionNewRdp(sessionId: _ffi.sessionId), child: Text( translate('New RDP'), ), diff --git a/flutter/lib/desktop/pages/port_forward_tab_page.dart b/flutter/lib/desktop/pages/port_forward_tab_page.dart index 32f02c9b7..65d6208fd 100644 --- a/flutter/lib/desktop/pages/port_forward_tab_page.dart +++ b/flutter/lib/desktop/pages/port_forward_tab_page.dart @@ -110,12 +110,12 @@ class _PortForwardTabPageState extends State { return Platform.isMacOS || kUseCompatibleUiMode ? tabWidget : Obx( - () => SubWindowDragToResizeArea( + () => SubWindowDragToResizeArea( child: tabWidget, resizeEdgeSize: stateGlobal.resizeEdgeSize.value, windowId: stateGlobal.windowId, ), - ); + ); } void onRemoveId(String id) { diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index ab8e55798..ba2138deb 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -76,6 +76,8 @@ class _RemotePageState extends State late FFI _ffi; + SessionID get sessionId => _ffi.sessionId; + void _initStates(String id) { initSharedStates(id); _zoomCursor = PeerBoolOption.find(id, 'zoom-cursor'); @@ -117,19 +119,19 @@ class _RemotePageState extends State debugPrint("id: $id, texture_key: $_textureKey"); if (id != -1) { final ptr = await textureRenderer.getTexturePtr(_textureKey); - platformFFI.registerTexture(widget.id, ptr); + platformFFI.registerTexture(sessionId, ptr); _textureId.value = id; } }); } - _ffi.ffiModel.updateEventListener(widget.id); + _ffi.ffiModel.updateEventListener(sessionId, widget.id); bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote); - _ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id); + _ffi.qualityMonitorModel.checkShowQualityMonitor(sessionId); // Session option should be set after models.dart/FFI.start _showRemoteCursor.value = bind.sessionGetToggleOptionSync( - id: widget.id, arg: 'show-remote-cursor'); - _zoomCursor.value = - bind.sessionGetToggleOptionSync(id: widget.id, arg: 'zoom-cursor'); + sessionId: sessionId, arg: 'show-remote-cursor'); + _zoomCursor.value = bind.sessionGetToggleOptionSync( + sessionId: sessionId, arg: 'zoom-cursor'); DesktopMultiWindow.addListener(this); // if (!_isCustomCursorInited) { // customCursorController.registerNeedUpdateCursorCallback( @@ -203,11 +205,11 @@ class _RemotePageState extends State void dispose() { debugPrint("REMOTE PAGE dispose ${widget.id}"); if (useTextureRender) { - platformFFI.registerTexture(widget.id, 0); + platformFFI.registerTexture(sessionId, 0); textureRenderer.closeTexture(_textureKey); } // ensure we leave this session, this is a double check - bind.sessionEnterOrLeave(id: widget.id, enter: false); + bind.sessionEnterOrLeave(sessionId: sessionId, enter: false); DesktopMultiWindow.removeListener(this); _ffi.dialogManager.hideMobileActionsOverlay(); _ffi.recordingModel.onClose(); @@ -278,7 +280,7 @@ class _RemotePageState extends State super.build(context); return WillPopScope( onWillPop: () async { - clientClose(widget.id, _ffi.dialogManager); + clientClose(sessionId, _ffi.dialogManager); return false; }, child: MultiProvider(providers: [ @@ -305,7 +307,7 @@ class _RemotePageState extends State if (!_rawKeyFocusNode.hasFocus) { _rawKeyFocusNode.requestFocus(); } - bind.sessionEnterOrLeave(id: widget.id, enter: true); + bind.sessionEnterOrLeave(sessionId: sessionId, enter: true); } } @@ -325,7 +327,7 @@ class _RemotePageState extends State } // See [onWindowBlur]. if (!Platform.isWindows) { - bind.sessionEnterOrLeave(id: widget.id, enter: false); + bind.sessionEnterOrLeave(sessionId: sessionId, enter: false); } } diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index 005c74522..154069405 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -56,7 +56,11 @@ class _ConnectionTabPageState extends State { if (peerId != null) { ConnectionTypeState.init(peerId); tabController.onSelected = (_, id) { - bind.setCurSessionId(id: id); + final remotePage = tabController.state.value.tabs + .firstWhere((tab) => tab.key == id) + .page as RemotePage; + final ffi = remotePage.ffi; + bind.setCurSessionId(sessionId: ffi.sessionId); WindowController.fromWindowId(windowId()) .setTitle(getWindowNameWithId(id)); }; @@ -243,6 +247,7 @@ class _ConnectionTabPageState extends State { final ffi = remotePage.ffi; final pi = ffi.ffiModel.pi; final perms = ffi.ffiModel.permissions; + final sessionId = ffi.sessionId; menu.addAll([ MenuEntryButton( childBuilder: (TextStyle? style) => Text( @@ -282,6 +287,7 @@ class _ConnectionTabPageState extends State { menu.add(MenuEntryDivider()); menu.add(RemoteMenuEntry.showRemoteCursor( key, + sessionId, padding, dismissFunc: cancelFunc, )); @@ -289,15 +295,15 @@ class _ConnectionTabPageState extends State { if (perms['keyboard'] != false && !ffi.ffiModel.viewOnly) { if (perms['clipboard'] != false) { - menu.add(RemoteMenuEntry.disableClipboard(key, padding, + menu.add(RemoteMenuEntry.disableClipboard(sessionId, padding, dismissFunc: cancelFunc)); } - menu.add( - RemoteMenuEntry.insertLock(key, padding, dismissFunc: cancelFunc)); + menu.add(RemoteMenuEntry.insertLock(sessionId, padding, + dismissFunc: cancelFunc)); if (pi.platform == kPeerPlatformLinux || pi.sasEnabled) { - menu.add(RemoteMenuEntry.insertCtrlAltDel(key, padding, + menu.add(RemoteMenuEntry.insertCtrlAltDel(sessionId, padding, dismissFunc: cancelFunc)); } } diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index a131a54b4..ee86ed31f 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -30,7 +30,7 @@ class _DesktopServerPageState extends State final tabController = gFFI.serverModel.tabController; @override void initState() { - gFFI.ffiModel.updateEventListener(""); + gFFI.ffiModel.updateEventListener(gFFI.sessionId, ""); windowManager.addListener(this); tabController.onRemoved = (_, id) { onRemoveId(id); diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index d8871464d..2a7ce4eab 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -141,14 +141,16 @@ class RemoteMenuEntry { ], curOptionGetter: () async { // null means peer id is not found, which there's no need to care about - final viewStyle = await bind.sessionGetViewStyle(id: remoteId) ?? ''; + final viewStyle = + await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? ''; if (rxViewStyle != null) { rxViewStyle.value = viewStyle; } return viewStyle; }, optionSetter: (String oldValue, String newValue) async { - await bind.sessionSetViewStyle(id: remoteId, value: newValue); + await bind.sessionSetViewStyle( + sessionId: ffi.sessionId, value: newValue); if (rxViewStyle != null) { rxViewStyle.value = newValue; } @@ -165,6 +167,7 @@ class RemoteMenuEntry { static MenuEntrySwitch2 showRemoteCursor( String remoteId, + SessionID sessionId, EdgeInsets padding, { DismissFunc? dismissFunc, DismissCallback? dismissCallback, @@ -178,9 +181,9 @@ class RemoteMenuEntry { return state; }, setter: (bool v) async { - await bind.sessionToggleOption(id: remoteId, value: optKey); + await bind.sessionToggleOption(sessionId: sessionId, value: optKey); state.value = - bind.sessionGetToggleOptionSync(id: remoteId, arg: optKey); + bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: optKey); if (dismissFunc != null) { dismissFunc(); } @@ -192,13 +195,13 @@ class RemoteMenuEntry { } static MenuEntrySwitch disableClipboard( - String remoteId, + SessionID sessionId, EdgeInsets? padding, { DismissFunc? dismissFunc, DismissCallback? dismissCallback, }) { return createSwitchMenuEntry( - remoteId, + sessionId, 'Disable clipboard', 'disable-clipboard', padding, @@ -208,7 +211,7 @@ class RemoteMenuEntry { } static MenuEntrySwitch createSwitchMenuEntry( - String remoteId, + SessionID sessionId, String text, String option, EdgeInsets? padding, @@ -220,10 +223,11 @@ class RemoteMenuEntry { switchType: SwitchType.scheckbox, text: translate(text), getter: () async { - return bind.sessionGetToggleOptionSync(id: remoteId, arg: option); + return bind.sessionGetToggleOptionSync( + sessionId: sessionId, arg: option); }, setter: (bool v) async { - await bind.sessionToggleOption(id: remoteId, value: option); + await bind.sessionToggleOption(sessionId: sessionId, value: option); if (dismissFunc != null) { dismissFunc(); } @@ -235,7 +239,7 @@ class RemoteMenuEntry { } static MenuEntryButton insertLock( - String remoteId, + SessionID sessionId, EdgeInsets? padding, { DismissFunc? dismissFunc, DismissCallback? dismissCallback, @@ -246,7 +250,7 @@ class RemoteMenuEntry { style: style, ), proc: () { - bind.sessionLockScreen(id: remoteId); + bind.sessionLockScreen(sessionId: sessionId); if (dismissFunc != null) { dismissFunc(); } @@ -258,7 +262,7 @@ class RemoteMenuEntry { } static insertCtrlAltDel( - String remoteId, + SessionID sessionId, EdgeInsets? padding, { DismissFunc? dismissFunc, DismissCallback? dismissCallback, @@ -269,7 +273,7 @@ class RemoteMenuEntry { style: style, ), proc: () { - bind.sessionCtrlAltDel(id: remoteId); + bind.sessionCtrlAltDel(sessionId: sessionId); if (dismissFunc != null) { dismissFunc(); } @@ -329,7 +333,8 @@ class _RemoteMenubarState extends State { Future.delayed(Duration.zero, () async { _fractionX.value = double.tryParse(await bind.sessionGetOption( - id: widget.id, arg: 'remote-menubar-drag-x') ?? + sessionId: widget.ffi.sessionId, + arg: 'remote-menubar-drag-x') ?? '0.5') ?? 0.5; }); @@ -387,7 +392,7 @@ class _RemoteMenubarState extends State { elevation: _MenubarTheme.elevation, shadowColor: MyTheme.color(context).shadow, child: _DraggableShowHide( - id: widget.id, + sessionId: widget.ffi.sessionId, dragging: _dragging, fractionX: _fractionX, show: show, @@ -621,7 +626,7 @@ class _MonitorMenu extends StatelessWidget { _menuDismissCallback(ffi); RxInt display = CurrentDisplayState.find(id); if (display.value != i) { - bind.sessionSwitchDisplay(id: id, value: i); + bind.sessionSwitchDisplay(sessionId: ffi.sessionId, value: i); } }, )); @@ -763,7 +768,8 @@ class ScreenAdjustor { } Future isWindowCanBeAdjusted() async { - final viewStyle = await bind.sessionGetViewStyle(id: id) ?? ''; + final viewStyle = + await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? ''; if (viewStyle != kRemoteViewStyleOriginal) { return false; } @@ -885,9 +891,11 @@ class _DisplayMenuState extends State<_DisplayMenu> { scrollStyle() { return futureBuilder(future: () async { - final viewStyle = await bind.sessionGetViewStyle(id: id) ?? ''; + final viewStyle = + await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? ''; final visible = viewStyle == kRemoteViewStyleOriginal; - final scrollStyle = await bind.sessionGetScrollStyle(id: widget.id) ?? ''; + final scrollStyle = + await bind.sessionGetScrollStyle(sessionId: ffi.sessionId) ?? ''; return {'visible': visible, 'scrollStyle': scrollStyle}; }(), hasData: (data) { final visible = data['visible'] as bool; @@ -895,7 +903,8 @@ class _DisplayMenuState extends State<_DisplayMenu> { final groupValue = data['scrollStyle'] as String; onChange(String? value) async { if (value == null) return; - await bind.sessionSetScrollStyle(id: widget.id, value: value); + await bind.sessionSetScrollStyle( + sessionId: ffi.sessionId, value: value); widget.ffi.canvasModel.updateScrollStyle(); } @@ -1007,6 +1016,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { late final TextEditingController _customHeight = TextEditingController(text: display.height.toString()); + FFI get ffi => widget.ffi; PeerInfo get pi => widget.ffi.ffiModel.pi; FfiModel get ffiModel => widget.ffi.ffiModel; Display get display => ffiModel.display; @@ -1101,7 +1111,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { _changeResolution(int w, int h) async { await bind.sessionChangeResolution( - id: widget.id, + sessionId: ffi.sessionId, display: pi.currentDisplay, width: w, height: h, @@ -1254,12 +1264,15 @@ class _KeyboardMenu extends StatelessWidget { if (!ffiModel.keyboard) return Offstage(); String? modeOnly; if (stateGlobal.grabKeyboard) { - if (bind.sessionIsKeyboardModeSupported(id: id, mode: _kKeyMapMode)) { - bind.sessionSetKeyboardMode(id: id, value: _kKeyMapMode); + if (bind.sessionIsKeyboardModeSupported( + sessionId: ffi.sessionId, mode: _kKeyMapMode)) { + bind.sessionSetKeyboardMode( + sessionId: ffi.sessionId, value: _kKeyMapMode); modeOnly = _kKeyMapMode; } else if (bind.sessionIsKeyboardModeSupported( - id: id, mode: _kKeyLegacyMode)) { - bind.sessionSetKeyboardMode(id: id, value: _kKeyLegacyMode); + sessionId: ffi.sessionId, mode: _kKeyLegacyMode)) { + bind.sessionSetKeyboardMode( + sessionId: ffi.sessionId, value: _kKeyLegacyMode); modeOnly = _kKeyLegacyMode; } } @@ -1279,7 +1292,8 @@ class _KeyboardMenu extends StatelessWidget { mode(String? modeOnly) { return futureBuilder(future: () async { - return await bind.sessionGetKeyboardMode(id: id) ?? _kKeyLegacyMode; + return await bind.sessionGetKeyboardMode(sessionId: ffi.sessionId) ?? + _kKeyLegacyMode; }(), hasData: (data) { final groupValue = data as String; List modes = [ @@ -1291,14 +1305,15 @@ class _KeyboardMenu extends StatelessWidget { final enabled = !ffi.ffiModel.viewOnly; onChanged(String? value) async { if (value == null) return; - await bind.sessionSetKeyboardMode(id: id, value: value); + await bind.sessionSetKeyboardMode( + sessionId: ffi.sessionId, value: value); } for (KeyboardModeMenu mode in modes) { if (modeOnly != null && mode.key != modeOnly) { continue; } else if (!bind.sessionIsKeyboardModeSupported( - id: id, mode: mode.key)) { + sessionId: ffi.sessionId, mode: mode.key)) { continue; } @@ -1351,7 +1366,8 @@ class _KeyboardMenu extends StatelessWidget { onChanged: enabled ? (value) async { if (value == null) return; - await bind.sessionToggleOption(id: id, value: 'view-only'); + await bind.sessionToggleOption( + sessionId: ffi.sessionId, value: 'view-only'); ffiModel.setViewOnly(id, value); } : null, @@ -1412,7 +1428,8 @@ class _ChatMenuState extends State<_ChatMenu> { return MenuButton( child: Text(translate('Voice call')), ffi: widget.ffi, - onPressed: () => bind.sessionRequestVoiceCall(id: widget.id), + onPressed: () => + bind.sessionRequestVoiceCall(sessionId: widget.ffi.sessionId), ); } } @@ -1447,7 +1464,8 @@ class _VoiceCallMenu extends StatelessWidget { return _IconMenuButton( assetName: icon, tooltip: tooltip, - onPressed: () => bind.sessionCloseVoiceCall(id: id), + onPressed: () => + bind.sessionCloseVoiceCall(sessionId: ffi.sessionId), color: _MenubarTheme.redColor, hoverColor: _MenubarTheme.hoverRedColor); }, @@ -1492,7 +1510,7 @@ class _CloseMenu extends StatelessWidget { return _IconMenuButton( assetName: 'assets/close.svg', tooltip: 'Close', - onPressed: () => clientClose(id, ffi.dialogManager), + onPressed: () => clientClose(ffi.sessionId, ffi.dialogManager), color: _MenubarTheme.redColor, hoverColor: _MenubarTheme.hoverRedColor, ); @@ -1753,13 +1771,13 @@ class RdoMenuButton extends StatelessWidget { } class _DraggableShowHide extends StatefulWidget { - final String id; + final SessionID sessionId; final RxDouble fractionX; final RxBool dragging; final RxBool show; const _DraggableShowHide({ Key? key, - required this.id, + required this.sessionId, required this.fractionX, required this.dragging, required this.show, @@ -1826,7 +1844,7 @@ class _DraggableShowHideState extends State<_DraggableShowHide> { widget.fractionX.value = right; } bind.sessionPeerOption( - id: widget.id, + sessionId: widget.sessionId, name: 'remote-menubar-drag-x', value: widget.fractionX.value.toString(), ); @@ -1952,7 +1970,7 @@ class _MultiMonitorMenu extends StatelessWidget { ), onPressed: () { if (display.value != i) { - bind.sessionSwitchDisplay(id: id, value: i); + bind.sessionSwitchDisplay(sessionId: ffi.sessionId, value: i); } }, ); diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index b93aa5927..d17b77285 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -17,6 +17,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:get/get_rx/src/rx_workers/utils/debouncer.dart'; import 'package:scroll_pos/scroll_pos.dart'; +import 'package:uuid/uuid.dart'; import 'package:window_manager/window_manager.dart'; import '../../utils/multi_window_manager.dart'; diff --git a/flutter/lib/mobile/pages/file_manager_page.dart b/flutter/lib/mobile/pages/file_manager_page.dart index c2a97a1a0..709b0ba81 100644 --- a/flutter/lib/mobile/pages/file_manager_page.dart +++ b/flutter/lib/mobile/pages/file_manager_page.dart @@ -73,7 +73,7 @@ class _FileManagerPageState extends State { gFFI.dialogManager .showLoading(translate('Connecting...'), onCancel: closeConnection); }); - gFFI.ffiModel.updateEventListener(widget.id); + gFFI.ffiModel.updateEventListener(gFFI.sessionId, widget.id); Wakelock.enable(); } @@ -104,7 +104,8 @@ class _FileManagerPageState extends State { leading: Row(children: [ IconButton( icon: Icon(Icons.close), - onPressed: () => clientClose(widget.id, gFFI.dialogManager)), + onPressed: () => + clientClose(gFFI.sessionId, gFFI.dialogManager)), ]), centerTitle: true, title: ToggleSwitch( diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 1ce1faef1..7d629ff4e 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -54,6 +54,7 @@ class _RemotePageState extends State { var _showEdit = false; // use soft keyboard InputModel get inputModel => gFFI.inputModel; + SessionID get sessionId => gFFI.sessionId; @override void initState() { @@ -66,9 +67,9 @@ class _RemotePageState extends State { }); Wakelock.enable(); _physicalFocusNode.requestFocus(); - gFFI.ffiModel.updateEventListener(widget.id); + gFFI.ffiModel.updateEventListener(sessionId, widget.id); gFFI.inputModel.listenToMouse(true); - gFFI.qualityMonitorModel.checkShowQualityMonitor(widget.id); + gFFI.qualityMonitorModel.checkShowQualityMonitor(sessionId); keyboardSubscription = keyboardVisibilityController.onChange.listen(onSoftKeyboardChanged); _blockableOverlayState.applyFfi(gFFI); @@ -130,7 +131,7 @@ class _RemotePageState extends State { if (newValue.length > common) { var s = newValue.substring(common); if (s.length > 1) { - bind.sessionInputString(id: widget.id, value: s); + bind.sessionInputString(sessionId: sessionId, value: s); } else { inputChar(s); } @@ -164,11 +165,11 @@ class _RemotePageState extends State { content == '()' || content == '【】')) { // can not only input content[0], because when input ], [ are also auo insert, which cause ] never be input - bind.sessionInputString(id: widget.id, value: content); + bind.sessionInputString(sessionId: sessionId, value: content); openKeyboard(); return; } - bind.sessionInputString(id: widget.id, value: content); + bind.sessionInputString(sessionId: sessionId, value: content); } else { inputChar(content); } @@ -213,7 +214,7 @@ class _RemotePageState extends State { return WillPopScope( onWillPop: () async { - clientClose(widget.id, gFFI.dialogManager); + clientClose(sessionId, gFFI.dialogManager); return false; }, child: getRawPointerAndKeyBody(Scaffold( @@ -305,7 +306,7 @@ class _RemotePageState extends State { color: Colors.white, icon: Icon(Icons.clear), onPressed: () { - clientClose(widget.id, gFFI.dialogManager); + clientClose(sessionId, gFFI.dialogManager); }, ) ] + @@ -476,7 +477,7 @@ class _RemotePageState extends State { }, onTwoFingerScaleEnd: (d) { _scale = 1; - bind.sessionSetViewStyle(id: widget.id, value: ""); + bind.sessionSetViewStyle(sessionId: sessionId, value: ""); }, onThreeFingerVerticalDragUpdate: gFFI.ffiModel.isPeerAndroid ? null @@ -535,7 +536,7 @@ class _RemotePageState extends State { var paints = [ImagePaint()]; if (!gFFI.canvasModel.cursorEmbedded) { final cursor = bind.sessionGetToggleOptionSync( - id: widget.id, arg: 'show-remote-cursor'); + sessionId: sessionId, arg: 'show-remote-cursor'); if (keyboard || cursor) { paints.add(CursorPaint()); } @@ -579,7 +580,7 @@ class _RemotePageState extends State { gFFI.ffiModel.toggleTouchMode(); final v = gFFI.ffiModel.touchMode ? 'Y' : ''; bind.sessionPeerOption( - id: widget.id, name: "touch", value: v); + sessionId: sessionId, name: "touch", value: v); }))); } @@ -830,7 +831,7 @@ void showOptions( children.add(InkWell( onTap: () { if (i == cur) return; - bind.sessionSwitchDisplay(id: id, value: i); + bind.sessionSwitchDisplay(sessionId: gFFI.sessionId, value: i); gFFI.dialogManager.dismissAll(); }, child: Ink( diff --git a/flutter/lib/models/chat_model.dart b/flutter/lib/models/chat_model.dart index 21ffc1eef..34e5c0d6d 100644 --- a/flutter/lib/models/chat_model.dart +++ b/flutter/lib/models/chat_model.dart @@ -74,7 +74,11 @@ class ChatModel with ChangeNotifier { final WeakReference parent; - ChatModel(this.parent); + late final SessionID sessionId; + + ChatModel(this.parent) { + sessionId = parent.target!.sessionId; + } FocusNode inputNode = FocusNode(); @@ -302,7 +306,7 @@ class ChatModel with ChangeNotifier { _messages[_currentID]?.insert(message); if (_currentID == clientModeID) { if (parent.target != null) { - bind.sessionSendChat(id: parent.target!.id, text: message.text); + bind.sessionSendChat(sessionId: sessionId, text: message.text); } } else { bind.cmSendChat(connId: _currentID, msg: message.text); @@ -347,8 +351,8 @@ class ChatModel with ChangeNotifier { } } - void closeVoiceCall(String id) { - bind.sessionCloseVoiceCall(id: id); + void closeVoiceCall() { + bind.sessionCloseVoiceCall(sessionId: sessionId); } } diff --git a/flutter/lib/models/file_model.dart b/flutter/lib/models/file_model.dart index 04153d174..95a4cad0c 100644 --- a/flutter/lib/models/file_model.dart +++ b/flutter/lib/models/file_model.dart @@ -33,11 +33,11 @@ class JobID { } } -typedef GetSessionID = String Function(); +typedef GetSessionID = SessionID Function(); class FileModel { final WeakReference parent; - // late final String sessionID; + // late final String sessionId; late final FileFetcher fileFetcher; late final JobController jobController; @@ -45,11 +45,11 @@ class FileModel { late final FileController remoteController; late final GetSessionID getSessionID; - String get sessionID => getSessionID(); + SessionID get sessionId => getSessionID(); late final FileDialogEventLoop evtLoop; FileModel(this.parent) { - getSessionID = () => parent.target?.id ?? ""; + getSessionID = () => parent.target!.sessionId; fileFetcher = FileFetcher(getSessionID); jobController = JobController(getSessionID); localController = FileController( @@ -133,7 +133,7 @@ class FileModel { evtLoop.setSkip(!need_override); } await bind.sessionSetConfirmOverrideFile( - id: sessionID, + sessionId: sessionId, actId: id, fileNum: int.parse(evt['file_num']), needOverride: need_override, @@ -236,7 +236,7 @@ class DirectoryData { class FileController { final bool isLocal; final GetSessionID getSessionID; - String get sessionID => getSessionID(); + SessionID get sessionId => getSessionID(); final FileFetcher fileFetcher; @@ -287,7 +287,7 @@ class FileController { options.value.home = await bind.mainGetHomeDir(); } options.value.showHidden = (await bind.sessionGetPeerOption( - id: sessionID, + sessionId: sessionId, name: isLocal ? "local_show_hidden" : "remote_show_hidden")) .isNotEmpty; options.value.isWindows = isLocal @@ -297,7 +297,7 @@ class FileController { await Future.delayed(Duration(milliseconds: 100)); final dir = (await bind.sessionGetPeerOption( - id: sessionID, name: isLocal ? "local_dir" : "remote_dir")); + sessionId: sessionId, name: isLocal ? "local_dir" : "remote_dir")); openDirectory(dir.isEmpty ? options.value.home : dir); await Future.delayed(Duration(seconds: 1)); @@ -315,7 +315,7 @@ class FileController { options.value.showHidden ? "Y" : ""; for (final msg in msgMap.entries) { await bind.sessionPeerOption( - id: sessionID, name: msg.key, value: msg.value); + sessionId: sessionId, name: msg.key, value: msg.value); } directory.value.clear(); options.value.clear(); @@ -447,7 +447,7 @@ class FileController { for (var from in items.items) { final jobID = jobController.add(from, isRemoteToLocal); bind.sessionSendFiles( - id: sessionID, + sessionId: sessionId, actId: jobID, path: from.path, to: PathUtil.join(toPath, from.name, isWindows), @@ -547,7 +547,8 @@ class FileController { Future showRemoveDialog( String title, String content, bool showCheckbox) async { - return await dialogManager?.show((setState, Function(bool v) close, context) { + return await dialogManager?.show( + (setState, Function(bool v) close, context) { cancel() => close(false); submit() => close(true); return CustomAlertDialog( @@ -611,7 +612,7 @@ class FileController { void sendRemoveFile(String path, int fileNum) { bind.sessionRemoveFile( - id: sessionID, + sessionId: sessionId, actId: JobController.jobID.next(), path: path, isRemote: !isLocal, @@ -621,7 +622,7 @@ class FileController { void sendRemoveEmptyDir(String path, int fileNum) { history.removeWhere((element) => element.contains(path)); bind.sessionRemoveAllEmptyDirs( - id: sessionID, + sessionId: sessionId, actId: JobController.jobID.next(), path: path, isRemote: !isLocal); @@ -629,7 +630,7 @@ class FileController { Future createDir(String path) async { bind.sessionCreateDir( - id: sessionID, + sessionId: sessionId, actId: JobController.jobID.next(), path: path, isRemote: !isLocal); @@ -641,7 +642,7 @@ class JobController { final jobTable = List.empty(growable: true).obs; final jobResultListener = JobResultListener>(); final GetSessionID getSessionID; - String get sessionID => getSessionID(); + SessionID get sessionId => getSessionID(); JobController(this.getSessionID); @@ -719,7 +720,7 @@ class JobController { } Future cancelJob(int id) async { - await bind.sessionCancelJob(id: sessionID, actId: id); + await bind.sessionCancelJob(sessionId: sessionId, actId: id); } void loadLastJob(Map evt) { @@ -745,7 +746,7 @@ class JobController { ..state = JobState.paused; jobTable.add(jobProgress); bind.sessionAddJob( - id: sessionID, + sessionId: sessionId, isRemote: isRemote, includeHidden: showHidden, actId: currJobId, @@ -760,7 +761,7 @@ class JobController { if (jobIndex != -1) { final job = jobTable[jobIndex]; bind.sessionResumeJob( - id: sessionID, actId: job.id, isRemote: job.isRemoteToLocal); + sessionId: sessionId, actId: job.id, isRemote: job.isRemoteToLocal); job.state = JobState.inProgress; jobTable.refresh(); } else { @@ -831,7 +832,7 @@ class FileFetcher { Map> readRecursiveTasks = {}; final GetSessionID getSessionID; - String get sessionID => getSessionID(); + SessionID get sessionId => getSessionID(); FileFetcher(this.getSessionID); @@ -896,12 +897,12 @@ class FileFetcher { try { if (isLocal) { final res = await bind.sessionReadLocalDirSync( - id: sessionID, path: path, showHidden: showHidden); + sessionId: sessionId, path: path, showHidden: showHidden); final fd = FileDirectory.fromJson(jsonDecode(res)); return fd; } else { await bind.sessionReadRemoteDir( - id: sessionID, path: path, includeHidden: showHidden); + sessionId: sessionId, path: path, includeHidden: showHidden); return registerReadTask(isLocal, path); } } catch (e) { @@ -914,7 +915,7 @@ class FileFetcher { // TODO test Recursive is show hidden default? try { await bind.sessionReadDirRecursive( - id: sessionID, + sessionId: sessionId, actId: actID, path: path, isRemote: !isLocal, diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 9e85b2b82..640c4d79b 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -59,9 +59,13 @@ class InputModel { get id => parent.target?.id ?? ""; + late final SessionID sessionId; + bool get keyboardPerm => parent.target!.ffiModel.keyboard; - InputModel(this.parent); + InputModel(this.parent) { + sessionId = parent.target!.sessionId; + } KeyEventResult handleRawKeyEvent(FocusNode data, RawKeyEvent e) { if (isDesktop && !stateGlobal.grabKeyboard) { @@ -70,7 +74,7 @@ class InputModel { // * Currently mobile does not enable map mode if (isDesktop) { - bind.sessionGetKeyboardMode(id: id).then((result) { + bind.sessionGetKeyboardMode(sessionId: sessionId).then((result) { keyboardMode = result.toString(); }); } @@ -169,7 +173,7 @@ class InputModel { lockModes |= (1 << scrolllock); } bind.sessionHandleFlutterKeyEvent( - id: id, + sessionId: sessionId, name: name, platformCode: platformCode, positionCode: positionCode, @@ -204,7 +208,7 @@ class InputModel { void inputKey(String name, {bool? down, bool? press}) { if (!keyboardPerm) return; bind.sessionInputKey( - id: id, + sessionId: sessionId, name: name, down: down ?? false, press: press ?? true, @@ -264,7 +268,7 @@ class InputModel { /// Send scroll event with scroll distance [y]. void scroll(int y) { bind.sessionSendMouse( - id: id, + sessionId: sessionId, msg: json .encode(modify({'id': id, 'type': 'wheel', 'y': y.toString()}))); } @@ -287,7 +291,7 @@ class InputModel { void sendMouse(String type, MouseButtons button) { if (!keyboardPerm) return; bind.sessionSendMouse( - id: id, + sessionId: sessionId, msg: json.encode(modify({'type': type, 'buttons': button.value}))); } @@ -297,7 +301,7 @@ class InputModel { resetModifiers(); } _flingTimer?.cancel(); - bind.sessionEnterOrLeave(id: id, enter: enter); + bind.sessionEnterOrLeave(sessionId: sessionId, enter: enter); } /// Send mouse movement event with distance in [x] and [y]. @@ -306,7 +310,8 @@ class InputModel { var x2 = x.toInt(); var y2 = y.toInt(); bind.sessionSendMouse( - id: id, msg: json.encode(modify({'x': '$x2', 'y': '$y2'}))); + sessionId: sessionId, + msg: json.encode(modify({'x': '$x2', 'y': '$y2'}))); } void onPointHoverImage(PointerHoverEvent e) { @@ -333,7 +338,8 @@ class InputModel { var y = delta.dy.toInt(); if (x != 0 || y != 0) { bind.sessionSendMouse( - id: id, msg: '{"type": "trackpad", "x": "$x", "y": "$y"}'); + sessionId: sessionId, + msg: '{"type": "trackpad", "x": "$x", "y": "$y"}'); } } @@ -364,7 +370,8 @@ class InputModel { } bind.sessionSendMouse( - id: id, msg: '{"type": "trackpad", "x": "$dx", "y": "$dy"}'); + sessionId: sessionId, + msg: '{"type": "trackpad", "x": "$dx", "y": "$dy"}'); _scheduleFling(x, y, delay); }); } @@ -439,7 +446,8 @@ class InputModel { dy = 1; } bind.sessionSendMouse( - id: id, msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}'); + sessionId: sessionId, + msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}'); } } @@ -632,7 +640,7 @@ class InputModel { break; } evt['buttons'] = buttons; - bind.sessionSendMouse(id: id, msg: json.encode(evt)); + bind.sessionSendMouse(sessionId: sessionId, msg: json.encode(evt)); } /// Web only diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 17863e53f..a39af3474 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -27,6 +27,7 @@ import 'package:image/image.dart' as img2; import 'package:flutter_custom_cursor/cursor_manager.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; +import 'package:uuid/uuid.dart'; import 'package:window_manager/window_manager.dart'; import '../common.dart'; @@ -36,7 +37,7 @@ import 'input_model.dart'; import 'platform_model.dart'; typedef HandleMsgBox = Function(Map evt, String id); -typedef ReconnectHandle = Function(OverlayDialogManager, String, bool); +typedef ReconnectHandle = Function(OverlayDialogManager, SessionID, bool); final _waitForImage = {}; class FfiModel with ChangeNotifier { @@ -52,6 +53,7 @@ class FfiModel with ChangeNotifier { var _reconnects = 1; bool _viewOnly = false; WeakReference parent; + late final SessionID sessionId; Map get permissions => _permissions; @@ -77,6 +79,7 @@ class FfiModel with ChangeNotifier { FfiModel(this.parent) { clear(); + sessionId = parent.target!.sessionId; } toggleTouchMode() { @@ -139,20 +142,21 @@ class FfiModel with ChangeNotifier { _permissions.clear(); } - StreamEventHandler startEventListener(String peerId) { + // todo: why called by two position + StreamEventHandler startEventListener(SessionID sessionId, String peerId) { return (evt) async { var name = evt['name']; if (name == 'msgbox') { - handleMsgBox(evt, peerId); + handleMsgBox(evt, sessionId, peerId); } else if (name == 'peer_info') { handlePeerInfo(evt, peerId); } else if (name == 'sync_peer_info') { - handleSyncPeerInfo(evt, peerId); + handleSyncPeerInfo(evt, sessionId); } else if (name == 'connection_ready') { setConnectionType( peerId, evt['secure'] == 'true', evt['direct'] == 'true'); } else if (name == 'switch_display') { - handleSwitchDisplay(evt, peerId); + handleSwitchDisplay(evt, sessionId, peerId); } else if (name == 'cursor_data') { await parent.target?.cursorModel.updateCursorData(evt); } else if (name == 'cursor_id') { @@ -193,7 +197,7 @@ class FfiModel with ChangeNotifier { } else if (name == 'update_block_input_state') { updateBlockInputState(evt, peerId); } else if (name == 'update_privacy_mode') { - updatePrivacyMode(evt, peerId); + updatePrivacyMode(evt, sessionId, peerId); } else if (name == 'new_connection') { var uni_links = evt['uni_links'].toString(); if (uni_links.startsWith(kUniLinksPrefix)) { @@ -205,10 +209,10 @@ class FfiModel with ChangeNotifier { final show = evt['show'].toString() == 'true'; parent.target?.serverModel.setShowElevation(show); } else if (name == 'cancel_msgbox') { - cancelMsgBox(evt, peerId); + cancelMsgBox(evt, sessionId); } else if (name == 'switch_back') { final peer_id = evt['peer_id'].toString(); - await bind.sessionSwitchSides(id: peer_id); + await bind.sessionSwitchSides(sessionId: sessionId); closeConnection(id: peer_id); } else if (name == 'portable_service_running') { parent.target?.elevationModel.onPortableServiceRunning(evt); @@ -234,12 +238,12 @@ class FfiModel with ChangeNotifier { } else if (name == 'plugin_manager') { pluginManager.handleEvent(evt); } else if (name == 'plugin_event') { - handlePluginEvent( - evt, peerId, (Map e) => handleMsgBox(e, peerId)); + handlePluginEvent(evt, + (Map e) => handleMsgBox(e, sessionId, peerId)); } else if (name == 'plugin_reload') { - handleReloading(evt, peerId); + handleReloading(evt); } else if (name == 'plugin_option') { - handleOption(evt, peerId); + handleOption(evt); } else { debugPrint('Unknown event name: $name'); } @@ -271,8 +275,8 @@ class FfiModel with ChangeNotifier { } /// Bind the event listener to receive events from the Rust core. - updateEventListener(String peerId) { - platformFFI.setEventCallback(startEventListener(peerId)); + updateEventListener(SessionID sessionId, String peerId) { + platformFFI.setEventCallback(startEventListener(sessionId, peerId)); } handleAliasChanged(Map evt) { @@ -282,18 +286,19 @@ class FfiModel with ChangeNotifier { } } - _updateCurDisplay(String peerId, Display newDisplay) { + _updateCurDisplay(SessionID sessionId, Display newDisplay) { if (newDisplay != _display) { if (newDisplay.x != _display.x || newDisplay.y != _display.y) { parent.target?.cursorModel .updateDisplayOrigin(newDisplay.x, newDisplay.y); } _display = newDisplay; - _updateSessionWidthHeight(peerId); + _updateSessionWidthHeight(sessionId); } } - handleSwitchDisplay(Map evt, String peerId) { + handleSwitchDisplay( + Map evt, SessionID sessionId, String peerId) { _pi.currentDisplay = int.parse(evt['display']); var newDisplay = Display(); newDisplay.x = double.tryParse(evt['x']) ?? newDisplay.x; @@ -306,7 +311,7 @@ class FfiModel with ChangeNotifier { newDisplay.originalHeight = int.tryParse(evt['original_height']) ?? kInvalidResolutionValue; - _updateCurDisplay(peerId, newDisplay); + _updateCurDisplay(sessionId, newDisplay); try { CurrentDisplayState.find(peerId).value = _pi.currentDisplay; @@ -318,15 +323,15 @@ class FfiModel with ChangeNotifier { notifyListeners(); } - cancelMsgBox(Map evt, String id) { + cancelMsgBox(Map evt, SessionID sessionId) { if (parent.target == null) return; final dialogManager = parent.target!.dialogManager; - final tag = '$id-${evt['tag']}'; + final tag = '$sessionId-${evt['tag']}'; dialogManager.dismissByTag(tag); } /// Handle the message box event based on [evt] and [id]. - handleMsgBox(Map evt, String id) { + handleMsgBox(Map evt, SessionID sessionId, String peerId) { if (parent.target == null) return; final dialogManager = parent.target!.dialogManager; final type = evt['type']; @@ -334,43 +339,43 @@ class FfiModel with ChangeNotifier { final text = evt['text']; final link = evt['link']; if (type == 're-input-password') { - wrongPasswordDialog(id, dialogManager, type, title, text); + wrongPasswordDialog(sessionId, dialogManager, type, title, text); } else if (type == 'input-password') { - enterPasswordDialog(id, dialogManager); + enterPasswordDialog(sessionId, dialogManager); } else if (type == 'session-login' || type == 'session-re-login') { - enterUserLoginDialog(id, dialogManager); + enterUserLoginDialog(sessionId, dialogManager); } else if (type == 'session-login-password' || type == 'session-login-password') { - enterUserLoginAndPasswordDialog(id, dialogManager); + enterUserLoginAndPasswordDialog(sessionId, dialogManager); } else if (type == 'restarting') { - showMsgBox(id, type, title, text, link, false, dialogManager, + showMsgBox(sessionId, type, title, text, link, false, dialogManager, hasCancel: false); } else if (type == 'wait-remote-accept-nook') { - showWaitAcceptDialog(id, type, title, text, dialogManager); + showWaitAcceptDialog(sessionId, type, title, text, dialogManager); } else if (type == 'on-uac' || type == 'on-foreground-elevated') { - showOnBlockDialog(id, type, title, text, dialogManager); + showOnBlockDialog(sessionId, type, title, text, dialogManager); } else if (type == 'wait-uac') { - showWaitUacDialog(id, dialogManager, type); + showWaitUacDialog(sessionId, dialogManager, type); } else if (type == 'elevation-error') { - showElevationError(id, type, title, text, dialogManager); + showElevationError(sessionId, type, title, text, dialogManager); } else if (type == 'relay-hint') { - showRelayHintDialog(id, type, title, text, dialogManager); + showRelayHintDialog(sessionId, type, title, text, dialogManager); } else { var hasRetry = evt['hasRetry'] == 'true'; - showMsgBox(id, type, title, text, link, hasRetry, dialogManager); + showMsgBox(sessionId, type, title, text, link, hasRetry, dialogManager); } } /// Show a message box with [type], [title] and [text]. - showMsgBox(String id, String type, String title, String text, String link, - bool hasRetry, OverlayDialogManager dialogManager, + showMsgBox(SessionID sessionId, String type, String title, String text, + String link, bool hasRetry, OverlayDialogManager dialogManager, {bool? hasCancel}) { - msgBox(id, type, title, text, link, dialogManager, + msgBox(sessionId, type, title, text, link, dialogManager, hasCancel: hasCancel, reconnect: reconnect); _timer?.cancel(); if (hasRetry) { _timer = Timer(Duration(seconds: _reconnects), () { - reconnect(dialogManager, id, false); + reconnect(dialogManager, sessionId, false); }); _reconnects *= 2; } else { @@ -378,17 +383,17 @@ class FfiModel with ChangeNotifier { } } - void reconnect( - OverlayDialogManager dialogManager, String id, bool forceRelay) { - bind.sessionReconnect(id: id, forceRelay: forceRelay); + void reconnect(OverlayDialogManager dialogManager, SessionID sessionId, + bool forceRelay) { + bind.sessionReconnect(sessionId: sessionId, forceRelay: forceRelay); clearPermissions(); dialogManager.showLoading(translate('Connecting...'), onCancel: closeConnection); } - void showRelayHintDialog(String id, String type, String title, String text, - OverlayDialogManager dialogManager) { - dialogManager.show(tag: '$id-$type', (setState, close, context) { + void showRelayHintDialog(SessionID sessionId, String type, String title, + String text, OverlayDialogManager dialogManager) { + dialogManager.show(tag: '$sessionId-$type', (setState, close, context) { onClose() { closeConnection(); close(); @@ -403,15 +408,17 @@ class FfiModel with ChangeNotifier { actions: [ dialogButton('Close', onPressed: onClose, isOutline: true), dialogButton('Retry', - onPressed: () => reconnect(dialogManager, id, false)), + onPressed: () => reconnect(dialogManager, sessionId, false)), dialogButton('Connect via relay', - onPressed: () => reconnect(dialogManager, id, true), + onPressed: () => reconnect(dialogManager, sessionId, true), buttonStyle: style), dialogButton('Always connect via relay', onPressed: () { const option = 'force-always-relay'; bind.sessionPeerOption( - id: id, name: option, value: bool2option(option, true)); - reconnect(dialogManager, id, true); + sessionId: sessionId, + name: option, + value: bool2option(option, true)); + reconnect(dialogManager, sessionId, true); }, buttonStyle: style), ], onCancel: onClose, @@ -419,13 +426,14 @@ class FfiModel with ChangeNotifier { }); } - _updateSessionWidthHeight(String id) { + _updateSessionWidthHeight(SessionID sessionId) { parent.target?.canvasModel.updateViewStyle(); if (display.width <= 0 || display.height <= 0) { debugPrintStack( label: 'invalid display size (${display.width},${display.height})'); } else { - bind.sessionSetSize(id: id, width: display.width, height: display.height); + bind.sessionSetSize( + sessionId: sessionId, width: display.width, height: display.height); } } @@ -461,8 +469,9 @@ class FfiModel with ChangeNotifier { .showMobileActionsOverlay(ffi: parent.target!)); } } else { - _touchMode = - await bind.sessionGetOption(id: peerId, arg: 'touch-mode') != ''; + _touchMode = await bind.sessionGetOption( + sessionId: sessionId, arg: 'touch-mode') != + ''; } if (connType == ConnType.fileTransfer) { @@ -476,7 +485,7 @@ class FfiModel with ChangeNotifier { stateGlobal.displaysCount.value = _pi.displays.length; if (_pi.currentDisplay < _pi.displays.length) { _display = _pi.displays[_pi.currentDisplay]; - _updateSessionWidthHeight(peerId); + _updateSessionWidthHeight(sessionId); } if (displays.isNotEmpty) { parent.target?.dialogManager.showLoading( @@ -491,8 +500,10 @@ class FfiModel with ChangeNotifier { parent.target?.elevationModel.onPeerInfo(_pi); } if (connType == ConnType.defaultConn) { - setViewOnly(peerId, - bind.sessionGetToggleOptionSync(id: peerId, arg: 'view-only')); + setViewOnly( + peerId, + bind.sessionGetToggleOptionSync( + sessionId: sessionId, arg: 'view-only')); } if (connType == ConnType.defaultConn) { final platform_additions = evt['platform_additions']; @@ -547,7 +558,7 @@ class FfiModel with ChangeNotifier { } /// Handle the peer info synchronization event based on [evt]. - handleSyncPeerInfo(Map evt, String peerId) async { + handleSyncPeerInfo(Map evt, SessionID sessionId) async { if (evt['displays'] != null) { List displays = json.decode(evt['displays']); List newDisplays = []; @@ -557,7 +568,7 @@ class FfiModel with ChangeNotifier { _pi.displays = newDisplays; stateGlobal.displaysCount.value = _pi.displays.length; if (_pi.currentDisplay >= 0 && _pi.currentDisplay < _pi.displays.length) { - _updateCurDisplay(peerId, _pi.displays[_pi.currentDisplay]); + _updateCurDisplay(sessionId, _pi.displays[_pi.currentDisplay]); } } notifyListeners(); @@ -573,11 +584,12 @@ class FfiModel with ChangeNotifier { } } - updatePrivacyMode(Map evt, String peerId) { + updatePrivacyMode( + Map evt, SessionID sessionId, String peerId) { notifyListeners(); try { - PrivacyModeState.find(peerId).value = - bind.sessionGetToggleOptionSync(id: peerId, arg: 'privacy-mode'); + PrivacyModeState.find(peerId).value = bind.sessionGetToggleOptionSync( + sessionId: sessionId, arg: 'privacy-mode'); } catch (e) { // } @@ -592,8 +604,8 @@ class FfiModel with ChangeNotifier { if (value) { ShowRemoteCursorState.find(id).value = value; } else { - ShowRemoteCursorState.find(id).value = - bind.sessionGetToggleOptionSync(id: id, arg: 'show-remote-cursor'); + ShowRemoteCursorState.find(id).value = bind.sessionGetToggleOptionSync( + sessionId: sessionId, arg: 'show-remote-cursor'); } } catch (e) { // @@ -612,11 +624,15 @@ class ImageModel with ChangeNotifier { String id = ''; + late final SessionID sessionId; + WeakReference parent; final List callbacksOnFirstImage = []; - ImageModel(this.parent); + ImageModel(this.parent) { + sessionId = parent.target!.sessionId; + } addCallbackOnFirstImage(Function(String) cb) => callbacksOnFirstImage.add(cb); @@ -645,7 +661,7 @@ class ImageModel with ChangeNotifier { isWeb ? ui.PixelFormat.rgba8888 : ui.PixelFormat.bgra8888, onPixelsCopied: () { // Unlock the rgba memory from rust codes. - platformFFI.nextRgba(id); + platformFFI.nextRgba(sessionId); }).then((image) { if (parent.target?.id != pid) return; try { @@ -674,7 +690,7 @@ class ImageModel with ChangeNotifier { await initializeCursorAndCanvas(parent.target!); } if (parent.target?.ffiModel.isPeerAndroid ?? false) { - bind.sessionSetViewStyle(id: id, value: 'adaptive'); + bind.sessionSetViewStyle(sessionId: sessionId, value: 'adaptive'); parent.target?.canvasModel.updateViewStyle(); } } @@ -793,6 +809,7 @@ class CanvasModel with ChangeNotifier { // double windowBorderWidth = 0.0; // remote id String id = ''; + late final SessionID sessionId; // scroll offset x percent double _scrollX = 0.0; // scroll offset y percent @@ -804,7 +821,9 @@ class CanvasModel with ChangeNotifier { WeakReference parent; - CanvasModel(this.parent); + CanvasModel(this.parent) { + sessionId = parent.target!.sessionId; + } double get x => _x; double get y => _y; @@ -847,7 +866,7 @@ class CanvasModel with ChangeNotifier { return Size(w < 0 ? 0 : w, h < 0 ? 0 : h); } - final style = await bind.sessionGetViewStyle(id: id); + final style = await bind.sessionGetViewStyle(sessionId: sessionId); if (style == null) { return; } @@ -883,7 +902,7 @@ class CanvasModel with ChangeNotifier { } updateScrollStyle() async { - final style = await bind.sessionGetScrollStyle(id: id); + final style = await bind.sessionGetScrollStyle(sessionId: sessionId); if (style == kRemoteScrollStyleBar) { _scrollStyle = ScrollStyle.scrollbar; _resetScroll(); @@ -1358,8 +1377,8 @@ class CursorModel with ChangeNotifier { Future _updateCache( Uint8List rgba, ui.Image image, int id, int w, int h) async { Uint8List? data; - img2.Image imgOrigin = - img2.Image.fromBytes(width: w, height:h, bytes: rgba.buffer, order: img2.ChannelOrder.rgba); + img2.Image imgOrigin = img2.Image.fromBytes( + width: w, height: h, bytes: rgba.buffer, order: img2.ChannelOrder.rgba); if (Platform.isWindows) { data = imgOrigin.getBytes(order: img2.ChannelOrder.bgra); } else { @@ -1474,9 +1493,9 @@ class QualityMonitorModel with ChangeNotifier { bool get show => _show; QualityMonitorData get data => _data; - checkShowQualityMonitor(String id) async { + checkShowQualityMonitor(SessionID sessionId) async { final show = await bind.sessionGetToggleOption( - id: id, arg: 'show-quality-monitor') == + sessionId: sessionId, arg: 'show-quality-monitor') == true; if (_show != show) { _show = show; @@ -1510,32 +1529,35 @@ class RecordingModel with ChangeNotifier { onSwitchDisplay() { if (isIOS || !_start) return; - var id = parent.target?.id; + final sessionId = parent.target?.sessionId; int? width = parent.target?.canvasModel.getDisplayWidth(); int? height = parent.target?.canvasModel.getDisplayHeight(); - if (id == null || width == null || height == null) return; - bind.sessionRecordScreen(id: id, start: true, width: width, height: height); + if (sessionId == null || width == null || height == null) return; + bind.sessionRecordScreen( + sessionId: sessionId, start: true, width: width, height: height); } toggle() { if (isIOS) return; - var id = parent.target?.id; - if (id == null) return; + final sessionId = parent.target?.sessionId; + if (sessionId == null) return; _start = !_start; notifyListeners(); if (_start) { - bind.sessionRefresh(id: id); + bind.sessionRefresh(sessionId: sessionId); } else { - bind.sessionRecordScreen(id: id, start: false, width: 0, height: 0); + bind.sessionRecordScreen( + sessionId: sessionId, start: false, width: 0, height: 0); } } onClose() { if (isIOS) return; - var id = parent.target?.id; - if (id == null) return; + final sessionId = parent.target?.sessionId; + if (sessionId == null) return; _start = false; - bind.sessionRecordScreen(id: id, start: false, width: 0, height: 0); + bind.sessionRecordScreen( + sessionId: sessionId, start: false, width: 0, height: 0); } } @@ -1558,6 +1580,7 @@ enum ConnType { defaultConn, fileTransfer, portForward, rdp } /// Flutter state manager and data communication with the Rust core. class FFI { + final sessionId = Uuid().v4obj(); var id = ''; var version = ''; var connType = ConnType.defaultConn; @@ -1610,10 +1633,8 @@ class FFI { assert(!(isFileTransfer && isPortForward), 'more than one connect type'); if (isFileTransfer) { connType = ConnType.fileTransfer; - id = 'ft_$id'; } else if (isPortForward) { connType = ConnType.portForward; - id = 'pf_$id'; } else { chatModel.resetClientMode(); connType = ConnType.defaultConn; @@ -1623,6 +1644,7 @@ class FFI { } // ignore: unused_local_variable final addRes = bind.sessionAddSync( + sessionId: sessionId, id: id, isFileTransfer: isFileTransfer, isPortForward: isPortForward, @@ -1631,8 +1653,8 @@ class FFI { forceRelay: forceRelay ?? false, password: password ?? "", ); - final stream = bind.sessionStart(id: id); - final cb = ffiModel.startEventListener(id); + final stream = bind.sessionStart(sessionId: sessionId, id: id); + final cb = ffiModel.startEventListener(sessionId, id); () async { final useTextureRender = bind.mainUseTextureRender(); // Preserved for the rgba data. @@ -1664,11 +1686,11 @@ class FFI { } } else { // Fetch the image buffer from rust codes. - final sz = platformFFI.getRgbaSize(id); + final sz = platformFFI.getRgbaSize(sessionId); if (sz == null || sz == 0) { return; } - final rgba = platformFFI.getRgba(id, sz); + final rgba = platformFFI.getRgba(sessionId, sz); if (rgba != null) { imageModel.onRgba(rgba); } @@ -1682,10 +1704,10 @@ class FFI { } /// Login with [password], choose if the client should [remember] it. - void login(String osUsername, String osPassword, String id, String password, - bool remember) { + void login(String osUsername, String osPassword, SessionID sessionId, + String password, bool remember) { bind.sessionLogin( - id: id, + sessionId: sessionId, osUsername: osUsername, osPassword: osPassword, password: password, @@ -1696,15 +1718,21 @@ class FFI { Future close() async { chatModel.close(); if (imageModel.image != null && !isWebDesktop) { - await setCanvasConfig(id, cursorModel.x, cursorModel.y, canvasModel.x, - canvasModel.y, canvasModel.scale, ffiModel.pi.currentDisplay); + await setCanvasConfig( + sessionId, + cursorModel.x, + cursorModel.y, + canvasModel.x, + canvasModel.y, + canvasModel.scale, + ffiModel.pi.currentDisplay); } imageModel.update(null); cursorModel.clear(); ffiModel.clear(); canvasModel.clear(); inputModel.resetModifiers(); - await bind.sessionClose(id: id); + await bind.sessionClose(sessionId: sessionId); debugPrint('model $id closed'); id = ''; } @@ -1795,8 +1823,14 @@ class PeerInfo { const canvasKey = 'canvas'; -Future setCanvasConfig(String id, double xCursor, double yCursor, - double xCanvas, double yCanvas, double scale, int currentDisplay) async { +Future setCanvasConfig( + SessionID sessionId, + double xCursor, + double yCursor, + double xCanvas, + double yCanvas, + double scale, + int currentDisplay) async { final p = {}; p['xCursor'] = xCursor; p['yCursor'] = yCursor; @@ -1804,12 +1838,14 @@ Future setCanvasConfig(String id, double xCursor, double yCursor, p['yCanvas'] = yCanvas; p['scale'] = scale; p['currentDisplay'] = currentDisplay; - await bind.sessionSetFlutterConfig(id: id, k: canvasKey, v: jsonEncode(p)); + await bind.sessionSetFlutterConfig( + sessionId: sessionId, k: canvasKey, v: jsonEncode(p)); } -Future?> getCanvasConfig(String id) async { +Future?> getCanvasConfig(SessionID sessionId) async { if (!isWebDesktop) return null; - var p = await bind.sessionGetFlutterConfig(id: id, k: canvasKey); + var p = + await bind.sessionGetFlutterConfig(sessionId: sessionId, k: canvasKey); if (p == null || p.isEmpty) return null; try { Map m = json.decode(p); @@ -1819,12 +1855,8 @@ Future?> getCanvasConfig(String id) async { } } -void removePreference(String id) async { - await bind.sessionSetFlutterConfig(id: id, k: canvasKey, v: ''); -} - Future initializeCursorAndCanvas(FFI ffi) async { - var p = await getCanvasConfig(ffi.id); + var p = await getCanvasConfig(ffi.sessionId); int currentDisplay = 0; if (p != null) { currentDisplay = p['currentDisplay']; diff --git a/flutter/lib/models/native_model.dart b/flutter/lib/models/native_model.dart index 6da8dda27..bf8009005 100644 --- a/flutter/lib/models/native_model.dart +++ b/flutter/lib/models/native_model.dart @@ -104,9 +104,10 @@ class PlatformFFI { return res; } - Uint8List? getRgba(String id, int bufSize) { + Uint8List? getRgba(SessionID sessionId, int bufSize) { if (_session_get_rgba == null) return null; - var a = id.toNativeUtf8(); + final sessionIdStr = sessionId.toString(); + var a = sessionIdStr.toNativeUtf8(); try { final buffer = _session_get_rgba!(a); if (buffer == nullptr) { @@ -119,24 +120,27 @@ class PlatformFFI { } } - int? getRgbaSize(String id) { + int? getRgbaSize(SessionID sessionId) { if (_session_get_rgba_size == null) return null; - var a = id.toNativeUtf8(); + final sessionIdStr = sessionId.toString(); + var a = sessionIdStr.toNativeUtf8(); final bufferSize = _session_get_rgba_size!(a); malloc.free(a); return bufferSize; } - void nextRgba(String id) { + void nextRgba(SessionID sessionId) { if (_session_next_rgba == null) return; - final a = id.toNativeUtf8(); + final sessionIdStr = sessionId.toString(); + final a = sessionIdStr.toNativeUtf8(); _session_next_rgba!(a); malloc.free(a); } - void registerTexture(String id, int ptr) { + void registerTexture(SessionID sessionId, int ptr) { if (_session_register_texture == null) return; - final a = id.toNativeUtf8(); + final sessionIdStr = sessionId.toString(); + final a = sessionIdStr.toNativeUtf8(); _session_register_texture!(a, ptr); malloc.free(a); } diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index 44c4e0d74..a65c3ad52 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -343,7 +343,7 @@ class ServerModel with ChangeNotifier { Future startService() async { _isStart = true; notifyListeners(); - parent.target?.ffiModel.updateEventListener(""); + parent.target?.ffiModel.updateEventListener(parent.target!.sessionId, ""); await parent.target?.invokeMethod("init_service"); // ugly is here, because for desktop, below is useless await bind.mainStartService(); diff --git a/flutter/lib/plugin/event.dart b/flutter/lib/plugin/event.dart index 4b6f52aa9..29a2ae44c 100644 --- a/flutter/lib/plugin/event.dart +++ b/flutter/lib/plugin/event.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; void handlePluginEvent( Map evt, - String peer, Function(Map e) handleMsgBox, ) { Map? content; diff --git a/flutter/lib/plugin/widgets/desc_ui.dart b/flutter/lib/plugin/widgets/desc_ui.dart index d67b298b5..10c231f98 100644 --- a/flutter/lib/plugin/widgets/desc_ui.dart +++ b/flutter/lib/plugin/widgets/desc_ui.dart @@ -275,7 +275,7 @@ class PluginItem extends StatelessWidget { } } -void handleReloading(Map evt, String peer) { +void handleReloading(Map evt) { if (evt['id'] == null || evt['location'] == null) { return; } @@ -295,7 +295,7 @@ void handleReloading(Map evt, String peer) { } } -void handleOption(Map evt, String peer) { +void handleOption(Map evt) { updateOption( evt['location'], evt['id'], evt['peer'] ?? '', evt['key'], evt['value']); } diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index 17be53309..a01a5a02b 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -1331,7 +1331,7 @@ packages: source: hosted version: "3.0.3" uuid: - dependency: transitive + dependency: "direct main" description: name: uuid sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 278f6a7c7..a1388f067 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -95,6 +95,7 @@ dependencies: texture_rgba_renderer: ^0.0.16 percent_indicator: ^4.2.2 dropdown_button2: ^2.0.0 + uuid: ^3.0.7 dev_dependencies: icons_launcher: ^2.0.4 diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index e7a533d69..fb2255796 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -5,7 +5,7 @@ use hbb_common::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, Mutex as TokioMutex, }, - ResultType, + ResultType, SessionID, }; use serde_derive::{Deserialize, Serialize}; use std::{ @@ -59,7 +59,7 @@ struct ConnEnabled { } struct MsgChannel { - peer_id: String, + session_uuid: SessionID, conn_id: i32, sender: UnboundedSender, receiver: Arc>>, @@ -78,20 +78,23 @@ lazy_static::lazy_static! { static ref PROCESS_SIDE: RwLock = RwLock::new(ProcessSide::UnknownSide); } -pub fn get_client_conn_id(peer_id: &str) -> Option { +pub fn get_client_conn_id(session_uuid: &SessionID) -> Option { VEC_MSG_CHANNEL .read() .unwrap() .iter() - .find(|x| x.peer_id == peer_id.to_owned()) + .find(|x| x.session_uuid == session_uuid.to_owned()) .map(|x| x.conn_id) } pub fn get_rx_cliprdr_client( - peer_id: &str, + session_uuid: &SessionID, ) -> (i32, Arc>>) { let mut lock = VEC_MSG_CHANNEL.write().unwrap(); - match lock.iter().find(|x| x.peer_id == peer_id.to_owned()) { + match lock + .iter() + .find(|x| x.session_uuid == session_uuid.to_owned()) + { Some(msg_channel) => (msg_channel.conn_id, msg_channel.receiver.clone()), None => { let (sender, receiver) = unbounded_channel(); @@ -99,7 +102,7 @@ pub fn get_rx_cliprdr_client( let receiver2 = receiver.clone(); let conn_id = lock.len() as i32 + 1; let msg_channel = MsgChannel { - peer_id: peer_id.to_owned(), + session_uuid: session_uuid.to_owned(), conn_id, sender, receiver, @@ -119,7 +122,7 @@ pub fn get_rx_cliprdr_server(conn_id: i32) -> Arc Remote { || self.handler.is_rdp(); if !is_conn_not_default { (self.client_conn_id, rx_clip_client_lock) = - clipboard::get_rx_cliprdr_client(&self.handler.id); + clipboard::get_rx_cliprdr_client(&self.handler.session_id); }; } #[cfg(windows)] @@ -262,7 +262,7 @@ impl Remote { } } #[cfg(not(any(target_os = "android", target_os = "ios")))] - Client::try_stop_clipboard(&self.handler.id); + Client::try_stop_clipboard(&self.handler.session_id); } fn handle_job_status(&mut self, id: i32, file_num: i32, err: Option) { diff --git a/src/flutter.rs b/src/flutter.rs index 1748d63df..08bc7bb5e 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -1,11 +1,11 @@ use crate::{ client::*, - flutter_ffi::EventToUI, + flutter_ffi::{EventToUI, SessionID}, ui_session_interface::{io_loop, InvokeUiSession, Session}, }; use flutter_rust_bridge::StreamSink; use hbb_common::{ - bail, config::LocalConfig, get_version_number, log, message_proto::*, + anyhow::anyhow, bail, config::LocalConfig, get_version_number, log, message_proto::*, rendezvous_proto::ConnType, ResultType, }; #[cfg(feature = "flutter_texture_render")] @@ -24,6 +24,7 @@ use std::{ collections::HashMap, ffi::CString, os::raw::{c_char, c_int}, + str::FromStr, sync::{Arc, RwLock}, }; @@ -40,8 +41,8 @@ pub(crate) const APP_TYPE_DESKTOP_FILE_TRANSFER: &str = "file transfer"; pub(crate) const APP_TYPE_DESKTOP_PORT_FORWARD: &str = "port forward"; lazy_static::lazy_static! { - pub(crate) static ref CUR_SESSION_ID: RwLock = Default::default(); - pub(crate) static ref SESSIONS: RwLock>> = Default::default(); + pub(crate) static ref CUR_SESSION_ID: RwLock = Default::default(); + pub(crate) static ref SESSIONS: RwLock>> = Default::default(); static ref GLOBAL_EVENT_STREAM: RwLock>> = Default::default(); // rust to dart event channel } @@ -695,6 +696,7 @@ impl InvokeUiSession for FlutterHandler { /// * `is_file_transfer` - If the session is used for file transfer. /// * `is_port_forward` - If the session is used for port forward. pub fn session_add( + session_id: &SessionID, id: &str, is_file_transfer: bool, is_port_forward: bool, @@ -703,11 +705,11 @@ pub fn session_add( force_relay: bool, password: String, ) -> ResultType> { - let session_id = get_session_id(id.to_owned()); - LocalConfig::set_remote_id(&session_id); + LocalConfig::set_remote_id(&id); let session: Session = Session { - id: session_id.clone(), + session_id: session_id.clone(), + id: id.to_owned(), password, server_keyboard_enabled: Arc::new(RwLock::new(true)), server_file_transfer_enabled: Arc::new(RwLock::new(true)), @@ -737,13 +739,14 @@ pub fn session_add( .lc .write() .unwrap() - .initialize(session_id, conn_type, switch_uuid, force_relay); + .initialize(id.to_owned(), conn_type, switch_uuid, force_relay); if let Some(same_id_session) = SESSIONS .write() .unwrap() - .insert(id.to_owned(), session.clone()) + .insert(session_id.to_owned(), session.clone()) { + log::error!("Should not happen"); same_id_session.close(); } @@ -756,8 +759,12 @@ pub fn session_add( /// /// * `id` - The identifier of the remote session with prefix. Regex: [\w]*[\_]*[\d]+ /// * `events2ui` - The events channel to ui. -pub fn session_start_(id: &str, event_stream: StreamSink) -> ResultType<()> { - if let Some(session) = SESSIONS.write().unwrap().get_mut(id) { +pub fn session_start_( + session_id: &SessionID, + id: &str, + event_stream: StreamSink, +) -> ResultType<()> { + if let Some(session) = SESSIONS.write().unwrap().get_mut(session_id) { #[cfg(feature = "flutter_texture_render")] log::info!( "Session {} start, render by flutter texture rgba plugin", @@ -788,8 +795,14 @@ pub fn update_text_clipboard_required() { #[inline] #[cfg(not(any(target_os = "android", target_os = "ios")))] -pub fn other_sessions_running(id: &str) -> bool { - SESSIONS.read().unwrap().keys().filter(|k| *k != id).count() != 0 +pub fn other_sessions_running(session_id: &SessionID) -> bool { + SESSIONS + .read() + .unwrap() + .keys() + .filter(|k| *k != session_id) + .count() + != 0 } #[cfg(not(any(target_os = "android", target_os = "ios")))] @@ -928,15 +941,6 @@ pub mod connection_manager { } } -#[inline] -pub fn get_session_id(id: String) -> String { - return if let Some(index) = id.find('_') { - id[index + 1..].to_string() - } else { - id - }; -} - pub fn make_fd_flutter(id: i32, entries: &Vec, only_count: bool) -> String { let mut m = serde_json::Map::new(); m.insert("id".into(), json!(id)); @@ -964,13 +968,13 @@ pub fn make_fd_flutter(id: i32, entries: &Vec, only_count: bool) -> S serde_json::to_string(&m).unwrap_or("".into()) } -pub fn get_cur_session_id() -> String { +pub fn get_cur_session_id() -> SessionID { CUR_SESSION_ID.read().unwrap().clone() } -pub fn set_cur_session_id(id: String) { - if get_cur_session_id() != id { - *CUR_SESSION_ID.write().unwrap() = id; +pub fn set_cur_session_id(session_id: SessionID) { + if get_cur_session_id() != session_id { + *CUR_SESSION_ID.write().unwrap() = session_id; } } @@ -995,12 +999,17 @@ fn serialize_resolutions(resolutions: &Vec) -> String { serde_json::ser::to_string(&v).unwrap_or("".to_string()) } +fn char_to_session_id(c: *const char) -> ResultType { + let cstr = unsafe { std::ffi::CStr::from_ptr(c as _) }; + let str = cstr.to_str()?; + SessionID::from_str(str).map_err(|e| anyhow!("{:?}", e)) +} + #[no_mangle] -#[cfg(not(feature = "flutter_texture_render"))] -pub fn session_get_rgba_size(id: *const char) -> usize { - let id = unsafe { std::ffi::CStr::from_ptr(id as _) }; - if let Ok(id) = id.to_str() { - if let Some(session) = SESSIONS.read().unwrap().get(id) { +pub fn session_get_rgba_size(_session_uuid_str: *const char) -> usize { + #[cfg(not(feature = "flutter_texture_render"))] + if let Ok(session_id) = char_to_session_id(_session_uuid_str) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { return session.rgba.read().unwrap().len(); } } @@ -1008,27 +1017,20 @@ pub fn session_get_rgba_size(id: *const char) -> usize { } #[no_mangle] -#[cfg(feature = "flutter_texture_render")] -pub fn session_get_rgba_size(_id: *const char) -> usize { - 0 -} - -#[no_mangle] -pub fn session_get_rgba(id: *const char) -> *const u8 { - let id = unsafe { std::ffi::CStr::from_ptr(id as _) }; - if let Ok(id) = id.to_str() { - if let Some(session) = SESSIONS.read().unwrap().get(id) { +pub fn session_get_rgba(session_uuid_str: *const char) -> *const u8 { + if let Ok(session_id) = char_to_session_id(session_uuid_str) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { return session.get_rgba(); } } + std::ptr::null() } #[no_mangle] -pub fn session_next_rgba(id: *const char) { - let id = unsafe { std::ffi::CStr::from_ptr(id as _) }; - if let Ok(id) = id.to_str() { - if let Some(session) = SESSIONS.read().unwrap().get(id) { +pub fn session_next_rgba(session_uuid_str: *const char) { + if let Ok(session_id) = char_to_session_id(session_uuid_str) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { return session.next_rgba(); } } @@ -1036,24 +1038,26 @@ pub fn session_next_rgba(id: *const char) { #[inline] #[no_mangle] -#[cfg(feature = "flutter_texture_render")] -pub fn session_register_texture(id: *const char, ptr: usize) { - let id = unsafe { std::ffi::CStr::from_ptr(id as _) }; - if let Ok(id) = id.to_str() { - if let Some(session) = SESSIONS.write().unwrap().get_mut(id) { - return session.register_texture(ptr); +pub fn session_register_texture(_session_uuid_str: *const char, _ptr: usize) { + #[cfg(feature = "flutter_texture_render")] + if let Ok(session_id) = char_to_session_id(_session_uuid_str) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { + return session.register_texture(_ptr); } } } #[inline] -#[no_mangle] -#[cfg(not(feature = "flutter_texture_render"))] -pub fn session_register_texture(_id: *const char, _ptr: usize) {} - -#[inline] -pub fn push_session_event(peer: &str, name: &str, event: Vec<(&str, &str)>) -> Option { - SESSIONS.read().unwrap().get(peer)?.push_event(name, event) +pub fn push_session_event( + session_id: &SessionID, + name: &str, + event: Vec<(&str, &str)>, +) -> Option { + SESSIONS + .read() + .unwrap() + .get(session_id)? + .push_event(name, event) } #[inline] diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 7d4962dc9..33227a721 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -28,7 +28,7 @@ use std::{ time::SystemTime, }; -// use crate::hbbs_http::account::AuthResult; +pub type SessionID = uuid::Uuid; fn initialize(app_dir: &str) { *config::APP_DIR.write().unwrap() = app_dir.to_owned(); @@ -74,6 +74,7 @@ pub fn host_stop_system_key_propagate(_stopped: bool) { // FIXME: -> ResultType<()> cannot be parsed by frb_codegen // thread 'main' panicked at 'Failed to parse function output type `ResultType<()>`', $HOME\.cargo\git\checkouts\flutter_rust_bridge-ddba876d3ebb2a1e\e5adce5\frb_codegen\src\parser\mod.rs:151:25 pub fn session_add_sync( + session_id: SessionID, id: String, is_file_transfer: bool, is_port_forward: bool, @@ -83,6 +84,7 @@ pub fn session_add_sync( password: String, ) -> SyncReturn { if let Err(e) = session_add( + &session_id, &id, is_file_transfer, is_port_forward, @@ -97,33 +99,37 @@ pub fn session_add_sync( } } -pub fn session_start(events2ui: StreamSink, id: String) -> ResultType<()> { - session_start_(&id, events2ui) +pub fn session_start( + events2ui: StreamSink, + session_id: SessionID, + id: String, +) -> ResultType<()> { + session_start_(&session_id, &id, events2ui) } -pub fn session_get_remember(id: String) -> Option { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_get_remember(session_id: SessionID) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { Some(session.get_remember()) } else { None } } -pub fn session_get_toggle_option(id: String, arg: String) -> Option { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_get_toggle_option(session_id: SessionID, arg: String) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { Some(session.get_toggle_option(arg)) } else { None } } -pub fn session_get_toggle_option_sync(id: String, arg: String) -> SyncReturn { - let res = session_get_toggle_option(id, arg) == Some(true); +pub fn session_get_toggle_option_sync(session_id: SessionID, arg: String) -> SyncReturn { + let res = session_get_toggle_option(session_id, arg) == Some(true); SyncReturn(res) } -pub fn session_get_option(id: String, arg: String) -> Option { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_get_option(session_id: SessionID, arg: String) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { Some(session.get_option(arg)) } else { None @@ -131,63 +137,63 @@ pub fn session_get_option(id: String, arg: String) -> Option { } pub fn session_login( - id: String, + session_id: SessionID, os_username: String, os_password: String, password: String, remember: bool, ) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.login(os_username, os_password, password, remember); } } -pub fn session_close(id: String) { - if let Some(mut session) = SESSIONS.write().unwrap().remove(&id) { +pub fn session_close(session_id: SessionID) { + if let Some(mut session) = SESSIONS.write().unwrap().remove(&session_id) { session.close_event_stream(); session.close(); } } -pub fn session_refresh(id: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_refresh(session_id: SessionID) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.refresh_video(); } } -pub fn session_record_screen(id: String, start: bool, width: usize, height: usize) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_record_screen(session_id: SessionID, start: bool, width: usize, height: usize) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.record_screen(start, width as _, height as _); } } -pub fn session_reconnect(id: String, force_relay: bool) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_reconnect(session_id: SessionID, force_relay: bool) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.reconnect(force_relay); } } -pub fn session_toggle_option(id: String, value: String) { - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { +pub fn session_toggle_option(session_id: SessionID, value: String) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { log::warn!("toggle option {}", &value); session.toggle_option(value.clone()); } #[cfg(not(any(target_os = "android", target_os = "ios")))] - if SESSIONS.read().unwrap().get(&id).is_some() && value == "disable-clipboard" { + if SESSIONS.read().unwrap().get(&session_id).is_some() && value == "disable-clipboard" { crate::flutter::update_text_clipboard_required(); } } -pub fn session_get_flutter_config(id: String, k: String) -> Option { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_get_flutter_config(session_id: SessionID, k: String) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { Some(session.get_flutter_config(k)) } else { None } } -pub fn session_set_flutter_config(id: String, k: String, v: String) { - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { +pub fn session_set_flutter_config(session_id: SessionID, k: String, v: String) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { session.save_flutter_config(k, v); } } @@ -208,59 +214,59 @@ pub fn set_local_kb_layout_type(kb_layout_type: String) { ui_interface::set_kb_layout_type(kb_layout_type) } -pub fn session_get_view_style(id: String) -> Option { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_get_view_style(session_id: SessionID) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { Some(session.get_view_style()) } else { None } } -pub fn session_set_view_style(id: String, value: String) { - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { +pub fn session_set_view_style(session_id: SessionID, value: String) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { session.save_view_style(value); } } -pub fn session_get_scroll_style(id: String) -> Option { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_get_scroll_style(session_id: SessionID) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { Some(session.get_scroll_style()) } else { None } } -pub fn session_set_scroll_style(id: String, value: String) { - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { +pub fn session_set_scroll_style(session_id: SessionID, value: String) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { session.save_scroll_style(value); } } -pub fn session_get_image_quality(id: String) -> Option { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_get_image_quality(session_id: SessionID) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { Some(session.get_image_quality()) } else { None } } -pub fn session_set_image_quality(id: String, value: String) { - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { +pub fn session_set_image_quality(session_id: SessionID, value: String) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { session.save_image_quality(value); } } -pub fn session_get_keyboard_mode(id: String) -> Option { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_get_keyboard_mode(session_id: SessionID) -> Option { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { Some(session.get_keyboard_mode()) } else { None } } -pub fn session_set_keyboard_mode(id: String, value: String) { +pub fn session_set_keyboard_mode(session_id: SessionID, value: String) { let mut _mode_updated = false; - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { session.save_keyboard_mode(value); _mode_updated = true; } @@ -270,16 +276,16 @@ pub fn session_set_keyboard_mode(id: String, value: String) { } } -pub fn session_get_custom_image_quality(id: String) -> Option> { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_get_custom_image_quality(session_id: SessionID) -> Option> { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { Some(session.get_custom_image_quality()) } else { None } } -pub fn session_is_keyboard_mode_supported(id: String, mode: String) -> SyncReturn { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_is_keyboard_mode_supported(session_id: SessionID, mode: String) -> SyncReturn { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { if let Ok(mode) = KeyboardMode::from_str(&mode[..]) { SyncReturn(is_keyboard_mode_supported( &mode, @@ -293,45 +299,45 @@ pub fn session_is_keyboard_mode_supported(id: String, mode: String) -> SyncRetur } } -pub fn session_set_custom_image_quality(id: String, value: i32) { - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { +pub fn session_set_custom_image_quality(session_id: SessionID, value: i32) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { session.save_custom_image_quality(value); } } -pub fn session_set_custom_fps(id: String, fps: i32) { - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { +pub fn session_set_custom_fps(session_id: SessionID, fps: i32) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { session.set_custom_fps(fps); } } -pub fn session_lock_screen(id: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_lock_screen(session_id: SessionID) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.lock_screen(); } } -pub fn session_ctrl_alt_del(id: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_ctrl_alt_del(session_id: SessionID) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.ctrl_alt_del(); } } -pub fn session_switch_display(id: String, value: i32) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_switch_display(session_id: SessionID, value: i32) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.switch_display(value); } } pub fn session_handle_flutter_key_event( - id: String, + session_id: SessionID, name: String, platform_code: i32, position_code: i32, lock_modes: i32, down_or_up: bool, ) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.handle_flutter_key_event( &name, platform_code, @@ -342,9 +348,9 @@ pub fn session_handle_flutter_key_event( } } -pub fn session_enter_or_leave(_id: String, _enter: bool) { +pub fn session_enter_or_leave(_session_id: SessionID, _enter: bool) { #[cfg(not(any(target_os = "android", target_os = "ios")))] - if let Some(session) = SESSIONS.read().unwrap().get(&_id) { + if let Some(session) = SESSIONS.read().unwrap().get(&_session_id) { if _enter { session.enter(); } else { @@ -354,7 +360,7 @@ pub fn session_enter_or_leave(_id: String, _enter: bool) { } pub fn session_input_key( - id: String, + session_id: SessionID, name: String, down: bool, press: bool, @@ -363,54 +369,54 @@ pub fn session_input_key( shift: bool, command: bool, ) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { // #[cfg(any(target_os = "android", target_os = "ios"))] session.input_key(&name, down, press, alt, ctrl, shift, command); } } -pub fn session_input_string(id: String, value: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_input_string(session_id: SessionID, value: String) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { // #[cfg(any(target_os = "android", target_os = "ios"))] session.input_string(&value); } } // chat_client_mode -pub fn session_send_chat(id: String, text: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_send_chat(session_id: SessionID, text: String) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.send_chat(text); } } -pub fn session_peer_option(id: String, name: String, value: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_peer_option(session_id: SessionID, name: String, value: String) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.set_option(name, value); } } -pub fn session_get_peer_option(id: String, name: String) -> String { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_get_peer_option(session_id: SessionID, name: String) -> String { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { return session.get_option(name); } "".to_string() } -pub fn session_input_os_password(id: String, value: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_input_os_password(session_id: SessionID, value: String) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.input_os_password(value, true); } } // File Action -pub fn session_read_remote_dir(id: String, path: String, include_hidden: bool) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_read_remote_dir(session_id: SessionID, path: String, include_hidden: bool) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.read_remote_dir(path, include_hidden); } } pub fn session_send_files( - id: String, + session_id: SessionID, act_id: i32, path: String, to: String, @@ -418,76 +424,91 @@ pub fn session_send_files( include_hidden: bool, is_remote: bool, ) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.send_files(act_id, path, to, file_num, include_hidden, is_remote); } } pub fn session_set_confirm_override_file( - id: String, + session_id: SessionID, act_id: i32, file_num: i32, need_override: bool, remember: bool, is_upload: bool, ) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.set_confirm_override_file(act_id, file_num, need_override, remember, is_upload); } } -pub fn session_remove_file(id: String, act_id: i32, path: String, file_num: i32, is_remote: bool) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_remove_file( + session_id: SessionID, + act_id: i32, + path: String, + file_num: i32, + is_remote: bool, +) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.remove_file(act_id, path, file_num, is_remote); } } pub fn session_read_dir_recursive( - id: String, + session_id: SessionID, act_id: i32, path: String, is_remote: bool, show_hidden: bool, ) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.remove_dir_all(act_id, path, is_remote, show_hidden); } } -pub fn session_remove_all_empty_dirs(id: String, act_id: i32, path: String, is_remote: bool) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_remove_all_empty_dirs( + session_id: SessionID, + act_id: i32, + path: String, + is_remote: bool, +) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.remove_dir(act_id, path, is_remote); } } -pub fn session_cancel_job(id: String, act_id: i32) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_cancel_job(session_id: SessionID, act_id: i32) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.cancel_job(act_id); } } -pub fn session_create_dir(id: String, act_id: i32, path: String, is_remote: bool) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_create_dir(session_id: SessionID, act_id: i32, path: String, is_remote: bool) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.create_dir(act_id, path, is_remote); } } -pub fn session_read_local_dir_sync(_id: String, path: String, show_hidden: bool) -> String { +pub fn session_read_local_dir_sync( + _session_id: SessionID, + path: String, + show_hidden: bool, +) -> String { if let Ok(fd) = fs::read_dir(&fs::get_path(&path), show_hidden) { return make_fd_to_json(fd.id, path, &fd.entries); } "".to_string() } -pub fn session_get_platform(id: String, is_remote: bool) -> String { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_get_platform(session_id: SessionID, is_remote: bool) -> String { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { return session.get_platform(is_remote); } "".to_string() } -pub fn session_load_last_transfer_jobs(id: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_load_last_transfer_jobs(session_id: SessionID) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { return session.load_last_jobs(); } else { // a tip for flutter dev @@ -499,7 +520,7 @@ pub fn session_load_last_transfer_jobs(id: String) { } pub fn session_add_job( - id: String, + session_id: SessionID, act_id: i32, path: String, to: String, @@ -507,44 +528,44 @@ pub fn session_add_job( include_hidden: bool, is_remote: bool, ) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.add_job(act_id, path, to, file_num, include_hidden, is_remote); } } -pub fn session_resume_job(id: String, act_id: i32, is_remote: bool) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_resume_job(session_id: SessionID, act_id: i32, is_remote: bool) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.resume_job(act_id, is_remote); } } -pub fn session_elevate_direct(id: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_elevate_direct(session_id: SessionID) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.elevate_direct(); } } -pub fn session_elevate_with_logon(id: String, username: String, password: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_elevate_with_logon(session_id: SessionID, username: String, password: String) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.elevate_with_logon(username, password); } } -pub fn session_switch_sides(id: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_switch_sides(session_id: SessionID) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.switch_sides(); } } -pub fn session_change_resolution(id: String, display: i32, width: i32, height: i32) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_change_resolution(session_id: SessionID, display: i32, width: i32, height: i32) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.change_resolution(display, width, height); } } -pub fn session_set_size(_id: String, _width: usize, _height: usize) { +pub fn session_set_size(_session_id: SessionID, _width: usize, _height: usize) { #[cfg(feature = "flutter_texture_render")] - if let Some(session) = SESSIONS.write().unwrap().get_mut(&_id) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&_session_id) { session.set_size(_width, _height); } } @@ -897,36 +918,36 @@ pub fn main_get_current_display() -> SyncReturn { } pub fn session_add_port_forward( - id: String, + session_id: SessionID, local_port: i32, remote_host: String, remote_port: i32, ) { - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { session.add_port_forward(local_port, remote_host, remote_port); } } -pub fn session_remove_port_forward(id: String, local_port: i32) { - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { +pub fn session_remove_port_forward(session_id: SessionID, local_port: i32) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { session.remove_port_forward(local_port); } } -pub fn session_new_rdp(id: String) { - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { +pub fn session_new_rdp(session_id: SessionID) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { session.new_rdp(); } } -pub fn session_request_voice_call(id: String) { - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { +pub fn session_request_voice_call(session_id: SessionID) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { session.request_voice_call(); } } -pub fn session_close_voice_call(id: String) { - if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { +pub fn session_close_voice_call(session_id: SessionID) { + if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) { session.close_voice_call(); } } @@ -1038,7 +1059,7 @@ pub fn main_start_dbus_server() { } } -pub fn session_send_mouse(id: String, msg: String) { +pub fn session_send_mouse(session_id: SessionID, msg: String) { if let Ok(m) = serde_json::from_str::>(&msg) { let alt = m.get("alt").is_some(); let ctrl = m.get("ctrl").is_some(); @@ -1072,20 +1093,20 @@ pub fn session_send_mouse(id: String, msg: String) { _ => 0, } << 3; } - if let Some(session) = SESSIONS.read().unwrap().get(&id) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.send_mouse(mask, x, y, alt, ctrl, shift, command); } } } -pub fn session_restart_remote_device(id: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_restart_remote_device(session_id: SessionID) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.restart_remote_device(); } } -pub fn session_get_audit_server_sync(id: String, typ: String) -> SyncReturn { - let res = if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_get_audit_server_sync(session_id: SessionID, typ: String) -> SyncReturn { + let res = if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.get_audit_server(typ) } else { "".to_owned() @@ -1093,14 +1114,14 @@ pub fn session_get_audit_server_sync(id: String, typ: String) -> SyncReturn String { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_alternative_codecs(session_id: SessionID) -> String { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { let (vp8, av1, h264, h265) = session.alternative_codecs(); let msg = HashMap::from([("vp8", vp8), ("av1", av1), ("h264", h264), ("h265", h265)]); serde_json::ser::to_string(&msg).unwrap_or("".to_owned()) @@ -1109,8 +1130,8 @@ pub fn session_alternative_codecs(id: String) -> String { } } -pub fn session_change_prefer_codec(id: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { +pub fn session_change_prefer_codec(session_id: SessionID) { + if let Some(session) = SESSIONS.read().unwrap().get(&session_id) { session.change_prefer_codec(); } } @@ -1338,8 +1359,8 @@ pub fn main_update_me() -> SyncReturn { SyncReturn(true) } -pub fn set_cur_session_id(id: String) { - super::flutter::set_cur_session_id(id); +pub fn set_cur_session_id(session_id: SessionID) { + super::flutter::set_cur_session_id(session_id); #[cfg(windows)] crate::keyboard::update_grab_get_key_name(); } diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index be67adb8a..5fd1ef918 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -28,7 +28,7 @@ use hbb_common::{ sync::mpsc, time::{Duration as TokioDuration, Instant}, }, - Stream, + SessionID, Stream, }; use crate::client::io_loop::Remote; @@ -49,7 +49,8 @@ const CHANGE_RESOLUTION_VALID_TIMEOUT_SECS: u64 = 15; #[derive(Clone, Default)] pub struct Session { - pub id: String, + pub session_id: SessionID, + pub id: String, // peer id pub password: String, pub args: Vec, pub lc: Arc>,