mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-04 02:31:28 +03:00
Merge pull request #674 from Heap-Hop/option_multi_instances
multi instances
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1477,7 +1477,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "flutter_rust_bridge_codegen"
|
name = "flutter_rust_bridge_codegen"
|
||||||
version = "1.32.0"
|
version = "1.32.0"
|
||||||
source = "git+https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge#827fc60143988dfc3759f7e8ce16a20d80edd710"
|
source = "git+https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge#e5adce55eea0b74d3680e66a2c5252edf17b07e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cargo_metadata",
|
"cargo_metadata",
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
Wakelock.enable();
|
Wakelock.enable();
|
||||||
}
|
}
|
||||||
_physicalFocusNode.requestFocus();
|
_physicalFocusNode.requestFocus();
|
||||||
FFI.ffiModel.updateEventListener(widget.id);
|
// FFI.ffiModel.updateEventListener(widget.id);
|
||||||
FFI.listenToMouse(true);
|
FFI.listenToMouse(true);
|
||||||
WindowManager.instance.addListener(this);
|
WindowManager.instance.addListener(this);
|
||||||
}
|
}
|
||||||
@@ -143,7 +143,7 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
if (newValue.length > common) {
|
if (newValue.length > common) {
|
||||||
var s = newValue.substring(common);
|
var s = newValue.substring(common);
|
||||||
if (s.length > 1) {
|
if (s.length > 1) {
|
||||||
FFI.setByName('input_string', s);
|
FFI.bind.sessionInputString(id: widget.id, value: s);
|
||||||
} else {
|
} else {
|
||||||
inputChar(s);
|
inputChar(s);
|
||||||
}
|
}
|
||||||
@@ -177,11 +177,11 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
content == '()' ||
|
content == '()' ||
|
||||||
content == '【】')) {
|
content == '【】')) {
|
||||||
// can not only input content[0], because when input ], [ are also auo insert, which cause ] never be input
|
// can not only input content[0], because when input ], [ are also auo insert, which cause ] never be input
|
||||||
FFI.setByName('input_string', content);
|
FFI.bind.sessionInputString(id: widget.id, value: content);
|
||||||
openKeyboard();
|
openKeyboard();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FFI.setByName('input_string', content);
|
FFI.bind.sessionInputString(id: widget.id, value: content);
|
||||||
} else {
|
} else {
|
||||||
inputChar(content);
|
inputChar(content);
|
||||||
}
|
}
|
||||||
@@ -328,8 +328,8 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
if (dy > 0)
|
if (dy > 0)
|
||||||
dy = -1;
|
dy = -1;
|
||||||
else if (dy < 0) dy = 1;
|
else if (dy < 0) dy = 1;
|
||||||
FFI.setByName(
|
FFI.setByName('send_mouse',
|
||||||
'send_mouse', '{"type": "wheel", "x": "$dx", "y": "$dy"}');
|
'{"id": "${widget.id}", "type": "wheel", "x": "$dx", "y": "$dy"}');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
@@ -404,7 +404,7 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
icon: Icon(Icons.tv),
|
icon: Icon(Icons.tv),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() => _showEdit = false);
|
setState(() => _showEdit = false);
|
||||||
showOptions();
|
showOptions(widget.id);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
] +
|
] +
|
||||||
@@ -456,7 +456,7 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
icon: Icon(Icons.more_vert),
|
icon: Icon(Icons.more_vert),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() => _showEdit = false);
|
setState(() => _showEdit = false);
|
||||||
showActions();
|
showActions(widget.id);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
@@ -553,7 +553,8 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
},
|
},
|
||||||
onTwoFingerScaleEnd: (d) {
|
onTwoFingerScaleEnd: (d) {
|
||||||
_scale = 1;
|
_scale = 1;
|
||||||
FFI.setByName('peer_option', '{"name": "view-style", "value": ""}');
|
FFI.bind
|
||||||
|
.sessionPeerOption(id: widget.id, name: "view-style", value: "");
|
||||||
},
|
},
|
||||||
onThreeFingerVerticalDragUpdate: FFI.ffiModel.isPeerAndroid
|
onThreeFingerVerticalDragUpdate: FFI.ffiModel.isPeerAndroid
|
||||||
? null
|
? null
|
||||||
@@ -599,8 +600,9 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
|
|
||||||
Widget getBodyForDesktopWithListener(bool keyboard) {
|
Widget getBodyForDesktopWithListener(bool keyboard) {
|
||||||
var paints = <Widget>[ImagePaint()];
|
var paints = <Widget>[ImagePaint()];
|
||||||
if (keyboard ||
|
final cursor = FFI.bind
|
||||||
FFI.getByName('toggle_option', 'show-remote-cursor') == 'true') {
|
.getSessionToggleOptionSync(id: widget.id, arg: 'show-remote-cursor');
|
||||||
|
if (keyboard || cursor) {
|
||||||
paints.add(CursorPaint());
|
paints.add(CursorPaint());
|
||||||
}
|
}
|
||||||
return Container(
|
return Container(
|
||||||
@@ -628,7 +630,7 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void showActions() {
|
void showActions(String id) async {
|
||||||
final size = MediaQuery.of(context).size;
|
final size = MediaQuery.of(context).size;
|
||||||
final x = 120.0;
|
final x = 120.0;
|
||||||
final y = size.height;
|
final y = size.height;
|
||||||
@@ -647,7 +649,7 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
style: flatButtonStyle,
|
style: flatButtonStyle,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
showSetOSPassword(false);
|
showSetOSPassword(widget.id, false);
|
||||||
},
|
},
|
||||||
child: Icon(Icons.edit, color: MyTheme.accent),
|
child: Icon(Icons.edit, color: MyTheme.accent),
|
||||||
)
|
)
|
||||||
@@ -670,7 +672,8 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
more.add(PopupMenuItem<String>(
|
more.add(PopupMenuItem<String>(
|
||||||
child: Text(translate('Insert Lock')), value: 'lock'));
|
child: Text(translate('Insert Lock')), value: 'lock'));
|
||||||
if (pi.platform == 'Windows' &&
|
if (pi.platform == 'Windows' &&
|
||||||
FFI.getByName('toggle_option', 'privacy-mode') != 'true') {
|
await FFI.bind.getSessionToggleOption(id: id, arg: 'privacy-mode') !=
|
||||||
|
true) {
|
||||||
more.add(PopupMenuItem<String>(
|
more.add(PopupMenuItem<String>(
|
||||||
child: Text(translate(
|
child: Text(translate(
|
||||||
(FFI.ffiModel.inputBlocked ? 'Unb' : 'B') + 'lock user input')),
|
(FFI.ffiModel.inputBlocked ? 'Unb' : 'B') + 'lock user input')),
|
||||||
@@ -685,28 +688,30 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
elevation: 8,
|
elevation: 8,
|
||||||
);
|
);
|
||||||
if (value == 'cad') {
|
if (value == 'cad') {
|
||||||
FFI.setByName('ctrl_alt_del');
|
FFI.bind.sessionCtrlAltDel(id: widget.id);
|
||||||
} else if (value == 'lock') {
|
} else if (value == 'lock') {
|
||||||
FFI.setByName('lock_screen');
|
FFI.bind.sessionLockScreen(id: widget.id);
|
||||||
} else if (value == 'block-input') {
|
} else if (value == 'block-input') {
|
||||||
FFI.setByName('toggle_option',
|
FFI.bind.sessionToggleOption(
|
||||||
(FFI.ffiModel.inputBlocked ? 'un' : '') + 'block-input');
|
id: widget.id,
|
||||||
|
value: (FFI.ffiModel.inputBlocked ? 'un' : '') + 'block-input');
|
||||||
FFI.ffiModel.inputBlocked = !FFI.ffiModel.inputBlocked;
|
FFI.ffiModel.inputBlocked = !FFI.ffiModel.inputBlocked;
|
||||||
} else if (value == 'refresh') {
|
} else if (value == 'refresh') {
|
||||||
FFI.setByName('refresh');
|
FFI.bind.sessionRefresh(id: widget.id);
|
||||||
} else if (value == 'paste') {
|
} else if (value == 'paste') {
|
||||||
() async {
|
() async {
|
||||||
ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
|
ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
|
||||||
if (data != null && data.text != null) {
|
if (data != null && data.text != null) {
|
||||||
FFI.setByName('input_string', '${data.text}');
|
FFI.bind.sessionInputString(id: widget.id, value: data.text ?? "");
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
} else if (value == 'enter_os_password') {
|
} else if (value == 'enter_os_password') {
|
||||||
var password = FFI.getByName('peer_option', "os-password");
|
var password =
|
||||||
if (password != "") {
|
await FFI.bind.getSessionOption(id: id, arg: "os-password");
|
||||||
FFI.setByName('input_os_password', password);
|
if (password != null) {
|
||||||
|
FFI.bind.sessionInputOsPassword(id: widget.id, value: password);
|
||||||
} else {
|
} else {
|
||||||
showSetOSPassword(true);
|
showSetOSPassword(widget.id, true);
|
||||||
}
|
}
|
||||||
} else if (value == 'reset_canvas') {
|
} else if (value == 'reset_canvas') {
|
||||||
FFI.cursorModel.reset();
|
FFI.cursorModel.reset();
|
||||||
@@ -732,8 +737,8 @@ class _RemotePageState extends State<RemotePage> with WindowListener {
|
|||||||
onTouchModeChange: (t) {
|
onTouchModeChange: (t) {
|
||||||
FFI.ffiModel.toggleTouchMode();
|
FFI.ffiModel.toggleTouchMode();
|
||||||
final v = FFI.ffiModel.touchMode ? 'Y' : '';
|
final v = FFI.ffiModel.touchMode ? 'Y' : '';
|
||||||
FFI.setByName('peer_option',
|
FFI.bind.sessionPeerOption(
|
||||||
'{"name": "touch-mode", "value": "$v"}');
|
id: widget.id, name: "touch-mode", value: v);
|
||||||
}));
|
}));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -948,12 +953,13 @@ class ImagePainter extends CustomPainter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CheckboxListTile getToggle(
|
CheckboxListTile getToggle(
|
||||||
void Function(void Function()) setState, option, name) {
|
String id, void Function(void Function()) setState, option, name) {
|
||||||
|
final opt = FFI.bind.getSessionToggleOptionSync(id: id, arg: option);
|
||||||
return CheckboxListTile(
|
return CheckboxListTile(
|
||||||
value: FFI.getByName('toggle_option', option) == 'true',
|
value: opt,
|
||||||
onChanged: (v) {
|
onChanged: (v) {
|
||||||
setState(() {
|
setState(() {
|
||||||
FFI.setByName('toggle_option', option);
|
FFI.bind.sessionToggleOption(id: id, value: option);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
dense: true,
|
dense: true,
|
||||||
@@ -972,10 +978,11 @@ RadioListTile<String> getRadio(String name, String toValue, String curValue,
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showOptions() {
|
void showOptions(String id) async {
|
||||||
String quality = FFI.getByName('image_quality');
|
String quality = await FFI.bind.getSessionImageQuality(id: id) ?? 'balanced';
|
||||||
if (quality == '') quality = 'balanced';
|
if (quality == '') quality = 'balanced';
|
||||||
String viewStyle = FFI.getByName('peer_option', 'view-style');
|
String viewStyle =
|
||||||
|
await FFI.bind.getSessionOption(id: id, arg: 'view-style') ?? '';
|
||||||
var displays = <Widget>[];
|
var displays = <Widget>[];
|
||||||
final pi = FFI.ffiModel.pi;
|
final pi = FFI.ffiModel.pi;
|
||||||
final image = FFI.ffiModel.getConnectionImage();
|
final image = FFI.ffiModel.getConnectionImage();
|
||||||
@@ -988,7 +995,7 @@ void showOptions() {
|
|||||||
children.add(InkWell(
|
children.add(InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (i == cur) return;
|
if (i == cur) return;
|
||||||
FFI.setByName('switch_display', i.toString());
|
FFI.bind.sessionSwitchDisplay(id: id, value: i);
|
||||||
SmartDialog.dismiss();
|
SmartDialog.dismiss();
|
||||||
},
|
},
|
||||||
child: Ink(
|
child: Ink(
|
||||||
@@ -1017,30 +1024,30 @@ void showOptions() {
|
|||||||
DialogManager.show((setState, close) {
|
DialogManager.show((setState, close) {
|
||||||
final more = <Widget>[];
|
final more = <Widget>[];
|
||||||
if (perms['audio'] != false) {
|
if (perms['audio'] != false) {
|
||||||
more.add(getToggle(setState, 'disable-audio', 'Mute'));
|
more.add(getToggle(id, setState, 'disable-audio', 'Mute'));
|
||||||
}
|
}
|
||||||
if (perms['keyboard'] != false) {
|
if (perms['keyboard'] != false) {
|
||||||
if (perms['clipboard'] != false)
|
if (perms['clipboard'] != false)
|
||||||
more.add(getToggle(setState, 'disable-clipboard', 'Disable clipboard'));
|
more.add(
|
||||||
|
getToggle(id, setState, 'disable-clipboard', 'Disable clipboard'));
|
||||||
more.add(getToggle(
|
more.add(getToggle(
|
||||||
setState, 'lock-after-session-end', 'Lock after session end'));
|
id, setState, 'lock-after-session-end', 'Lock after session end'));
|
||||||
if (pi.platform == 'Windows') {
|
if (pi.platform == 'Windows') {
|
||||||
more.add(getToggle(setState, 'privacy-mode', 'Privacy mode'));
|
more.add(getToggle(id, setState, 'privacy-mode', 'Privacy mode'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var setQuality = (String? value) {
|
var setQuality = (String? value) {
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
quality = value;
|
quality = value;
|
||||||
FFI.setByName('image_quality', value);
|
FFI.bind.sessionSetImageQuality(id: id, value: value);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var setViewStyle = (String? value) {
|
var setViewStyle = (String? value) {
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
viewStyle = value;
|
viewStyle = value;
|
||||||
FFI.setByName(
|
FFI.bind.sessionPeerOption(id: id, name: "view-style", value: value);
|
||||||
'peer_option', '{"name": "view-style", "value": "$value"}');
|
|
||||||
FFI.canvasModel.updateViewStyle();
|
FFI.canvasModel.updateViewStyle();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -1058,7 +1065,8 @@ void showOptions() {
|
|||||||
getRadio('Balanced', 'balanced', quality, setQuality),
|
getRadio('Balanced', 'balanced', quality, setQuality),
|
||||||
getRadio('Optimize reaction time', 'low', quality, setQuality),
|
getRadio('Optimize reaction time', 'low', quality, setQuality),
|
||||||
Divider(color: MyTheme.border),
|
Divider(color: MyTheme.border),
|
||||||
getToggle(setState, 'show-remote-cursor', 'Show remote cursor'),
|
getToggle(
|
||||||
|
id, setState, 'show-remote-cursor', 'Show remote cursor'),
|
||||||
] +
|
] +
|
||||||
more),
|
more),
|
||||||
actions: [],
|
actions: [],
|
||||||
@@ -1067,10 +1075,12 @@ void showOptions() {
|
|||||||
}, clickMaskDismiss: true, backDismiss: true);
|
}, clickMaskDismiss: true, backDismiss: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showSetOSPassword(bool login) {
|
void showSetOSPassword(String id, bool login) async {
|
||||||
final controller = TextEditingController();
|
final controller = TextEditingController();
|
||||||
var password = FFI.getByName('peer_option', "os-password");
|
var password =
|
||||||
var autoLogin = FFI.getByName('peer_option', "auto-login") != "";
|
await FFI.bind.getSessionOption(id: id, arg: "os-password") ?? "";
|
||||||
|
var autoLogin =
|
||||||
|
await FFI.bind.getSessionOption(id: id, arg: "auto-login") != "";
|
||||||
controller.text = password;
|
controller.text = password;
|
||||||
DialogManager.show((setState, close) {
|
DialogManager.show((setState, close) {
|
||||||
return CustomAlertDialog(
|
return CustomAlertDialog(
|
||||||
@@ -1103,12 +1113,12 @@ void showSetOSPassword(bool login) {
|
|||||||
style: flatButtonStyle,
|
style: flatButtonStyle,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
var text = controller.text.trim();
|
var text = controller.text.trim();
|
||||||
FFI.setByName(
|
FFI.bind
|
||||||
'peer_option', '{"name": "os-password", "value": "$text"}');
|
.sessionPeerOption(id: id, name: "os-password", value: text);
|
||||||
FFI.setByName('peer_option',
|
FFI.bind.sessionPeerOption(
|
||||||
'{"name": "auto-login", "value": "${autoLogin ? 'Y' : ''}"}');
|
id: id, name: "auto-login", value: autoLogin ? 'Y' : '');
|
||||||
if (text != "" && login) {
|
if (text != "" && login) {
|
||||||
FFI.setByName('input_os_password', text);
|
FFI.bind.sessionInputOsPassword(id: id, value: text);
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ void enterPasswordDialog(String id) {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
var text = controller.text.trim();
|
var text = controller.text.trim();
|
||||||
if (text == '') return;
|
if (text == '') return;
|
||||||
FFI.login(text, remember);
|
FFI.login(id, text, remember);
|
||||||
close();
|
close();
|
||||||
showLoading(translate('Logging in...'));
|
showLoading(translate('Logging in...'));
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import 'dart:ui' as ui;
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_hbb/generated_bridge.dart';
|
||||||
import 'package:flutter_hbb/models/chat_model.dart';
|
import 'package:flutter_hbb/models/chat_model.dart';
|
||||||
import 'package:flutter_hbb/models/file_model.dart';
|
import 'package:flutter_hbb/models/file_model.dart';
|
||||||
import 'package:flutter_hbb/models/server_model.dart';
|
import 'package:flutter_hbb/models/server_model.dart';
|
||||||
@@ -121,6 +122,53 @@ class FfiModel with ChangeNotifier {
|
|||||||
_permissions.clear();
|
_permissions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Function(Map<String, dynamic>) startEventListener(String peerId) {
|
||||||
|
return (evt) {
|
||||||
|
var name = evt['name'];
|
||||||
|
if (name == 'msgbox') {
|
||||||
|
handleMsgBox(evt, peerId);
|
||||||
|
} else if (name == 'peer_info') {
|
||||||
|
handlePeerInfo(evt, peerId);
|
||||||
|
} else if (name == 'connection_ready') {
|
||||||
|
FFI.ffiModel.setConnectionType(
|
||||||
|
evt['secure'] == 'true', evt['direct'] == 'true');
|
||||||
|
} else if (name == 'switch_display') {
|
||||||
|
handleSwitchDisplay(evt);
|
||||||
|
} else if (name == 'cursor_data') {
|
||||||
|
FFI.cursorModel.updateCursorData(evt);
|
||||||
|
} else if (name == 'cursor_id') {
|
||||||
|
FFI.cursorModel.updateCursorId(evt);
|
||||||
|
} else if (name == 'cursor_position') {
|
||||||
|
FFI.cursorModel.updateCursorPosition(evt);
|
||||||
|
} else if (name == 'clipboard') {
|
||||||
|
Clipboard.setData(ClipboardData(text: evt['content']));
|
||||||
|
} else if (name == 'permission') {
|
||||||
|
FFI.ffiModel.updatePermission(evt);
|
||||||
|
} else if (name == 'chat_client_mode') {
|
||||||
|
FFI.chatModel.receive(ChatModel.clientModeID, evt['text'] ?? "");
|
||||||
|
} else if (name == 'chat_server_mode') {
|
||||||
|
FFI.chatModel
|
||||||
|
.receive(int.parse(evt['id'] as String), evt['text'] ?? "");
|
||||||
|
} else if (name == 'file_dir') {
|
||||||
|
FFI.fileModel.receiveFileDir(evt);
|
||||||
|
} else if (name == 'job_progress') {
|
||||||
|
FFI.fileModel.tryUpdateJobProgress(evt);
|
||||||
|
} else if (name == 'job_done') {
|
||||||
|
FFI.fileModel.jobDone(evt);
|
||||||
|
} else if (name == 'job_error') {
|
||||||
|
FFI.fileModel.jobError(evt);
|
||||||
|
} else if (name == 'override_file_confirm') {
|
||||||
|
FFI.fileModel.overrideFileConfirm(evt);
|
||||||
|
} else if (name == 'try_start_without_auth') {
|
||||||
|
FFI.serverModel.loginRequest(evt);
|
||||||
|
} else if (name == 'on_client_authorized') {
|
||||||
|
FFI.serverModel.onClientAuthorized(evt);
|
||||||
|
} else if (name == 'on_client_remove') {
|
||||||
|
FFI.serverModel.onClientRemove(evt);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Bind the event listener to receive events from the Rust core.
|
/// Bind the event listener to receive events from the Rust core.
|
||||||
void updateEventListener(String peerId) {
|
void updateEventListener(String peerId) {
|
||||||
final void Function(Map<String, dynamic>) cb = (evt) {
|
final void Function(Map<String, dynamic>) cb = (evt) {
|
||||||
@@ -128,7 +176,7 @@ class FfiModel with ChangeNotifier {
|
|||||||
if (name == 'msgbox') {
|
if (name == 'msgbox') {
|
||||||
handleMsgBox(evt, peerId);
|
handleMsgBox(evt, peerId);
|
||||||
} else if (name == 'peer_info') {
|
} else if (name == 'peer_info') {
|
||||||
handlePeerInfo(evt);
|
handlePeerInfo(evt, peerId);
|
||||||
} else if (name == 'connection_ready') {
|
} else if (name == 'connection_ready') {
|
||||||
FFI.ffiModel.setConnectionType(
|
FFI.ffiModel.setConnectionType(
|
||||||
evt['secure'] == 'true', evt['direct'] == 'true');
|
evt['secure'] == 'true', evt['direct'] == 'true');
|
||||||
@@ -193,17 +241,19 @@ class FfiModel with ChangeNotifier {
|
|||||||
enterPasswordDialog(id);
|
enterPasswordDialog(id);
|
||||||
} else {
|
} else {
|
||||||
var hasRetry = evt['hasRetry'] == 'true';
|
var hasRetry = evt['hasRetry'] == 'true';
|
||||||
showMsgBox(type, title, text, hasRetry);
|
showMsgBox(id, type, title, text, hasRetry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show a message box with [type], [title] and [text].
|
/// Show a message box with [type], [title] and [text].
|
||||||
void showMsgBox(String type, String title, String text, bool hasRetry) {
|
void showMsgBox(
|
||||||
|
String id, String type, String title, String text, bool hasRetry) {
|
||||||
msgBox(type, title, text);
|
msgBox(type, title, text);
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
if (hasRetry) {
|
if (hasRetry) {
|
||||||
_timer = Timer(Duration(seconds: _reconnects), () {
|
_timer = Timer(Duration(seconds: _reconnects), () {
|
||||||
FFI.reconnect();
|
FFI.bind.sessionReconnect(id: id);
|
||||||
|
clearPermissions();
|
||||||
showLoading(translate('Connecting...'));
|
showLoading(translate('Connecting...'));
|
||||||
});
|
});
|
||||||
_reconnects *= 2;
|
_reconnects *= 2;
|
||||||
@@ -213,7 +263,7 @@ class FfiModel with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Handle the peer info event based on [evt].
|
/// Handle the peer info event based on [evt].
|
||||||
void handlePeerInfo(Map<String, dynamic> evt) {
|
void handlePeerInfo(Map<String, dynamic> evt, String peerId) async {
|
||||||
SmartDialog.dismiss();
|
SmartDialog.dismiss();
|
||||||
_pi.version = evt['version'];
|
_pi.version = evt['version'];
|
||||||
_pi.username = evt['username'];
|
_pi.username = evt['username'];
|
||||||
@@ -228,7 +278,8 @@ class FfiModel with ChangeNotifier {
|
|||||||
Timer(Duration(milliseconds: 100), showMobileActionsOverlay);
|
Timer(Duration(milliseconds: 100), showMobileActionsOverlay);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_touchMode = FFI.getByName('peer_option', "touch-mode") != '';
|
_touchMode =
|
||||||
|
await FFI.bind.getSessionOption(id: peerId, arg: "touch-mode") != '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evt['is_file_transfer'] == "true") {
|
if (evt['is_file_transfer'] == "true") {
|
||||||
@@ -263,26 +314,26 @@ class ImageModel with ChangeNotifier {
|
|||||||
|
|
||||||
ui.Image? get image => _image;
|
ui.Image? get image => _image;
|
||||||
|
|
||||||
ImageModel() {
|
String _id = "";
|
||||||
PlatformFFI.setRgbaCallback((rgba) {
|
|
||||||
if (_waitForImage) {
|
void onRgba(Uint8List rgba) {
|
||||||
_waitForImage = false;
|
if (_waitForImage) {
|
||||||
SmartDialog.dismiss();
|
_waitForImage = false;
|
||||||
|
SmartDialog.dismiss();
|
||||||
|
}
|
||||||
|
final pid = FFI.id;
|
||||||
|
ui.decodeImageFromPixels(
|
||||||
|
rgba,
|
||||||
|
FFI.ffiModel.display.width,
|
||||||
|
FFI.ffiModel.display.height,
|
||||||
|
isWeb ? ui.PixelFormat.rgba8888 : ui.PixelFormat.bgra8888, (image) {
|
||||||
|
if (FFI.id != pid) return;
|
||||||
|
try {
|
||||||
|
// my throw exception, because the listener maybe already dispose
|
||||||
|
update(image);
|
||||||
|
} catch (e) {
|
||||||
|
print('update image: $e');
|
||||||
}
|
}
|
||||||
final pid = FFI.id;
|
|
||||||
ui.decodeImageFromPixels(
|
|
||||||
rgba,
|
|
||||||
FFI.ffiModel.display.width,
|
|
||||||
FFI.ffiModel.display.height,
|
|
||||||
isWeb ? ui.PixelFormat.rgba8888 : ui.PixelFormat.bgra8888, (image) {
|
|
||||||
if (FFI.id != pid) return;
|
|
||||||
try {
|
|
||||||
// my throw exception, because the listener maybe already dispose
|
|
||||||
FFI.imageModel.update(image);
|
|
||||||
} catch (e) {
|
|
||||||
print('update image: $e');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,8 +350,8 @@ class ImageModel with ChangeNotifier {
|
|||||||
initializeCursorAndCanvas();
|
initializeCursorAndCanvas();
|
||||||
Future.delayed(Duration(milliseconds: 1), () {
|
Future.delayed(Duration(milliseconds: 1), () {
|
||||||
if (FFI.ffiModel.isPeerAndroid) {
|
if (FFI.ffiModel.isPeerAndroid) {
|
||||||
FFI.setByName(
|
FFI.bind
|
||||||
'peer_option', '{"name": "view-style", "value": "shrink"}');
|
.sessionPeerOption(id: _id, name: "view-style", value: "shrink");
|
||||||
FFI.canvasModel.updateViewStyle();
|
FFI.canvasModel.updateViewStyle();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -330,6 +381,7 @@ class CanvasModel with ChangeNotifier {
|
|||||||
double _x = 0;
|
double _x = 0;
|
||||||
double _y = 0;
|
double _y = 0;
|
||||||
double _scale = 1.0;
|
double _scale = 1.0;
|
||||||
|
String id = ""; // TODO multi canvas model
|
||||||
|
|
||||||
CanvasModel();
|
CanvasModel();
|
||||||
|
|
||||||
@@ -339,8 +391,11 @@ class CanvasModel with ChangeNotifier {
|
|||||||
|
|
||||||
double get scale => _scale;
|
double get scale => _scale;
|
||||||
|
|
||||||
void updateViewStyle() {
|
void updateViewStyle() async {
|
||||||
final s = FFI.getByName('peer_option', 'view-style');
|
final s = await FFI.bind.getSessionOption(id: id, arg: 'view-style');
|
||||||
|
if (s == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final size = MediaQueryData.fromWindow(ui.window).size;
|
final size = MediaQueryData.fromWindow(ui.window).size;
|
||||||
final s1 = size.width / FFI.ffiModel.display.width;
|
final s1 = size.width / FFI.ffiModel.display.width;
|
||||||
final s2 = size.height / FFI.ffiModel.display.height;
|
final s2 = size.height / FFI.ffiModel.display.height;
|
||||||
@@ -450,6 +505,7 @@ class CursorModel with ChangeNotifier {
|
|||||||
double _hoty = 0;
|
double _hoty = 0;
|
||||||
double _displayOriginX = 0;
|
double _displayOriginX = 0;
|
||||||
double _displayOriginY = 0;
|
double _displayOriginY = 0;
|
||||||
|
String id = ""; // TODO multi cursor model
|
||||||
|
|
||||||
ui.Image? get image => _image;
|
ui.Image? get image => _image;
|
||||||
|
|
||||||
@@ -598,17 +654,17 @@ class CursorModel with ChangeNotifier {
|
|||||||
final rgba = Uint8List.fromList(colors.map((s) => s as int).toList());
|
final rgba = Uint8List.fromList(colors.map((s) => s as int).toList());
|
||||||
var pid = FFI.id;
|
var pid = FFI.id;
|
||||||
ui.decodeImageFromPixels(rgba, width, height, ui.PixelFormat.rgba8888,
|
ui.decodeImageFromPixels(rgba, width, height, ui.PixelFormat.rgba8888,
|
||||||
(image) {
|
(image) {
|
||||||
if (FFI.id != pid) return;
|
if (FFI.id != pid) return;
|
||||||
_image = image;
|
_image = image;
|
||||||
_images[id] = Tuple3(image, _hotx, _hoty);
|
_images[id] = Tuple3(image, _hotx, _hoty);
|
||||||
try {
|
try {
|
||||||
// my throw exception, because the listener maybe already dispose
|
// my throw exception, because the listener maybe already dispose
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('notify cursor: $e');
|
print('notify cursor: $e');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateCursorId(Map<String, dynamic> evt) {
|
void updateCursorId(Map<String, dynamic> evt) {
|
||||||
@@ -637,7 +693,8 @@ class CursorModel with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDisplayOriginWithCursor(double x, double y, double xCursor, double yCursor) {
|
void updateDisplayOriginWithCursor(
|
||||||
|
double x, double y, double xCursor, double yCursor) {
|
||||||
_displayOriginX = x;
|
_displayOriginX = x;
|
||||||
_displayOriginY = y;
|
_displayOriginY = y;
|
||||||
_x = xCursor;
|
_x = xCursor;
|
||||||
@@ -688,7 +745,7 @@ class FFI {
|
|||||||
|
|
||||||
/// Get the remote id for current client.
|
/// Get the remote id for current client.
|
||||||
static String getId() {
|
static String getId() {
|
||||||
return getByName('remote_id');
|
return getByName('remote_id'); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a mouse tap event(down and up).
|
/// Send a mouse tap event(down and up).
|
||||||
@@ -700,14 +757,14 @@ class FFI {
|
|||||||
/// Send scroll event with scroll distance [y].
|
/// Send scroll event with scroll distance [y].
|
||||||
static void scroll(int y) {
|
static void scroll(int y) {
|
||||||
setByName('send_mouse',
|
setByName('send_mouse',
|
||||||
json.encode(modify({'type': 'wheel', 'y': y.toString()})));
|
json.encode(modify({'id': id, 'type': 'wheel', 'y': y.toString()})));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reconnect to the remote peer.
|
/// Reconnect to the remote peer.
|
||||||
static void reconnect() {
|
// static void reconnect() {
|
||||||
setByName('reconnect');
|
// setByName('reconnect');
|
||||||
FFI.ffiModel.clearPermissions();
|
// FFI.ffiModel.clearPermissions();
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Reset key modifiers to false, including [shift], [ctrl], [alt] and [command].
|
/// Reset key modifiers to false, including [shift], [ctrl], [alt] and [command].
|
||||||
static void resetModifiers() {
|
static void resetModifiers() {
|
||||||
@@ -727,7 +784,7 @@ class FFI {
|
|||||||
static void sendMouse(String type, MouseButtons button) {
|
static void sendMouse(String type, MouseButtons button) {
|
||||||
if (!ffiModel.keyboard()) return;
|
if (!ffiModel.keyboard()) return;
|
||||||
setByName('send_mouse',
|
setByName('send_mouse',
|
||||||
json.encode(modify({'type': type, 'buttons': button.value})));
|
json.encode(modify({'id': id, 'type': type, 'buttons': button.value})));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send key stroke event.
|
/// Send key stroke event.
|
||||||
@@ -735,17 +792,27 @@ class FFI {
|
|||||||
/// [press] indicates a click event(down and up).
|
/// [press] indicates a click event(down and up).
|
||||||
static void inputKey(String name, {bool? down, bool? press}) {
|
static void inputKey(String name, {bool? down, bool? press}) {
|
||||||
if (!ffiModel.keyboard()) return;
|
if (!ffiModel.keyboard()) return;
|
||||||
final Map<String, String> out = Map();
|
// final Map<String, String> out = Map();
|
||||||
out['name'] = name;
|
// out['name'] = name;
|
||||||
// default: down = false
|
// // default: down = false
|
||||||
if (down == true) {
|
// if (down == true) {
|
||||||
out['down'] = "true";
|
// out['down'] = "true";
|
||||||
}
|
// }
|
||||||
// default: press = true
|
// // default: press = true
|
||||||
if (press != false) {
|
// if (press != false) {
|
||||||
out['press'] = "true";
|
// out['press'] = "true";
|
||||||
}
|
// }
|
||||||
setByName('input_key', json.encode(modify(out)));
|
// setByName('input_key', json.encode(modify(out)));
|
||||||
|
// TODO id
|
||||||
|
FFI.bind.sessionInputKey(
|
||||||
|
id: id,
|
||||||
|
name: name,
|
||||||
|
down: down ?? false,
|
||||||
|
press: press ?? true,
|
||||||
|
alt: alt,
|
||||||
|
ctrl: ctrl,
|
||||||
|
shift: shift,
|
||||||
|
command: command);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send mouse movement event with distance in [x] and [y].
|
/// Send mouse movement event with distance in [x] and [y].
|
||||||
@@ -753,19 +820,20 @@ class FFI {
|
|||||||
if (!ffiModel.keyboard()) return;
|
if (!ffiModel.keyboard()) return;
|
||||||
var x2 = x.toInt();
|
var x2 = x.toInt();
|
||||||
var y2 = y.toInt();
|
var y2 = y.toInt();
|
||||||
setByName('send_mouse', json.encode(modify({'x': '$x2', 'y': '$y2'})));
|
setByName(
|
||||||
|
'send_mouse', json.encode(modify({'id': id, 'x': '$x2', 'y': '$y2'})));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List the saved peers.
|
/// List the saved peers.
|
||||||
static List<Peer> peers() {
|
static List<Peer> peers() {
|
||||||
try {
|
try {
|
||||||
var str = getByName('peers');
|
var str = getByName('peers'); // TODO
|
||||||
if (str == "") return [];
|
if (str == "") return [];
|
||||||
List<dynamic> peers = json.decode(str);
|
List<dynamic> peers = json.decode(str);
|
||||||
return peers
|
return peers
|
||||||
.map((s) => s as List<dynamic>)
|
.map((s) => s as List<dynamic>)
|
||||||
.map((s) =>
|
.map((s) =>
|
||||||
Peer.fromJson(s[0] as String, s[1] as Map<String, dynamic>))
|
Peer.fromJson(s[0] as String, s[1] as Map<String, dynamic>))
|
||||||
.toList();
|
.toList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('peers(): $e');
|
print('peers(): $e');
|
||||||
@@ -779,31 +847,37 @@ class FFI {
|
|||||||
setByName('connect_file_transfer', id);
|
setByName('connect_file_transfer', id);
|
||||||
} else {
|
} else {
|
||||||
FFI.chatModel.resetClientMode();
|
FFI.chatModel.resetClientMode();
|
||||||
setByName('connect', id);
|
// setByName('connect', id);
|
||||||
|
// TODO multi model instances
|
||||||
|
FFI.canvasModel.id = id;
|
||||||
|
FFI.imageModel._id = id;
|
||||||
|
FFI.cursorModel.id = id;
|
||||||
|
final stream =
|
||||||
|
FFI.bind.sessionConnect(id: id, isFileTransfer: isFileTransfer);
|
||||||
|
final cb = FFI.ffiModel.startEventListener(id);
|
||||||
|
() async {
|
||||||
|
await for (final message in stream) {
|
||||||
|
if (message is Event) {
|
||||||
|
try {
|
||||||
|
debugPrint("event:${message.field0}");
|
||||||
|
Map<String, dynamic> event = json.decode(message.field0);
|
||||||
|
cb(event);
|
||||||
|
} catch (e) {
|
||||||
|
print('json.decode fail(): $e');
|
||||||
|
}
|
||||||
|
} else if (message is Rgba) {
|
||||||
|
FFI.imageModel.onRgba(message.field0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
// every instance will bind a stream
|
||||||
}
|
}
|
||||||
FFI.id = id;
|
FFI.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Map<String, dynamic>? popEvent() {
|
|
||||||
var s = getByName('event');
|
|
||||||
if (s == '') return null;
|
|
||||||
try {
|
|
||||||
Map<String, dynamic> event = json.decode(s);
|
|
||||||
return event;
|
|
||||||
} catch (e) {
|
|
||||||
print('popEvent(): $e');
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Login with [password], choose if the client should [remember] it.
|
/// Login with [password], choose if the client should [remember] it.
|
||||||
static void login(String password, bool remember) {
|
static void login(String id, String password, bool remember) {
|
||||||
setByName(
|
FFI.bind.sessionLogin(id: id, password: password, remember: remember);
|
||||||
'login',
|
|
||||||
json.encode({
|
|
||||||
'password': password,
|
|
||||||
'remember': remember ? 'true' : 'false',
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Close the remote session.
|
/// Close the remote session.
|
||||||
@@ -813,8 +887,8 @@ class FFI {
|
|||||||
savePreference(id, cursorModel.x, cursorModel.y, canvasModel.x,
|
savePreference(id, cursorModel.x, cursorModel.y, canvasModel.x,
|
||||||
canvasModel.y, canvasModel.scale, ffiModel.pi.currentDisplay);
|
canvasModel.y, canvasModel.scale, ffiModel.pi.currentDisplay);
|
||||||
}
|
}
|
||||||
|
FFI.bind.sessionClose(id: id);
|
||||||
id = "";
|
id = "";
|
||||||
setByName('close', '');
|
|
||||||
imageModel.update(null);
|
imageModel.update(null);
|
||||||
cursorModel.clear();
|
cursorModel.clear();
|
||||||
ffiModel.clear();
|
ffiModel.clear();
|
||||||
@@ -833,6 +907,8 @@ class FFI {
|
|||||||
PlatformFFI.setByName(name, value);
|
PlatformFFI.setByName(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static RustdeskImpl get bind => PlatformFFI.ffiBind;
|
||||||
|
|
||||||
static handleMouse(Map<String, dynamic> evt) {
|
static handleMouse(Map<String, dynamic> evt) {
|
||||||
var type = '';
|
var type = '';
|
||||||
var isMove = false;
|
var isMove = false;
|
||||||
@@ -884,6 +960,7 @@ class FFI {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
evt['buttons'] = buttons;
|
evt['buttons'] = buttons;
|
||||||
|
evt['id'] = id;
|
||||||
setByName('send_mouse', json.encode(evt));
|
setByName('send_mouse', json.encode(evt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ class PlatformFFI {
|
|||||||
static String _homeDir = '';
|
static String _homeDir = '';
|
||||||
static F2? _getByName;
|
static F2? _getByName;
|
||||||
static F3? _setByName;
|
static F3? _setByName;
|
||||||
|
static late RustdeskImpl _ffiBind;
|
||||||
static void Function(Map<String, dynamic>)? _eventCallback;
|
static void Function(Map<String, dynamic>)? _eventCallback;
|
||||||
static void Function(Uint8List)? _rgbaCallback;
|
|
||||||
|
static RustdeskImpl get ffiBind => _ffiBind;
|
||||||
|
|
||||||
static Future<String> getVersion() async {
|
static Future<String> getVersion() async {
|
||||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||||
@@ -88,7 +90,8 @@ class PlatformFFI {
|
|||||||
dylib.lookupFunction<Void Function(Pointer<Utf8>, Pointer<Utf8>), F3>(
|
dylib.lookupFunction<Void Function(Pointer<Utf8>, Pointer<Utf8>), F3>(
|
||||||
'set_by_name');
|
'set_by_name');
|
||||||
_dir = (await getApplicationDocumentsDirectory()).path;
|
_dir = (await getApplicationDocumentsDirectory()).path;
|
||||||
_startListenEvent(RustdeskImpl(dylib));
|
_ffiBind = RustdeskImpl(dylib);
|
||||||
|
_startListenEvent(_ffiBind); // global event
|
||||||
try {
|
try {
|
||||||
_homeDir = (await ExternalPath.getExternalStorageDirectories())[0];
|
_homeDir = (await ExternalPath.getExternalStorageDirectories())[0];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -133,7 +136,7 @@ class PlatformFFI {
|
|||||||
/// Start listening to the Rust core's events and frames.
|
/// Start listening to the Rust core's events and frames.
|
||||||
static void _startListenEvent(RustdeskImpl rustdeskImpl) {
|
static void _startListenEvent(RustdeskImpl rustdeskImpl) {
|
||||||
() async {
|
() async {
|
||||||
await for (final message in rustdeskImpl.startEventStream()) {
|
await for (final message in rustdeskImpl.startGlobalEventStream()) {
|
||||||
if (_eventCallback != null) {
|
if (_eventCallback != null) {
|
||||||
try {
|
try {
|
||||||
Map<String, dynamic> event = json.decode(message);
|
Map<String, dynamic> event = json.decode(message);
|
||||||
@@ -144,24 +147,13 @@ class PlatformFFI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
() async {
|
|
||||||
await for (final rgba in rustdeskImpl.startRgbaStream()) {
|
|
||||||
if (_rgbaCallback != null) {
|
|
||||||
_rgbaCallback!(rgba);
|
|
||||||
} else {
|
|
||||||
rgba.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setEventCallback(void Function(Map<String, dynamic>) fun) async {
|
static void setEventCallback(void Function(Map<String, dynamic>) fun) async {
|
||||||
_eventCallback = fun;
|
_eventCallback = fun;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setRgbaCallback(void Function(Uint8List) fun) async {
|
static void setRgbaCallback(void Function(Uint8List) fun) async {}
|
||||||
_rgbaCallback = fun;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void startDesktopWebListener() {}
|
static void startDesktopWebListener() {}
|
||||||
|
|
||||||
|
|||||||
@@ -396,9 +396,11 @@ packages:
|
|||||||
flutter_rust_bridge:
|
flutter_rust_bridge:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_rust_bridge
|
path: frb_dart
|
||||||
url: "https://pub.dartlang.org"
|
ref: master
|
||||||
source: hosted
|
resolved-ref: e5adce55eea0b74d3680e66a2c5252edf17b07e1
|
||||||
|
url: "https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge"
|
||||||
|
source: git
|
||||||
version: "1.32.0"
|
version: "1.32.0"
|
||||||
flutter_smart_dialog:
|
flutter_smart_dialog:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
|
|||||||
@@ -53,7 +53,11 @@ dependencies:
|
|||||||
image_picker: ^0.8.5
|
image_picker: ^0.8.5
|
||||||
image: ^3.1.3
|
image: ^3.1.3
|
||||||
flutter_smart_dialog: ^4.3.1
|
flutter_smart_dialog: ^4.3.1
|
||||||
flutter_rust_bridge: ^1.30.0
|
flutter_rust_bridge:
|
||||||
|
git:
|
||||||
|
url: https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge
|
||||||
|
ref: master
|
||||||
|
path: frb_dart
|
||||||
window_manager: ^0.2.3
|
window_manager: ^0.2.3
|
||||||
desktop_multi_window:
|
desktop_multi_window:
|
||||||
git:
|
git:
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
use super::{Data, Interface};
|
use super::{Data, Interface};
|
||||||
use hbb_common::{
|
use hbb_common::{fs, message_proto::*};
|
||||||
fs,
|
|
||||||
message_proto::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub trait FileManager: Interface {
|
pub trait FileManager: Interface {
|
||||||
fn get_home_dir(&self) -> String{
|
fn get_home_dir(&self) -> String {
|
||||||
fs::get_home_as_string()
|
fs::get_home_as_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
fn read_dir(&self,path: String, include_hidden: bool) -> sciter::Value {
|
fn read_dir(&self, path: String, include_hidden: bool) -> sciter::Value {
|
||||||
match fs::read_dir(&fs::get_path(&path), include_hidden) {
|
match fs::read_dir(&fs::get_path(&path), include_hidden) {
|
||||||
Err(_) => sciter::Value::null(),
|
Err(_) => sciter::Value::null(),
|
||||||
Ok(fd) => {
|
Ok(fd) => {
|
||||||
@@ -23,15 +20,15 @@ pub trait FileManager: Interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
fn read_dir(&self,path: &str, include_hidden: bool) -> String {
|
fn read_dir(&self, path: &str, include_hidden: bool) -> String {
|
||||||
use crate::flutter::make_fd_to_json;
|
use crate::flutter::make_fd_to_json;
|
||||||
match fs::read_dir(&fs::get_path(path), include_hidden){
|
match fs::read_dir(&fs::get_path(path), include_hidden) {
|
||||||
Ok(fd) => make_fd_to_json(fd),
|
Ok(fd) => make_fd_to_json(fd),
|
||||||
Err(_)=>"".into()
|
Err(_) => "".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cancel_job(&mut self, id: i32) {
|
fn cancel_job(&self, id: i32) {
|
||||||
self.send(Data::CancelJob(id));
|
self.send(Data::CancelJob(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,23 +44,23 @@ pub trait FileManager: Interface {
|
|||||||
self.send(Data::Message(msg_out));
|
self.send(Data::Message(msg_out));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_file(&mut self, id: i32, path: String, file_num: i32, is_remote: bool) {
|
fn remove_file(&self, id: i32, path: String, file_num: i32, is_remote: bool) {
|
||||||
self.send(Data::RemoveFile((id, path, file_num, is_remote)));
|
self.send(Data::RemoveFile((id, path, file_num, is_remote)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_dir_all(&mut self, id: i32, path: String, is_remote: bool) {
|
fn remove_dir_all(&self, id: i32, path: String, is_remote: bool) {
|
||||||
self.send(Data::RemoveDirAll((id, path, is_remote)));
|
self.send(Data::RemoveDirAll((id, path, is_remote)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_delete_files(&mut self, id: i32, file_num: i32) {
|
fn confirm_delete_files(&self, id: i32, file_num: i32) {
|
||||||
self.send(Data::ConfirmDeleteFiles((id, file_num)));
|
self.send(Data::ConfirmDeleteFiles((id, file_num)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_no_confirm(&mut self, id: i32) {
|
fn set_no_confirm(&self, id: i32) {
|
||||||
self.send(Data::SetNoConfirm(id));
|
self.send(Data::SetNoConfirm(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_dir(&mut self, id: i32, path: String, is_remote: bool) {
|
fn remove_dir(&self, id: i32, path: String, is_remote: bool) {
|
||||||
if is_remote {
|
if is_remote {
|
||||||
self.send(Data::RemoveDir((id, path)));
|
self.send(Data::RemoveDir((id, path)));
|
||||||
} else {
|
} else {
|
||||||
@@ -71,12 +68,12 @@ pub trait FileManager: Interface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_dir(&mut self, id: i32, path: String, is_remote: bool) {
|
fn create_dir(&self, id: i32, path: String, is_remote: bool) {
|
||||||
self.send(Data::CreateDir((id, path, is_remote)));
|
self.send(Data::CreateDir((id, path, is_remote)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_files(
|
fn send_files(
|
||||||
&mut self,
|
&self,
|
||||||
id: i32,
|
id: i32,
|
||||||
path: String,
|
path: String,
|
||||||
to: String,
|
to: String,
|
||||||
@@ -84,7 +81,14 @@ pub trait FileManager: Interface {
|
|||||||
include_hidden: bool,
|
include_hidden: bool,
|
||||||
is_remote: bool,
|
is_remote: bool,
|
||||||
) {
|
) {
|
||||||
self.send(Data::SendFiles((id, path, to, file_num, include_hidden, is_remote)));
|
self.send(Data::SendFiles((
|
||||||
|
id,
|
||||||
|
path,
|
||||||
|
to,
|
||||||
|
file_num,
|
||||||
|
include_hidden,
|
||||||
|
is_remote,
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_job(
|
fn add_job(
|
||||||
@@ -96,10 +100,17 @@ pub trait FileManager: Interface {
|
|||||||
include_hidden: bool,
|
include_hidden: bool,
|
||||||
is_remote: bool,
|
is_remote: bool,
|
||||||
) {
|
) {
|
||||||
self.send(Data::AddJob((id, path, to, file_num, include_hidden, is_remote)));
|
self.send(Data::AddJob((
|
||||||
|
id,
|
||||||
|
path,
|
||||||
|
to,
|
||||||
|
file_num,
|
||||||
|
include_hidden,
|
||||||
|
is_remote,
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resume_job(&mut self, id: i32, is_remote: bool){
|
fn resume_job(&mut self, id: i32, is_remote: bool) {
|
||||||
self.send(Data::ResumeJob((id,is_remote)));
|
self.send(Data::ResumeJob((id, is_remote)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
331
src/flutter.rs
331
src/flutter.rs
@@ -1,4 +1,4 @@
|
|||||||
use crate::client::*;
|
use crate::{client::*, flutter_ffi::EventToUI};
|
||||||
use flutter_rust_bridge::{StreamSink, ZeroCopyBuffer};
|
use flutter_rust_bridge::{StreamSink, ZeroCopyBuffer};
|
||||||
use hbb_common::{
|
use hbb_common::{
|
||||||
allow_err,
|
allow_err,
|
||||||
@@ -26,17 +26,21 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref SESSION: Arc<RwLock<Option<Session>>> = Default::default();
|
// static ref SESSION: Arc<RwLock<Option<Session>>> = Default::default();
|
||||||
pub static ref EVENT_STREAM: RwLock<Option<StreamSink<String>>> = Default::default(); // rust to dart event channel
|
pub static ref SESSIONS: RwLock<HashMap<String,Session>> = Default::default();
|
||||||
pub static ref RGBA_STREAM: RwLock<Option<StreamSink<ZeroCopyBuffer<Vec<u8>>>>> = Default::default(); // rust to dart rgba (big u8 list) channel
|
pub static ref GLOBAL_EVENT_STREAM: RwLock<Option<StreamSink<String>>> = Default::default(); // rust to dart event channel
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
// pub fn get_session<'a>(id: &str) -> Option<&'a Session> {
|
||||||
|
// SESSIONS.read().unwrap().get(id)
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
id: String,
|
id: String,
|
||||||
sender: Arc<RwLock<Option<mpsc::UnboundedSender<Data>>>>,
|
sender: Arc<RwLock<Option<mpsc::UnboundedSender<Data>>>>, // UI to rust
|
||||||
lc: Arc<RwLock<LoginConfigHandler>>,
|
lc: Arc<RwLock<LoginConfigHandler>>,
|
||||||
events2ui: Arc<RwLock<VecDeque<String>>>,
|
events2ui: Arc<RwLock<StreamSink<EventToUI>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Session {
|
impl Session {
|
||||||
@@ -46,40 +50,47 @@ impl Session {
|
|||||||
///
|
///
|
||||||
/// * `id` - The id of the remote session.
|
/// * `id` - The id of the remote session.
|
||||||
/// * `is_file_transfer` - If the session is used for file transfer.
|
/// * `is_file_transfer` - If the session is used for file transfer.
|
||||||
pub fn start(id: &str, is_file_transfer: bool) {
|
pub fn start(id: &str, is_file_transfer: bool, events2ui: StreamSink<EventToUI>) {
|
||||||
LocalConfig::set_remote_id(id);
|
LocalConfig::set_remote_id(&id);
|
||||||
Self::close();
|
// TODO check same id
|
||||||
let mut session = Session::default();
|
// TODO close
|
||||||
|
// Self::close();
|
||||||
|
let events2ui = Arc::new(RwLock::new(events2ui));
|
||||||
|
let mut session = Session {
|
||||||
|
id: id.to_owned(),
|
||||||
|
sender: Default::default(),
|
||||||
|
lc: Default::default(),
|
||||||
|
events2ui,
|
||||||
|
};
|
||||||
session
|
session
|
||||||
.lc
|
.lc
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.initialize(id.to_owned(), false, false);
|
.initialize(id.to_owned(), false, false);
|
||||||
session.id = id.to_owned();
|
SESSIONS
|
||||||
*SESSION.write().unwrap() = Some(session.clone());
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.insert(id.to_owned(), session.clone());
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
Connection::start(session, is_file_transfer);
|
Connection::start(session, is_file_transfer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current session instance.
|
/// Get the current session instance.
|
||||||
pub fn get() -> Arc<RwLock<Option<Session>>> {
|
// pub fn get() -> Arc<RwLock<Option<Session>>> {
|
||||||
SESSION.clone()
|
// SESSION.clone()
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Get the option of the current session.
|
/// Get the option of the current session.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `name` - The name of the option to get. Currently only `remote_dir` is supported.
|
/// * `name` - The name of the option to get. Currently only `remote_dir` is supported.
|
||||||
pub fn get_option(name: &str) -> String {
|
pub fn get_option(&self, name: &str) -> String {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
if name == "remote_dir" {
|
||||||
if name == "remote_dir" {
|
return self.lc.read().unwrap().get_remote_dir();
|
||||||
return session.lc.read().unwrap().get_remote_dir();
|
|
||||||
}
|
|
||||||
return session.lc.read().unwrap().get_option(name);
|
|
||||||
}
|
}
|
||||||
"".to_owned()
|
self.lc.read().unwrap().get_option(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the option of the current session.
|
/// Set the option of the current session.
|
||||||
@@ -88,78 +99,59 @@ impl Session {
|
|||||||
///
|
///
|
||||||
/// * `name` - The name of the option to set. Currently only `remote_dir` is supported.
|
/// * `name` - The name of the option to set. Currently only `remote_dir` is supported.
|
||||||
/// * `value` - The value of the option to set.
|
/// * `value` - The value of the option to set.
|
||||||
pub fn set_option(name: String, value: String) {
|
pub fn set_option(&self, name: String, value: String) {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
let mut value = value;
|
||||||
let mut value = value;
|
let mut lc = self.lc.write().unwrap();
|
||||||
if name == "remote_dir" {
|
if name == "remote_dir" {
|
||||||
value = session.lc.write().unwrap().get_all_remote_dir(value);
|
value = lc.get_all_remote_dir(value);
|
||||||
}
|
|
||||||
return session.lc.write().unwrap().set_option(name, value);
|
|
||||||
}
|
}
|
||||||
|
lc.set_option(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Input the OS password.
|
/// Input the OS password.
|
||||||
pub fn input_os_password(pass: String, activate: bool) {
|
pub fn input_os_password(&self, pass: String, activate: bool) {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
input_os_password(pass, activate, self.clone());
|
||||||
input_os_password(pass, activate, session.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// impl Interface
|
||||||
/// Send message to the remote session.
|
/// Send message to the remote session.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `data` - The data to send. See [`Data`] for more details.
|
/// * `data` - The data to send. See [`Data`] for more details.
|
||||||
fn send(data: Data) {
|
// fn send(data: Data) {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
// if let Some(session) = SESSION.read().unwrap().as_ref() {
|
||||||
session.send(data);
|
// session.send(data);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Pop a event from the event queue.
|
|
||||||
pub fn pop_event() -> Option<String> {
|
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
|
||||||
session.events2ui.write().unwrap().pop_front()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Toggle an option.
|
/// Toggle an option.
|
||||||
pub fn toggle_option(name: &str) {
|
pub fn toggle_option(&self, name: &str) {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
let msg = self.lc.write().unwrap().toggle_option(name.to_owned());
|
||||||
let msg = session.lc.write().unwrap().toggle_option(name.to_owned());
|
if let Some(msg) = msg {
|
||||||
if let Some(msg) = msg {
|
self.send_msg(msg);
|
||||||
session.send_msg(msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a refresh command.
|
/// Send a refresh command.
|
||||||
pub fn refresh() {
|
pub fn refresh(&self) {
|
||||||
Self::send(Data::Message(LoginConfigHandler::refresh()));
|
self.send(Data::Message(LoginConfigHandler::refresh()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get image quality.
|
/// Get image quality.
|
||||||
pub fn get_image_quality() -> String {
|
pub fn get_image_quality(&self) -> String {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
self.lc.read().unwrap().image_quality.clone()
|
||||||
session.lc.read().unwrap().image_quality.clone()
|
|
||||||
} else {
|
|
||||||
"".to_owned()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set image quality.
|
/// Set image quality.
|
||||||
pub fn set_image_quality(value: &str) {
|
pub fn set_image_quality(&self, value: &str) {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
let msg = self
|
||||||
let msg = session
|
.lc
|
||||||
.lc
|
.write()
|
||||||
.write()
|
.unwrap()
|
||||||
.unwrap()
|
.save_image_quality(value.to_owned());
|
||||||
.save_image_quality(value.to_owned());
|
if let Some(msg) = msg {
|
||||||
if let Some(msg) = msg {
|
self.send_msg(msg);
|
||||||
session.send_msg(msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,12 +161,8 @@ impl Session {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `name` - The name of the option to get.
|
/// * `name` - The name of the option to get.
|
||||||
pub fn get_toggle_option(name: &str) -> Option<bool> {
|
pub fn get_toggle_option(&self, name: &str) -> bool {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
self.lc.write().unwrap().get_toggle_option(name)
|
||||||
Some(session.lc.write().unwrap().get_toggle_option(name))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Login.
|
/// Login.
|
||||||
@@ -183,36 +171,28 @@ impl Session {
|
|||||||
///
|
///
|
||||||
/// * `password` - The password to login.
|
/// * `password` - The password to login.
|
||||||
/// * `remember` - If the password should be remembered.
|
/// * `remember` - If the password should be remembered.
|
||||||
pub fn login(password: &str, remember: bool) {
|
pub fn login(&self, password: &str, remember: bool) {
|
||||||
Session::send(Data::Login((password.to_owned(), remember)));
|
self.send(Data::Login((password.to_owned(), remember)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Close the session.
|
/// Close the session.
|
||||||
pub fn close() {
|
pub fn close(&self) {
|
||||||
Session::send(Data::Close);
|
self.send(Data::Close);
|
||||||
SESSION.write().unwrap().take();
|
let _ = SESSIONS.write().unwrap().remove(&self.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reconnect to the current session.
|
/// Reconnect to the current session.
|
||||||
pub fn reconnect() {
|
pub fn reconnect(&self) {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
self.send(Data::Close);
|
||||||
if let Some(sender) = session.sender.read().unwrap().as_ref() {
|
let session = self.clone();
|
||||||
sender.send(Data::Close).ok();
|
std::thread::spawn(move || {
|
||||||
}
|
Connection::start(session, false);
|
||||||
let session = session.clone();
|
});
|
||||||
std::thread::spawn(move || {
|
|
||||||
Connection::start(session, false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get `remember` flag in [`LoginConfigHandler`].
|
/// Get `remember` flag in [`LoginConfigHandler`].
|
||||||
pub fn get_remember() -> bool {
|
pub fn get_remember(&self) -> bool {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
self.lc.read().unwrap().remember
|
||||||
session.lc.read().unwrap().remember
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send message over the current session.
|
/// Send message over the current session.
|
||||||
@@ -222,9 +202,7 @@ impl Session {
|
|||||||
/// * `msg` - The message to send.
|
/// * `msg` - The message to send.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn send_msg(&self, msg: Message) {
|
pub fn send_msg(&self, msg: Message) {
|
||||||
if let Some(sender) = self.sender.read().unwrap().as_ref() {
|
self.send(Data::Message(msg));
|
||||||
sender.send(Data::Message(msg)).ok();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send chat message over the current session.
|
/// Send chat message over the current session.
|
||||||
@@ -232,7 +210,7 @@ impl Session {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `text` - The message to send.
|
/// * `text` - The message to send.
|
||||||
pub fn send_chat(text: String) {
|
pub fn send_chat(&self, text: String) {
|
||||||
let mut misc = Misc::new();
|
let mut misc = Misc::new();
|
||||||
misc.set_chat_message(ChatMessage {
|
misc.set_chat_message(ChatMessage {
|
||||||
text,
|
text,
|
||||||
@@ -240,49 +218,46 @@ impl Session {
|
|||||||
});
|
});
|
||||||
let mut msg_out = Message::new();
|
let mut msg_out = Message::new();
|
||||||
msg_out.set_misc(misc);
|
msg_out.set_misc(misc);
|
||||||
Self::send_msg_static(msg_out);
|
self.send_msg(msg_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// file trait
|
||||||
/// Send file over the current session.
|
/// Send file over the current session.
|
||||||
pub fn send_files(
|
// pub fn send_files(
|
||||||
id: i32,
|
// id: i32,
|
||||||
path: String,
|
// path: String,
|
||||||
to: String,
|
// to: String,
|
||||||
file_num: i32,
|
// file_num: i32,
|
||||||
include_hidden: bool,
|
// include_hidden: bool,
|
||||||
is_remote: bool,
|
// is_remote: bool,
|
||||||
) {
|
// ) {
|
||||||
if let Some(session) = SESSION.write().unwrap().as_mut() {
|
// if let Some(session) = SESSION.write().unwrap().as_mut() {
|
||||||
session.send_files(id, path, to, file_num, include_hidden, is_remote);
|
// session.send_files(id, path, to, file_num, include_hidden, is_remote);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
// TODO into file trait
|
||||||
/// Confirm file override.
|
/// Confirm file override.
|
||||||
pub fn set_confirm_override_file(
|
pub fn set_confirm_override_file(
|
||||||
|
&self,
|
||||||
id: i32,
|
id: i32,
|
||||||
file_num: i32,
|
file_num: i32,
|
||||||
need_override: bool,
|
need_override: bool,
|
||||||
remember: bool,
|
remember: bool,
|
||||||
is_upload: bool,
|
is_upload: bool,
|
||||||
) {
|
) {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
log::info!(
|
||||||
if let Some(sender) = session.sender.read().unwrap().as_ref() {
|
"confirm file transfer, job: {}, need_override: {}",
|
||||||
log::info!(
|
id,
|
||||||
"confirm file transfer, job: {}, need_override: {}",
|
need_override
|
||||||
id,
|
);
|
||||||
need_override
|
self.send(Data::SetConfirmOverrideFile((
|
||||||
);
|
id,
|
||||||
sender
|
file_num,
|
||||||
.send(Data::SetConfirmOverrideFile((
|
need_override,
|
||||||
id,
|
remember,
|
||||||
file_num,
|
is_upload,
|
||||||
need_override,
|
)));
|
||||||
remember,
|
|
||||||
is_upload,
|
|
||||||
)))
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Static method to send message over the current session.
|
/// Static method to send message over the current session.
|
||||||
@@ -290,12 +265,12 @@ impl Session {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `msg` - The message to send.
|
/// * `msg` - The message to send.
|
||||||
#[inline]
|
// #[inline]
|
||||||
pub fn send_msg_static(msg: Message) {
|
// pub fn send_msg_static(msg: Message) {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
// if let Some(session) = SESSION.read().unwrap().as_ref() {
|
||||||
session.send_msg(msg);
|
// session.send_msg(msg);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Push an event to the event queue.
|
/// Push an event to the event queue.
|
||||||
/// An event is stored as json in the event queue.
|
/// An event is stored as json in the event queue.
|
||||||
@@ -308,10 +283,8 @@ impl Session {
|
|||||||
let mut h: HashMap<&str, &str> = event.iter().cloned().collect();
|
let mut h: HashMap<&str, &str> = event.iter().cloned().collect();
|
||||||
assert!(h.get("name").is_none());
|
assert!(h.get("name").is_none());
|
||||||
h.insert("name", name);
|
h.insert("name", name);
|
||||||
|
let out = serde_json::ser::to_string(&h).unwrap_or("".to_owned());
|
||||||
if let Some(s) = EVENT_STREAM.read().unwrap().as_ref() {
|
self.events2ui.read().unwrap().add(EventToUI::Event(out));
|
||||||
s.add(serde_json::ser::to_string(&h).unwrap_or("".to_owned()));
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get platform of peer.
|
/// Get platform of peer.
|
||||||
@@ -321,15 +294,13 @@ impl Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Quick method for sending a ctrl_alt_del command.
|
/// Quick method for sending a ctrl_alt_del command.
|
||||||
pub fn ctrl_alt_del() {
|
pub fn ctrl_alt_del(&self) {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
if self.peer_platform() == "Windows" {
|
||||||
if session.peer_platform() == "Windows" {
|
let k = Key::ControlKey(ControlKey::CtrlAltDel);
|
||||||
let k = Key::ControlKey(ControlKey::CtrlAltDel);
|
self.key_down_or_up(1, k, false, false, false, false);
|
||||||
session.key_down_or_up(1, k, false, false, false, false);
|
} else {
|
||||||
} else {
|
let k = Key::ControlKey(ControlKey::Delete);
|
||||||
let k = Key::ControlKey(ControlKey::Delete);
|
self.key_down_or_up(3, k, true, true, false, false);
|
||||||
session.key_down_or_up(3, k, true, true, false, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,7 +309,7 @@ impl Session {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `display` - The display to switch to.
|
/// * `display` - The display to switch to.
|
||||||
pub fn switch_display(display: i32) {
|
pub fn switch_display(&self, display: i32) {
|
||||||
let mut misc = Misc::new();
|
let mut misc = Misc::new();
|
||||||
misc.set_switch_display(SwitchDisplay {
|
misc.set_switch_display(SwitchDisplay {
|
||||||
display,
|
display,
|
||||||
@@ -346,15 +317,13 @@ impl Session {
|
|||||||
});
|
});
|
||||||
let mut msg_out = Message::new();
|
let mut msg_out = Message::new();
|
||||||
msg_out.set_misc(misc);
|
msg_out.set_misc(misc);
|
||||||
Self::send_msg_static(msg_out);
|
self.send_msg(msg_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send lock screen command.
|
/// Send lock screen command.
|
||||||
pub fn lock_screen() {
|
pub fn lock_screen(&self) {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
let k = Key::ControlKey(ControlKey::LockScreen);
|
||||||
let k = Key::ControlKey(ControlKey::LockScreen);
|
self.key_down_or_up(1, k, false, false, false, false);
|
||||||
session.key_down_or_up(1, k, false, false, false, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send key input command.
|
/// Send key input command.
|
||||||
@@ -369,6 +338,7 @@ impl Session {
|
|||||||
/// * `shift` - If the shift key is also pressed.
|
/// * `shift` - If the shift key is also pressed.
|
||||||
/// * `command` - If the command key is also pressed.
|
/// * `command` - If the command key is also pressed.
|
||||||
pub fn input_key(
|
pub fn input_key(
|
||||||
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
down: bool,
|
down: bool,
|
||||||
press: bool,
|
press: bool,
|
||||||
@@ -377,15 +347,13 @@ impl Session {
|
|||||||
shift: bool,
|
shift: bool,
|
||||||
command: bool,
|
command: bool,
|
||||||
) {
|
) {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
let chars: Vec<char> = name.chars().collect();
|
||||||
let chars: Vec<char> = name.chars().collect();
|
if chars.len() == 1 {
|
||||||
if chars.len() == 1 {
|
let key = Key::_Raw(chars[0] as _);
|
||||||
let key = Key::_Raw(chars[0] as _);
|
self._input_key(key, down, press, alt, ctrl, shift, command);
|
||||||
session._input_key(key, down, press, alt, ctrl, shift, command);
|
} else {
|
||||||
} else {
|
if let Some(key) = KEY_MAP.get(name) {
|
||||||
if let Some(key) = KEY_MAP.get(name) {
|
self._input_key(key.clone(), down, press, alt, ctrl, shift, command);
|
||||||
session._input_key(key.clone(), down, press, alt, ctrl, shift, command);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,13 +363,13 @@ impl Session {
|
|||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `value` - The text to input.
|
/// * `value` - The text to input. TODO &str -> String
|
||||||
pub fn input_string(value: &str) {
|
pub fn input_string(&self, value: &str) {
|
||||||
let mut key_event = KeyEvent::new();
|
let mut key_event = KeyEvent::new();
|
||||||
key_event.set_seq(value.to_owned());
|
key_event.set_seq(value.to_owned());
|
||||||
let mut msg_out = Message::new();
|
let mut msg_out = Message::new();
|
||||||
msg_out.set_key_event(key_event);
|
msg_out.set_key_event(key_event);
|
||||||
Self::send_msg_static(msg_out);
|
self.send_msg(msg_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _input_key(
|
fn _input_key(
|
||||||
@@ -425,6 +393,7 @@ impl Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_mouse(
|
pub fn send_mouse(
|
||||||
|
&self,
|
||||||
mask: i32,
|
mask: i32,
|
||||||
x: i32,
|
x: i32,
|
||||||
y: i32,
|
y: i32,
|
||||||
@@ -433,9 +402,7 @@ impl Session {
|
|||||||
shift: bool,
|
shift: bool,
|
||||||
command: bool,
|
command: bool,
|
||||||
) {
|
) {
|
||||||
if let Some(session) = SESSION.read().unwrap().as_ref() {
|
send_mouse(mask, x, y, alt, ctrl, shift, command, self);
|
||||||
send_mouse(mask, x, y, alt, ctrl, shift, command, session);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key_down_or_up(
|
fn key_down_or_up(
|
||||||
@@ -705,11 +672,11 @@ impl Connection {
|
|||||||
if !self.first_frame {
|
if !self.first_frame {
|
||||||
self.first_frame = true;
|
self.first_frame = true;
|
||||||
}
|
}
|
||||||
if let (Ok(true), Some(s)) = (
|
if let Ok(true) = self.video_handler.handle_frame(vf) {
|
||||||
self.video_handler.handle_frame(vf),
|
let stream = self.session.events2ui.read().unwrap();
|
||||||
RGBA_STREAM.read().unwrap().as_ref(),
|
stream.add(EventToUI::Rgba(ZeroCopyBuffer(
|
||||||
) {
|
self.video_handler.rgb.clone(),
|
||||||
s.add(ZeroCopyBuffer(self.video_handler.rgb.clone()));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(message::Union::hash(hash)) => {
|
Some(message::Union::hash(hash)) => {
|
||||||
@@ -1303,7 +1270,7 @@ pub mod connection_manager {
|
|||||||
use scrap::android::call_main_service_set_by_name;
|
use scrap::android::call_main_service_set_by_name;
|
||||||
use serde_derive::Serialize;
|
use serde_derive::Serialize;
|
||||||
|
|
||||||
use super::EVENT_STREAM;
|
use super::GLOBAL_EVENT_STREAM;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
struct Client {
|
struct Client {
|
||||||
@@ -1411,7 +1378,7 @@ pub mod connection_manager {
|
|||||||
assert!(h.get("name").is_none());
|
assert!(h.get("name").is_none());
|
||||||
h.insert("name", name);
|
h.insert("name", name);
|
||||||
|
|
||||||
if let Some(s) = EVENT_STREAM.read().unwrap().as_ref() {
|
if let Some(s) = GLOBAL_EVENT_STREAM.read().unwrap().as_ref() {
|
||||||
s.add(serde_json::ser::to_string(&h).unwrap_or("".to_owned()));
|
s.add(serde_json::ser::to_string(&h).unwrap_or("".to_owned()));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::client::file_trait::FileManager;
|
use crate::client::file_trait::FileManager;
|
||||||
use crate::flutter::connection_manager::{self, get_clients_length, get_clients_state};
|
use crate::flutter::connection_manager::{self, get_clients_length, get_clients_state};
|
||||||
use crate::flutter::{self, make_fd_to_json, Session};
|
use crate::flutter::{self, make_fd_to_json, Session, SESSIONS};
|
||||||
use crate::start_server;
|
use crate::start_server;
|
||||||
use crate::ui_interface;
|
use crate::ui_interface;
|
||||||
use flutter_rust_bridge::{StreamSink, ZeroCopyBuffer};
|
use flutter_rust_bridge::{StreamSink, SyncReturn, ZeroCopyBuffer};
|
||||||
use hbb_common::ResultType;
|
use hbb_common::ResultType;
|
||||||
use hbb_common::{
|
use hbb_common::{
|
||||||
config::{self, Config, LocalConfig, PeerConfig, ONLINE},
|
config::{self, Config, LocalConfig, PeerConfig, ONLINE},
|
||||||
@@ -59,16 +59,254 @@ pub extern "C" fn rustdesk_core_main() -> bool {
|
|||||||
crate::core_main::core_main()
|
crate::core_main::core_main()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_event_stream(s: StreamSink<String>) -> ResultType<()> {
|
pub enum EventToUI {
|
||||||
let _ = flutter::EVENT_STREAM.write().unwrap().insert(s);
|
Event(String),
|
||||||
|
Rgba(ZeroCopyBuffer<Vec<u8>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_global_event_stream(s: StreamSink<String>) -> ResultType<()> {
|
||||||
|
let _ = flutter::GLOBAL_EVENT_STREAM.write().unwrap().insert(s);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_rgba_stream(s: StreamSink<ZeroCopyBuffer<Vec<u8>>>) -> ResultType<()> {
|
pub fn session_connect(
|
||||||
let _ = flutter::RGBA_STREAM.write().unwrap().insert(s);
|
events2ui: StreamSink<EventToUI>,
|
||||||
|
id: String,
|
||||||
|
is_file_transfer: bool,
|
||||||
|
) -> ResultType<()> {
|
||||||
|
Session::start(&id, is_file_transfer, events2ui);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_session_remember(id: String) -> Option<bool> {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
Some(session.get_remember())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO sync
|
||||||
|
pub fn get_session_toggle_option(id: String, arg: String) -> Option<bool> {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
Some(session.get_toggle_option(&arg))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_session_toggle_option_sync(id: String, arg: String) -> SyncReturn<bool> {
|
||||||
|
let res = get_session_toggle_option(id, arg) == Some(true);
|
||||||
|
SyncReturn(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_session_image_quality(id: String) -> Option<String> {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
Some(session.get_image_quality())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_session_option(id: String, arg: String) -> Option<String> {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
Some(session.get_option(&arg))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// void
|
||||||
|
pub fn session_login(id: String, password: String, remember: bool) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.login(&password, remember);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_close(id: String) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_refresh(id: String) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_reconnect(id: String) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.reconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_toggle_option(id: String, value: String) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.toggle_option(&value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_set_image_quality(id: String, value: String) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.set_image_quality(&value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_lock_screen(id: String) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.lock_screen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_ctrl_alt_del(id: String) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.ctrl_alt_del();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_switch_display(id: String, value: i32) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.switch_display(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_input_key(
|
||||||
|
id: String,
|
||||||
|
name: String,
|
||||||
|
down: bool,
|
||||||
|
press: bool,
|
||||||
|
alt: bool,
|
||||||
|
ctrl: bool,
|
||||||
|
shift: bool,
|
||||||
|
command: bool,
|
||||||
|
) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
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) {
|
||||||
|
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) {
|
||||||
|
session.send_chat(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if let Some(_type) = m.get("type") {
|
||||||
|
// mask = match _type.as_str() {
|
||||||
|
// "down" => 1,
|
||||||
|
// "up" => 2,
|
||||||
|
// "wheel" => 3,
|
||||||
|
// _ => 0,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// if let Some(buttons) = m.get("buttons") {
|
||||||
|
// mask |= match buttons.as_str() {
|
||||||
|
// "left" => 1,
|
||||||
|
// "right" => 2,
|
||||||
|
// "wheel" => 4,
|
||||||
|
// _ => 0,
|
||||||
|
// } << 3;
|
||||||
|
// }
|
||||||
|
// TODO
|
||||||
|
pub fn session_send_mouse(
|
||||||
|
id: String,
|
||||||
|
mask: i32,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
alt: bool,
|
||||||
|
ctrl: bool,
|
||||||
|
shift: bool,
|
||||||
|
command: bool,
|
||||||
|
) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.send_mouse(mask, x, y, alt, ctrl, shift, command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_peer_option(id: String, name: String, value: String) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.set_option(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_input_os_password(id: String, value: String) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&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) {
|
||||||
|
session.read_remote_dir(path, include_hidden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_send_files(
|
||||||
|
id: String,
|
||||||
|
act_id: i32,
|
||||||
|
path: String,
|
||||||
|
to: String,
|
||||||
|
file_num: i32,
|
||||||
|
include_hidden: bool,
|
||||||
|
is_remote: bool,
|
||||||
|
) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.send_files(act_id, path, to, file_num, include_hidden, is_remote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_set_confirm_override_file(
|
||||||
|
id: String,
|
||||||
|
act_id: i32,
|
||||||
|
file_num: i32,
|
||||||
|
need_override: bool,
|
||||||
|
remember: bool,
|
||||||
|
is_upload: bool,
|
||||||
|
) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&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) {
|
||||||
|
session.remove_file(act_id, path, file_num, is_remote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_read_dir_recursive(id: String, act_id: i32, path: String, is_remote: bool) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.remove_dir_all(act_id, path, is_remote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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) {
|
||||||
|
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) {
|
||||||
|
session.create_dir(act_id, path, is_remote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// FFI for **get** commands which are idempotent.
|
/// FFI for **get** commands which are idempotent.
|
||||||
/// Return result in c string.
|
/// Return result in c string.
|
||||||
///
|
///
|
||||||
@@ -97,21 +335,16 @@ unsafe extern "C" fn get_by_name(name: *const c_char, arg: *const c_char) -> *co
|
|||||||
res = LocalConfig::get_remote_id();
|
res = LocalConfig::get_remote_id();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"remember" => {
|
// "remember" => {
|
||||||
res = Session::get_remember().to_string();
|
// res = Session::get_remember().to_string();
|
||||||
}
|
// }
|
||||||
"event" => {
|
// "toggle_option" => {
|
||||||
if let Some(e) = Session::pop_event() {
|
// if let Ok(arg) = arg.to_str() {
|
||||||
res = e;
|
// if let Some(v) = Session::get_toggle_option(arg) {
|
||||||
}
|
// res = v.to_string();
|
||||||
}
|
// }
|
||||||
"toggle_option" => {
|
// }
|
||||||
if let Ok(arg) = arg.to_str() {
|
// }
|
||||||
if let Some(v) = Session::get_toggle_option(arg) {
|
|
||||||
res = v.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"test_if_valid_server" => {
|
"test_if_valid_server" => {
|
||||||
if let Ok(arg) = arg.to_str() {
|
if let Ok(arg) = arg.to_str() {
|
||||||
res = hbb_common::socket_client::test_if_valid_server(arg);
|
res = hbb_common::socket_client::test_if_valid_server(arg);
|
||||||
@@ -122,9 +355,9 @@ unsafe extern "C" fn get_by_name(name: *const c_char, arg: *const c_char) -> *co
|
|||||||
res = Config::get_option(arg);
|
res = Config::get_option(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"image_quality" => {
|
// "image_quality" => {
|
||||||
res = Session::get_image_quality();
|
// res = Session::get_image_quality();
|
||||||
}
|
// }
|
||||||
"software_update_url" => {
|
"software_update_url" => {
|
||||||
res = crate::common::SOFTWARE_UPDATE_URL.lock().unwrap().clone()
|
res = crate::common::SOFTWARE_UPDATE_URL.lock().unwrap().clone()
|
||||||
}
|
}
|
||||||
@@ -139,11 +372,11 @@ unsafe extern "C" fn get_by_name(name: *const c_char, arg: *const c_char) -> *co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"peer_option" => {
|
// "peer_option" => {
|
||||||
if let Ok(arg) = arg.to_str() {
|
// if let Ok(arg) = arg.to_str() {
|
||||||
res = Session::get_option(arg);
|
// res = Session::get_option(arg);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"server_id" => {
|
"server_id" => {
|
||||||
res = ui_interface::get_id();
|
res = ui_interface::get_id();
|
||||||
}
|
}
|
||||||
@@ -227,71 +460,78 @@ unsafe extern "C" fn set_by_name(name: *const c_char, value: *const c_char) {
|
|||||||
"info2" => {
|
"info2" => {
|
||||||
*crate::common::MOBILE_INFO2.lock().unwrap() = value.to_owned();
|
*crate::common::MOBILE_INFO2.lock().unwrap() = value.to_owned();
|
||||||
}
|
}
|
||||||
"connect" => {
|
// "connect" => {
|
||||||
Session::start(value, false);
|
// Session::start(value, false);
|
||||||
}
|
// }
|
||||||
"connect_file_transfer" => {
|
// "connect_file_transfer" => {
|
||||||
Session::start(value, true);
|
// Session::start(value, true);
|
||||||
}
|
// }
|
||||||
"login" => {
|
// "login" => {
|
||||||
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
// if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
||||||
if let Some(password) = m.get("password") {
|
// if let Some(password) = m.get("password") {
|
||||||
if let Some(remember) = m.get("remember") {
|
// if let Some(remember) = m.get("remember") {
|
||||||
Session::login(password, remember == "true");
|
// Session::login(password, remember == "true");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"close" => {
|
// "close" => {
|
||||||
Session::close();
|
// Session::close();
|
||||||
}
|
// }
|
||||||
"refresh" => {
|
// "refresh" => {
|
||||||
Session::refresh();
|
// Session::refresh();
|
||||||
}
|
// }
|
||||||
"reconnect" => {
|
// "reconnect" => {
|
||||||
Session::reconnect();
|
// Session::reconnect();
|
||||||
}
|
// }
|
||||||
"toggle_option" => {
|
// "toggle_option" => {
|
||||||
Session::toggle_option(value);
|
// Session::toggle_option(value);
|
||||||
}
|
// }
|
||||||
"image_quality" => {
|
// "image_quality" => {
|
||||||
Session::set_image_quality(value);
|
// Session::set_image_quality(value);
|
||||||
}
|
// }
|
||||||
"lock_screen" => {
|
// "lock_screen" => {
|
||||||
Session::lock_screen();
|
// Session::lock_screen();
|
||||||
}
|
// }
|
||||||
"ctrl_alt_del" => {
|
// "ctrl_alt_del" => {
|
||||||
Session::ctrl_alt_del();
|
// Session::ctrl_alt_del();
|
||||||
}
|
// }
|
||||||
"switch_display" => {
|
// "switch_display" => {
|
||||||
if let Ok(v) = value.parse::<i32>() {
|
// if let Ok(v) = value.parse::<i32>() {
|
||||||
Session::switch_display(v);
|
// Session::switch_display(v);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"remove" => {
|
"remove" => {
|
||||||
PeerConfig::remove(value);
|
PeerConfig::remove(value);
|
||||||
}
|
}
|
||||||
"input_key" => {
|
// "input_key" => {
|
||||||
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
// if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
||||||
let alt = m.get("alt").is_some();
|
// let alt = m.get("alt").is_some();
|
||||||
let ctrl = m.get("ctrl").is_some();
|
// let ctrl = m.get("ctrl").is_some();
|
||||||
let shift = m.get("shift").is_some();
|
// let shift = m.get("shift").is_some();
|
||||||
let command = m.get("command").is_some();
|
// let command = m.get("command").is_some();
|
||||||
let down = m.get("down").is_some();
|
// let down = m.get("down").is_some();
|
||||||
let press = m.get("press").is_some();
|
// let press = m.get("press").is_some();
|
||||||
if let Some(name) = m.get("name") {
|
// if let Some(name) = m.get("name") {
|
||||||
Session::input_key(name, down, press, alt, ctrl, shift, command);
|
// Session::input_key(name, down, press, alt, ctrl, shift, command);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"input_string" => {
|
// "input_string" => {
|
||||||
Session::input_string(value);
|
// Session::input_string(value);
|
||||||
}
|
// }
|
||||||
"chat_client_mode" => {
|
// "chat_client_mode" => {
|
||||||
Session::send_chat(value.to_owned());
|
// Session::send_chat(value.to_owned());
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
// TODO
|
||||||
"send_mouse" => {
|
"send_mouse" => {
|
||||||
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
||||||
|
let id = m.get("id");
|
||||||
|
if id.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let id = id.unwrap();
|
||||||
let alt = m.get("alt").is_some();
|
let alt = m.get("alt").is_some();
|
||||||
let ctrl = m.get("ctrl").is_some();
|
let ctrl = m.get("ctrl").is_some();
|
||||||
let shift = m.get("shift").is_some();
|
let shift = m.get("shift").is_some();
|
||||||
@@ -321,7 +561,9 @@ unsafe extern "C" fn set_by_name(name: *const c_char, value: *const c_char) {
|
|||||||
_ => 0,
|
_ => 0,
|
||||||
} << 3;
|
} << 3;
|
||||||
}
|
}
|
||||||
Session::send_mouse(mask, x, y, alt, ctrl, shift, command);
|
if let Some(session) = SESSIONS.read().unwrap().get(id) {
|
||||||
|
session.send_mouse(mask, x, y, alt, ctrl, shift, command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"option" => {
|
"option" => {
|
||||||
@@ -343,162 +585,163 @@ unsafe extern "C" fn set_by_name(name: *const c_char, value: *const c_char) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"peer_option" => {
|
// "peer_option" => {
|
||||||
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
// if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
||||||
if let Some(name) = m.get("name") {
|
// if let Some(name) = m.get("name") {
|
||||||
if let Some(value) = m.get("value") {
|
// if let Some(value) = m.get("value") {
|
||||||
Session::set_option(name.to_owned(), value.to_owned());
|
// Session::set_option(name.to_owned(), value.to_owned());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"input_os_password" => {
|
// "input_os_password" => {
|
||||||
Session::input_os_password(value.to_owned(), true);
|
// Session::input_os_password(value.to_owned(), true);
|
||||||
}
|
// }
|
||||||
// File Action
|
// // File Action
|
||||||
"read_remote_dir" => {
|
// "read_remote_dir" => {
|
||||||
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
// if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
||||||
if let (Some(path), Some(show_hidden), Some(session)) = (
|
// if let (Some(path), Some(show_hidden), Some(session)) = (
|
||||||
m.get("path"),
|
// m.get("path"),
|
||||||
m.get("show_hidden"),
|
// m.get("show_hidden"),
|
||||||
Session::get().read().unwrap().as_ref(),
|
// Session::get().read().unwrap().as_ref(),
|
||||||
) {
|
// ) {
|
||||||
session.read_remote_dir(path.to_owned(), show_hidden.eq("true"));
|
// session.read_remote_dir(path.to_owned(), show_hidden.eq("true"));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"send_files" => {
|
// "send_files" => {
|
||||||
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
// if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
||||||
if let (
|
// if let (
|
||||||
Some(id),
|
// Some(id),
|
||||||
Some(path),
|
// Some(path),
|
||||||
Some(to),
|
// Some(to),
|
||||||
Some(file_num),
|
// Some(file_num),
|
||||||
Some(show_hidden),
|
// Some(show_hidden),
|
||||||
Some(is_remote),
|
// Some(is_remote),
|
||||||
) = (
|
// ) = (
|
||||||
m.get("id"),
|
// m.get("id"),
|
||||||
m.get("path"),
|
// m.get("path"),
|
||||||
m.get("to"),
|
// m.get("to"),
|
||||||
m.get("file_num"),
|
// m.get("file_num"),
|
||||||
m.get("show_hidden"),
|
// m.get("show_hidden"),
|
||||||
m.get("is_remote"),
|
// m.get("is_remote"),
|
||||||
) {
|
// ) {
|
||||||
Session::send_files(
|
// Session::send_files(
|
||||||
id.parse().unwrap_or(0),
|
// id.parse().unwrap_or(0),
|
||||||
path.to_owned(),
|
// path.to_owned(),
|
||||||
to.to_owned(),
|
// to.to_owned(),
|
||||||
file_num.parse().unwrap_or(0),
|
// file_num.parse().unwrap_or(0),
|
||||||
show_hidden.eq("true"),
|
// show_hidden.eq("true"),
|
||||||
is_remote.eq("true"),
|
// is_remote.eq("true"),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"set_confirm_override_file" => {
|
// "set_confirm_override_file" => {
|
||||||
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
// if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
||||||
if let (
|
// if let (
|
||||||
Some(id),
|
// Some(id),
|
||||||
Some(file_num),
|
// Some(file_num),
|
||||||
Some(need_override),
|
// Some(need_override),
|
||||||
Some(remember),
|
// Some(remember),
|
||||||
Some(is_upload),
|
// Some(is_upload),
|
||||||
) = (
|
// ) = (
|
||||||
m.get("id"),
|
// m.get("id"),
|
||||||
m.get("file_num"),
|
// m.get("file_num"),
|
||||||
m.get("need_override"),
|
// m.get("need_override"),
|
||||||
m.get("remember"),
|
// m.get("remember"),
|
||||||
m.get("is_upload"),
|
// m.get("is_upload"),
|
||||||
) {
|
// ) {
|
||||||
Session::set_confirm_override_file(
|
// Session::set_confirm_override_file(
|
||||||
id.parse().unwrap_or(0),
|
// id.parse().unwrap_or(0),
|
||||||
file_num.parse().unwrap_or(0),
|
// file_num.parse().unwrap_or(0),
|
||||||
need_override.eq("true"),
|
// need_override.eq("true"),
|
||||||
remember.eq("true"),
|
// remember.eq("true"),
|
||||||
is_upload.eq("true"),
|
// is_upload.eq("true"),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"remove_file" => {
|
// ** TODO ** continue
|
||||||
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
// "remove_file" => {
|
||||||
if let (
|
// if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
||||||
Some(id),
|
// if let (
|
||||||
Some(path),
|
// Some(id),
|
||||||
Some(file_num),
|
// Some(path),
|
||||||
Some(is_remote),
|
// Some(file_num),
|
||||||
Some(session),
|
// Some(is_remote),
|
||||||
) = (
|
// Some(session),
|
||||||
m.get("id"),
|
// ) = (
|
||||||
m.get("path"),
|
// m.get("id"),
|
||||||
m.get("file_num"),
|
// m.get("path"),
|
||||||
m.get("is_remote"),
|
// m.get("file_num"),
|
||||||
Session::get().write().unwrap().as_mut(),
|
// m.get("is_remote"),
|
||||||
) {
|
// Session::get().write().unwrap().as_mut(),
|
||||||
session.remove_file(
|
// ) {
|
||||||
id.parse().unwrap_or(0),
|
// session.remove_file(
|
||||||
path.to_owned(),
|
// id.parse().unwrap_or(0),
|
||||||
file_num.parse().unwrap_or(0),
|
// path.to_owned(),
|
||||||
is_remote.eq("true"),
|
// file_num.parse().unwrap_or(0),
|
||||||
);
|
// is_remote.eq("true"),
|
||||||
}
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"read_dir_recursive" => {
|
// }
|
||||||
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
// "read_dir_recursive" => {
|
||||||
if let (Some(id), Some(path), Some(is_remote), Some(session)) = (
|
// if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
||||||
m.get("id"),
|
// if let (Some(id), Some(path), Some(is_remote), Some(session)) = (
|
||||||
m.get("path"),
|
// m.get("id"),
|
||||||
m.get("is_remote"),
|
// m.get("path"),
|
||||||
Session::get().write().unwrap().as_mut(),
|
// m.get("is_remote"),
|
||||||
) {
|
// Session::get().write().unwrap().as_mut(),
|
||||||
session.remove_dir_all(
|
// ) {
|
||||||
id.parse().unwrap_or(0),
|
// session.remove_dir_all(
|
||||||
path.to_owned(),
|
// id.parse().unwrap_or(0),
|
||||||
is_remote.eq("true"),
|
// path.to_owned(),
|
||||||
);
|
// is_remote.eq("true"),
|
||||||
}
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"remove_all_empty_dirs" => {
|
// }
|
||||||
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
// "remove_all_empty_dirs" => {
|
||||||
if let (Some(id), Some(path), Some(is_remote), Some(session)) = (
|
// if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
||||||
m.get("id"),
|
// if let (Some(id), Some(path), Some(is_remote), Some(session)) = (
|
||||||
m.get("path"),
|
// m.get("id"),
|
||||||
m.get("is_remote"),
|
// m.get("path"),
|
||||||
Session::get().write().unwrap().as_mut(),
|
// m.get("is_remote"),
|
||||||
) {
|
// Session::get().write().unwrap().as_mut(),
|
||||||
session.remove_dir(
|
// ) {
|
||||||
id.parse().unwrap_or(0),
|
// session.remove_dir(
|
||||||
path.to_owned(),
|
// id.parse().unwrap_or(0),
|
||||||
is_remote.eq("true"),
|
// path.to_owned(),
|
||||||
);
|
// is_remote.eq("true"),
|
||||||
}
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"cancel_job" => {
|
// }
|
||||||
if let (Ok(id), Some(session)) =
|
// "cancel_job" => {
|
||||||
(value.parse(), Session::get().write().unwrap().as_mut())
|
// if let (Ok(id), Some(session)) =
|
||||||
{
|
// (value.parse(), Session::get().write().unwrap().as_mut())
|
||||||
session.cancel_job(id);
|
// {
|
||||||
}
|
// session.cancel_job(id);
|
||||||
}
|
// }
|
||||||
"create_dir" => {
|
// }
|
||||||
if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
// "create_dir" => {
|
||||||
if let (Some(id), Some(path), Some(is_remote), Some(session)) = (
|
// if let Ok(m) = serde_json::from_str::<HashMap<String, String>>(value) {
|
||||||
m.get("id"),
|
// if let (Some(id), Some(path), Some(is_remote), Some(session)) = (
|
||||||
m.get("path"),
|
// m.get("id"),
|
||||||
m.get("is_remote"),
|
// m.get("path"),
|
||||||
Session::get().write().unwrap().as_mut(),
|
// m.get("is_remote"),
|
||||||
) {
|
// Session::get().write().unwrap().as_mut(),
|
||||||
session.create_dir(
|
// ) {
|
||||||
id.parse().unwrap_or(0),
|
// session.create_dir(
|
||||||
path.to_owned(),
|
// id.parse().unwrap_or(0),
|
||||||
is_remote.eq("true"),
|
// path.to_owned(),
|
||||||
);
|
// is_remote.eq("true"),
|
||||||
}
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
// Server Side
|
// Server Side
|
||||||
"update_password" => {
|
"update_password" => {
|
||||||
if value.is_empty() {
|
if value.is_empty() {
|
||||||
|
|||||||
Reference in New Issue
Block a user