Merge pull request #674 from Heap-Hop/option_multi_instances

multi instances
This commit is contained in:
RustDesk
2022-06-01 15:13:34 +08:00
committed by GitHub
10 changed files with 908 additions and 602 deletions

2
Cargo.lock generated
View File

@@ -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",

View File

@@ -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();
}, },

View File

@@ -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...'));
}, },

View File

@@ -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));
} }

View File

@@ -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() {}

View File

@@ -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"

View File

@@ -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:

View File

@@ -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)));
} }
} }

View File

@@ -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()));
}; };
} }

View File

@@ -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() {