use uuid as session id

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2023-06-06 07:39:44 +08:00
parent 71838ad821
commit 2ececed0c1
36 changed files with 706 additions and 546 deletions

View File

@ -61,7 +61,7 @@ jobs:
- name: Install flutter rust bridge deps - name: Install flutter rust bridge deps
shell: bash shell: bash
run: | 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 pushd flutter && flutter pub get && popd
- name: Run flutter rust bridge - name: Run flutter rust bridge

View File

@ -79,7 +79,7 @@ jobs:
- name: Install flutter rust bridge deps - name: Install flutter rust bridge deps
run: | 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 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 ~/.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 - name: Install flutter rust bridge deps
shell: bash shell: bash
run: | 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 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 ~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart

3
Cargo.lock generated
View File

@ -58,6 +58,7 @@ dependencies = [
"anyhow", "anyhow",
"atomic", "atomic",
"chrono", "chrono",
"uuid",
] ]
[[package]] [[package]]
@ -2103,6 +2104,7 @@ dependencies = [
"log", "log",
"parking_lot", "parking_lot",
"threadpool", "threadpool",
"uuid",
"wasm-bindgen", "wasm-bindgen",
"web-sys", "web-sys",
] ]
@ -2878,6 +2880,7 @@ dependencies = [
"tokio-socks", "tokio-socks",
"tokio-util", "tokio-util",
"toml 0.7.3", "toml 0.7.3",
"uuid",
"winapi 0.3.9", "winapi 0.3.9",
"zstd 0.12.3+zstd.1.5.2", "zstd 0.12.3+zstd.1.5.2",
] ]

View File

@ -62,7 +62,7 @@ num_cpus = "1.15"
bytes = { version = "1.4", features = ["serde"] } bytes = { version = "1.4", features = ["serde"] }
default-net = "0.14" default-net = "0.14"
wol-rs = "1.0" 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" errno = "0.3"
rdev = { git = "https://github.com/fufesou/rdev" } rdev = { git = "https://github.com/fufesou/rdev" }
url = { version = "2.3", features = ["serde"] } url = { version = "2.3", features = ["serde"] }

View File

@ -23,6 +23,7 @@ import 'package:texture_rgba_renderer/texture_rgba_renderer.dart';
import 'package:uni_links/uni_links.dart'; import 'package:uni_links/uni_links.dart';
import 'package:uni_links_desktop/uni_links_desktop.dart'; import 'package:uni_links_desktop/uni_links_desktop.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:uuid/uuid.dart';
import 'package:win32/win32.dart' as win32; import 'package:win32/win32.dart' as win32;
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
import 'package:window_size/window_size.dart' as window_size; 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 FMethod = String Function(String, dynamic);
typedef StreamEventHandler = Future<void> Function(Map<String, dynamic>); typedef StreamEventHandler = Future<void> Function(Map<String, dynamic>);
typedef SessionID = UuidValue;
final iconHardDrive = MemoryImage(Uint8List.fromList(base64Decode( 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=='))); '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, void msgBox(SessionID sessionId, String type, String title, String text,
OverlayDialogManager dialogManager, String link, OverlayDialogManager dialogManager,
{bool? hasCancel, ReconnectHandle? reconnect}) { {bool? hasCancel, ReconnectHandle? reconnect}) {
dialogManager.dismissAll(); dialogManager.dismissAll();
List<Widget> buttons = []; List<Widget> buttons = [];
@ -936,7 +938,7 @@ void msgBox(String id, String type, String title, String text, String link,
buttons.insert( buttons.insert(
0, 0,
dialogButton('Reconnect', isOutline: true, onPressed: () { dialogButton('Reconnect', isOutline: true, onPressed: () {
reconnect(dialogManager, id, false); reconnect(dialogManager, sessionId, false);
})); }));
} }
if (link.isNotEmpty) { if (link.isNotEmpty) {
@ -950,7 +952,7 @@ void msgBox(String id, String type, String title, String text, String link,
onSubmit: hasOk ? submit : null, onSubmit: hasOk ? submit : null,
onCancel: hasCancel == true ? cancel : null, onCancel: hasCancel == true ? cancel : null,
), ),
tag: '$id-$type-$title-$text-$link', tag: '$sessionId-$type-$title-$text-$link',
); );
} }

View File

