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
shell: bash
run: |
cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }}
cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid"
pushd flutter && flutter pub get && popd
- name: Run flutter rust bridge

View File

@ -79,7 +79,7 @@ jobs:
- name: Install flutter rust bridge deps
run: |
cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }}
cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid"
Push-Location flutter ; flutter pub get ; Pop-Location
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart
@ -312,7 +312,7 @@ jobs:
- name: Install flutter rust bridge deps
shell: bash
run: |
cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }}
cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid"
pushd flutter && flutter pub get && popd
~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart

3
Cargo.lock generated
View File

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

View File

@ -62,7 +62,7 @@ num_cpus = "1.15"
bytes = { version = "1.4", features = ["serde"] }
default-net = "0.14"
wol-rs = "1.0"
flutter_rust_bridge = { version = "1.75", optional = true }
flutter_rust_bridge = { version = "1.75", features = ["uuid"], optional = true}
errno = "0.3"
rdev = { git = "https://github.com/fufesou/rdev" }
url = { version = "2.3", features = ["serde"] }

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_desktop/uni_links_desktop.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:uuid/uuid.dart';
import 'package:win32/win32.dart' as win32;
import 'package:window_manager/window_manager.dart';
import 'package:window_size/window_size.dart' as window_size;
@ -68,6 +69,7 @@ typedef F = String Function(String);
typedef FMethod = String Function(String, dynamic);
typedef StreamEventHandler = Future<void> Function(Map<String, dynamic>);
typedef SessionID = UuidValue;
final iconHardDrive = MemoryImage(Uint8List.fromList(base64Decode(
'iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAmVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjHWqVAAAAMnRSTlMAv0BmzLJNXlhiUu2fxXDgu7WuSUUe29LJvpqUjX53VTstD7ilNujCqTEk5IYH+vEoFjKvAagAAAPpSURBVHja7d0JbhpBEIXhB3jYzb5vBgzYgO04df/DJXGUKMwU9ECmZ6pQfSfw028LCXW3YYwxxhhjjDHGGGOM0eZ9VV1MckdKWLM1bRQ/35GW/WxHHu1me6ShuyHvNl34VhlTKsYVeDWj1EzgUZ1S1DrAk/UDparZgxd9Sl0BHnxSBhpI3jfKQG2FpLUpE69I2ILikv1nsvygjBwPSNKYMlNHggqUoSKS80AZCnwHqQ1zCRvW+CRegwRFeFAMKKrtM8gTPJlzSfwFgT9dJom3IDN4VGaSeAryAK8m0SSeghTg1ZYiql6CjBDhO8mzlyAVhKhIwgXxrh5NojGIhyRckEdwpCdhgpSQgiWTRGMQNonGIGySp0SDvMDBX5KWxiB8Eo1BgE00SYJBykhNnkmSWJAcLpGaJNMgfJKyxiDAK4WNEwryhMtkJsk8CJtEYxA+icYgQIfCcgkEqcJNXhIRQdgkGoPwSTQG+e8khdu/7JOVREwQIKCwF41B2CQljUH4JLcH6SI+OUlEBQHa0SQag/BJNAbhkjxqDMIn0RgEeI4muSlID9eSkERgEKAVTaIxCJ9EYxA2ydVB8hCASVLRGAQYR5NoDMIn0RgEyFHYSGMQPonGII4kziCNvBgNJonEk4u3GAk8Sprk6eYaqbMDY0oKvUm5jfC/viGiSypV7+M3i2iDsAGpNEDYjlTa3W8RdR/r544g50ilnA0RxoZIE2NIXqQbhkAkGyKNDZHGhkhjQ6SxIdLYEGlsiDQ2JGTVeD0264U9zipPh7XOooffpA6pfNCXjxl4/c3pUzlChwzor53zwYYVfpI5pOV6LWFF/2jiJ5FDSs5jdY/0rwUAkUMeXWdBqnSqD0DikBqdqCHsjTvELm9In0IOri/0pwAEDtlSyNaRjAIAAoesKWTtuusxByBwCJp0oomwBXcYUuCQgE50ENajE4OvZAKHLB1/68Br5NqiyCGYOY8YRd77kTkEb64n7lZN+mOIX4QOwb5FX0ZVx3uOxwW+SB0CbBubemWP8/rlaaeRX+M3uUOuZENsiA25zIbYkPsZElBIHwL13U/PTjJ/cyOOEoVM3I+hziDQlELm7pPxw3eI8/7gPh1fpLA6xGnEeDDgO0UcIAzzM35HxLPIq5SXe9BLzOsj9eUaQqyXzxS1QFSfWM2cCANiHcAISJ0AnCKpUwTuIkkA3EeSInAXSQKcs1V18e24wlllUmQp9v9zXKeHi+akRAMOPVKhAqdPBZeUmnnEsO6QcJ0+4qmOSbBxFfGVRiTUqITrdKcCbyYO3/K4wX4+aQ+FfNjXhu3JfAVjjDHGGGOMMcYYY4xIPwCgfqT6TbhCLAAAAABJRU5ErkJggg==')));
@ -890,8 +892,8 @@ class CustomAlertDialog extends StatelessWidget {
}
}
void msgBox(String id, String type, String title, String text, String link,
OverlayDialogManager dialogManager,
void msgBox(SessionID sessionId, String type, String title, String text,
String link, OverlayDialogManager dialogManager,
{bool? hasCancel, ReconnectHandle? reconnect}) {
dialogManager.dismissAll();
List<Widget> buttons = [];
@ -936,7 +938,7 @@ void msgBox(String id, String type, String title, String text, String link,
buttons.insert(
0,
dialogButton('Reconnect', isOutline: true, onPressed: () {
reconnect(dialogManager, id, false);
reconnect(dialogManager, sessionId, false);
}));
}
if (link.isNotEmpty) {
@ -950,7 +952,7 @@ void msgBox(String id, String type, String title, String text, String link,
onSubmit: hasOk ? submit : null,
onCancel: hasCancel == true ? cancel : null,
),
tag: '$id-$type-$title-$text-$link',
tag: '$sessionId-$type-$title-$text-$link',
);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -76,6 +76,8 @@ class _RemotePageState extends State<RemotePage>
late FFI _ffi;
SessionID get sessionId => _ffi.sessionId;
void _initStates(String id) {
initSharedStates(id);
_zoomCursor = PeerBoolOption.find(id, 'zoom-cursor');
@ -117,19 +119,19 @@ class _RemotePageState extends State<RemotePage>
debugPrint("id: $id, texture_key: $_textureKey");
if (id != -1) {
final ptr = await textureRenderer.getTexturePtr(_textureKey);
platformFFI.registerTexture(widget.id, ptr);
platformFFI.registerTexture(sessionId, ptr);
_textureId.value = id;
}
});
}
_ffi.ffiModel.updateEventListener(widget.id);
_ffi.ffiModel.updateEventListener(sessionId, widget.id);
bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote);
_ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id);
_ffi.qualityMonitorModel.checkShowQualityMonitor(sessionId);
// Session option should be set after models.dart/FFI.start
_showRemoteCursor.value = bind.sessionGetToggleOptionSync(
id: widget.id, arg: 'show-remote-cursor');
_zoomCursor.value =
bind.sessionGetToggleOptionSync(id: widget.id, arg: 'zoom-cursor');
sessionId: sessionId, arg: 'show-remote-cursor');
_zoomCursor.value = bind.sessionGetToggleOptionSync(
sessionId: sessionId, arg: 'zoom-cursor');
DesktopMultiWindow.addListener(this);
// if (!_isCustomCursorInited) {
// customCursorController.registerNeedUpdateCursorCallback(
@ -203,11 +205,11 @@ class _RemotePageState extends State<RemotePage>
void dispose() {
debugPrint("REMOTE PAGE dispose ${widget.id}");
if (useTextureRender) {
platformFFI.registerTexture(widget.id, 0);
platformFFI.registerTexture(sessionId, 0);
textureRenderer.closeTexture(_textureKey);
}
// ensure we leave this session, this is a double check
bind.sessionEnterOrLeave(id: widget.id, enter: false);
bind.sessionEnterOrLeave(sessionId: sessionId, enter: false);
DesktopMultiWindow.removeListener(this);
_ffi.dialogManager.hideMobileActionsOverlay();
_ffi.recordingModel.onClose();
@ -278,7 +280,7 @@ class _RemotePageState extends State<RemotePage>
super.build(context);
return WillPopScope(
onWillPop: () async {
clientClose(widget.id, _ffi.dialogManager);
clientClose(sessionId, _ffi.dialogManager);
return false;
},
child: MultiProvider(providers: [
@ -305,7 +307,7 @@ class _RemotePageState extends State<RemotePage>
if (!_rawKeyFocusNode.hasFocus) {
_rawKeyFocusNode.requestFocus();
}
bind.sessionEnterOrLeave(id: widget.id, enter: true);
bind.sessionEnterOrLeave(sessionId: sessionId, enter: true);
}
}
@ -325,7 +327,7 @@ class _RemotePageState extends State<RemotePage>
}
// See [onWindowBlur].
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) {
ConnectionTypeState.init(peerId);
tabController.onSelected = (_, id) {
bind.setCurSessionId(id: id);
final remotePage = tabController.state.value.tabs
.firstWhere((tab) => tab.key == id)
.page as RemotePage;
final ffi = remotePage.ffi;
bind.setCurSessionId(sessionId: ffi.sessionId);
WindowController.fromWindowId(windowId())
.setTitle(getWindowNameWithId(id));
};
@ -243,6 +247,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
final ffi = remotePage.ffi;
final pi = ffi.ffiModel.pi;
final perms = ffi.ffiModel.permissions;
final sessionId = ffi.sessionId;
menu.addAll([
MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text(
@ -282,6 +287,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
menu.add(MenuEntryDivider<String>());
menu.add(RemoteMenuEntry.showRemoteCursor(
key,
sessionId,
padding,
dismissFunc: cancelFunc,
));
@ -289,15 +295,15 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
if (perms['keyboard'] != false && !ffi.ffiModel.viewOnly) {
if (perms['clipboard'] != false) {
menu.add(RemoteMenuEntry.disableClipboard(key, padding,
menu.add(RemoteMenuEntry.disableClipboard(sessionId, padding,
dismissFunc: cancelFunc));
}
menu.add(
RemoteMenuEntry.insertLock(key, padding, dismissFunc: cancelFunc));
menu.add(RemoteMenuEntry.insertLock(sessionId, padding,
dismissFunc: cancelFunc));
if (pi.platform == kPeerPlatformLinux || pi.sasEnabled) {
menu.add(RemoteMenuEntry.insertCtrlAltDel(key, padding,
menu.add(RemoteMenuEntry.insertCtrlAltDel(sessionId, padding,
dismissFunc: cancelFunc));
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
void handlePluginEvent(
Map<String, dynamic> evt,
String peer,
Function(Map<String, dynamic> e) handleMsgBox,
) {
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) {
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(
evt['location'], evt['id'], evt['peer'] ?? '', evt['key'], evt['value']);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -43,15 +43,17 @@ pub use directories_next;
pub use libc;
pub mod keyboard;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub use sysinfo;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub use dlopen;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub use sysinfo;
pub use toml;
pub use uuid;
#[cfg(feature = "quic")]
pub type Stream = quic::Connection;
#[cfg(not(feature = "quic"))]
pub type Stream = tcp::FramedStream;
pub type SessionID = uuid::Uuid;
#[inline]
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]:1"));
}
#[test]
fn test_ipv4() {
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.1/24"));
assert!(!is_ipv4_str("192.168.0."));
assert!(!is_ipv4_str("192.168..1"));
assert!(!is_ipv4_str("192.168..1"));
}
#[test]

View File

@ -672,9 +672,9 @@ impl Client {
}
#[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")]
if crate::flutter::other_sessions_running(_self_id) {
if crate::flutter::other_sessions_running(_self_uuid) {
return;
}
TEXT_CLIPBOARD_STATE.lock().unwrap().running = false;

View File

@ -145,7 +145,7 @@ impl<T: InvokeUiSession> Remote<T> {
|| self.handler.is_rdp();
if !is_conn_not_default {
(self.client_conn_id, rx_clip_client_lock) =
clipboard::get_rx_cliprdr_client(&self.handler.id);
clipboard::get_rx_cliprdr_client(&self.handler.session_id);
};
}
#[cfg(windows)]
@ -262,7 +262,7 @@ impl<T: InvokeUiSession> Remote<T> {
}
}
#[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>) {

View File

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

View File

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

View File

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