@ -10,9 +10,9 @@ import '../../common.dart';
import '../../models/model.dart'; import '../../models/model.dart';
import '../../models/platform_model.dart'; import '../../models/platform_model.dart';
void clientClose(String id, OverlayDialogManager dialogManager) { void clientClose(SessionID sessionId, OverlayDialogManager dialogManager) {
msgBox(id, 'info', 'Close', 'Are you sure to close the connection?', '', msgBox(sessionId, 'info', 'Close', 'Are you sure to close the connection?',
dialogManager); '', dialogManager);
} }
abstract class ValidationRule { abstract class ValidationRule {
@ -423,8 +423,8 @@ class _PasswordWidgetState extends State<PasswordWidget> {
} }
} }
void wrongPasswordDialog( void wrongPasswordDialog(SessionID sessionId,
String id, OverlayDialogManager dialogManager, type, title, text) { OverlayDialogManager dialogManager, type, title, text) {
dialogManager.dismissAll(); dialogManager.dismissAll();
dialogManager.show((setState, close, context) { dialogManager.show((setState, close, context) {
cancel() { cancel() {
@ -433,7 +433,7 @@ void wrongPasswordDialog(
} }
submit() { submit() {
enterPasswordDialog(id, dialogManager); enterPasswordDialog(sessionId, dialogManager);
} }
return CustomAlertDialog( return CustomAlertDialog(
@ -455,17 +455,19 @@ void wrongPasswordDialog(
}); });
} }
void enterPasswordDialog(String id, OverlayDialogManager dialogManager) async { void enterPasswordDialog(
SessionID sessionId, OverlayDialogManager dialogManager) async {
await _connectDialog( await _connectDialog(
id, sessionId,
dialogManager, dialogManager,
passwordController: TextEditingController(), passwordController: TextEditingController(),
); );
} }
void enterUserLoginDialog(String id, OverlayDialogManager dialogManager) async { void enterUserLoginDialog(
SessionID sessionId, OverlayDialogManager dialogManager) async {
await _connectDialog( await _connectDialog(
id, sessionId,
dialogManager, dialogManager,
osUsernameController: TextEditingController(), osUsernameController: TextEditingController(),
osPasswordController: TextEditingController(), osPasswordController: TextEditingController(),
@ -473,9 +475,9 @@ void enterUserLoginDialog(String id, OverlayDialogManager dialogManager) async {
} }
void enterUserLoginAndPasswordDialog( void enterUserLoginAndPasswordDialog(
String id, OverlayDialogManager dialogManager) async { SessionID sessionId, OverlayDialogManager dialogManager) async {
await _connectDialog( await _connectDialog(
id, sessionId,
dialogManager, dialogManager,
osUsernameController: TextEditingController(), osUsernameController: TextEditingController(),
osPasswordController: TextEditingController(), osPasswordController: TextEditingController(),
@ -484,7 +486,7 @@ void enterUserLoginAndPasswordDialog(
} }
_connectDialog( _connectDialog(
String id, SessionID sessionId,
OverlayDialogManager dialogManager, { OverlayDialogManager dialogManager, {
TextEditingController? osUsernameController, TextEditingController? osUsernameController,
TextEditingController? osPasswordController, TextEditingController? osPasswordController,
@ -492,11 +494,13 @@ _connectDialog(
}) async { }) async {
var rememberPassword = false; var rememberPassword = false;
if (passwordController != null) { if (passwordController != null) {
rememberPassword = await bind.sessionGetRemember(id: id) ?? false; rememberPassword =
await bind.sessionGetRemember(sessionId: sessionId) ?? false;
} }
var rememberAccount = false; var rememberAccount = false;
if (osUsernameController != null) { if (osUsernameController != null) {
rememberAccount = await bind.sessionGetRemember(id: id) ?? false; rememberAccount =
await bind.sessionGetRemember(sessionId: sessionId) ?? false;
} }
dialogManager.dismissAll(); dialogManager.dismissAll();
dialogManager.show((setState, close, context) { dialogManager.show((setState, close, context) {
@ -511,13 +515,15 @@ _connectDialog(
final password = passwordController?.text.trim() ?? ''; final password = passwordController?.text.trim() ?? '';
if (passwordController != null && password.isEmpty) return; if (passwordController != null && password.isEmpty) return;
if (rememberAccount) { if (rememberAccount) {
bind.sessionPeerOption(id: id, name: 'os-username', value: osUsername); bind.sessionPeerOption(
bind.sessionPeerOption(id: id, name: 'os-password', value: osPassword); sessionId: sessionId, name: 'os-username', value: osUsername);
bind.sessionPeerOption(
sessionId: sessionId, name: 'os-password', value: osPassword);
} }
gFFI.login( gFFI.login(
osUsername, osUsername,
osPassword, osPassword,
id, sessionId,
password, password,
rememberPassword, rememberPassword,
); );
@ -650,10 +656,10 @@ _connectDialog(
} }
void showWaitUacDialog( void showWaitUacDialog(
String id, OverlayDialogManager dialogManager, String type) { SessionID sessionId, OverlayDialogManager dialogManager, String type) {
dialogManager.dismissAll(); dialogManager.dismissAll();
dialogManager.show( dialogManager.show(
tag: '$id-wait-uac', tag: '$sessionId-wait-uac',
(setState, close, context) => CustomAlertDialog( (setState, close, context) => CustomAlertDialog(
title: null, title: null,
content: msgboxContent(type, 'Wait', 'wait_accept_uac_tip'), content: msgboxContent(type, 'Wait', 'wait_accept_uac_tip'),
@ -661,7 +667,8 @@ void showWaitUacDialog(
} }
// Another username && password dialog? // Another username && password dialog?
void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) { void showRequestElevationDialog(
SessionID sessionId, OverlayDialogManager dialogManager) {
RxString groupValue = ''.obs; RxString groupValue = ''.obs;
RxString errUser = ''.obs; RxString errUser = ''.obs;
RxString errPwd = ''.obs; RxString errPwd = ''.obs;
@ -785,7 +792,8 @@ void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) {
); );
dialogManager.dismissAll(); dialogManager.dismissAll();
dialogManager.show(tag: '$id-request-elevation', (setState, close, context) { dialogManager.show(tag: '$sessionId-request-elevation',
(setState, close, context) {
void submit() { void submit() {
if (groupValue.value == 'logon') { if (groupValue.value == 'logon') {
if (userController.text.isEmpty) { if (userController.text.isEmpty) {
@ -797,11 +805,11 @@ void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) {
return; return;
} }
bind.sessionElevateWithLogon( bind.sessionElevateWithLogon(
id: id, sessionId: sessionId,
username: userController.text, username: userController.text,
password: pwdController.text); password: pwdController.text);
} else { } else {
bind.sessionElevateDirect(id: id); bind.sessionElevateDirect(sessionId: sessionId);
} }
} }
@ -828,20 +836,20 @@ void showRequestElevationDialog(String id, OverlayDialogManager dialogManager) {
} }
void showOnBlockDialog( void showOnBlockDialog(
String id, SessionID sessionId,
String type, String type,
String title, String title,
String text, String text,
OverlayDialogManager dialogManager, OverlayDialogManager dialogManager,
) { ) {
if (dialogManager.existing('$id-wait-uac') || if (dialogManager.existing('$sessionId-wait-uac') ||
dialogManager.existing('$id-request-elevation')) { dialogManager.existing('$sessionId-request-elevation')) {
return; return;
} }
dialogManager.show(tag: '$id-$type', (setState, close, context) { dialogManager.show(tag: '$sessionId-$type', (setState, close, context) {
void submit() { void submit() {
close(); close();
showRequestElevationDialog(id, dialogManager); showRequestElevationDialog(sessionId, dialogManager);
} }
return CustomAlertDialog( return CustomAlertDialog(
@ -858,12 +866,12 @@ void showOnBlockDialog(
}); });
} }
void showElevationError(String id, String type, String title, String text, void showElevationError(SessionID sessionId, String type, String title,
OverlayDialogManager dialogManager) { String text, OverlayDialogManager dialogManager) {
dialogManager.show(tag: '$id-$type', (setState, close, context) { dialogManager.show(tag: '$sessionId-$type', (setState, close, context) {
void submit() { void submit() {
close(); close();
showRequestElevationDialog(id, dialogManager); showRequestElevationDialog(sessionId, dialogManager);
} }
return CustomAlertDialog( 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, void showWaitAcceptDialog(SessionID sessionId, String type, String title,
OverlayDialogManager dialogManager) { String text, OverlayDialogManager dialogManager) {
dialogManager.dismissAll(); dialogManager.dismissAll();
dialogManager.show((setState, close, context) { dialogManager.show((setState, close, context) {
onCancel() { onCancel() {
@ -900,8 +908,8 @@ void showWaitAcceptDialog(String id, String type, String title, String text,
}); });
} }
void showRestartRemoteDevice( void showRestartRemoteDevice(PeerInfo pi, String id, SessionID sessionId,
PeerInfo pi, String id, OverlayDialogManager dialogManager) async { OverlayDialogManager dialogManager) async {
final res = await dialogManager final res = await dialogManager
.show<bool>((setState, close, context) => CustomAlertDialog( .show<bool>((setState, close, context) => CustomAlertDialog(
title: Row(children: [ title: Row(children: [
@ -928,26 +936,33 @@ void showRestartRemoteDevice(
onCancel: close, onCancel: close,
onSubmit: () => close(true), onSubmit: () => close(true),
)); ));
if (res == true) bind.sessionRestartRemoteDevice(id: id); if (res == true) bind.sessionRestartRemoteDevice(sessionId: sessionId);
} }
showSetOSPassword( showSetOSPassword(
String id, SessionID sessionId,
bool login, bool login,
OverlayDialogManager dialogManager, OverlayDialogManager dialogManager,
) async { ) async {
final controller = TextEditingController(); final controller = TextEditingController();
var password = await bind.sessionGetOption(id: id, arg: 'os-password') ?? ''; var password =
var autoLogin = await bind.sessionGetOption(id: id, arg: 'auto-login') != ''; await bind.sessionGetOption(sessionId: sessionId, arg: 'os-password') ??
'';
var autoLogin =
await bind.sessionGetOption(sessionId: sessionId, arg: 'auto-login') !=
'';
controller.text = password; controller.text = password;
dialogManager.show((setState, close, context) { dialogManager.show((setState, close, context) {
submit() { submit() {
var text = controller.text.trim(); var text = controller.text.trim();
bind.sessionPeerOption(id: id, name: 'os-password', value: text);
bind.sessionPeerOption( 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) { if (text != '' && login) {
bind.sessionInputOsPassword(id: id, value: text); bind.sessionInputOsPassword(sessionId: sessionId, value: text);
} }
close(); close();
} }
@ -999,21 +1014,27 @@ showSetOSPassword(
} }
showSetOSAccount( showSetOSAccount(
String id, SessionID sessionId,
OverlayDialogManager dialogManager, OverlayDialogManager dialogManager,
) async { ) async {
final usernameController = TextEditingController(); final usernameController = TextEditingController();
final passwdController = TextEditingController(); final passwdController = TextEditingController();
var username = await bind.sessionGetOption(id: id, arg: 'os-username') ?? ''; var username =
var password = await bind.sessionGetOption(id: id, arg: 'os-password') ?? ''; await bind.sessionGetOption(sessionId: sessionId, arg: 'os-username') ??
'';
var password =
await bind.sessionGetOption(sessionId: sessionId, arg: 'os-password') ??
'';
usernameController.text = username; usernameController.text = username;
passwdController.text = password; passwdController.text = password;
dialogManager.show((setState, close, context) { dialogManager.show((setState, close, context) {
submit() { submit() {
final username = usernameController.text.trim(); final username = usernameController.text.trim();
final password = usernameController.text.trim(); final password = usernameController.text.trim();
bind.sessionPeerOption(id: id, name: 'os-username', value: username); bind.sessionPeerOption(
bind.sessionPeerOption(id: id, name: 'os-password', value: password); sessionId: sessionId, name: 'os-username', value: username);
bind.sessionPeerOption(
sessionId: sessionId, name: 'os-password', value: password);
close(); close();
} }
@ -1077,13 +1098,13 @@ showSetOSAccount(
}); });
} }
showAuditDialog(String id, dialogManager) async { showAuditDialog(SessionID sessionId, dialogManager) async {
final controller = TextEditingController(); final controller = TextEditingController();
dialogManager.show((setState, close) { dialogManager.show((setState, close) {
submit() { submit() {
var text = controller.text.trim(); var text = controller.text.trim();
if (text != '') { if (text != '') {
bind.sessionSendNote(id: id, note: text); bind.sessionSendNote(sessionId: sessionId, note: text);
} }
close(); close();
} }
@ -1139,10 +1160,10 @@ showAuditDialog(String id, dialogManager) async {
} }
void showConfirmSwitchSidesDialog( void showConfirmSwitchSidesDialog(
String id, OverlayDialogManager dialogManager) async { SessionID sessionId, String id, OverlayDialogManager dialogManager) async {
dialogManager.show((setState, close, context) { dialogManager.show((setState, close, context) {
submit() async { submit() async {
await bind.sessionSwitchSides(id: id); await bind.sessionSwitchSides(sessionId: sessionId);
closeConnection(id: id); 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 qualityInitValue = 50;
double fpsInitValue = 30; double fpsInitValue = 30;
bool qualitySet = false; bool qualitySet = false;
@ -1167,20 +1188,22 @@ customImageQualityDialog(String id, FFI ffi) async {
setCustomValues({double? quality, double? fps}) async { setCustomValues({double? quality, double? fps}) async {
if (quality != null) { if (quality != null) {
qualitySet = true; qualitySet = true;
await bind.sessionSetCustomImageQuality(id: id, value: quality.toInt()); await bind.sessionSetCustomImageQuality(
sessionId: sessionId, value: quality.toInt());
} }
if (fps != null) { if (fps != null) {
fpsSet = true; fpsSet = true;
await bind.sessionSetCustomFps(id: id, fps: fps.toInt()); await bind.sessionSetCustomFps(sessionId: sessionId, fps: fps.toInt());
} }
if (!qualitySet) { if (!qualitySet) {
qualitySet = true; qualitySet = true;
await bind.sessionSetCustomImageQuality( await bind.sessionSetCustomImageQuality(
id: id, value: qualityInitValue.toInt()); sessionId: sessionId, value: qualityInitValue.toInt());
} }
if (!fpsSet) { if (!fpsSet) {
fpsSet = true; 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 // quality
final quality = await bind.sessionGetCustomImageQuality(id: id); final quality = await bind.sessionGetCustomImageQuality(sessionId: sessionId);
qualityInitValue = qualityInitValue =
quality != null && quality.isNotEmpty ? quality[0].toDouble() : 50.0; quality != null && quality.isNotEmpty ? quality[0].toDouble() : 50.0;
const qualityMinValue = 10.0; const qualityMinValue = 10.0;
@ -1238,7 +1261,8 @@ customImageQualityDialog(String id, FFI ffi) async {
], ],
)); ));
// fps // 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; fpsInitValue = fpsOption == null ? 30 : double.tryParse(fpsOption) ?? 30;
if (fpsInitValue < 5 || fpsInitValue > 120) { if (fpsInitValue < 5 || fpsInitValue > 120) {
fpsInitValue = 30; fpsInitValue = 30;

View File

@ -735,7 +735,6 @@ abstract class BasePeerCard extends StatelessWidget {
} }
await bind.mainRemovePeer(id: id); await bind.mainRemovePeer(id: id);
} }
removePreference(id);
await reloadFunc(); await reloadFunc();
close(); close();
} }

View File

@ -48,6 +48,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
final ffiModel = ffi.ffiModel; final ffiModel = ffi.ffiModel;
final pi = ffiModel.pi; final pi = ffiModel.pi;
final perms = ffiModel.permissions; final perms = ffiModel.permissions;
final sessionId = ffi.sessionId;
List<TTextMenu> v = []; List<TTextMenu> v = [];
// elevation // elevation
@ -55,7 +56,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
v.add( v.add(
TTextMenu( TTextMenu(
child: Text(translate('Request Elevation')), child: Text(translate('Request Elevation')),
onPressed: () => showRequestElevationDialog(id, ffi.dialogManager)), onPressed: () =>
showRequestElevationDialog(sessionId, ffi.dialogManager)),
); );
} }
// osAccount / osPassword // osAccount / osPassword
@ -70,8 +72,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
]), ]),
trailingIcon: Transform.scale(scale: 0.8, child: Icon(Icons.edit)), trailingIcon: Transform.scale(scale: 0.8, child: Icon(Icons.edit)),
onPressed: () => pi.is_headless onPressed: () => pi.is_headless
? showSetOSAccount(id, ffi.dialogManager) ? showSetOSAccount(sessionId, ffi.dialogManager)
: showSetOSPassword(id, false, ffi.dialogManager)), : showSetOSPassword(sessionId, false, ffi.dialogManager)),
); );
// paste // paste
if (isMobile && perms['keyboard'] != false && perms['clipboard'] != false) { if (isMobile && perms['keyboard'] != false && perms['clipboard'] != false) {
@ -80,7 +82,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
onPressed: () async { onPressed: () async {
ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
if (data != null && data.text != null) { 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<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
); );
} }
// note // note
if (bind.sessionGetAuditServerSync(id: id, typ: "conn").isNotEmpty) { if (bind
.sessionGetAuditServerSync(sessionId: sessionId, typ: "conn")
.isNotEmpty) {
v.add( v.add(
TTextMenu( TTextMenu(
child: Text(translate('Note')), child: Text(translate('Note')),
onPressed: () => showAuditDialog(id, ffi.dialogManager)), onPressed: () => showAuditDialog(sessionId, ffi.dialogManager)),
); );
} }
// divider // divider
@ -125,7 +130,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
v.add( v.add(
TTextMenu( TTextMenu(
child: Text('${translate("Insert")} Ctrl + Alt + Del'), child: Text('${translate("Insert")} Ctrl + Alt + Del'),
onPressed: () => bind.sessionCtrlAltDel(id: id)), onPressed: () => bind.sessionCtrlAltDel(sessionId: sessionId)),
); );
} }
// restart // restart
@ -136,7 +141,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
v.add( v.add(
TTextMenu( TTextMenu(
child: Text(translate('Restart Remote Device')), child: Text(translate('Restart Remote Device')),
onPressed: () => showRestartRemoteDevice(pi, id, ffi.dialogManager)), onPressed: () =>
showRestartRemoteDevice(pi, id, sessionId, ffi.dialogManager)),
); );
} }
// insertLock // insertLock
@ -144,7 +150,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
v.add( v.add(
TTextMenu( TTextMenu(
child: Text(translate('Insert Lock')), child: Text(translate('Insert Lock')),
onPressed: () => bind.sessionLockScreen(id: id)), onPressed: () => bind.sessionLockScreen(sessionId: sessionId)),
); );
} }
// blockUserInput // blockUserInput
@ -157,7 +163,8 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
onPressed: () { onPressed: () {
RxBool blockInput = BlockInputState.find(id); RxBool blockInput = BlockInputState.find(id);
bind.sessionToggleOption( bind.sessionToggleOption(
id: id, value: '${blockInput.value ? 'un' : ''}block-input'); sessionId: sessionId,
value: '${blockInput.value ? 'un' : ''}block-input');
blockInput.value = !blockInput.value; blockInput.value = !blockInput.value;
})); }));
} }
@ -169,13 +176,14 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
version_cmp(pi.version, '1.2.0') >= 0) { version_cmp(pi.version, '1.2.0') >= 0) {
v.add(TTextMenu( v.add(TTextMenu(
child: Text(translate('Switch Sides')), child: Text(translate('Switch Sides')),
onPressed: () => showConfirmSwitchSidesDialog(id, ffi.dialogManager))); onPressed: () =>
showConfirmSwitchSidesDialog(sessionId, id, ffi.dialogManager)));
} }
// refresh // refresh
if (pi.version.isNotEmpty) { if (pi.version.isNotEmpty) {
v.add(TTextMenu( v.add(TTextMenu(
child: Text(translate('Refresh')), child: Text(translate('Refresh')),
onPressed: () => bind.sessionRefresh(id: id))); onPressed: () => bind.sessionRefresh(sessionId: sessionId)));
} }
// record // record
var codecFormat = ffi.qualityMonitorModel.data.codecFormat; var codecFormat = ffi.qualityMonitorModel.data.codecFormat;
@ -213,11 +221,12 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
Future<List<TRadioMenu<String>>> toolbarViewStyle( Future<List<TRadioMenu<String>>> toolbarViewStyle(
BuildContext context, String id, FFI ffi) async { 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 { void onChanged(String? value) async {
if (value == null) return; if (value == null) return;
bind bind
.sessionSetViewStyle(id: id, value: value) .sessionSetViewStyle(sessionId: ffi.sessionId, value: value)
.then((_) => ffi.canvasModel.updateViewStyle()); .then((_) => ffi.canvasModel.updateViewStyle());
} }
@ -237,10 +246,11 @@ Future<List<TRadioMenu<String>>> toolbarViewStyle(
Future<List<TRadioMenu<String>>> toolbarImageQuality( Future<List<TRadioMenu<String>>> toolbarImageQuality(
BuildContext context, String id, FFI ffi) async { 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 { onChanged(String? value) async {
if (value == null) return; if (value == null) return;
await bind.sessionSetImageQuality(id: id, value: value); await bind.sessionSetImageQuality(sessionId: ffi.sessionId, value: value);
} }
return [ return [
@ -265,7 +275,7 @@ Future<List<TRadioMenu<String>>> toolbarImageQuality(
groupValue: groupValue, groupValue: groupValue,
onChanged: (value) { onChanged: (value) {
onChanged(value); onChanged(value);
customImageQualityDialog(id, ffi); customImageQualityDialog(ffi.sessionId, id, ffi);
}, },
), ),
]; ];
@ -273,9 +283,12 @@ Future<List<TRadioMenu<String>>> toolbarImageQuality(
Future<List<TRadioMenu<String>>> toolbarCodec( Future<List<TRadioMenu<String>>> toolbarCodec(
BuildContext context, String id, FFI ffi) async { BuildContext context, String id, FFI ffi) async {
final alternativeCodecs = await bind.sessionAlternativeCodecs(id: id); final sessionId = ffi.sessionId;
final groupValue = final alternativeCodecs =
await bind.sessionGetOption(id: id, arg: 'codec-preference') ?? ''; await bind.sessionAlternativeCodecs(sessionId: sessionId);
final groupValue = await bind.sessionGetOption(
sessionId: sessionId, arg: 'codec-preference') ??
'';
final List<bool> codecs = []; final List<bool> codecs = [];
try { try {
final Map codecsJson = jsonDecode(alternativeCodecs); final Map codecsJson = jsonDecode(alternativeCodecs);
@ -296,8 +309,8 @@ Future<List<TRadioMenu<String>>> toolbarCodec(
onChanged(String? value) async { onChanged(String? value) async {
if (value == null) return; if (value == null) return;
await bind.sessionPeerOption( await bind.sessionPeerOption(
id: id, name: 'codec-preference', value: value); sessionId: sessionId, name: 'codec-preference', value: value);
bind.sessionChangePreferCodec(id: id); bind.sessionChangePreferCodec(sessionId: sessionId);
} }
TRadioMenu<String> radio(String label, String value, bool enabled) { TRadioMenu<String> radio(String label, String value, bool enabled) {
@ -324,6 +337,7 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
final ffiModel = ffi.ffiModel; final ffiModel = ffi.ffiModel;
final pi = ffiModel.pi; final pi = ffiModel.pi;
final perms = ffiModel.permissions; final perms = ffiModel.permissions;
final sessionId = ffi.sessionId;
// show remote cursor // show remote cursor
if (pi.platform != kPeerPlatformAndroid && if (pi.platform != kPeerPlatformAndroid &&
@ -338,14 +352,15 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
onChanged: enabled onChanged: enabled
? (value) async { ? (value) async {
if (value == null) return; if (value == null) return;
await bind.sessionToggleOption(id: id, value: option); await bind.sessionToggleOption(
state.value = sessionId: sessionId, value: option);
bind.sessionGetToggleOptionSync(id: id, arg: option); state.value = bind.sessionGetToggleOptionSync(
sessionId: sessionId, arg: option);
} }
: null)); : null));
} }
// zoom cursor // zoom cursor
final viewStyle = await bind.sessionGetViewStyle(id: id) ?? ''; final viewStyle = await bind.sessionGetViewStyle(sessionId: sessionId) ?? '';
if (!isMobile && if (!isMobile &&
pi.platform != kPeerPlatformAndroid && pi.platform != kPeerPlatformAndroid &&
viewStyle != kRemoteViewStyleOriginal) { viewStyle != kRemoteViewStyleOriginal) {
@ -356,30 +371,32 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
value: peerState.value, value: peerState.value,
onChanged: (value) async { onChanged: (value) async {
if (value == null) return; if (value == null) return;
await bind.sessionToggleOption(id: id, value: option); await bind.sessionToggleOption(sessionId: sessionId, value: option);
peerState.value = bind.sessionGetToggleOptionSync(id: id, arg: option); peerState.value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);
}, },
)); ));
} }
// show quality monitor // show quality monitor
final option = 'show-quality-monitor'; final option = 'show-quality-monitor';
v.add(TToggleMenu( v.add(TToggleMenu(
value: bind.sessionGetToggleOptionSync(id: id, arg: option), value: bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option),
onChanged: (value) async { onChanged: (value) async {
if (value == null) return; if (value == null) return;
await bind.sessionToggleOption(id: id, value: option); await bind.sessionToggleOption(sessionId: sessionId, value: option);
ffi.qualityMonitorModel.checkShowQualityMonitor(id); ffi.qualityMonitorModel.checkShowQualityMonitor(sessionId);
}, },
child: Text(translate('Show quality monitor')))); child: Text(translate('Show quality monitor'))));
// mute // mute
if (perms['audio'] != false) { if (perms['audio'] != false) {
final option = 'disable-audio'; final option = 'disable-audio';
final value = bind.sessionGetToggleOptionSync(id: id, arg: option); final value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);
v.add(TToggleMenu( v.add(TToggleMenu(
value: value, value: value,
onChanged: (value) { onChanged: (value) {
if (value == null) return; if (value == null) return;
bind.sessionToggleOption(id: id, value: option); bind.sessionToggleOption(sessionId: sessionId, value: option);
}, },
child: Text(translate('Mute')))); child: Text(translate('Mute'))));
} }
@ -388,12 +405,13 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
pi.platform == kPeerPlatformWindows && pi.platform == kPeerPlatformWindows &&
perms['file'] != false) { perms['file'] != false) {
final option = 'enable-file-transfer'; final option = 'enable-file-transfer';
final value = bind.sessionGetToggleOptionSync(id: id, arg: option); final value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);
v.add(TToggleMenu( v.add(TToggleMenu(
value: value, value: value,
onChanged: (value) { onChanged: (value) {
if (value == null) return; if (value == null) return;
bind.sessionToggleOption(id: id, value: option); bind.sessionToggleOption(sessionId: sessionId, value: option);
}, },
child: Text(translate('Allow file copy and paste')))); child: Text(translate('Allow file copy and paste'))));
} }
@ -401,14 +419,15 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
if (ffiModel.keyboard && perms['clipboard'] != false) { if (ffiModel.keyboard && perms['clipboard'] != false) {
final enabled = !ffiModel.viewOnly; final enabled = !ffiModel.viewOnly;
final option = 'disable-clipboard'; 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; if (ffiModel.viewOnly) value = true;
v.add(TToggleMenu( v.add(TToggleMenu(
value: value, value: value,
onChanged: enabled onChanged: enabled
? (value) { ? (value) {
if (value == null) return; if (value == null) return;
bind.sessionToggleOption(id: id, value: option); bind.sessionToggleOption(sessionId: sessionId, value: option);
} }
: null, : null,
child: Text(translate('Disable clipboard')))); child: Text(translate('Disable clipboard'))));
@ -416,12 +435,13 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
// lock after session end // lock after session end
if (ffiModel.keyboard) { if (ffiModel.keyboard) {
final option = 'lock-after-session-end'; 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( v.add(TToggleMenu(
value: value, value: value,
onChanged: (value) { onChanged: (value) {
if (value == null) return; if (value == null) return;
bind.sessionToggleOption(id: id, value: option); bind.sessionToggleOption(sessionId: sessionId, value: option);
}, },
child: Text(translate('Lock after session end')))); child: Text(translate('Lock after session end'))));
} }
@ -434,11 +454,11 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
onChanged: (value) { onChanged: (value) {
if (value == null) return; if (value == null) return;
if (ffiModel.pi.currentDisplay != 0) { 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); 'Please switch to Display 1 first', '', ffi.dialogManager);
return; return;
} }
bind.sessionToggleOption(id: id, value: option); bind.sessionToggleOption(sessionId: sessionId, value: option);
}, },
child: Text(translate('Privacy mode')))); child: Text(translate('Privacy mode'))));
} }
@ -447,12 +467,13 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
((Platform.isMacOS && pi.platform != kPeerPlatformMacOS) || ((Platform.isMacOS && pi.platform != kPeerPlatformMacOS) ||
(!Platform.isMacOS && pi.platform == kPeerPlatformMacOS))) { (!Platform.isMacOS && pi.platform == kPeerPlatformMacOS))) {
final option = 'allow_swap_key'; final option = 'allow_swap_key';
final value = bind.sessionGetToggleOptionSync(id: id, arg: option); final value =
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);
v.add(TToggleMenu( v.add(TToggleMenu(
value: value, value: value,
onChanged: (value) { onChanged: (value) {
if (value == null) return; if (value == null) return;
bind.sessionToggleOption(id: id, value: option); bind.sessionToggleOption(sessionId: sessionId, value: option);
}, },
child: Text(translate('Swap control-command key')))); child: Text(translate('Swap control-command key'))));
} }

View File

@ -449,7 +449,8 @@ class _FileManagerViewState extends State<FileManagerView> {
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
child: FutureBuilder<String>( child: FutureBuilder<String>(
future: bind.sessionGetPlatform( future: bind.sessionGetPlatform(
id: _ffi.id, isRemote: !isLocal), sessionId: _ffi.sessionId,
isRemote: !isLocal),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && if (snapshot.hasData &&
snapshot.data!.isNotEmpty) { snapshot.data!.isNotEmpty) {

View File

@ -194,7 +194,7 @@ class _PortForwardPageState extends State<PortForwardPage>
(remoteHostController.text.isEmpty || (remoteHostController.text.isEmpty ||
remoteHostController.text.trim().isNotEmpty)) { remoteHostController.text.trim().isNotEmpty)) {
await bind.sessionAddPortForward( await bind.sessionAddPortForward(
id: 'pf_${widget.id}', sessionId: _ffi.sessionId,
localPort: localPort, localPort: localPort,
remoteHost: remoteHostController.text.trim().isEmpty remoteHost: remoteHostController.text.trim().isEmpty
? 'localhost' ? 'localhost'
@ -254,7 +254,7 @@ class _PortForwardPageState extends State<PortForwardPage>
icon: const Icon(Icons.close), icon: const Icon(Icons.close),
onPressed: () async { onPressed: () async {
await bind.sessionRemovePortForward( await bind.sessionRemovePortForward(
id: 'pf_${widget.id}', localPort: pf.localPort); sessionId: _ffi.sessionId, localPort: pf.localPort);
refreshTunnelConfig(); refreshTunnelConfig();
}, },
), ),
@ -313,7 +313,7 @@ class _PortForwardPageState extends State<PortForwardPage>
width: 120, width: 120,
child: ElevatedButton( child: ElevatedButton(
onPressed: () => onPressed: () =>
bind.sessionNewRdp(id: "pf_${widget.id}"), bind.sessionNewRdp(sessionId: _ffi.sessionId),
child: Text( child: Text(
translate('New RDP'), translate('New RDP'),
), ),

View File

@ -110,12 +110,12 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
return Platform.isMacOS || kUseCompatibleUiMode return Platform.isMacOS || kUseCompatibleUiMode
? tabWidget ? tabWidget
: Obx( : Obx(
() => SubWindowDragToResizeArea( () => SubWindowDragToResizeArea(
child: tabWidget, child: tabWidget,
resizeEdgeSize: stateGlobal.resizeEdgeSize.value, resizeEdgeSize: stateGlobal.resizeEdgeSize.value,
windowId: stateGlobal.windowId, windowId: stateGlobal.windowId,
), ),
); );
} }
void onRemoveId(String id) { void onRemoveId(String id) {

View File

@ -76,6 +76,8 @@ class _RemotePageState extends State<RemotePage>
late FFI _ffi; late FFI _ffi;
SessionID get sessionId => _ffi.sessionId;
void _initStates(String id) { void _initStates(String id) {
initSharedStates(id); initSharedStates(id);
_zoomCursor = PeerBoolOption.find(id, 'zoom-cursor'); _zoomCursor = PeerBoolOption.find(id, 'zoom-cursor');
@ -117,19 +119,19 @@ class _RemotePageState extends State<RemotePage>
debugPrint("id: $id, texture_key: $_textureKey"); debugPrint("id: $id, texture_key: $_textureKey");
if (id != -1) { if (id != -1) {
final ptr = await textureRenderer.getTexturePtr(_textureKey); final ptr = await textureRenderer.getTexturePtr(_textureKey);
platformFFI.registerTexture(widget.id, ptr); platformFFI.registerTexture(sessionId, ptr);
_textureId.value = id; _textureId.value = id;
} }
}); });
} }
_ffi.ffiModel.updateEventListener(widget.id); _ffi.ffiModel.updateEventListener(sessionId, widget.id);
bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote); bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote);
_ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id); _ffi.qualityMonitorModel.checkShowQualityMonitor(sessionId);
// Session option should be set after models.dart/FFI.start // Session option should be set after models.dart/FFI.start
_showRemoteCursor.value = bind.sessionGetToggleOptionSync( _showRemoteCursor.value = bind.sessionGetToggleOptionSync(
id: widget.id, arg: 'show-remote-cursor'); sessionId: sessionId, arg: 'show-remote-cursor');
_zoomCursor.value = _zoomCursor.value = bind.sessionGetToggleOptionSync(
bind.sessionGetToggleOptionSync(id: widget.id, arg: 'zoom-cursor'); sessionId: sessionId, arg: 'zoom-cursor');
DesktopMultiWindow.addListener(this); DesktopMultiWindow.addListener(this);
// if (!_isCustomCursorInited) { // if (!_isCustomCursorInited) {
// customCursorController.registerNeedUpdateCursorCallback( // customCursorController.registerNeedUpdateCursorCallback(
@ -203,11 +205,11 @@ class _RemotePageState extends State<RemotePage>
void dispose() { void dispose() {
debugPrint("REMOTE PAGE dispose ${widget.id}"); debugPrint("REMOTE PAGE dispose ${widget.id}");
if (useTextureRender) { if (useTextureRender) {
platformFFI.registerTexture(widget.id, 0); platformFFI.registerTexture(sessionId, 0);
textureRenderer.closeTexture(_textureKey); textureRenderer.closeTexture(_textureKey);
} }
// ensure we leave this session, this is a double check // 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); DesktopMultiWindow.removeListener(this);
_ffi.dialogManager.hideMobileActionsOverlay(); _ffi.dialogManager.hideMobileActionsOverlay();
_ffi.recordingModel.onClose(); _ffi.recordingModel.onClose();
@ -278,7 +280,7 @@ class _RemotePageState extends State<RemotePage>
super.build(context); super.build(context);
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
clientClose(widget.id, _ffi.dialogManager); clientClose(sessionId, _ffi.dialogManager);
return false; return false;
}, },
child: MultiProvider(providers: [ child: MultiProvider(providers: [
@ -305,7 +307,7 @@ class _RemotePageState extends State<RemotePage>
if (!_rawKeyFocusNode.hasFocus) { if (!_rawKeyFocusNode.hasFocus) {
_rawKeyFocusNode.requestFocus(); _rawKeyFocusNode.requestFocus();
} }
bind.sessionEnterOrLeave(id: widget.id, enter: true); bind.sessionEnterOrLeave(sessionId: sessionId, enter: true);
} }
} }
@ -325,7 +327,7 @@ class _RemotePageState extends State<RemotePage>
} }
// See [onWindowBlur]. // See [onWindowBlur].
if (!Platform.isWindows) { if (!Platform.isWindows) {
bind.sessionEnterOrLeave(id: widget.id, enter: false); bind.sessionEnterOrLeave(sessionId: sessionId, enter: false);
} }
} }

View File

@ -56,7 +56,11 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
if (peerId != null) { if (peerId != null) {
ConnectionTypeState.init(peerId); ConnectionTypeState.init(peerId);
tabController.onSelected = (_, id) { 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()) WindowController.fromWindowId(windowId())
.setTitle(getWindowNameWithId(id)); .setTitle(getWindowNameWithId(id));
}; };
@ -243,6 +247,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
final ffi = remotePage.ffi; final ffi = remotePage.ffi;
final pi = ffi.ffiModel.pi; final pi = ffi.ffiModel.pi;
final perms = ffi.ffiModel.permissions; final perms = ffi.ffiModel.permissions;
final sessionId = ffi.sessionId;
menu.addAll([ menu.addAll([
MenuEntryButton<String>( MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text( childBuilder: (TextStyle? style) => Text(
@ -282,6 +287,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
menu.add(MenuEntryDivider<String>()); menu.add(MenuEntryDivider<String>());
menu.add(RemoteMenuEntry.showRemoteCursor( menu.add(RemoteMenuEntry.showRemoteCursor(
key, key,
sessionId,
padding, padding,
dismissFunc: cancelFunc, dismissFunc: cancelFunc,
)); ));
@ -289,15 +295,15 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
if (perms['keyboard'] != false && !ffi.ffiModel.viewOnly) { if (perms['keyboard'] != false && !ffi.ffiModel.viewOnly) {
if (perms['clipboard'] != false) { if (perms['clipboard'] != false) {
menu.add(RemoteMenuEntry.disableClipboard(key, padding, menu.add(RemoteMenuEntry.disableClipboard(sessionId, padding,
dismissFunc: cancelFunc)); dismissFunc: cancelFunc));
} }
menu.add( menu.add(RemoteMenuEntry.insertLock(sessionId, padding,
RemoteMenuEntry.insertLock(key, padding, dismissFunc: cancelFunc)); dismissFunc: cancelFunc));
if (pi.platform == kPeerPlatformLinux || pi.sasEnabled) { if (pi.platform == kPeerPlatformLinux || pi.sasEnabled) {
menu.add(RemoteMenuEntry.insertCtrlAltDel(key, padding, menu.add(RemoteMenuEntry.insertCtrlAltDel(sessionId, padding,
dismissFunc: cancelFunc)); dismissFunc: cancelFunc));
} }
} }

View File

@ -30,7 +30,7 @@ class _DesktopServerPageState extends State<DesktopServerPage>
final tabController = gFFI.serverModel.tabController; final tabController = gFFI.serverModel.tabController;
@override @override
void initState() { void initState() {
gFFI.ffiModel.updateEventListener(""); gFFI.ffiModel.updateEventListener(gFFI.sessionId, "");
windowManager.addListener(this); windowManager.addListener(this);
tabController.onRemoved = (_, id) { tabController.onRemoved = (_, id) {
onRemoveId(id); onRemoveId(id);

View File

@ -141,14 +141,16 @@ class RemoteMenuEntry {
], ],
curOptionGetter: () async { curOptionGetter: () async {
// null means peer id is not found, which there's no need to care about // 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) { if (rxViewStyle != null) {
rxViewStyle.value = viewStyle; rxViewStyle.value = viewStyle;
} }
return viewStyle; return viewStyle;
}, },
optionSetter: (String oldValue, String newValue) async { optionSetter: (String oldValue, String newValue) async {
await bind.sessionSetViewStyle(id: remoteId, value: newValue); await bind.sessionSetViewStyle(
sessionId: ffi.sessionId, value: newValue);
if (rxViewStyle != null) { if (rxViewStyle != null) {
rxViewStyle.value = newValue; rxViewStyle.value = newValue;
} }
@ -165,6 +167,7 @@ class RemoteMenuEntry {
static MenuEntrySwitch2<String> showRemoteCursor( static MenuEntrySwitch2<String> showRemoteCursor(
String remoteId, String remoteId,
SessionID sessionId,
EdgeInsets padding, { EdgeInsets padding, {
DismissFunc? dismissFunc, DismissFunc? dismissFunc,
DismissCallback? dismissCallback, DismissCallback? dismissCallback,
@ -178,9 +181,9 @@ class RemoteMenuEntry {
return state; return state;
}, },
setter: (bool v) async { setter: (bool v) async {
await bind.sessionToggleOption(id: remoteId, value: optKey); await bind.sessionToggleOption(sessionId: sessionId, value: optKey);
state.value = state.value =
bind.sessionGetToggleOptionSync(id: remoteId, arg: optKey); bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: optKey);
if (dismissFunc != null) { if (dismissFunc != null) {
dismissFunc(); dismissFunc();
} }
@ -192,13 +195,13 @@ class RemoteMenuEntry {
} }
static MenuEntrySwitch<String> disableClipboard( static MenuEntrySwitch<String> disableClipboard(
String remoteId, SessionID sessionId,
EdgeInsets? padding, { EdgeInsets? padding, {
DismissFunc? dismissFunc, DismissFunc? dismissFunc,
DismissCallback? dismissCallback, DismissCallback? dismissCallback,
}) { }) {
return createSwitchMenuEntry( return createSwitchMenuEntry(
remoteId, sessionId,
'Disable clipboard', 'Disable clipboard',
'disable-clipboard', 'disable-clipboard',
padding, padding,
@ -208,7 +211,7 @@ class RemoteMenuEntry {
} }
static MenuEntrySwitch<String> createSwitchMenuEntry( static MenuEntrySwitch<String> createSwitchMenuEntry(
String remoteId, SessionID sessionId,
String text, String text,
String option, String option,
EdgeInsets? padding, EdgeInsets? padding,
@ -220,10 +223,11 @@ class RemoteMenuEntry {
switchType: SwitchType.scheckbox, switchType: SwitchType.scheckbox,
text: translate(text), text: translate(text),
getter: () async { getter: () async {
return bind.sessionGetToggleOptionSync(id: remoteId, arg: option); return bind.sessionGetToggleOptionSync(
sessionId: sessionId, arg: option);
}, },
setter: (bool v) async { setter: (bool v) async {
await bind.sessionToggleOption(id: remoteId, value: option); await bind.sessionToggleOption(sessionId: sessionId, value: option);
if (dismissFunc != null) { if (dismissFunc != null) {
dismissFunc(); dismissFunc();
} }
@ -235,7 +239,7 @@ class RemoteMenuEntry {
} }
static MenuEntryButton<String> insertLock( static MenuEntryButton<String> insertLock(
String remoteId, SessionID sessionId,
EdgeInsets? padding, { EdgeInsets? padding, {
DismissFunc? dismissFunc, DismissFunc? dismissFunc,
DismissCallback? dismissCallback, DismissCallback? dismissCallback,
@ -246,7 +250,7 @@ class RemoteMenuEntry {
style: style, style: style,
), ),
proc: () { proc: () {
bind.sessionLockScreen(id: remoteId); bind.sessionLockScreen(sessionId: sessionId);
if (dismissFunc != null) { if (dismissFunc != null) {
dismissFunc(); dismissFunc();
} }
@ -258,7 +262,7 @@ class RemoteMenuEntry {
} }
static insertCtrlAltDel( static insertCtrlAltDel(
String remoteId, SessionID sessionId,
EdgeInsets? padding, { EdgeInsets? padding, {
DismissFunc? dismissFunc, DismissFunc? dismissFunc,
DismissCallback? dismissCallback, DismissCallback? dismissCallback,
@ -269,7 +273,7 @@ class RemoteMenuEntry {
style: style, style: style,
), ),
proc: () { proc: () {
bind.sessionCtrlAltDel(id: remoteId); bind.sessionCtrlAltDel(sessionId: sessionId);
if (dismissFunc != null) { if (dismissFunc != null) {
dismissFunc(); dismissFunc();
} }
@ -329,7 +333,8 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
Future.delayed(Duration.zero, () async { Future.delayed(Duration.zero, () async {
_fractionX.value = double.tryParse(await bind.sessionGetOption( _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') ??
0.5; 0.5;
}); });
@ -387,7 +392,7 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
elevation: _MenubarTheme.elevation, elevation: _MenubarTheme.elevation,
shadowColor: MyTheme.color(context).shadow, shadowColor: MyTheme.color(context).shadow,
child: _DraggableShowHide( child: _DraggableShowHide(
id: widget.id, sessionId: widget.ffi.sessionId,
dragging: _dragging, dragging: _dragging,
fractionX: _fractionX, fractionX: _fractionX,
show: show, show: show,
@ -621,7 +626,7 @@ class _MonitorMenu extends StatelessWidget {
_menuDismissCallback(ffi); _menuDismissCallback(ffi);
RxInt display = CurrentDisplayState.find(id); RxInt display = CurrentDisplayState.find(id);
if (display.value != i) { if (display.value != i) {
bind.sessionSwitchDisplay(id: id, value: i); bind.sessionSwitchDisplay(sessionId: ffi.sessionId, value: i);
} }
}, },
)); ));
@ -763,7 +768,8 @@ class ScreenAdjustor {
} }
Future<bool> isWindowCanBeAdjusted() async { Future<bool> isWindowCanBeAdjusted() async {
final viewStyle = await bind.sessionGetViewStyle(id: id) ?? ''; final viewStyle =
await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? '';
if (viewStyle != kRemoteViewStyleOriginal) { if (viewStyle != kRemoteViewStyleOriginal) {
return false; return false;
} }
@ -885,9 +891,11 @@ class _DisplayMenuState extends State<_DisplayMenu> {
scrollStyle() { scrollStyle() {
return futureBuilder(future: () async { return futureBuilder(future: () async {
final viewStyle = await bind.sessionGetViewStyle(id: id) ?? ''; final viewStyle =
await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? '';
final visible = viewStyle == kRemoteViewStyleOriginal; 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}; return {'visible': visible, 'scrollStyle': scrollStyle};
}(), hasData: (data) { }(), hasData: (data) {
final visible = data['visible'] as bool; final visible = data['visible'] as bool;
@ -895,7 +903,8 @@ class _DisplayMenuState extends State<_DisplayMenu> {
final groupValue = data['scrollStyle'] as String; final groupValue = data['scrollStyle'] as String;
onChange(String? value) async { onChange(String? value) async {
if (value == null) return; if (value == null) return;
await bind.sessionSetScrollStyle(id: widget.id, value: value); await bind.sessionSetScrollStyle(
sessionId: ffi.sessionId, value: value);
widget.ffi.canvasModel.updateScrollStyle(); widget.ffi.canvasModel.updateScrollStyle();
} }
@ -1007,6 +1016,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
late final TextEditingController _customHeight = late final TextEditingController _customHeight =
TextEditingController(text: display.height.toString()); TextEditingController(text: display.height.toString());
FFI get ffi => widget.ffi;
PeerInfo get pi => widget.ffi.ffiModel.pi; PeerInfo get pi => widget.ffi.ffiModel.pi;
FfiModel get ffiModel => widget.ffi.ffiModel; FfiModel get ffiModel => widget.ffi.ffiModel;
Display get display => ffiModel.display; Display get display => ffiModel.display;
@ -1101,7 +1111,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
_changeResolution(int w, int h) async { _changeResolution(int w, int h) async {
await bind.sessionChangeResolution( await bind.sessionChangeResolution(
id: widget.id, sessionId: ffi.sessionId,
display: pi.currentDisplay, display: pi.currentDisplay,
width: w, width: w,
height: h, height: h,
@ -1254,12 +1264,15 @@ class _KeyboardMenu extends StatelessWidget {
if (!ffiModel.keyboard) return Offstage(); if (!ffiModel.keyboard) return Offstage();
String? modeOnly; String? modeOnly;
if (stateGlobal.grabKeyboard) { if (stateGlobal.grabKeyboard) {
if (bind.sessionIsKeyboardModeSupported(id: id, mode: _kKeyMapMode)) { if (bind.sessionIsKeyboardModeSupported(
bind.sessionSetKeyboardMode(id: id, value: _kKeyMapMode); sessionId: ffi.sessionId, mode: _kKeyMapMode)) {
bind.sessionSetKeyboardMode(
sessionId: ffi.sessionId, value: _kKeyMapMode);
modeOnly = _kKeyMapMode; modeOnly = _kKeyMapMode;
} else if (bind.sessionIsKeyboardModeSupported( } else if (bind.sessionIsKeyboardModeSupported(
id: id, mode: _kKeyLegacyMode)) { sessionId: ffi.sessionId, mode: _kKeyLegacyMode)) {
bind.sessionSetKeyboardMode(id: id, value: _kKeyLegacyMode); bind.sessionSetKeyboardMode(
sessionId: ffi.sessionId, value: _kKeyLegacyMode);
modeOnly = _kKeyLegacyMode; modeOnly = _kKeyLegacyMode;
} }
} }
@ -1279,7 +1292,8 @@ class _KeyboardMenu extends StatelessWidget {
mode(String? modeOnly) { mode(String? modeOnly) {
return futureBuilder(future: () async { return futureBuilder(future: () async {
return await bind.sessionGetKeyboardMode(id: id) ?? _kKeyLegacyMode; return await bind.sessionGetKeyboardMode(sessionId: ffi.sessionId) ??
_kKeyLegacyMode;
}(), hasData: (data) { }(), hasData: (data) {
final groupValue = data as String; final groupValue = data as String;
List<KeyboardModeMenu> modes = [ List<KeyboardModeMenu> modes = [
@ -1291,14 +1305,15 @@ class _KeyboardMenu extends StatelessWidget {
final enabled = !ffi.ffiModel.viewOnly; final enabled = !ffi.ffiModel.viewOnly;
onChanged(String? value) async { onChanged(String? value) async {
if (value == null) return; if (value == null) return;
await bind.sessionSetKeyboardMode(id: id, value: value); await bind.sessionSetKeyboardMode(
sessionId: ffi.sessionId, value: value);
} }
for (KeyboardModeMenu mode in modes) { for (KeyboardModeMenu mode in modes) {
if (modeOnly != null && mode.key != modeOnly) { if (modeOnly != null && mode.key != modeOnly) {
continue; continue;
} else if (!bind.sessionIsKeyboardModeSupported( } else if (!bind.sessionIsKeyboardModeSupported(
id: id, mode: mode.key)) { sessionId: ffi.sessionId, mode: mode.key)) {
continue; continue;
} }
@ -1351,7 +1366,8 @@ class _KeyboardMenu extends StatelessWidget {
onChanged: enabled onChanged: enabled
? (value) async { ? (value) async {
if (value == null) return; 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); ffiModel.setViewOnly(id, value);
} }
: null, : null,
@ -1412,7 +1428,8 @@ class _ChatMenuState extends State<_ChatMenu> {
return MenuButton( return MenuButton(
child: Text(translate('Voice call')), child: Text(translate('Voice call')),
ffi: widget.ffi, 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( return _IconMenuButton(
assetName: icon, assetName: icon,
tooltip: tooltip, tooltip: tooltip,
onPressed: () => bind.sessionCloseVoiceCall(id: id), onPressed: () =>
bind.sessionCloseVoiceCall(sessionId: ffi.sessionId),
color: _MenubarTheme.redColor, color: _MenubarTheme.redColor,
hoverColor: _MenubarTheme.hoverRedColor); hoverColor: _MenubarTheme.hoverRedColor);
}, },
@ -1492,7 +1510,7 @@ class _CloseMenu extends StatelessWidget {
return _IconMenuButton( return _IconMenuButton(
assetName: 'assets/close.svg', assetName: 'assets/close.svg',
tooltip: 'Close', tooltip: 'Close',
onPressed: () => clientClose(id, ffi.dialogManager), onPressed: () => clientClose(ffi.sessionId, ffi.dialogManager),
color: _MenubarTheme.redColor, color: _MenubarTheme.redColor,
hoverColor: _MenubarTheme.hoverRedColor, hoverColor: _MenubarTheme.hoverRedColor,
); );
@ -1753,13 +1771,13 @@ class RdoMenuButton<T> extends StatelessWidget {
} }
class _DraggableShowHide extends StatefulWidget { class _DraggableShowHide extends StatefulWidget {
final String id; final SessionID sessionId;
final RxDouble fractionX; final RxDouble fractionX;
final RxBool dragging; final RxBool dragging;
final RxBool show; final RxBool show;
const _DraggableShowHide({ const _DraggableShowHide({
Key? key, Key? key,
required this.id, required this.sessionId,
required this.fractionX, required this.fractionX,
required this.dragging, required this.dragging,
required this.show, required this.show,
@ -1826,7 +1844,7 @@ class _DraggableShowHideState extends State<_DraggableShowHide> {
widget.fractionX.value = right; widget.fractionX.value = right;
} }
bind.sessionPeerOption( bind.sessionPeerOption(
id: widget.id, sessionId: widget.sessionId,
name: 'remote-menubar-drag-x', name: 'remote-menubar-drag-x',
value: widget.fractionX.value.toString(), value: widget.fractionX.value.toString(),
); );
@ -1952,7 +1970,7 @@ class _MultiMonitorMenu extends StatelessWidget {
), ),
onPressed: () { onPressed: () {
if (display.value != i) { if (display.value != i) {
bind.sessionSwitchDisplay(id: id, value: i); bind.sessionSwitchDisplay(sessionId: ffi.sessionId, value: i);
} }
}, },
); );

View File

@ -17,6 +17,7 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get/get_rx/src/rx_workers/utils/debouncer.dart'; import 'package:get/get_rx/src/rx_workers/utils/debouncer.dart';
import 'package:scroll_pos/scroll_pos.dart'; import 'package:scroll_pos/scroll_pos.dart';
import 'package:uuid/uuid.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
import '../../utils/multi_window_manager.dart'; import '../../utils/multi_window_manager.dart';

View File

@ -73,7 +73,7 @@ class _FileManagerPageState extends State<FileManagerPage> {
gFFI.dialogManager gFFI.dialogManager
.showLoading(translate('Connecting...'), onCancel: closeConnection); .showLoading(translate('Connecting...'), onCancel: closeConnection);
}); });
gFFI.ffiModel.updateEventListener(widget.id); gFFI.ffiModel.updateEventListener(gFFI.sessionId, widget.id);
Wakelock.enable(); Wakelock.enable();
} }
@ -104,7 +104,8 @@ class _FileManagerPageState extends State<FileManagerPage> {
leading: Row(children: [ leading: Row(children: [
IconButton( IconButton(
icon: Icon(Icons.close), icon: Icon(Icons.close),
onPressed: () => clientClose(widget.id, gFFI.dialogManager)), onPressed: () =>
clientClose(gFFI.sessionId, gFFI.dialogManager)),
]), ]),
centerTitle: true, centerTitle: true,
title: ToggleSwitch( title: ToggleSwitch(

View File

@ -54,6 +54,7 @@ class _RemotePageState extends State<RemotePage> {
var _showEdit = false; // use soft keyboard var _showEdit = false; // use soft keyboard
InputModel get inputModel => gFFI.inputModel; InputModel get inputModel => gFFI.inputModel;
SessionID get sessionId => gFFI.sessionId;
@override @override
void initState() { void initState() {
@ -66,9 +67,9 @@ class _RemotePageState extends State<RemotePage> {
}); });
Wakelock.enable(); Wakelock.enable();
_physicalFocusNode.requestFocus(); _physicalFocusNode.requestFocus();
gFFI.ffiModel.updateEventListener(widget.id); gFFI.ffiModel.updateEventListener(sessionId, widget.id);
gFFI.inputModel.listenToMouse(true); gFFI.inputModel.listenToMouse(true);
gFFI.qualityMonitorModel.checkShowQualityMonitor(widget.id); gFFI.qualityMonitorModel.checkShowQualityMonitor(sessionId);
keyboardSubscription = keyboardSubscription =
keyboardVisibilityController.onChange.listen(onSoftKeyboardChanged); keyboardVisibilityController.onChange.listen(onSoftKeyboardChanged);
_blockableOverlayState.applyFfi(gFFI); _blockableOverlayState.applyFfi(gFFI);
@ -130,7 +131,7 @@ class _RemotePageState extends State<RemotePage> {
if (newValue.length > common) { if (newValue.length > common) {
var s = newValue.substring(common); var s = newValue.substring(common);
if (s.length > 1) { if (s.length > 1) {
bind.sessionInputString(id: widget.id, value: s); bind.sessionInputString(sessionId: sessionId, value: s);
} else { } else {
inputChar(s); inputChar(s);
} }
@ -164,11 +165,11 @@ class _RemotePageState extends State<RemotePage> {
content == '' || content == '' ||
content == '【】')) { content == '【】')) {
// can not only input content[0], because when input ], [ are also auo insert, which cause ] never be input // 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(); openKeyboard();
return; return;
} }
bind.sessionInputString(id: widget.id, value: content); bind.sessionInputString(sessionId: sessionId, value: content);
} else { } else {
inputChar(content); inputChar(content);
} }
@ -213,7 +214,7 @@ class _RemotePageState extends State<RemotePage> {
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
clientClose(widget.id, gFFI.dialogManager); clientClose(sessionId, gFFI.dialogManager);
return false; return false;
}, },
child: getRawPointerAndKeyBody(Scaffold( child: getRawPointerAndKeyBody(Scaffold(
@ -305,7 +306,7 @@ class _RemotePageState extends State<RemotePage> {
color: Colors.white, color: Colors.white,
icon: Icon(Icons.clear), icon: Icon(Icons.clear),
onPressed: () { onPressed: () {
clientClose(widget.id, gFFI.dialogManager); clientClose(sessionId, gFFI.dialogManager);
}, },
) )
] + ] +
@ -476,7 +477,7 @@ class _RemotePageState extends State<RemotePage> {
}, },
onTwoFingerScaleEnd: (d) { onTwoFingerScaleEnd: (d) {
_scale = 1; _scale = 1;
bind.sessionSetViewStyle(id: widget.id, value: ""); bind.sessionSetViewStyle(sessionId: sessionId, value: "");
}, },
onThreeFingerVerticalDragUpdate: gFFI.ffiModel.isPeerAndroid onThreeFingerVerticalDragUpdate: gFFI.ffiModel.isPeerAndroid
? null ? null
@ -535,7 +536,7 @@ class _RemotePageState extends State<RemotePage> {
var paints = <Widget>[ImagePaint()]; var paints = <Widget>[ImagePaint()];
if (!gFFI.canvasModel.cursorEmbedded) { if (!gFFI.canvasModel.cursorEmbedded) {
final cursor = bind.sessionGetToggleOptionSync( final cursor = bind.sessionGetToggleOptionSync(
id: widget.id, arg: 'show-remote-cursor'); sessionId: sessionId, arg: 'show-remote-cursor');
if (keyboard || cursor) { if (keyboard || cursor) {
paints.add(CursorPaint()); paints.add(CursorPaint());
} }
@ -579,7 +580,7 @@ class _RemotePageState extends State<RemotePage> {
gFFI.ffiModel.toggleTouchMode(); gFFI.ffiModel.toggleTouchMode();
final v = gFFI.ffiModel.touchMode ? 'Y' : ''; final v = gFFI.ffiModel.touchMode ? 'Y' : '';
bind.sessionPeerOption( bind.sessionPeerOption(
id: widget.id, name: "touch", value: v); sessionId: sessionId, name: "touch", value: v);
}))); })));
} }
@ -830,7 +831,7 @@ void showOptions(
children.add(InkWell( children.add(InkWell(
onTap: () { onTap: () {
if (i == cur) return; if (i == cur) return;
bind.sessionSwitchDisplay(id: id, value: i); bind.sessionSwitchDisplay(sessionId: gFFI.sessionId, value: i);
gFFI.dialogManager.dismissAll(); gFFI.dialogManager.dismissAll();
}, },
child: Ink( child: Ink(

View File

@ -74,7 +74,11 @@ class ChatModel with ChangeNotifier {
final WeakReference<FFI> parent; final WeakReference<FFI> parent;
ChatModel(this.parent); late final SessionID sessionId;
ChatModel(this.parent) {
sessionId = parent.target!.sessionId;
}
FocusNode inputNode = FocusNode(); FocusNode inputNode = FocusNode();
@ -302,7 +306,7 @@ class ChatModel with ChangeNotifier {
_messages[_currentID]?.insert(message); _messages[_currentID]?.insert(message);
if (_currentID == clientModeID) { if (_currentID == clientModeID) {
if (parent.target != null) { if (parent.target != null) {
bind.sessionSendChat(id: parent.target!.id, text: message.text); bind.sessionSendChat(sessionId: sessionId, text: message.text);
} }
} else { } else {
bind.cmSendChat(connId: _currentID, msg: message.text); bind.cmSendChat(connId: _currentID, msg: message.text);
@ -347,8 +351,8 @@ class ChatModel with ChangeNotifier {
} }
} }
void closeVoiceCall(String id) { void closeVoiceCall() {
bind.sessionCloseVoiceCall(id: id); bind.sessionCloseVoiceCall(sessionId: sessionId);
} }
} }

View File

@ -33,11 +33,11 @@ class JobID {
} }
} }
typedef GetSessionID = String Function(); typedef GetSessionID = SessionID Function();
class FileModel { class FileModel {
final WeakReference<FFI> parent; final WeakReference<FFI> parent;
// late final String sessionID; // late final String sessionId;
late final FileFetcher fileFetcher; late final FileFetcher fileFetcher;
late final JobController jobController; late final JobController jobController;
@ -45,11 +45,11 @@ class FileModel {
late final FileController remoteController; late final FileController remoteController;
late final GetSessionID getSessionID; late final GetSessionID getSessionID;
String get sessionID => getSessionID(); SessionID get sessionId => getSessionID();
late final FileDialogEventLoop evtLoop; late final FileDialogEventLoop evtLoop;
FileModel(this.parent) { FileModel(this.parent) {
getSessionID = () => parent.target?.id ?? ""; getSessionID = () => parent.target!.sessionId;
fileFetcher = FileFetcher(getSessionID); fileFetcher = FileFetcher(getSessionID);
jobController = JobController(getSessionID); jobController = JobController(getSessionID);
localController = FileController( localController = FileController(
@ -133,7 +133,7 @@ class FileModel {
evtLoop.setSkip(!need_override); evtLoop.setSkip(!need_override);
} }
await bind.sessionSetConfirmOverrideFile( await bind.sessionSetConfirmOverrideFile(
id: sessionID, sessionId: sessionId,
actId: id, actId: id,
fileNum: int.parse(evt['file_num']), fileNum: int.parse(evt['file_num']),
needOverride: need_override, needOverride: need_override,
@ -236,7 +236,7 @@ class DirectoryData {
class FileController { class FileController {
final bool isLocal; final bool isLocal;
final GetSessionID getSessionID; final GetSessionID getSessionID;
String get sessionID => getSessionID(); SessionID get sessionId => getSessionID();
final FileFetcher fileFetcher; final FileFetcher fileFetcher;
@ -287,7 +287,7 @@ class FileController {
options.value.home = await bind.mainGetHomeDir(); options.value.home = await bind.mainGetHomeDir();
} }
options.value.showHidden = (await bind.sessionGetPeerOption( options.value.showHidden = (await bind.sessionGetPeerOption(
id: sessionID, sessionId: sessionId,
name: isLocal ? "local_show_hidden" : "remote_show_hidden")) name: isLocal ? "local_show_hidden" : "remote_show_hidden"))
.isNotEmpty; .isNotEmpty;
options.value.isWindows = isLocal options.value.isWindows = isLocal
@ -297,7 +297,7 @@ class FileController {
await Future.delayed(Duration(milliseconds: 100)); await Future.delayed(Duration(milliseconds: 100));
final dir = (await bind.sessionGetPeerOption( 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); openDirectory(dir.isEmpty ? options.value.home : dir);
await Future.delayed(Duration(seconds: 1)); await Future.delayed(Duration(seconds: 1));
@ -315,7 +315,7 @@ class FileController {
options.value.showHidden ? "Y" : ""; options.value.showHidden ? "Y" : "";
for (final msg in msgMap.entries) { for (final msg in msgMap.entries) {
await bind.sessionPeerOption( await bind.sessionPeerOption(
id: sessionID, name: msg.key, value: msg.value); sessionId: sessionId, name: msg.key, value: msg.value);
} }
directory.value.clear(); directory.value.clear();
options.value.clear(); options.value.clear();
@ -447,7 +447,7 @@ class FileController {
for (var from in items.items) { for (var from in items.items) {
final jobID = jobController.add(from, isRemoteToLocal); final jobID = jobController.add(from, isRemoteToLocal);
bind.sessionSendFiles( bind.sessionSendFiles(
id: sessionID, sessionId: sessionId,
actId: jobID, actId: jobID,
path: from.path, path: from.path,
to: PathUtil.join(toPath, from.name, isWindows), to: PathUtil.join(toPath, from.name, isWindows),
@ -547,7 +547,8 @@ class FileController {
Future<bool?> showRemoveDialog( Future<bool?> showRemoveDialog(
String title, String content, bool showCheckbox) async { String title, String content, bool showCheckbox) async {
return await dialogManager?.show<bool>((setState, Function(bool v) close, context) { return await dialogManager?.show<bool>(
(setState, Function(bool v) close, context) {
cancel() => close(false); cancel() => close(false);
submit() => close(true); submit() => close(true);
return CustomAlertDialog( return CustomAlertDialog(
@ -611,7 +612,7 @@ class FileController {
void sendRemoveFile(String path, int fileNum) { void sendRemoveFile(String path, int fileNum) {
bind.sessionRemoveFile( bind.sessionRemoveFile(
id: sessionID, sessionId: sessionId,
actId: JobController.jobID.next(), actId: JobController.jobID.next(),
path: path, path: path,
isRemote: !isLocal, isRemote: !isLocal,
@ -621,7 +622,7 @@ class FileController {
void sendRemoveEmptyDir(String path, int fileNum) { void sendRemoveEmptyDir(String path, int fileNum) {
history.removeWhere((element) => element.contains(path)); history.removeWhere((element) => element.contains(path));
bind.sessionRemoveAllEmptyDirs( bind.sessionRemoveAllEmptyDirs(
id: sessionID, sessionId: sessionId,
actId: JobController.jobID.next(), actId: JobController.jobID.next(),
path: path, path: path,
isRemote: !isLocal); isRemote: !isLocal);
@ -629,7 +630,7 @@ class FileController {
Future<void> createDir(String path) async { Future<void> createDir(String path) async {
bind.sessionCreateDir( bind.sessionCreateDir(
id: sessionID, sessionId: sessionId,
actId: JobController.jobID.next(), actId: JobController.jobID.next(),
path: path, path: path,
isRemote: !isLocal); isRemote: !isLocal);
@ -641,7 +642,7 @@ class JobController {
final jobTable = List<JobProgress>.empty(growable: true).obs; final jobTable = List<JobProgress>.empty(growable: true).obs;
final jobResultListener = JobResultListener<Map<String, dynamic>>(); final jobResultListener = JobResultListener<Map<String, dynamic>>();
final GetSessionID getSessionID; final GetSessionID getSessionID;
String get sessionID => getSessionID(); SessionID get sessionId => getSessionID();
JobController(this.getSessionID); JobController(this.getSessionID);
@ -719,7 +720,7 @@ class JobController {
} }
Future<void> cancelJob(int id) async { Future<void> cancelJob(int id) async {
await bind.sessionCancelJob(id: sessionID, actId: id); await bind.sessionCancelJob(sessionId: sessionId, actId: id);
} }
void loadLastJob(Map<String, dynamic> evt) { void loadLastJob(Map<String, dynamic> evt) {
@ -745,7 +746,7 @@ class JobController {
..state = JobState.paused; ..state = JobState.paused;
jobTable.add(jobProgress); jobTable.add(jobProgress);
bind.sessionAddJob( bind.sessionAddJob(
id: sessionID, sessionId: sessionId,
isRemote: isRemote, isRemote: isRemote,
includeHidden: showHidden, includeHidden: showHidden,
actId: currJobId, actId: currJobId,
@ -760,7 +761,7 @@ class JobController {
if (jobIndex != -1) { if (jobIndex != -1) {
final job = jobTable[jobIndex]; final job = jobTable[jobIndex];
bind.sessionResumeJob( bind.sessionResumeJob(
id: sessionID, actId: job.id, isRemote: job.isRemoteToLocal); sessionId: sessionId, actId: job.id, isRemote: job.isRemoteToLocal);
job.state = JobState.inProgress; job.state = JobState.inProgress;
jobTable.refresh(); jobTable.refresh();
} else { } else {
@ -831,7 +832,7 @@ class FileFetcher {
Map<int, Completer<FileDirectory>> readRecursiveTasks = {}; Map<int, Completer<FileDirectory>> readRecursiveTasks = {};
final GetSessionID getSessionID; final GetSessionID getSessionID;
String get sessionID => getSessionID(); SessionID get sessionId => getSessionID();
FileFetcher(this.getSessionID); FileFetcher(this.getSessionID);
@ -896,12 +897,12 @@ class FileFetcher {
try { try {
if (isLocal) { if (isLocal) {
final res = await bind.sessionReadLocalDirSync( final res = await bind.sessionReadLocalDirSync(
id: sessionID, path: path, showHidden: showHidden); sessionId: sessionId, path: path, showHidden: showHidden);
final fd = FileDirectory.fromJson(jsonDecode(res)); final fd = FileDirectory.fromJson(jsonDecode(res));
return fd; return fd;
} else { } else {
await bind.sessionReadRemoteDir( await bind.sessionReadRemoteDir(
id: sessionID, path: path, includeHidden: showHidden); sessionId: sessionId, path: path, includeHidden: showHidden);
return registerReadTask(isLocal, path); return registerReadTask(isLocal, path);
} }
} catch (e) { } catch (e) {
@ -914,7 +915,7 @@ class FileFetcher {
// TODO test Recursive is show hidden default? // TODO test Recursive is show hidden default?
try { try {
await bind.sessionReadDirRecursive( await bind.sessionReadDirRecursive(
id: sessionID, sessionId: sessionId,
actId: actID, actId: actID,
path: path, path: path,
isRemote: !isLocal, isRemote: !isLocal,

View File

@ -59,9 +59,13 @@ class InputModel {
get id => parent.target?.id ?? ""; get id => parent.target?.id ?? "";
late final SessionID sessionId;
bool get keyboardPerm => parent.target!.ffiModel.keyboard; bool get keyboardPerm => parent.target!.ffiModel.keyboard;
InputModel(this.parent); InputModel(this.parent) {
sessionId = parent.target!.sessionId;
}
KeyEventResult handleRawKeyEvent(FocusNode data, RawKeyEvent e) { KeyEventResult handleRawKeyEvent(FocusNode data, RawKeyEvent e) {
if (isDesktop && !stateGlobal.grabKeyboard) { if (isDesktop && !stateGlobal.grabKeyboard) {
@ -70,7 +74,7 @@ class InputModel {
// * Currently mobile does not enable map mode // * Currently mobile does not enable map mode
if (isDesktop) { if (isDesktop) {
bind.sessionGetKeyboardMode(id: id).then((result) { bind.sessionGetKeyboardMode(sessionId: sessionId).then((result) {
keyboardMode = result.toString(); keyboardMode = result.toString();
}); });
} }
@ -169,7 +173,7 @@ class InputModel {
lockModes |= (1 << scrolllock); lockModes |= (1 << scrolllock);
} }
bind.sessionHandleFlutterKeyEvent( bind.sessionHandleFlutterKeyEvent(
id: id, sessionId: sessionId,
name: name, name: name,
platformCode: platformCode, platformCode: platformCode,
positionCode: positionCode, positionCode: positionCode,
@ -204,7 +208,7 @@ class InputModel {
void inputKey(String name, {bool? down, bool? press}) { void inputKey(String name, {bool? down, bool? press}) {
if (!keyboardPerm) return; if (!keyboardPerm) return;
bind.sessionInputKey( bind.sessionInputKey(
id: id, sessionId: sessionId,
name: name, name: name,
down: down ?? false, down: down ?? false,
press: press ?? true, press: press ?? true,
@ -264,7 +268,7 @@ class InputModel {
/// Send scroll event with scroll distance [y]. /// Send scroll event with scroll distance [y].
void scroll(int y) { void scroll(int y) {
bind.sessionSendMouse( bind.sessionSendMouse(
id: id, sessionId: sessionId,
msg: json msg: json
.encode(modify({'id': id, 'type': 'wheel', 'y': y.toString()}))); .encode(modify({'id': id, 'type': 'wheel', 'y': y.toString()})));
} }
@ -287,7 +291,7 @@ class InputModel {
void sendMouse(String type, MouseButtons button) { void sendMouse(String type, MouseButtons button) {
if (!keyboardPerm) return; if (!keyboardPerm) return;
bind.sessionSendMouse( bind.sessionSendMouse(
id: id, sessionId: sessionId,
msg: json.encode(modify({'type': type, 'buttons': button.value}))); msg: json.encode(modify({'type': type, 'buttons': button.value})));
} }
@ -297,7 +301,7 @@ class InputModel {
resetModifiers(); resetModifiers();
} }
_flingTimer?.cancel(); _flingTimer?.cancel();
bind.sessionEnterOrLeave(id: id, enter: enter); bind.sessionEnterOrLeave(sessionId: sessionId, enter: enter);
} }
/// Send mouse movement event with distance in [x] and [y]. /// Send mouse movement event with distance in [x] and [y].
@ -306,7 +310,8 @@ class InputModel {
var x2 = x.toInt(); var x2 = x.toInt();
var y2 = y.toInt(); var y2 = y.toInt();
bind.sessionSendMouse( 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) { void onPointHoverImage(PointerHoverEvent e) {
@ -333,7 +338,8 @@ class InputModel {
var y = delta.dy.toInt(); var y = delta.dy.toInt();
if (x != 0 || y != 0) { if (x != 0 || y != 0) {
bind.sessionSendMouse( 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( bind.sessionSendMouse(
id: id, msg: '{"type": "trackpad", "x": "$dx", "y": "$dy"}'); sessionId: sessionId,
msg: '{"type": "trackpad", "x": "$dx", "y": "$dy"}');
_scheduleFling(x, y, delay); _scheduleFling(x, y, delay);
}); });
} }
@ -439,7 +446,8 @@ class InputModel {
dy = 1; dy = 1;
} }
bind.sessionSendMouse( 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; break;
} }
evt['buttons'] = buttons; evt['buttons'] = buttons;
bind.sessionSendMouse(id: id, msg: json.encode(evt)); bind.sessionSendMouse(sessionId: sessionId, msg: json.encode(evt));
} }
/// Web only /// Web only

View File

@ -27,6 +27,7 @@ import 'package:image/image.dart' as img2;
import 'package:flutter_custom_cursor/cursor_manager.dart'; import 'package:flutter_custom_cursor/cursor_manager.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:uuid/uuid.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
import '../common.dart'; import '../common.dart';
@ -36,7 +37,7 @@ import 'input_model.dart';
import 'platform_model.dart'; import 'platform_model.dart';
typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id); typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id);
typedef ReconnectHandle = Function(OverlayDialogManager, String, bool); typedef ReconnectHandle = Function(OverlayDialogManager, SessionID, bool);
final _waitForImage = <String, bool>{}; final _waitForImage = <String, bool>{};
class FfiModel with ChangeNotifier { class FfiModel with ChangeNotifier {
@ -52,6 +53,7 @@ class FfiModel with ChangeNotifier {
var _reconnects = 1; var _reconnects = 1;
bool _viewOnly = false; bool _viewOnly = false;
WeakReference<FFI> parent; WeakReference<FFI> parent;
late final SessionID sessionId;
Map<String, bool> get permissions => _permissions; Map<String, bool> get permissions => _permissions;
@ -77,6 +79,7 @@ class FfiModel with ChangeNotifier {
FfiModel(this.parent) { FfiModel(this.parent) {
clear(); clear();
sessionId = parent.target!.sessionId;
} }
toggleTouchMode() { toggleTouchMode() {
@ -139,20 +142,21 @@ class FfiModel with ChangeNotifier {
_permissions.clear(); _permissions.clear();
} }
StreamEventHandler startEventListener(String peerId) { // todo: why called by two position
StreamEventHandler startEventListener(SessionID sessionId, String peerId) {
return (evt) async { return (evt) async {
var name = evt['name']; var name = evt['name'];
if (name == 'msgbox') { if (name == 'msgbox') {
handleMsgBox(evt, peerId); handleMsgBox(evt, sessionId, peerId);
} else if (name == 'peer_info') { } else if (name == 'peer_info') {
handlePeerInfo(evt, peerId); handlePeerInfo(evt, peerId);
} else if (name == 'sync_peer_info') { } else if (name == 'sync_peer_info') {
handleSyncPeerInfo(evt, peerId); handleSyncPeerInfo(evt, sessionId);
} else if (name == 'connection_ready') { } else if (name == 'connection_ready') {
setConnectionType( setConnectionType(
peerId, evt['secure'] == 'true', evt['direct'] == 'true'); peerId, evt['secure'] == 'true', evt['direct'] == 'true');
} else if (name == 'switch_display') { } else if (name == 'switch_display') {
handleSwitchDisplay(evt, peerId); handleSwitchDisplay(evt, sessionId, peerId);
} else if (name == 'cursor_data') { } else if (name == 'cursor_data') {
await parent.target?.cursorModel.updateCursorData(evt); await parent.target?.cursorModel.updateCursorData(evt);
} else if (name == 'cursor_id') { } else if (name == 'cursor_id') {
@ -193,7 +197,7 @@ class FfiModel with ChangeNotifier {
} else if (name == 'update_block_input_state') { } else if (name == 'update_block_input_state') {
updateBlockInputState(evt, peerId); updateBlockInputState(evt, peerId);
} else if (name == 'update_privacy_mode') { } else if (name == 'update_privacy_mode') {
updatePrivacyMode(evt, peerId); updatePrivacyMode(evt, sessionId, peerId);
} else if (name == 'new_connection') { } else if (name == 'new_connection') {
var uni_links = evt['uni_links'].toString(); var uni_links = evt['uni_links'].toString();
if (uni_links.startsWith(kUniLinksPrefix)) { if (uni_links.startsWith(kUniLinksPrefix)) {
@ -205,10 +209,10 @@ class FfiModel with ChangeNotifier {
final show = evt['show'].toString() == 'true'; final show = evt['show'].toString() == 'true';
parent.target?.serverModel.setShowElevation(show); parent.target?.serverModel.setShowElevation(show);
} else if (name == 'cancel_msgbox') { } else if (name == 'cancel_msgbox') {
cancelMsgBox(evt, peerId); cancelMsgBox(evt, sessionId);
} else if (name == 'switch_back') { } else if (name == 'switch_back') {
final peer_id = evt['peer_id'].toString(); final peer_id = evt['peer_id'].toString();
await bind.sessionSwitchSides(id: peer_id); await bind.sessionSwitchSides(sessionId: sessionId);
closeConnection(id: peer_id); closeConnection(id: peer_id);
} else if (name == 'portable_service_running') { } else if (name == 'portable_service_running') {
parent.target?.elevationModel.onPortableServiceRunning(evt); parent.target?.elevationModel.onPortableServiceRunning(evt);
@ -234,12 +238,12 @@ class FfiModel with ChangeNotifier {
} else if (name == 'plugin_manager') { } else if (name == 'plugin_manager') {
pluginManager.handleEvent(evt); pluginManager.handleEvent(evt);
} else if (name == 'plugin_event') { } else if (name == 'plugin_event') {
handlePluginEvent( handlePluginEvent(evt,
evt, peerId, (Map<String, dynamic> e) => handleMsgBox(e, peerId)); (Map<String, dynamic> e) => handleMsgBox(e, sessionId, peerId));
} else if (name == 'plugin_reload') { } else if (name == 'plugin_reload') {
handleReloading(evt, peerId); handleReloading(evt);
} else if (name == 'plugin_option') { } else if (name == 'plugin_option') {
handleOption(evt, peerId); handleOption(evt);
} else { } else {
debugPrint('Unknown event name: $name'); debugPrint('Unknown event name: $name');
} }
@ -271,8 +275,8 @@ class FfiModel with ChangeNotifier {
} }
/// Bind the event listener to receive events from the Rust core. /// Bind the event listener to receive events from the Rust core.
updateEventListener(String peerId) { updateEventListener(SessionID sessionId, String peerId) {
platformFFI.setEventCallback(startEventListener(peerId)); platformFFI.setEventCallback(startEventListener(sessionId, peerId));
} }
handleAliasChanged(Map<String, dynamic> evt) { handleAliasChanged(Map<String, dynamic> evt) {
@ -282,18 +286,19 @@ class FfiModel with ChangeNotifier {
} }
} }
_updateCurDisplay(String peerId, Display newDisplay) { _updateCurDisplay(SessionID sessionId, Display newDisplay) {
if (newDisplay != _display) { if (newDisplay != _display) {
if (newDisplay.x != _display.x || newDisplay.y != _display.y) { if (newDisplay.x != _display.x || newDisplay.y != _display.y) {
parent.target?.cursorModel parent.target?.cursorModel
.updateDisplayOrigin(newDisplay.x, newDisplay.y); .updateDisplayOrigin(newDisplay.x, newDisplay.y);
} }
_display = newDisplay; _display = newDisplay;
_updateSessionWidthHeight(peerId); _updateSessionWidthHeight(sessionId);
} }
} }
handleSwitchDisplay(Map<String, dynamic> evt, String peerId) { handleSwitchDisplay(
Map<String, dynamic> evt, SessionID sessionId, String peerId) {
_pi.currentDisplay = int.parse(evt['display']); _pi.currentDisplay = int.parse(evt['display']);
var newDisplay = Display(); var newDisplay = Display();
newDisplay.x = double.tryParse(evt['x']) ?? newDisplay.x; newDisplay.x = double.tryParse(evt['x']) ?? newDisplay.x;
@ -306,7 +311,7 @@ class FfiModel with ChangeNotifier {
newDisplay.originalHeight = newDisplay.originalHeight =
int.tryParse(evt['original_height']) ?? kInvalidResolutionValue; int.tryParse(evt['original_height']) ?? kInvalidResolutionValue;
_updateCurDisplay(peerId, newDisplay); _updateCurDisplay(sessionId, newDisplay);
try { try {
CurrentDisplayState.find(peerId).value = _pi.currentDisplay; CurrentDisplayState.find(peerId).value = _pi.currentDisplay;
@ -318,15 +323,15 @@ class FfiModel with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
cancelMsgBox(Map<String, dynamic> evt, String id) { cancelMsgBox(Map<String, dynamic> evt, SessionID sessionId) {
if (parent.target == null) return; if (parent.target == null) return;
final dialogManager = parent.target!.dialogManager; final dialogManager = parent.target!.dialogManager;
final tag = '$id-${evt['tag']}'; final tag = '$sessionId-${evt['tag']}';
dialogManager.dismissByTag(tag); dialogManager.dismissByTag(tag);
} }
/// Handle the message box event based on [evt] and [id]. /// Handle the message box event based on [evt] and [id].
handleMsgBox(Map<String, dynamic> evt, String id) { handleMsgBox(Map<String, dynamic> evt, SessionID sessionId, String peerId) {
if (parent.target == null) return; if (parent.target == null) return;
final dialogManager = parent.target!.dialogManager; final dialogManager = parent.target!.dialogManager;
final type = evt['type']; final type = evt['type'];
@ -334,43 +339,43 @@ class FfiModel with ChangeNotifier {
final text = evt['text']; final text = evt['text'];
final link = evt['link']; final link = evt['link'];
if (type == 're-input-password') { if (type == 're-input-password') {
wrongPasswordDialog(id, dialogManager, type, title, text); wrongPasswordDialog(sessionId, dialogManager, type, title, text);
} else if (type == 'input-password') { } else if (type == 'input-password') {
enterPasswordDialog(id, dialogManager); enterPasswordDialog(sessionId, dialogManager);
} else if (type == 'session-login' || type == 'session-re-login') { } else if (type == 'session-login' || type == 'session-re-login') {
enterUserLoginDialog(id, dialogManager); enterUserLoginDialog(sessionId, dialogManager);
} else if (type == 'session-login-password' || } else if (type == 'session-login-password' ||
type == 'session-login-password') { type == 'session-login-password') {
enterUserLoginAndPasswordDialog(id, dialogManager); enterUserLoginAndPasswordDialog(sessionId, dialogManager);
} else if (type == 'restarting') { } else if (type == 'restarting') {
showMsgBox(id, type, title, text, link, false, dialogManager, showMsgBox(sessionId, type, title, text, link, false, dialogManager,
hasCancel: false); hasCancel: false);
} else if (type == 'wait-remote-accept-nook') { } 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') { } 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') { } else if (type == 'wait-uac') {
showWaitUacDialog(id, dialogManager, type); showWaitUacDialog(sessionId, dialogManager, type);
} else if (type == 'elevation-error') { } else if (type == 'elevation-error') {
showElevationError(id, type, title, text, dialogManager); showElevationError(sessionId, type, title, text, dialogManager);
} else if (type == 'relay-hint') { } else if (type == 'relay-hint') {
showRelayHintDialog(id, type, title, text, dialogManager); showRelayHintDialog(sessionId, type, title, text, dialogManager);
} else { } else {
var hasRetry = evt['hasRetry'] == 'true'; 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]. /// Show a message box with [type], [title] and [text].
showMsgBox(String id, String type, String title, String text, String link, showMsgBox(SessionID sessionId, String type, String title, String text,
bool hasRetry, OverlayDialogManager dialogManager, String link, bool hasRetry, OverlayDialogManager dialogManager,
{bool? hasCancel}) { {bool? hasCancel}) {
msgBox(id, type, title, text, link, dialogManager, msgBox(sessionId, type, title, text, link, dialogManager,
hasCancel: hasCancel, reconnect: reconnect); hasCancel: hasCancel, reconnect: reconnect);
_timer?.cancel(); _timer?.cancel();
if (hasRetry) { if (hasRetry) {
_timer = Timer(Duration(seconds: _reconnects), () { _timer = Timer(Duration(seconds: _reconnects), () {
reconnect(dialogManager, id, false); reconnect(dialogManager, sessionId, false);
}); });
_reconnects *= 2; _reconnects *= 2;
} else { } else {
@ -378,17 +383,17 @@ class FfiModel with ChangeNotifier {
} }
} }
void reconnect( void reconnect(OverlayDialogManager dialogManager, SessionID sessionId,
OverlayDialogManager dialogManager, String id, bool forceRelay) { bool forceRelay) {
bind.sessionReconnect(id: id, forceRelay: forceRelay); bind.sessionReconnect(sessionId: sessionId, forceRelay: forceRelay);
clearPermissions(); clearPermissions();
dialogManager.showLoading(translate('Connecting...'), dialogManager.showLoading(translate('Connecting...'),
onCancel: closeConnection); onCancel: closeConnection);
} }
void showRelayHintDialog(String id, String type, String title, String text, void showRelayHintDialog(SessionID sessionId, String type, String title,
OverlayDialogManager dialogManager) { String text, OverlayDialogManager dialogManager) {
dialogManager.show(tag: '$id-$type', (setState, close, context) { dialogManager.show(tag: '$sessionId-$type', (setState, close, context) {
onClose() { onClose() {
closeConnection(); closeConnection();
close(); close();
@ -403,15 +408,17 @@ class FfiModel with ChangeNotifier {
actions: [ actions: [
dialogButton('Close', onPressed: onClose, isOutline: true), dialogButton('Close', onPressed: onClose, isOutline: true),
dialogButton('Retry', dialogButton('Retry',
onPressed: () => reconnect(dialogManager, id, false)), onPressed: () => reconnect(dialogManager, sessionId, false)),
dialogButton('Connect via relay', dialogButton('Connect via relay',
onPressed: () => reconnect(dialogManager, id, true), onPressed: () => reconnect(dialogManager, sessionId, true),
buttonStyle: style), buttonStyle: style),
dialogButton('Always connect via relay', onPressed: () { dialogButton('Always connect via relay', onPressed: () {
const option = 'force-always-relay'; const option = 'force-always-relay';
bind.sessionPeerOption( bind.sessionPeerOption(
id: id, name: option, value: bool2option(option, true)); sessionId: sessionId,
reconnect(dialogManager, id, true); name: option,
value: bool2option(option, true));
reconnect(dialogManager, sessionId, true);
}, buttonStyle: style), }, buttonStyle: style),
], ],
onCancel: onClose, onCancel: onClose,
@ -419,13 +426,14 @@ class FfiModel with ChangeNotifier {
}); });
} }
_updateSessionWidthHeight(String id) { _updateSessionWidthHeight(SessionID sessionId) {
parent.target?.canvasModel.updateViewStyle(); parent.target?.canvasModel.updateViewStyle();
if (display.width <= 0 || display.height <= 0) { if (display.width <= 0 || display.height <= 0) {
debugPrintStack( debugPrintStack(
label: 'invalid display size (${display.width},${display.height})'); label: 'invalid display size (${display.width},${display.height})');
} else { } 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!)); .showMobileActionsOverlay(ffi: parent.target!));
} }
} else { } else {
_touchMode = _touchMode = await bind.sessionGetOption(
await bind.sessionGetOption(id: peerId, arg: 'touch-mode') != ''; sessionId: sessionId, arg: 'touch-mode') !=
'';
} }
if (connType == ConnType.fileTransfer) { if (connType == ConnType.fileTransfer) {
@ -476,7 +485,7 @@ class FfiModel with ChangeNotifier {
stateGlobal.displaysCount.value = _pi.displays.length; stateGlobal.displaysCount.value = _pi.displays.length;
if (_pi.currentDisplay < _pi.displays.length) { if (_pi.currentDisplay < _pi.displays.length) {
_display = _pi.displays[_pi.currentDisplay]; _display = _pi.displays[_pi.currentDisplay];
_updateSessionWidthHeight(peerId); _updateSessionWidthHeight(sessionId);
} }
if (displays.isNotEmpty) { if (displays.isNotEmpty) {
parent.target?.dialogManager.showLoading( parent.target?.dialogManager.showLoading(
@ -491,8 +500,10 @@ class FfiModel with ChangeNotifier {
parent.target?.elevationModel.onPeerInfo(_pi); parent.target?.elevationModel.onPeerInfo(_pi);
} }
if (connType == ConnType.defaultConn) { if (connType == ConnType.defaultConn) {
setViewOnly(peerId, setViewOnly(
bind.sessionGetToggleOptionSync(id: peerId, arg: 'view-only')); peerId,
bind.sessionGetToggleOptionSync(
sessionId: sessionId, arg: 'view-only'));
} }
if (connType == ConnType.defaultConn) { if (connType == ConnType.defaultConn) {
final platform_additions = evt['platform_additions']; final platform_additions = evt['platform_additions'];
@ -547,7 +558,7 @@ class FfiModel with ChangeNotifier {
} }
/// Handle the peer info synchronization event based on [evt]. /// Handle the peer info synchronization event based on [evt].
handleSyncPeerInfo(Map<String, dynamic> evt, String peerId) async { handleSyncPeerInfo(Map<String, dynamic> evt, SessionID sessionId) async {
if (evt['displays'] != null) { if (evt['displays'] != null) {
List<dynamic> displays = json.decode(evt['displays']); List<dynamic> displays = json.decode(evt['displays']);
List<Display> newDisplays = []; List<Display> newDisplays = [];
@ -557,7 +568,7 @@ class FfiModel with ChangeNotifier {
_pi.displays = newDisplays; _pi.displays = newDisplays;
stateGlobal.displaysCount.value = _pi.displays.length; stateGlobal.displaysCount.value = _pi.displays.length;
if (_pi.currentDisplay >= 0 && _pi.currentDisplay < _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(); notifyListeners();
@ -573,11 +584,12 @@ class FfiModel with ChangeNotifier {
} }
} }
updatePrivacyMode(Map<String, dynamic> evt, String peerId) { updatePrivacyMode(
Map<String, dynamic> evt, SessionID sessionId, String peerId) {
notifyListeners(); notifyListeners();
try { try {
PrivacyModeState.find(peerId).value = PrivacyModeState.find(peerId).value = bind.sessionGetToggleOptionSync(
bind.sessionGetToggleOptionSync(id: peerId, arg: 'privacy-mode'); sessionId: sessionId, arg: 'privacy-mode');
} catch (e) { } catch (e) {
// //
} }
@ -592,8 +604,8 @@ class FfiModel with ChangeNotifier {
if (value) { if (value) {
ShowRemoteCursorState.find(id).value = value; ShowRemoteCursorState.find(id).value = value;
} else { } else {
ShowRemoteCursorState.find(id).value = ShowRemoteCursorState.find(id).value = bind.sessionGetToggleOptionSync(
bind.sessionGetToggleOptionSync(id: id, arg: 'show-remote-cursor'); sessionId: sessionId, arg: 'show-remote-cursor');
} }
} catch (e) { } catch (e) {
// //
@ -612,11 +624,15 @@ class ImageModel with ChangeNotifier {
String id = ''; String id = '';
late final SessionID sessionId;
WeakReference<FFI> parent; WeakReference<FFI> parent;
final List<Function(String)> callbacksOnFirstImage = []; final List<Function(String)> callbacksOnFirstImage = [];
ImageModel(this.parent); ImageModel(this.parent) {
sessionId = parent.target!.sessionId;
}
addCallbackOnFirstImage(Function(String) cb) => callbacksOnFirstImage.add(cb); addCallbackOnFirstImage(Function(String) cb) => callbacksOnFirstImage.add(cb);
@ -645,7 +661,7 @@ class ImageModel with ChangeNotifier {
isWeb ? ui.PixelFormat.rgba8888 : ui.PixelFormat.bgra8888, isWeb ? ui.PixelFormat.rgba8888 : ui.PixelFormat.bgra8888,
onPixelsCopied: () { onPixelsCopied: () {
// Unlock the rgba memory from rust codes. // Unlock the rgba memory from rust codes.
platformFFI.nextRgba(id); platformFFI.nextRgba(sessionId);
}).then((image) { }).then((image) {
if (parent.target?.id != pid) return; if (parent.target?.id != pid) return;
try { try {
@ -674,7 +690,7 @@ class ImageModel with ChangeNotifier {
await initializeCursorAndCanvas(parent.target!); await initializeCursorAndCanvas(parent.target!);
} }
if (parent.target?.ffiModel.isPeerAndroid ?? false) { if (parent.target?.ffiModel.isPeerAndroid ?? false) {
bind.sessionSetViewStyle(id: id, value: 'adaptive'); bind.sessionSetViewStyle(sessionId: sessionId, value: 'adaptive');
parent.target?.canvasModel.updateViewStyle(); parent.target?.canvasModel.updateViewStyle();
} }
} }
@ -793,6 +809,7 @@ class CanvasModel with ChangeNotifier {
// double windowBorderWidth = 0.0; // double windowBorderWidth = 0.0;
// remote id // remote id
String id = ''; String id = '';
late final SessionID sessionId;
// scroll offset x percent // scroll offset x percent
double _scrollX = 0.0; double _scrollX = 0.0;
// scroll offset y percent // scroll offset y percent
@ -804,7 +821,9 @@ class CanvasModel with ChangeNotifier {
WeakReference<FFI> parent; WeakReference<FFI> parent;
CanvasModel(this.parent); CanvasModel(this.parent) {
sessionId = parent.target!.sessionId;
}
double get x => _x; double get x => _x;
double get y => _y; double get y => _y;
@ -847,7 +866,7 @@ class CanvasModel with ChangeNotifier {
return Size(w < 0 ? 0 : w, h < 0 ? 0 : h); 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) { if (style == null) {
return; return;
} }
@ -883,7 +902,7 @@ class CanvasModel with ChangeNotifier {
} }
updateScrollStyle() async { updateScrollStyle() async {
final style = await bind.sessionGetScrollStyle(id: id); final style = await bind.sessionGetScrollStyle(sessionId: sessionId);
if (style == kRemoteScrollStyleBar) { if (style == kRemoteScrollStyleBar) {
_scrollStyle = ScrollStyle.scrollbar; _scrollStyle = ScrollStyle.scrollbar;
_resetScroll(); _resetScroll();
@ -1358,8 +1377,8 @@ class CursorModel with ChangeNotifier {
Future<bool> _updateCache( Future<bool> _updateCache(
Uint8List rgba, ui.Image image, int id, int w, int h) async { Uint8List rgba, ui.Image image, int id, int w, int h) async {
Uint8List? data; Uint8List? data;
img2.Image imgOrigin = img2.Image imgOrigin = img2.Image.fromBytes(
img2.Image.fromBytes(width: w, height:h, bytes: rgba.buffer, order: img2.ChannelOrder.rgba); width: w, height: h, bytes: rgba.buffer, order: img2.ChannelOrder.rgba);
if (Platform.isWindows) { if (Platform.isWindows) {
data = imgOrigin.getBytes(order: img2.ChannelOrder.bgra); data = imgOrigin.getBytes(order: img2.ChannelOrder.bgra);
} else { } else {
@ -1474,9 +1493,9 @@ class QualityMonitorModel with ChangeNotifier {
bool get show => _show; bool get show => _show;
QualityMonitorData get data => _data; QualityMonitorData get data => _data;
checkShowQualityMonitor(String id) async { checkShowQualityMonitor(SessionID sessionId) async {
final show = await bind.sessionGetToggleOption( final show = await bind.sessionGetToggleOption(
id: id, arg: 'show-quality-monitor') == sessionId: sessionId, arg: 'show-quality-monitor') ==
true; true;
if (_show != show) { if (_show != show) {
_show = show; _show = show;
@ -1510,32 +1529,35 @@ class RecordingModel with ChangeNotifier {
onSwitchDisplay() { onSwitchDisplay() {
if (isIOS || !_start) return; if (isIOS || !_start) return;
var id = parent.target?.id; final sessionId = parent.target?.sessionId;
int? width = parent.target?.canvasModel.getDisplayWidth(); int? width = parent.target?.canvasModel.getDisplayWidth();
int? height = parent.target?.canvasModel.getDisplayHeight(); int? height = parent.target?.canvasModel.getDisplayHeight();
if (id == null || width == null || height == null) return; if (sessionId == null || width == null || height == null) return;
bind.sessionRecordScreen(id: id, start: true, width: width, height: height); bind.sessionRecordScreen(
sessionId: sessionId, start: true, width: width, height: height);
} }
toggle() { toggle() {
if (isIOS) return; if (isIOS) return;
var id = parent.target?.id; final sessionId = parent.target?.sessionId;
if (id == null) return; if (sessionId == null) return;
_start = !_start; _start = !_start;
notifyListeners(); notifyListeners();
if (_start) { if (_start) {
bind.sessionRefresh(id: id); bind.sessionRefresh(sessionId: sessionId);
} else { } else {
bind.sessionRecordScreen(id: id, start: false, width: 0, height: 0); bind.sessionRecordScreen(
sessionId: sessionId, start: false, width: 0, height: 0);
} }
} }
onClose() { onClose() {
if (isIOS) return; if (isIOS) return;
var id = parent.target?.id; final sessionId = parent.target?.sessionId;
if (id == null) return; if (sessionId == null) return;
_start = false; _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. /// Flutter state manager and data communication with the Rust core.
class FFI { class FFI {
final sessionId = Uuid().v4obj();
var id = ''; var id = '';
var version = ''; var version = '';
var connType = ConnType.defaultConn; var connType = ConnType.defaultConn;
@ -1610,10 +1633,8 @@ class FFI {
assert(!(isFileTransfer && isPortForward), 'more than one connect type'); assert(!(isFileTransfer && isPortForward), 'more than one connect type');
if (isFileTransfer) { if (isFileTransfer) {
connType = ConnType.fileTransfer; connType = ConnType.fileTransfer;
id = 'ft_$id';
} else if (isPortForward) { } else if (isPortForward) {
connType = ConnType.portForward; connType = ConnType.portForward;
id = 'pf_$id';
} else { } else {
chatModel.resetClientMode(); chatModel.resetClientMode();
connType = ConnType.defaultConn; connType = ConnType.defaultConn;
@ -1623,6 +1644,7 @@ class FFI {
} }
// ignore: unused_local_variable // ignore: unused_local_variable
final addRes = bind.sessionAddSync( final addRes = bind.sessionAddSync(
sessionId: sessionId,
id: id, id: id,
isFileTransfer: isFileTransfer, isFileTransfer: isFileTransfer,
isPortForward: isPortForward, isPortForward: isPortForward,
@ -1631,8 +1653,8 @@ class FFI {
forceRelay: forceRelay ?? false, forceRelay: forceRelay ?? false,
password: password ?? "", password: password ?? "",
); );
final stream = bind.sessionStart(id: id); final stream = bind.sessionStart(sessionId: sessionId, id: id);
final cb = ffiModel.startEventListener(id); final cb = ffiModel.startEventListener(sessionId, id);
() async { () async {
final useTextureRender = bind.mainUseTextureRender(); final useTextureRender = bind.mainUseTextureRender();
// Preserved for the rgba data. // Preserved for the rgba data.
@ -1664,11 +1686,11 @@ class FFI {
} }
} else { } else {
// Fetch the image buffer from rust codes. // Fetch the image buffer from rust codes.
final sz = platformFFI.getRgbaSize(id); final sz = platformFFI.getRgbaSize(sessionId);
if (sz == null || sz == 0) { if (sz == null || sz == 0) {
return; return;
} }
final rgba = platformFFI.getRgba(id, sz); final rgba = platformFFI.getRgba(sessionId, sz);
if (rgba != null) { if (rgba != null) {
imageModel.onRgba(rgba); imageModel.onRgba(rgba);
} }
@ -1682,10 +1704,10 @@ class FFI {
} }
/// Login with [password], choose if the client should [remember] it. /// Login with [password], choose if the client should [remember] it.
void login(String osUsername, String osPassword, String id, String password, void login(String osUsername, String osPassword, SessionID sessionId,
bool remember) { String password, bool remember) {
bind.sessionLogin( bind.sessionLogin(
id: id, sessionId: sessionId,
osUsername: osUsername, osUsername: osUsername,
osPassword: osPassword, osPassword: osPassword,
password: password, password: password,
@ -1696,15 +1718,21 @@ class FFI {
Future<void> close() async { Future<void> close() async {
chatModel.close(); chatModel.close();
if (imageModel.image != null && !isWebDesktop) { if (imageModel.image != null && !isWebDesktop) {
await setCanvasConfig(id, cursorModel.x, cursorModel.y, canvasModel.x, await setCanvasConfig(
canvasModel.y, canvasModel.scale, ffiModel.pi.currentDisplay); sessionId,
cursorModel.x,
cursorModel.y,
canvasModel.x,
canvasModel.y,
canvasModel.scale,
ffiModel.pi.currentDisplay);
} }
imageModel.update(null); imageModel.update(null);
cursorModel.clear(); cursorModel.clear();
ffiModel.clear(); ffiModel.clear();
canvasModel.clear(); canvasModel.clear();
inputModel.resetModifiers(); inputModel.resetModifiers();
await bind.sessionClose(id: id); await bind.sessionClose(sessionId: sessionId);
debugPrint('model $id closed'); debugPrint('model $id closed');
id = ''; id = '';
} }
@ -1795,8 +1823,14 @@ class PeerInfo {
const canvasKey = 'canvas'; const canvasKey = 'canvas';
Future<void> setCanvasConfig(String id, double xCursor, double yCursor, Future<void> setCanvasConfig(
double xCanvas, double yCanvas, double scale, int currentDisplay) async { SessionID sessionId,
double xCursor,
double yCursor,
double xCanvas,
double yCanvas,
double scale,
int currentDisplay) async {
final p = <String, dynamic>{}; final p = <String, dynamic>{};
p['xCursor'] = xCursor; p['xCursor'] = xCursor;
p['yCursor'] = yCursor; p['yCursor'] = yCursor;
@ -1804,12 +1838,14 @@ Future<void> setCanvasConfig(String id, double xCursor, double yCursor,
p['yCanvas'] = yCanvas; p['yCanvas'] = yCanvas;
p['scale'] = scale; p['scale'] = scale;
p['currentDisplay'] = currentDisplay; p['currentDisplay'] = currentDisplay;
await bind.sessionSetFlutterConfig(id: id, k: canvasKey, v: jsonEncode(p)); await bind.sessionSetFlutterConfig(
sessionId: sessionId, k: canvasKey, v: jsonEncode(p));
} }
Future<Map<String, dynamic>?> getCanvasConfig(String id) async { Future<Map<String, dynamic>?> getCanvasConfig(SessionID sessionId) async {
if (!isWebDesktop) return null; 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; if (p == null || p.isEmpty) return null;
try { try {
Map<String, dynamic> m = json.decode(p); Map<String, dynamic> m = json.decode(p);
@ -1819,12 +1855,8 @@ Future<Map<String, dynamic>?> getCanvasConfig(String id) async {
} }
} }
void removePreference(String id) async {
await bind.sessionSetFlutterConfig(id: id, k: canvasKey, v: '');
}
Future<void> initializeCursorAndCanvas(FFI ffi) async { Future<void> initializeCursorAndCanvas(FFI ffi) async {
var p = await getCanvasConfig(ffi.id); var p = await getCanvasConfig(ffi.sessionId);
int currentDisplay = 0; int currentDisplay = 0;
if (p != null) { if (p != null) {
currentDisplay = p['currentDisplay']; currentDisplay = p['currentDisplay'];

View File

@ -104,9 +104,10 @@ class PlatformFFI {
return res; return res;
} }
Uint8List? getRgba(String id, int bufSize) { Uint8List? getRgba(SessionID sessionId, int bufSize) {
if (_session_get_rgba == null) return null; if (_session_get_rgba == null) return null;
var a = id.toNativeUtf8(); final sessionIdStr = sessionId.toString();
var a = sessionIdStr.toNativeUtf8();
try { try {
final buffer = _session_get_rgba!(a); final buffer = _session_get_rgba!(a);
if (buffer == nullptr) { 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; 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); final bufferSize = _session_get_rgba_size!(a);
malloc.free(a); malloc.free(a);
return bufferSize; return bufferSize;
} }
void nextRgba(String id) { void nextRgba(SessionID sessionId) {
if (_session_next_rgba == null) return; if (_session_next_rgba == null) return;
final a = id.toNativeUtf8(); final sessionIdStr = sessionId.toString();
final a = sessionIdStr.toNativeUtf8();
_session_next_rgba!(a); _session_next_rgba!(a);
malloc.free(a); malloc.free(a);
} }
void registerTexture(String id, int ptr) { void registerTexture(SessionID sessionId, int ptr) {
if (_session_register_texture == null) return; if (_session_register_texture == null) return;
final a = id.toNativeUtf8(); final sessionIdStr = sessionId.toString();
final a = sessionIdStr.toNativeUtf8();
_session_register_texture!(a, ptr); _session_register_texture!(a, ptr);
malloc.free(a); malloc.free(a);
} }

View File

@ -343,7 +343,7 @@ class ServerModel with ChangeNotifier {
Future<void> startService() async { Future<void> startService() async {
_isStart = true; _isStart = true;
notifyListeners(); notifyListeners();
parent.target?.ffiModel.updateEventListener(""); parent.target?.ffiModel.updateEventListener(parent.target!.sessionId, "");
await parent.target?.invokeMethod("init_service"); await parent.target?.invokeMethod("init_service");
// ugly is here, because for desktop, below is useless // ugly is here, because for desktop, below is useless
await bind.mainStartService(); await bind.mainStartService();

View File

@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
void handlePluginEvent( void handlePluginEvent(
Map<String, dynamic> evt, Map<String, dynamic> evt,
String peer,
Function(Map<String, dynamic> e) handleMsgBox, Function(Map<String, dynamic> e) handleMsgBox,
) { ) {
Map<String, dynamic>? content; Map<String, dynamic>? content;

View File

@ -275,7 +275,7 @@ class PluginItem extends StatelessWidget {
} }
} }
void handleReloading(Map<String, dynamic> evt, String peer) { void handleReloading(Map<String, dynamic> evt) {
if (evt['id'] == null || evt['location'] == null) { if (evt['id'] == null || evt['location'] == null) {
return; return;
} }
@ -295,7 +295,7 @@ void handleReloading(Map<String, dynamic> evt, String peer) {
} }
} }
void handleOption(Map<String, dynamic> evt, String peer) { void handleOption(Map<String, dynamic> evt) {
updateOption( updateOption(
evt['location'], evt['id'], evt['peer'] ?? '', evt['key'], evt['value']); evt['location'], evt['id'], evt['peer'] ?? '', evt['key'], evt['value']);
} }

View File

@ -1331,7 +1331,7 @@ packages:
source: hosted source: hosted
version: "3.0.3" version: "3.0.3"
uuid: uuid:
dependency: transitive dependency: "direct main"
description: description:
name: uuid name: uuid
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"

View File

@ -95,6 +95,7 @@ dependencies:
texture_rgba_renderer: ^0.0.16 texture_rgba_renderer: ^0.0.16
percent_indicator: ^4.2.2 percent_indicator: ^4.2.2
dropdown_button2: ^2.0.0 dropdown_button2: ^2.0.0
uuid: ^3.0.7
dev_dependencies: dev_dependencies:
icons_launcher: ^2.0.4 icons_launcher: ^2.0.4

View File

@ -5,7 +5,7 @@ use hbb_common::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
Mutex as TokioMutex, Mutex as TokioMutex,
}, },
ResultType, ResultType, SessionID,
}; };
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::{ use std::{
@ -59,7 +59,7 @@ struct ConnEnabled {
} }
struct MsgChannel { struct MsgChannel {
peer_id: String, session_uuid: SessionID,
conn_id: i32, conn_id: i32,
sender: UnboundedSender<ClipboardFile>, sender: UnboundedSender<ClipboardFile>,
receiver: Arc<TokioMutex<UnboundedReceiver<ClipboardFile>>>, receiver: Arc<TokioMutex<UnboundedReceiver<ClipboardFile>>>,
@ -78,20 +78,23 @@ lazy_static::lazy_static! {
static ref PROCESS_SIDE: RwLock<ProcessSide> = RwLock::new(ProcessSide::UnknownSide); static ref PROCESS_SIDE: RwLock<ProcessSide> = RwLock::new(ProcessSide::UnknownSide);
} }
pub fn get_client_conn_id(peer_id: &str) -> Option<i32> { pub fn get_client_conn_id(session_uuid: &SessionID) -> Option<i32> {
VEC_MSG_CHANNEL VEC_MSG_CHANNEL
.read() .read()
.unwrap() .unwrap()
.iter() .iter()
.find(|x| x.peer_id == peer_id.to_owned()) .find(|x| x.session_uuid == session_uuid.to_owned())
.map(|x| x.conn_id) .map(|x| x.conn_id)
} }
pub fn get_rx_cliprdr_client( pub fn get_rx_cliprdr_client(
peer_id: &str, session_uuid: &SessionID,
) -> (i32, Arc<TokioMutex<UnboundedReceiver<ClipboardFile>>>) { ) -> (i32, Arc<TokioMutex<UnboundedReceiver<ClipboardFile>>>) {
let mut lock = VEC_MSG_CHANNEL.write().unwrap(); 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()), Some(msg_channel) => (msg_channel.conn_id, msg_channel.receiver.clone()),
None => { None => {
let (sender, receiver) = unbounded_channel(); let (sender, receiver) = unbounded_channel();
@ -99,7 +102,7 @@ pub fn get_rx_cliprdr_client(
let receiver2 = receiver.clone(); let receiver2 = receiver.clone();
let conn_id = lock.len() as i32 + 1; let conn_id = lock.len() as i32 + 1;
let msg_channel = MsgChannel { let msg_channel = MsgChannel {
peer_id: peer_id.to_owned(), session_uuid: session_uuid.to_owned(),
conn_id, conn_id,
sender, sender,
receiver, receiver,
@ -119,7 +122,7 @@ pub fn get_rx_cliprdr_server(conn_id: i32) -> Arc<TokioMutex<UnboundedReceiver<C
let receiver = Arc::new(TokioMutex::new(receiver)); let receiver = Arc::new(TokioMutex::new(receiver));
let receiver2 = receiver.clone(); let receiver2 = receiver.clone();
let msg_channel = MsgChannel { let msg_channel = MsgChannel {
peer_id: "".to_owned(), session_uuid: SessionID::nil(),
conn_id, conn_id,
sender, sender,
receiver, receiver,

View File

@ -36,6 +36,7 @@ backtrace = "0.3"
libc = "0.2" libc = "0.2"
dlopen = "0.1" dlopen = "0.1"
toml = "0.7" toml = "0.7"
uuid = { version = "1.3", features = ["v4"] }
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
mac_address = "1.1" mac_address = "1.1"

View File

@ -43,15 +43,17 @@ pub use directories_next;
pub use libc; pub use libc;
pub mod keyboard; pub mod keyboard;
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
pub use sysinfo;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub use dlopen; pub use dlopen;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub use sysinfo;
pub use toml; pub use toml;
pub use uuid;
#[cfg(feature = "quic")] #[cfg(feature = "quic")]
pub type Stream = quic::Connection; pub type Stream = quic::Connection;
#[cfg(not(feature = "quic"))] #[cfg(not(feature = "quic"))]
pub type Stream = tcp::FramedStream; pub type Stream = tcp::FramedStream;
pub type SessionID = uuid::Uuid;
#[inline] #[inline]
pub async fn sleep(sec: f32) { pub async fn sleep(sec: f32) {
@ -395,7 +397,7 @@ mod test {
assert!(!is_ipv6_str("[1:2::0]:")); assert!(!is_ipv6_str("[1:2::0]:"));
assert!(!is_ipv6_str("1:2::0]:1")); assert!(!is_ipv6_str("1:2::0]:1"));
} }
#[test] #[test]
fn test_ipv4() { fn test_ipv4() {
assert!(is_ipv4_str("1.2.3.4")); assert!(is_ipv4_str("1.2.3.4"));
@ -409,7 +411,7 @@ mod test {
assert!(!is_ipv4_str("192.168.0.256")); assert!(!is_ipv4_str("192.168.0.256"));
assert!(!is_ipv4_str("192.168.0.1/24")); assert!(!is_ipv4_str("192.168.0.1/24"));
assert!(!is_ipv4_str("192.168.0.")); assert!(!is_ipv4_str("192.168.0."));
assert!(!is_ipv4_str("192.168..1")); assert!(!is_ipv4_str("192.168..1"));
} }
#[test] #[test]

View File

@ -672,9 +672,9 @@ impl Client {
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
fn try_stop_clipboard(_self_id: &str) { fn try_stop_clipboard(_self_uuid: &uuid::Uuid) {
#[cfg(feature = "flutter")] #[cfg(feature = "flutter")]
if crate::flutter::other_sessions_running(_self_id) { if crate::flutter::other_sessions_running(_self_uuid) {
return; return;
} }
TEXT_CLIPBOARD_STATE.lock().unwrap().running = false; TEXT_CLIPBOARD_STATE.lock().unwrap().running = false;

View File

@ -145,7 +145,7 @@ impl<T: InvokeUiSession> Remote<T> {
|| self.handler.is_rdp(); || self.handler.is_rdp();
if !is_conn_not_default { if !is_conn_not_default {
(self.client_conn_id, rx_clip_client_lock) = (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)] #[cfg(windows)]
@ -262,7 +262,7 @@ impl<T: InvokeUiSession> Remote<T> {
} }
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[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<String>) { fn handle_job_status(&mut self, id: i32, file_num: i32, err: Option<String>) {

View File

@ -1,11 +1,11 @@
use crate::{ use crate::{
client::*, client::*,
flutter_ffi::EventToUI, flutter_ffi::{EventToUI, SessionID},
ui_session_interface::{io_loop, InvokeUiSession, Session}, ui_session_interface::{io_loop, InvokeUiSession, Session},
}; };
use flutter_rust_bridge::StreamSink; use flutter_rust_bridge::StreamSink;
use hbb_common::{ 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, rendezvous_proto::ConnType, ResultType,
}; };
#[cfg(feature = "flutter_texture_render")] #[cfg(feature = "flutter_texture_render")]
@ -24,6 +24,7 @@ use std::{
collections::HashMap, collections::HashMap,
ffi::CString, ffi::CString,
os::raw::{c_char, c_int}, os::raw::{c_char, c_int},
str::FromStr,
sync::{Arc, RwLock}, 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"; pub(crate) const APP_TYPE_DESKTOP_PORT_FORWARD: &str = "port forward";
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub(crate) static ref CUR_SESSION_ID: RwLock<String> = Default::default(); pub(crate) static ref CUR_SESSION_ID: RwLock<SessionID> = Default::default();
pub(crate) static ref SESSIONS: RwLock<HashMap<String, Session<FlutterHandler>>> = Default::default(); pub(crate) static ref SESSIONS: RwLock<HashMap<SessionID, Session<FlutterHandler>>> = Default::default();
static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = 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_file_transfer` - If the session is used for file transfer.
/// * `is_port_forward` - If the session is used for port forward. /// * `is_port_forward` - If the session is used for port forward.
pub fn session_add( pub fn session_add(
session_id: &SessionID,
id: &str, id: &str,
is_file_transfer: bool, is_file_transfer: bool,
is_port_forward: bool, is_port_forward: bool,
@ -703,11 +705,11 @@ pub fn session_add(
force_relay: bool, force_relay: bool,
password: String, password: String,
) -> ResultType<Session<FlutterHandler>> { ) -> ResultType<Session<FlutterHandler>> {
let session_id = get_session_id(id.to_owned()); LocalConfig::set_remote_id(&id);
LocalConfig::set_remote_id(&session_id);
let session: Session<FlutterHandler> = Session { let session: Session<FlutterHandler> = Session {
id: session_id.clone(), session_id: session_id.clone(),
id: id.to_owned(),
password, password,
server_keyboard_enabled: Arc::new(RwLock::new(true)), server_keyboard_enabled: Arc::new(RwLock::new(true)),
server_file_transfer_enabled: Arc::new(RwLock::new(true)), server_file_transfer_enabled: Arc::new(RwLock::new(true)),
@ -737,13 +739,14 @@ pub fn session_add(
.lc .lc
.write() .write()
.unwrap() .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 if let Some(same_id_session) = SESSIONS
.write() .write()
.unwrap() .unwrap()
.insert(id.to_owned(), session.clone()) .insert(session_id.to_owned(), session.clone())
{ {
log::error!("Should not happen");
same_id_session.close(); same_id_session.close();
} }
@ -756,8 +759,12 @@ pub fn session_add(
/// ///
/// * `id` - The identifier of the remote session with prefix. Regex: [\w]*[\_]*[\d]+ /// * `id` - The identifier of the remote session with prefix. Regex: [\w]*[\_]*[\d]+
/// * `events2ui` - The events channel to ui. /// * `events2ui` - The events channel to ui.
pub fn session_start_(id: &str, event_stream: StreamSink<EventToUI>) -> ResultType<()> { pub fn session_start_(
if let Some(session) = SESSIONS.write().unwrap().get_mut(id) { session_id: &SessionID,
id: &str,
event_stream: StreamSink<EventToUI>,
) -> ResultType<()> {
if let Some(session) = SESSIONS.write().unwrap().get_mut(session_id) {
#[cfg(feature = "flutter_texture_render")] #[cfg(feature = "flutter_texture_render")]
log::info!( log::info!(
"Session {} start, render by flutter texture rgba plugin", "Session {} start, render by flutter texture rgba plugin",
@ -788,8 +795,14 @@ pub fn update_text_clipboard_required() {
#[inline] #[inline]
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
pub fn other_sessions_running(id: &str) -> bool { pub fn other_sessions_running(session_id: &SessionID) -> bool {
SESSIONS.read().unwrap().keys().filter(|k| *k != id).count() != 0 SESSIONS
.read()
.unwrap()
.keys()
.filter(|k| *k != session_id)
.count()
!= 0
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[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<FileEntry>, only_count: bool) -> String { pub fn make_fd_flutter(id: i32, entries: &Vec<FileEntry>, only_count: bool) -> String {
let mut m = serde_json::Map::new(); let mut m = serde_json::Map::new();
m.insert("id".into(), json!(id)); m.insert("id".into(), json!(id));
@ -964,13 +968,13 @@ pub fn make_fd_flutter(id: i32, entries: &Vec<FileEntry>, only_count: bool) -> S
serde_json::to_string(&m).unwrap_or("".into()) 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() CUR_SESSION_ID.read().unwrap().clone()
} }
pub fn set_cur_session_id(id: String) { pub fn set_cur_session_id(session_id: SessionID) {
if get_cur_session_id() != id { if get_cur_session_id() != session_id {
*CUR_SESSION_ID.write().unwrap() = id; *CUR_SESSION_ID.write().unwrap() = session_id;
} }
} }
@ -995,12 +999,17 @@ fn serialize_resolutions(resolutions: &Vec<Resolution>) -> String {
serde_json::ser::to_string(&v).unwrap_or("".to_string()) serde_json::ser::to_string(&v).unwrap_or("".to_string())
} }
fn char_to_session_id(c: *const char) -> ResultType<SessionID> {
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] #[no_mangle]
#[cfg(not(feature = "flutter_texture_render"))] pub fn session_get_rgba_size(_session_uuid_str: *const char) -> usize {
pub fn session_get_rgba_size(id: *const char) -> usize { #[cfg(not(feature = "flutter_texture_render"))]
let id = unsafe { std::ffi::CStr::from_ptr(id as _) }; if let Ok(session_id) = char_to_session_id(_session_uuid_str) {
if let Ok(id) = id.to_str() { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
if let Some(session) = SESSIONS.read().unwrap().get(id) {
return session.rgba.read().unwrap().len(); return session.rgba.read().unwrap().len();
} }
} }
@ -1008,27 +1017,20 @@ pub fn session_get_rgba_size(id: *const char) -> usize {
} }
#[no_mangle] #[no_mangle]
#[cfg(feature = "flutter_texture_render")] pub fn session_get_rgba(session_uuid_str: *const char) -> *const u8 {
pub fn session_get_rgba_size(_id: *const char) -> usize { if let Ok(session_id) = char_to_session_id(session_uuid_str) {
0 if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
}
#[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) {
return session.get_rgba(); return session.get_rgba();
} }
} }
std::ptr::null() std::ptr::null()
} }
#[no_mangle] #[no_mangle]
pub fn session_next_rgba(id: *const char) { pub fn session_next_rgba(session_uuid_str: *const char) {
let id = unsafe { std::ffi::CStr::from_ptr(id as _) }; if let Ok(session_id) = char_to_session_id(session_uuid_str) {
if let Ok(id) = id.to_str() { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
if let Some(session) = SESSIONS.read().unwrap().get(id) {
return session.next_rgba(); return session.next_rgba();
} }
} }
@ -1036,24 +1038,26 @@ pub fn session_next_rgba(id: *const char) {
#[inline] #[inline]
#[no_mangle] #[no_mangle]
#[cfg(feature = "flutter_texture_render")] pub fn session_register_texture(_session_uuid_str: *const char, _ptr: usize) {
pub fn session_register_texture(id: *const char, ptr: usize) { #[cfg(feature = "flutter_texture_render")]
let id = unsafe { std::ffi::CStr::from_ptr(id as _) }; if let Ok(session_id) = char_to_session_id(_session_uuid_str) {
if let Ok(id) = id.to_str() { if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) {
if let Some(session) = SESSIONS.write().unwrap().get_mut(id) { return session.register_texture(_ptr);
return session.register_texture(ptr);
} }
} }
} }
#[inline] #[inline]
#[no_mangle] pub fn push_session_event(
#[cfg(not(feature = "flutter_texture_render"))] session_id: &SessionID,
pub fn session_register_texture(_id: *const char, _ptr: usize) {} name: &str,
event: Vec<(&str, &str)>,
#[inline] ) -> Option<bool> {
pub fn push_session_event(peer: &str, name: &str, event: Vec<(&str, &str)>) -> Option<bool> { SESSIONS
SESSIONS.read().unwrap().get(peer)?.push_event(name, event) .read()
.unwrap()
.get(session_id)?
.push_event(name, event)
} }
#[inline] #[inline]

View File

@ -28,7 +28,7 @@ use std::{
time::SystemTime, time::SystemTime,
}; };
// use crate::hbbs_http::account::AuthResult; pub type SessionID = uuid::Uuid;
fn initialize(app_dir: &str) { fn initialize(app_dir: &str) {
*config::APP_DIR.write().unwrap() = app_dir.to_owned(); *config::APP_DIR.write().unwrap() = app_dir.to_owned();
@ -74,6 +74,7 @@ pub fn host_stop_system_key_propagate(_stopped: bool) {
// FIXME: -> ResultType<()> cannot be parsed by frb_codegen // 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 // 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( pub fn session_add_sync(
session_id: SessionID,
id: String, id: String,
is_file_transfer: bool, is_file_transfer: bool,
is_port_forward: bool, is_port_forward: bool,
@ -83,6 +84,7 @@ pub fn session_add_sync(
password: String, password: String,
) -> SyncReturn<String> { ) -> SyncReturn<String> {
if let Err(e) = session_add( if let Err(e) = session_add(
&session_id,
&id, &id,
is_file_transfer, is_file_transfer,
is_port_forward, is_port_forward,
@ -97,33 +99,37 @@ pub fn session_add_sync(
} }
} }
pub fn session_start(events2ui: StreamSink<EventToUI>, id: String) -> ResultType<()> { pub fn session_start(
session_start_(&id, events2ui) events2ui: StreamSink<EventToUI>,
session_id: SessionID,
id: String,
) -> ResultType<()> {
session_start_(&session_id, &id, events2ui)
} }
pub fn session_get_remember(id: String) -> Option<bool> { pub fn session_get_remember(session_id: SessionID) -> Option<bool> {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
Some(session.get_remember()) Some(session.get_remember())
} else { } else {
None None
} }
} }
pub fn session_get_toggle_option(id: String, arg: String) -> Option<bool> { pub fn session_get_toggle_option(session_id: SessionID, arg: String) -> Option<bool> {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
Some(session.get_toggle_option(arg)) Some(session.get_toggle_option(arg))
} else { } else {
None None
} }
} }
pub fn session_get_toggle_option_sync(id: String, arg: String) -> SyncReturn<bool> { pub fn session_get_toggle_option_sync(session_id: SessionID, arg: String) -> SyncReturn<bool> {
let res = session_get_toggle_option(id, arg) == Some(true); let res = session_get_toggle_option(session_id, arg) == Some(true);
SyncReturn(res) SyncReturn(res)
} }
pub fn session_get_option(id: String, arg: String) -> Option<String> { pub fn session_get_option(session_id: SessionID, arg: String) -> Option<String> {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
Some(session.get_option(arg)) Some(session.get_option(arg))
} else { } else {
None None
@ -131,63 +137,63 @@ pub fn session_get_option(id: String, arg: String) -> Option<String> {
} }
pub fn session_login( pub fn session_login(
id: String, session_id: SessionID,
os_username: String, os_username: String,
os_password: String, os_password: String,
password: String, password: String,
remember: bool, 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); session.login(os_username, os_password, password, remember);
} }
} }
pub fn session_close(id: String) { pub fn session_close(session_id: SessionID) {
if let Some(mut session) = SESSIONS.write().unwrap().remove(&id) { if let Some(mut session) = SESSIONS.write().unwrap().remove(&session_id) {
session.close_event_stream(); session.close_event_stream();
session.close(); session.close();
} }
} }
pub fn session_refresh(id: String) { pub fn session_refresh(session_id: SessionID) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.refresh_video(); session.refresh_video();
} }
} }
pub fn session_record_screen(id: String, start: bool, width: usize, height: usize) { pub fn session_record_screen(session_id: SessionID, start: bool, width: usize, height: usize) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.record_screen(start, width as _, height as _); session.record_screen(start, width as _, height as _);
} }
} }
pub fn session_reconnect(id: String, force_relay: bool) { pub fn session_reconnect(session_id: SessionID, force_relay: bool) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.reconnect(force_relay); session.reconnect(force_relay);
} }
} }
pub fn session_toggle_option(id: String, value: String) { pub fn session_toggle_option(session_id: SessionID, value: String) {
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) {
log::warn!("toggle option {}", &value); log::warn!("toggle option {}", &value);
session.toggle_option(value.clone()); session.toggle_option(value.clone());
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[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(); crate::flutter::update_text_clipboard_required();
} }
} }
pub fn session_get_flutter_config(id: String, k: String) -> Option<String> { pub fn session_get_flutter_config(session_id: SessionID, k: String) -> Option<String> {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
Some(session.get_flutter_config(k)) Some(session.get_flutter_config(k))
} else { } else {
None None
} }
} }
pub fn session_set_flutter_config(id: String, k: String, v: String) { pub fn session_set_flutter_config(session_id: SessionID, k: String, v: String) {
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) {
session.save_flutter_config(k, v); 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) ui_interface::set_kb_layout_type(kb_layout_type)
} }
pub fn session_get_view_style(id: String) -> Option<String> { pub fn session_get_view_style(session_id: SessionID) -> Option<String> {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
Some(session.get_view_style()) Some(session.get_view_style())
} else { } else {
None None
} }
} }
pub fn session_set_view_style(id: String, value: String) { pub fn session_set_view_style(session_id: SessionID, value: String) {
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) {
session.save_view_style(value); session.save_view_style(value);
} }
} }
pub fn session_get_scroll_style(id: String) -> Option<String> { pub fn session_get_scroll_style(session_id: SessionID) -> Option<String> {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
Some(session.get_scroll_style()) Some(session.get_scroll_style())
} else { } else {
None None
} }
} }
pub fn session_set_scroll_style(id: String, value: String) { pub fn session_set_scroll_style(session_id: SessionID, value: String) {
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) {
session.save_scroll_style(value); session.save_scroll_style(value);
} }
} }
pub fn session_get_image_quality(id: String) -> Option<String> { pub fn session_get_image_quality(session_id: SessionID) -> Option<String> {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
Some(session.get_image_quality()) Some(session.get_image_quality())
} else { } else {
None None
} }
} }
pub fn session_set_image_quality(id: String, value: String) { pub fn session_set_image_quality(session_id: SessionID, value: String) {
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) {
session.save_image_quality(value); session.save_image_quality(value);
} }
} }
pub fn session_get_keyboard_mode(id: String) -> Option<String> { pub fn session_get_keyboard_mode(session_id: SessionID) -> Option<String> {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
Some(session.get_keyboard_mode()) Some(session.get_keyboard_mode())
} else { } else {
None 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; 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); session.save_keyboard_mode(value);
_mode_updated = true; _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<Vec<i32>> { pub fn session_get_custom_image_quality(session_id: SessionID) -> Option<Vec<i32>> {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
Some(session.get_custom_image_quality()) Some(session.get_custom_image_quality())
} else { } else {
None None
} }
} }
pub fn session_is_keyboard_mode_supported(id: String, mode: String) -> SyncReturn<bool> { pub fn session_is_keyboard_mode_supported(session_id: SessionID, mode: String) -> SyncReturn<bool> {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
if let Ok(mode) = KeyboardMode::from_str(&mode[..]) { if let Ok(mode) = KeyboardMode::from_str(&mode[..]) {
SyncReturn(is_keyboard_mode_supported( SyncReturn(is_keyboard_mode_supported(
&mode, &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) { pub fn session_set_custom_image_quality(session_id: SessionID, value: i32) {
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) {
session.save_custom_image_quality(value); session.save_custom_image_quality(value);
} }
} }
pub fn session_set_custom_fps(id: String, fps: i32) { pub fn session_set_custom_fps(session_id: SessionID, fps: i32) {
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) {
session.set_custom_fps(fps); session.set_custom_fps(fps);
} }
} }
pub fn session_lock_screen(id: String) { pub fn session_lock_screen(session_id: SessionID) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.lock_screen(); session.lock_screen();
} }
} }
pub fn session_ctrl_alt_del(id: String) { pub fn session_ctrl_alt_del(session_id: SessionID) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.ctrl_alt_del(); session.ctrl_alt_del();
} }
} }
pub fn session_switch_display(id: String, value: i32) { pub fn session_switch_display(session_id: SessionID, value: i32) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.switch_display(value); session.switch_display(value);
} }
} }
pub fn session_handle_flutter_key_event( pub fn session_handle_flutter_key_event(
id: String, session_id: SessionID,
name: String, name: String,
platform_code: i32, platform_code: i32,
position_code: i32, position_code: i32,
lock_modes: i32, lock_modes: i32,
down_or_up: bool, 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( session.handle_flutter_key_event(
&name, &name,
platform_code, 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")))] #[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 { if _enter {
session.enter(); session.enter();
} else { } else {
@ -354,7 +360,7 @@ pub fn session_enter_or_leave(_id: String, _enter: bool) {
} }
pub fn session_input_key( pub fn session_input_key(
id: String, session_id: SessionID,
name: String, name: String,
down: bool, down: bool,
press: bool, press: bool,
@ -363,54 +369,54 @@ pub fn session_input_key(
shift: bool, shift: bool,
command: 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"))] // #[cfg(any(target_os = "android", target_os = "ios"))]
session.input_key(&name, down, press, alt, ctrl, shift, command); session.input_key(&name, down, press, alt, ctrl, shift, command);
} }
} }
pub fn session_input_string(id: String, value: String) { pub fn session_input_string(session_id: SessionID, value: String) {
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"))] // #[cfg(any(target_os = "android", target_os = "ios"))]
session.input_string(&value); session.input_string(&value);
} }
} }
// chat_client_mode // chat_client_mode
pub fn session_send_chat(id: String, text: String) { pub fn session_send_chat(session_id: SessionID, text: String) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.send_chat(text); session.send_chat(text);
} }
} }
pub fn session_peer_option(id: String, name: String, value: String) { pub fn session_peer_option(session_id: SessionID, name: String, value: String) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.set_option(name, value); session.set_option(name, value);
} }
} }
pub fn session_get_peer_option(id: String, name: String) -> String { pub fn session_get_peer_option(session_id: SessionID, name: String) -> String {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
return session.get_option(name); return session.get_option(name);
} }
"".to_string() "".to_string()
} }
pub fn session_input_os_password(id: String, value: String) { pub fn session_input_os_password(session_id: SessionID, value: String) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.input_os_password(value, true); session.input_os_password(value, true);
} }
} }
// File Action // File Action
pub fn session_read_remote_dir(id: String, path: String, include_hidden: bool) { pub fn session_read_remote_dir(session_id: SessionID, path: String, include_hidden: bool) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.read_remote_dir(path, include_hidden); session.read_remote_dir(path, include_hidden);
} }
} }
pub fn session_send_files( pub fn session_send_files(
id: String, session_id: SessionID,
act_id: i32, act_id: i32,
path: String, path: String,
to: String, to: String,
@ -418,76 +424,91 @@ pub fn session_send_files(
include_hidden: bool, include_hidden: bool,
is_remote: 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); session.send_files(act_id, path, to, file_num, include_hidden, is_remote);
} }
} }
pub fn session_set_confirm_override_file( pub fn session_set_confirm_override_file(
id: String, session_id: SessionID,
act_id: i32, act_id: i32,
file_num: i32, file_num: i32,
need_override: bool, need_override: bool,
remember: bool, remember: bool,
is_upload: 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); 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) { pub fn session_remove_file(
if let Some(session) = SESSIONS.read().unwrap().get(&id) { 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); session.remove_file(act_id, path, file_num, is_remote);
} }
} }
pub fn session_read_dir_recursive( pub fn session_read_dir_recursive(
id: String, session_id: SessionID,
act_id: i32, act_id: i32,
path: String, path: String,
is_remote: bool, is_remote: bool,
show_hidden: 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); 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) { pub fn session_remove_all_empty_dirs(
if let Some(session) = SESSIONS.read().unwrap().get(&id) { 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); session.remove_dir(act_id, path, is_remote);
} }
} }
pub fn session_cancel_job(id: String, act_id: i32) { pub fn session_cancel_job(session_id: SessionID, act_id: i32) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.cancel_job(act_id); session.cancel_job(act_id);
} }
} }
pub fn session_create_dir(id: String, act_id: i32, path: String, is_remote: bool) { pub fn session_create_dir(session_id: SessionID, act_id: i32, path: String, is_remote: bool) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.create_dir(act_id, path, is_remote); 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) { if let Ok(fd) = fs::read_dir(&fs::get_path(&path), show_hidden) {
return make_fd_to_json(fd.id, path, &fd.entries); return make_fd_to_json(fd.id, path, &fd.entries);
} }
"".to_string() "".to_string()
} }
pub fn session_get_platform(id: String, is_remote: bool) -> String { pub fn session_get_platform(session_id: SessionID, is_remote: bool) -> String {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
return session.get_platform(is_remote); return session.get_platform(is_remote);
} }
"".to_string() "".to_string()
} }
pub fn session_load_last_transfer_jobs(id: String) { pub fn session_load_last_transfer_jobs(session_id: SessionID) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
return session.load_last_jobs(); return session.load_last_jobs();
} else { } else {
// a tip for flutter dev // a tip for flutter dev
@ -499,7 +520,7 @@ pub fn session_load_last_transfer_jobs(id: String) {
} }
pub fn session_add_job( pub fn session_add_job(
id: String, session_id: SessionID,
act_id: i32, act_id: i32,
path: String, path: String,
to: String, to: String,
@ -507,44 +528,44 @@ pub fn session_add_job(
include_hidden: bool, include_hidden: bool,
is_remote: 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); 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) { pub fn session_resume_job(session_id: SessionID, act_id: i32, is_remote: bool) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.resume_job(act_id, is_remote); session.resume_job(act_id, is_remote);
} }
} }
pub fn session_elevate_direct(id: String) { pub fn session_elevate_direct(session_id: SessionID) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.elevate_direct(); session.elevate_direct();
} }
} }
pub fn session_elevate_with_logon(id: String, username: String, password: String) { pub fn session_elevate_with_logon(session_id: SessionID, username: String, password: String) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.elevate_with_logon(username, password); session.elevate_with_logon(username, password);
} }
} }
pub fn session_switch_sides(id: String) { pub fn session_switch_sides(session_id: SessionID) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.switch_sides(); session.switch_sides();
} }
} }
pub fn session_change_resolution(id: String, display: i32, width: i32, height: i32) { pub fn session_change_resolution(session_id: SessionID, display: i32, width: i32, height: i32) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.change_resolution(display, width, height); 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")] #[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); session.set_size(_width, _height);
} }
} }
@ -897,36 +918,36 @@ pub fn main_get_current_display() -> SyncReturn<String> {
} }
pub fn session_add_port_forward( pub fn session_add_port_forward(
id: String, session_id: SessionID,
local_port: i32, local_port: i32,
remote_host: String, remote_host: String,
remote_port: i32, 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); session.add_port_forward(local_port, remote_host, remote_port);
} }
} }
pub fn session_remove_port_forward(id: String, local_port: i32) { pub fn session_remove_port_forward(session_id: SessionID, local_port: i32) {
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) {
session.remove_port_forward(local_port); session.remove_port_forward(local_port);
} }
} }
pub fn session_new_rdp(id: String) { pub fn session_new_rdp(session_id: SessionID) {
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) {
session.new_rdp(); session.new_rdp();
} }
} }
pub fn session_request_voice_call(id: String) { pub fn session_request_voice_call(session_id: SessionID) {
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) {
session.request_voice_call(); session.request_voice_call();
} }
} }
pub fn session_close_voice_call(id: String) { pub fn session_close_voice_call(session_id: SessionID) {
if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { if let Some(session) = SESSIONS.write().unwrap().get_mut(&session_id) {
session.close_voice_call(); 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::<HashMap<String, String>>(&msg) { if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(&msg) {
let alt = m.get("alt").is_some(); let alt = m.get("alt").is_some();
let ctrl = m.get("ctrl").is_some(); let ctrl = m.get("ctrl").is_some();
@ -1072,20 +1093,20 @@ pub fn session_send_mouse(id: String, msg: String) {
_ => 0, _ => 0,
} << 3; } << 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); session.send_mouse(mask, x, y, alt, ctrl, shift, command);
} }
} }
} }
pub fn session_restart_remote_device(id: String) { pub fn session_restart_remote_device(session_id: SessionID) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.restart_remote_device(); session.restart_remote_device();
} }
} }
pub fn session_get_audit_server_sync(id: String, typ: String) -> SyncReturn<String> { pub fn session_get_audit_server_sync(session_id: SessionID, typ: String) -> SyncReturn<String> {
let res = if let Some(session) = SESSIONS.read().unwrap().get(&id) { let res = if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.get_audit_server(typ) session.get_audit_server(typ)
} else { } else {
"".to_owned() "".to_owned()
@ -1093,14 +1114,14 @@ pub fn session_get_audit_server_sync(id: String, typ: String) -> SyncReturn<Stri
SyncReturn(res) SyncReturn(res)
} }
pub fn session_send_note(id: String, note: String) { pub fn session_send_note(session_id: SessionID, note: String) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.send_note(note) session.send_note(note)
} }
} }
pub fn session_alternative_codecs(id: String) -> String { pub fn session_alternative_codecs(session_id: SessionID) -> String {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
let (vp8, av1, h264, h265) = session.alternative_codecs(); let (vp8, av1, h264, h265) = session.alternative_codecs();
let msg = HashMap::from([("vp8", vp8), ("av1", av1), ("h264", h264), ("h265", h265)]); let msg = HashMap::from([("vp8", vp8), ("av1", av1), ("h264", h264), ("h265", h265)]);
serde_json::ser::to_string(&msg).unwrap_or("".to_owned()) 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) { pub fn session_change_prefer_codec(session_id: SessionID) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&session_id) {
session.change_prefer_codec(); session.change_prefer_codec();
} }
} }
@ -1338,8 +1359,8 @@ pub fn main_update_me() -> SyncReturn<bool> {
SyncReturn(true) SyncReturn(true)
} }
pub fn set_cur_session_id(id: String) { pub fn set_cur_session_id(session_id: SessionID) {
super::flutter::set_cur_session_id(id); super::flutter::set_cur_session_id(session_id);
#[cfg(windows)] #[cfg(windows)]
crate::keyboard::update_grab_get_key_name(); crate::keyboard::update_grab_get_key_name();
} }

View File

@ -28,7 +28,7 @@ use hbb_common::{
sync::mpsc, sync::mpsc,
time::{Duration as TokioDuration, Instant}, time::{Duration as TokioDuration, Instant},
}, },
Stream, SessionID, Stream,
}; };
use crate::client::io_loop::Remote; use crate::client::io_loop::Remote;
@ -49,7 +49,8 @@ const CHANGE_RESOLUTION_VALID_TIMEOUT_SECS: u64 = 15;
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct Session<T: InvokeUiSession> { pub struct Session<T: InvokeUiSession> {
pub id: String, pub session_id: SessionID,
pub id: String, // peer id
pub password: String, pub password: String,
pub args: Vec<String>, pub args: Vec<String>,
pub lc: Arc<RwLock<LoginConfigHandler>>, pub lc: Arc<RwLock<LoginConfigHandler>>,