From e420178750574de079ee604e1e5ff9f46dad1cfe Mon Sep 17 00:00:00 2001 From: csf Date: Mon, 8 Aug 2022 22:27:27 +0800 Subject: [PATCH] refactor all [setByName] [getByName] to async bridge function --- .../lib/desktop/pages/connection_page.dart | 28 +- .../lib/desktop/pages/desktop_home_page.dart | 12 +- flutter/lib/desktop/pages/remote_page.dart | 5 +- .../lib/desktop/widgets/peercard_widget.dart | 2 +- flutter/lib/mobile/pages/connection_page.dart | 35 +- flutter/lib/mobile/pages/remote_page.dart | 7 +- flutter/lib/mobile/pages/server_page.dart | 18 +- flutter/lib/mobile/pages/settings_page.dart | 86 ++-- flutter/lib/mobile/widgets/dialog.dart | 23 +- flutter/lib/models/chat_model.dart | 11 +- flutter/lib/models/file_model.dart | 2 +- flutter/lib/models/model.dart | 30 +- flutter/lib/models/native_model.dart | 39 +- flutter/lib/models/server_model.dart | 79 ++-- src/client.rs | 2 +- src/common.rs | 6 +- src/flutter_ffi.rs | 413 ++++++------------ src/server/connection.rs | 4 +- 18 files changed, 332 insertions(+), 470 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index d992c6c62..d1080dbd3 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -825,10 +825,34 @@ class WebMenu extends StatefulWidget { } class _WebMenuState extends State { + String? username; + String url = ""; + + @override + void initState() { + super.initState(); + () async { + final usernameRes = await getUsername(); + final urlRes = await getUrl(); + var update = false; + if (usernameRes != username) { + username = usernameRes; + update = true; + } + if (urlRes != url) { + url = urlRes; + update = true; + } + + if (update) { + setState(() {}); + } + }(); + } + @override Widget build(BuildContext context) { Provider.of(context); - final username = getUsername(); return PopupMenuButton( icon: Icon(Icons.more_vert), itemBuilder: (context) { @@ -846,7 +870,7 @@ class _WebMenuState extends State { value: "server", ) ] + - (getUrl().contains('admin.rustdesk.com') + (url.contains('admin.rustdesk.com') ? >[] : [ PopupMenuItem( diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 3f908c3ce..f02e0fdfd 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -275,9 +275,7 @@ class _DesktopHomePageState extends State with TrayListener { ), IconButton( icon: Icon(Icons.refresh), - onPressed: () { - gFFI.setByName("temporary_password"); - }, + onPressed: () => bind.mainUpdateTemporaryPassword(), ), FutureBuilder( future: buildPasswordPopupMenu(context), @@ -360,7 +358,7 @@ class _DesktopHomePageState extends State with TrayListener { if (gFFI.serverModel.temporaryPasswordLength != e) { gFFI.serverModel.temporaryPasswordLength = e; - gFFI.setByName("temporary_password"); + bind.mainUpdateTemporaryPassword(); } }, )) @@ -1336,8 +1334,8 @@ Future loginDialog() async { return completer.future; } -void setPasswordDialog() { - final pw = gFFI.getByName("permanent_password"); +void setPasswordDialog() async { + final pw = await bind.mainGetPermanentPassword(); final p0 = TextEditingController(text: pw); final p1 = TextEditingController(text: pw); var errMsg0 = ""; @@ -1427,7 +1425,7 @@ void setPasswordDialog() { }); return; } - gFFI.setByName("permanent_password", pass); + bind.mainSetPermanentPassword(password: pass); close(); }, child: Text(translate("OK"))), diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index bfc193a89..a945e3ae3 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -348,8 +348,9 @@ class _RemotePageState extends State if (dy > 0) dy = -1; else if (dy < 0) dy = 1; - _ffi.setByName('send_mouse', - '{"id": "${widget.id}", "type": "wheel", "x": "$dx", "y": "$dy"}'); + bind.sessionSendMouse( + id: widget.id, + msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}'); } }, child: MouseRegion( diff --git a/flutter/lib/desktop/widgets/peercard_widget.dart b/flutter/lib/desktop/widgets/peercard_widget.dart index 949c46234..f4743a7b5 100644 --- a/flutter/lib/desktop/widgets/peercard_widget.dart +++ b/flutter/lib/desktop/widgets/peercard_widget.dart @@ -187,7 +187,7 @@ class _PeerCardState extends State<_PeerCard> elevation: 8, ); if (value == 'remove') { - setState(() => gFFI.setByName('remove', '$id')); + setState(() => bind.mainRemovePeer(id: id)); () async { removePreference(id); }(); diff --git a/flutter/lib/mobile/pages/connection_page.dart b/flutter/lib/mobile/pages/connection_page.dart index 69e7b9433..227bfb630 100644 --- a/flutter/lib/mobile/pages/connection_page.dart +++ b/flutter/lib/mobile/pages/connection_page.dart @@ -54,8 +54,9 @@ class _ConnectionPageState extends State { }(); } if (isAndroid) { - Timer(Duration(seconds: 5), () { - _updateUrl = gFFI.getByName('software_update_url'); + Timer(Duration(seconds: 5), () async { + _updateUrl = await bind.mainGetSoftwareUpdateUrl(); + ; if (_updateUrl.isNotEmpty) setState(() {}); }); } @@ -299,7 +300,7 @@ class _ConnectionPageState extends State { elevation: 8, ); if (value == 'remove') { - setState(() => gFFI.setByName('remove', '$id')); + setState(() => bind.mainRemovePeer(id: id)); () async { removePreference(id); }(); @@ -315,10 +316,34 @@ class WebMenu extends StatefulWidget { } class _WebMenuState extends State { + String? username; + String url = ""; + + @override + void initState() { + super.initState(); + () async { + final usernameRes = await getUsername(); + final urlRes = await getUrl(); + var update = false; + if (usernameRes != username) { + username = usernameRes; + update = true; + } + if (urlRes != url) { + url = urlRes; + update = true; + } + + if (update) { + setState(() {}); + } + }(); + } + @override Widget build(BuildContext context) { Provider.of(context); - final username = getUsername(); return PopupMenuButton( icon: Icon(Icons.more_vert), itemBuilder: (context) { @@ -336,7 +361,7 @@ class _WebMenuState extends State { value: "server", ) ] + - (getUrl().contains('admin.rustdesk.com') + (url.contains('admin.rustdesk.com') ? >[] : [ PopupMenuItem( diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 6ea4ca2e6..9b938a1ce 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -330,8 +330,9 @@ class _RemotePageState extends State { if (dy > 0) dy = -1; else if (dy < 0) dy = 1; - gFFI.setByName( - 'send_mouse', '{"type": "wheel", "x": "$dx", "y": "$dy"}'); + bind.sessionSendMouse( + id: widget.id, + msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}'); } }, child: MouseRegion( @@ -1124,7 +1125,7 @@ void showRestartRemoteDevice(PeerInfo pi, String id) async { onPressed: () => close(true), child: Text(translate("OK"))), ], )); - if (res == true) gFFI.setByName('restart_remote_device'); + if (res == true) bind.sessionRestartRemoteDevice(id: id); } void showSetOSPassword(String id, bool login) async { diff --git a/flutter/lib/mobile/pages/server_page.dart b/flutter/lib/mobile/pages/server_page.dart index 19753bcac..3abcd70da 100644 --- a/flutter/lib/mobile/pages/server_page.dart +++ b/flutter/lib/mobile/pages/server_page.dart @@ -1,13 +1,10 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:flutter_hbb/mobile/widgets/dialog.dart'; -import 'package:flutter_hbb/models/model.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:provider/provider.dart'; import '../../common.dart'; -import '../../models/model.dart'; +import '../../models/platform_model.dart'; import '../../models/server_model.dart'; import 'home_page.dart'; @@ -99,10 +96,7 @@ class ServerPage extends StatelessWidget implements PageShape { } else if (value == kUsePermanentPassword || value == kUseTemporaryPassword || value == kUseBothPasswords) { - Map msg = Map() - ..["name"] = "verification-method" - ..["value"] = value; - gFFI.setByName('option', jsonEncode(msg)); + bind.mainSetOption(key: "verification-method", value: value); gFFI.serverModel.updatePasswordModel(); } }) @@ -183,9 +177,8 @@ class ServerInfo extends StatelessWidget { ? null : IconButton( icon: const Icon(Icons.refresh), - onPressed: () { - gFFI.setByName("temporary_password"); - })), + onPressed: () => + bind.mainUpdateTemporaryPassword())), onSaved: (String? value) {}, ), ], @@ -406,8 +399,7 @@ class ConnectionManager extends StatelessWidget { MaterialStateProperty.all(Colors.red)), icon: Icon(Icons.close), onPressed: () { - gFFI.setByName( - "close_conn", entry.key.toString()); + bind.serverCloseConnection(connId: entry.key); gFFI.invokeMethod( "cancel_notification", entry.key); }, diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index 3646b59e9..4b8760413 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -31,15 +31,38 @@ class SettingsPage extends StatefulWidget implements PageShape { const url = 'https://rustdesk.com/'; final _hasIgnoreBattery = androidVersion >= 26; var _ignoreBatteryOpt = false; +var _enableAbr = false; class _SettingsState extends State with WidgetsBindingObserver { + String? username; + @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); - if (_hasIgnoreBattery) { - updateIgnoreBatteryStatus(); - } + + () async { + var update = false; + if (_hasIgnoreBattery) { + update = await updateIgnoreBatteryStatus(); + } + + final usernameRes = await getUsername(); + if (usernameRes != username) { + update = true; + username = usernameRes; + } + + final enableAbrRes = await bind.mainGetOption(key: "enable-abr") != "N"; + if (enableAbrRes != _enableAbr) { + update = true; + _enableAbr = enableAbrRes; + } + + if (update) { + setState(() {}); + } + }(); } @override @@ -51,16 +74,18 @@ class _SettingsState extends State with WidgetsBindingObserver { @override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { - updateIgnoreBatteryStatus(); + () async { + if (await updateIgnoreBatteryStatus()) { + setState(() {}); + } + }(); } } Future updateIgnoreBatteryStatus() async { final res = await PermissionManager.check("ignore_battery_optimizations"); if (_ignoreBatteryOpt != res) { - setState(() { - _ignoreBatteryOpt = res; - }); + _ignoreBatteryOpt = res; return true; } else { return false; @@ -70,21 +95,15 @@ class _SettingsState extends State with WidgetsBindingObserver { @override Widget build(BuildContext context) { Provider.of(context); - final username = getUsername(); - final enableAbr = gFFI.getByName("option", "enable-abr") != 'N'; final enhancementsTiles = [ SettingsTile.switchTile( - title: Text(translate('Adaptive Bitrate') + '(beta)'), - initialValue: enableAbr, + title: Text(translate('Adaptive Bitrate') + ' (beta)'), + initialValue: _enableAbr, onToggle: (v) { - final msg = Map() - ..["name"] = "enable-abr" - ..["value"] = ""; - if (!v) { - msg["value"] = "N"; - } - gFFI.setByName("option", json.encode(msg)); - setState(() {}); + bind.mainSetOption(key: "enable-abr", value: v ? "" : "N"); + setState(() { + _enableAbr = !_enableAbr; + }); }, ) ]; @@ -196,7 +215,7 @@ void showServerSettings() async { void showLanguageSettings() async { try { - final langs = json.decode(gFFI.getByName('langs')) as List; + final langs = json.decode(await bind.mainGetLangs()) as List; var lang = await bind.mainGetLocalOption(key: "lang"); DialogManager.show((setState, close) { final setLang = (v) { @@ -297,20 +316,19 @@ String parseResp(String body) { } final token = data['access_token']; if (token != null) { - gFFI.setByName('option', '{"name": "access_token", "value": "$token"}'); + bind.mainSetOption(key: "access_token", value: token); } final info = data['user']; if (info != null) { final value = json.encode(info); - gFFI.setByName( - 'option', json.encode({"name": "user_info", "value": value})); + bind.mainSetOption(key: "user_info", value: value); gFFI.ffiModel.updateUser(); } return ''; } void refreshCurrentUser() async { - final token = gFFI.getByName("option", "access_token"); + final token = await bind.mainGetOption(key: "access_token"); if (token == '') return; final url = getUrl(); final body = {'id': bind.mainGetMyId(), 'uuid': bind.mainGetUuid()}; @@ -333,7 +351,7 @@ void refreshCurrentUser() async { } void logout() async { - final token = gFFI.getByName("option", "access_token"); + final token = await bind.mainGetOption(key: "access_token"); if (token == '') return; final url = getUrl(); final body = {'id': bind.mainGetMyId(), 'uuid': bind.mainGetUuid()}; @@ -350,16 +368,16 @@ void logout() async { resetToken(); } -void resetToken() { - gFFI.setByName('option', '{"name": "access_token", "value": ""}'); - gFFI.setByName('option', '{"name": "user_info", "value": ""}'); +void resetToken() async { + await bind.mainSetOption(key: "access_token", value: ""); + await bind.mainSetOption(key: "user_info", value: ""); gFFI.ffiModel.updateUser(); } -String getUrl() { - var url = gFFI.getByName('option', 'api-server'); +Future getUrl() async { + var url = await bind.mainGetOption(key: "api-server"); if (url == '') { - url = gFFI.getByName('option', 'custom-rendezvous-server'); + url = await bind.mainGetOption(key: "custom-rendezvous-server"); if (url != '') { if (url.contains(':')) { final tmp = url.split(':'); @@ -448,11 +466,11 @@ void showLogin() { }); } -String? getUsername() { - final token = gFFI.getByName("option", "access_token"); +Future getUsername() async { + final token = await bind.mainGetOption(key: "access_token"); String? username; if (token != "") { - final info = gFFI.getByName("option", "user_info"); + final info = await bind.mainGetOption(key: "user_info"); if (info != "") { try { Map tmp = json.decode(info); diff --git a/flutter/lib/mobile/widgets/dialog.dart b/flutter/lib/mobile/widgets/dialog.dart index 3ab0489a9..ddd6816fb 100644 --- a/flutter/lib/mobile/widgets/dialog.dart +++ b/flutter/lib/mobile/widgets/dialog.dart @@ -1,11 +1,9 @@ import 'dart:async'; -import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import '../../common.dart'; -import '../../models/model.dart'; +import '../../models/platform_model.dart'; void clientClose() { msgBox('', 'Close', 'Are you sure to close the connection?'); @@ -22,8 +20,8 @@ void showError({Duration duration = SEC1}) { showToast(translate("Error"), duration: SEC1); } -void setPermanentPasswordDialog() { - final pw = gFFI.getByName("permanent_password"); +void setPermanentPasswordDialog() async { + final pw = await bind.mainGetPermanentPassword(); final p0 = TextEditingController(text: pw); final p1 = TextEditingController(text: pw); var validateLength = false; @@ -103,9 +101,9 @@ void setPermanentPasswordDialog() { }); } -void setTemporaryPasswordLengthDialog() { +void setTemporaryPasswordLengthDialog() async { List lengths = ['6', '8', '10']; - String length = gFFI.getByName('option', 'temporary-password-length'); + String length = await bind.mainGetOption(key: "temporary-password-length"); var index = lengths.indexOf(length); if (index < 0) index = 0; length = lengths[index]; @@ -116,11 +114,8 @@ void setTemporaryPasswordLengthDialog() { setState(() { length = newValue; }); - Map msg = Map() - ..["name"] = "temporary-password-length" - ..["value"] = newValue; - gFFI.setByName("option", jsonEncode(msg)); - gFFI.setByName("temporary_password"); + bind.mainSetOption(key: "temporary-password-length", value: newValue); + bind.mainUpdateTemporaryPassword(); Future.delayed(Duration(milliseconds: 200), () { close(); showSuccess(); @@ -138,9 +133,9 @@ void setTemporaryPasswordLengthDialog() { }, backDismiss: true, clickMaskDismiss: true); } -void enterPasswordDialog(String id) { +void enterPasswordDialog(String id) async { final controller = TextEditingController(); - var remember = gFFI.getByName('remember', id) == 'true'; + var remember = await bind.getSessionRemember(id: id) ?? false; DialogManager.show((setState, close) { return CustomAlertDialog( title: Text(translate('Password Required')), diff --git a/flutter/lib/models/chat_model.dart b/flutter/lib/models/chat_model.dart index 28ffa65e2..52f00aa01 100644 --- a/flutter/lib/models/chat_model.dart +++ b/flutter/lib/models/chat_model.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:dash_chat_2/dash_chat_2.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/models/platform_model.dart'; @@ -106,12 +104,11 @@ class ChatModel with ChangeNotifier { if (message.text.isNotEmpty) { _messages[_currentID]?.insert(message); if (_currentID == clientModeID) { - _ffi.target?.setByName("chat_client_mode", message.text); + if (_ffi.target != null) { + bind.sessionSendChat(id: _ffi.target!.id, text: message.text); + } } else { - final msg = Map() - ..["id"] = _currentID - ..["text"] = message.text; - _ffi.target?.setByName("chat_server_mode", jsonEncode(msg)); + bind.serverSendChat(connId: _currentID, msg: message.text); } } notifyListeners(); diff --git a/flutter/lib/models/file_model.dart b/flutter/lib/models/file_model.dart index 45f5ec970..75f3f8045 100644 --- a/flutter/lib/models/file_model.dart +++ b/flutter/lib/models/file_model.dart @@ -290,7 +290,7 @@ class FileModel extends ChangeNotifier { } onReady() async { - _localOption.home = _ffi.target?.getByName("get_home_dir") ?? ""; + _localOption.home = await bind.mainGetHomeDir(); _localOption.showHidden = (await bind.sessionGetPeerOption( id: _ffi.target?.id ?? "", name: "local_show_hidden")) .isNotEmpty; diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 7ca77f6cd..c7295f57e 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -889,8 +889,10 @@ class FFI { /// Send scroll event with scroll distance [y]. void scroll(int y) { - setByName('send_mouse', - json.encode(modify({'id': id, 'type': 'wheel', 'y': y.toString()}))); + bind.sessionSendMouse( + id: id, + msg: json + .encode(modify({'id': id, 'type': 'wheel', 'y': y.toString()}))); } /// Reconnect to the remote peer. @@ -916,8 +918,9 @@ class FFI { /// Send mouse press event. void sendMouse(String type, MouseButtons button) { if (!ffiModel.keyboard()) return; - setByName('send_mouse', - json.encode(modify({'id': id, 'type': type, 'buttons': button.value}))); + bind.sessionSendMouse( + id: id, + msg: json.encode(modify({'type': type, 'buttons': button.value}))); } /// Send key stroke event. @@ -953,8 +956,8 @@ class FFI { if (!ffiModel.keyboard()) return; var x2 = x.toInt(); var y2 = y.toInt(); - setByName( - 'send_mouse', json.encode(modify({'id': id, 'x': '$x2', 'y': '$y2'}))); + bind.sessionSendMouse( + id: id, msg: json.encode(modify({'x': '$x2', 'y': '$y2'}))); } /// List the saved peers. @@ -1032,14 +1035,14 @@ class FFI { /// Send **get** command to the Rust core based on [name] and [arg]. /// Return the result as a string. - String getByName(String name, [String arg = '']) { - return platformFFI.getByName(name, arg); - } + // String getByName(String name, [String arg = '']) { + // return platformFFI.getByName(name, arg); + // } /// Send **set** command to the Rust core based on [name] and [value]. - void setByName(String name, [String value = '']) { - platformFFI.setByName(name, value); - } + // void setByName(String name, [String value = '']) { + // platformFFI.setByName(name, value); + // } handleMouse(Map evt, {double tabBarHeight = 0.0}) { var type = ''; @@ -1092,8 +1095,7 @@ class FFI { break; } evt['buttons'] = buttons; - evt['id'] = id; - setByName('send_mouse', json.encode(evt)); + bind.sessionSendMouse(id: id, msg: json.encode(evt)); } listenToMouse(bool yesOrNo) { diff --git a/flutter/lib/models/native_model.dart b/flutter/lib/models/native_model.dart index c58577945..a55ed1d29 100644 --- a/flutter/lib/models/native_model.dart +++ b/flutter/lib/models/native_model.dart @@ -30,8 +30,6 @@ class PlatformFFI { String _dir = ''; String _homeDir = ''; F2? _translate; - F2? _getByName; - F3? _setByName; var _eventHandlers = Map>(); late RustdeskImpl _ffiBind; late String _appType; @@ -89,31 +87,6 @@ class PlatformFFI { return res; } - /// Send **get** command to the Rust core based on [name] and [arg]. - /// Return the result as a string. - String getByName(String name, [String arg = '']) { - if (_getByName == null) return ''; - var a = name.toNativeUtf8(); - var b = arg.toNativeUtf8(); - var p = _getByName!(a, b); - assert(p != nullptr); - var res = p.toDartString(); - calloc.free(p); - calloc.free(a); - calloc.free(b); - return res; - } - - /// Send **set** command to the Rust core based on [name] and [value]. - void setByName(String name, [String value = '']) { - if (_setByName == null) return; - var a = name.toNativeUtf8(); - var b = value.toNativeUtf8(); - _setByName!(a, b); - calloc.free(a); - calloc.free(b); - } - /// Init the FFI class, loads the native Rust core library. Future init(String appType) async { _appType = appType; @@ -133,10 +106,6 @@ class PlatformFFI { debugPrint('initializing FFI ${_appType}'); try { _translate = dylib.lookupFunction('translate'); - _getByName = dylib.lookupFunction('get_by_name'); - _setByName = - dylib.lookupFunction, Pointer), F3>( - 'set_by_name'); _dir = (await getApplicationDocumentsDirectory()).path; _ffiBind = RustdeskImpl(dylib); _startListenEvent(_ffiBind); // global event @@ -177,10 +146,10 @@ class PlatformFFI { } print( "_appType:$_appType,info1-id:$id,info2-name:$name,dir:$_dir,homeDir:$_homeDir"); - setByName('info1', id); - setByName('info2', name); - setByName('home_dir', _homeDir); - setByName('init', _dir); + await _ffiBind.mainDeviceId(id: id); + await _ffiBind.mainDeviceName(name: name); + await _ffiBind.mainSetHomeDir(home: _homeDir); + await _ffiBind.mainInit(appDir: _dir); } catch (e) { print(e); } diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index 362e47a78..6aa7016b2 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -99,42 +99,29 @@ class ServerModel with ChangeNotifier { // audio if (androidVersion < 30 || !await PermissionManager.check("audio")) { _audioOk = false; - parent.target?.setByName( - 'option', - jsonEncode(Map() - ..["name"] = "enable-audio" - ..["value"] = "N")); + bind.mainSetOption(key: "enable-audio", value: "N"); } else { - final audioOption = parent.target?.getByName('option', 'enable-audio'); - _audioOk = audioOption?.isEmpty ?? false; + final audioOption = await bind.mainGetOption(key: 'enable-audio'); + _audioOk = audioOption.isEmpty; } // file if (!await PermissionManager.check("file")) { _fileOk = false; - parent.target?.setByName( - 'option', - jsonEncode(Map() - ..["name"] = "enable-file-transfer" - ..["value"] = "N")); + bind.mainSetOption(key: "enable-file-transfer", value: "N"); } else { final fileOption = - parent.target?.getByName('option', 'enable-file-transfer'); - _fileOk = fileOption?.isEmpty ?? false; + await bind.mainGetOption(key: 'enable-file-transfer'); + _fileOk = fileOption.isEmpty; } - // input (mouse control) - Map res = Map() - ..["name"] = "enable-keyboard" - ..["value"] = 'N'; - parent.target - ?.setByName('option', jsonEncode(res)); // input false by default + // input (mouse control) false by default + bind.mainSetOption(key: "enable-keyboard", value: "N"); notifyListeners(); }(); - Timer.periodic(Duration(seconds: 1), (timer) { - var status = - int.tryParse(parent.target?.getByName('connect_statue') ?? "") ?? 0; + Timer.periodic(Duration(seconds: 1), (timer) async { + var status = await bind.mainGetOnlineStatue(); if (status > 0) { status = 1; } @@ -142,10 +129,8 @@ class ServerModel with ChangeNotifier { _connectStatus = status; notifyListeners(); } - final res = parent.target - ?.getByName('check_clients_length', _clients.length.toString()) ?? - ""; - if (res.isNotEmpty) { + final res = await bind.mainCheckClientsLength(length: _clients.length); + if (res != null) { debugPrint("clients not match!"); updateClientState(res); } @@ -156,7 +141,7 @@ class ServerModel with ChangeNotifier { updatePasswordModel() async { var update = false; - final temporaryPassword = gFFI.getByName("temporary_password"); + final temporaryPassword = await bind.mainGetTemporaryPassword(); final verificationMethod = await bind.mainGetOption(key: "verification-method"); final temporaryPasswordLength = @@ -194,10 +179,7 @@ class ServerModel with ChangeNotifier { } _audioOk = !_audioOk; - Map res = Map() - ..["name"] = "enable-audio" - ..["value"] = _audioOk ? '' : 'N'; - parent.target?.setByName('option', jsonEncode(res)); + bind.mainSetOption(key: "enable-audio", value: _audioOk ? '' : 'N'); notifyListeners(); } @@ -211,10 +193,7 @@ class ServerModel with ChangeNotifier { } _fileOk = !_fileOk; - Map res = Map() - ..["name"] = "enable-file-transfer" - ..["value"] = _fileOk ? '' : 'N'; - parent.target?.setByName('option', jsonEncode(res)); + bind.mainSetOption(key: "enable-file-transfer", value: _fileOk ? '' : 'N'); notifyListeners(); } @@ -284,7 +263,7 @@ class ServerModel with ChangeNotifier { // TODO parent.target?.ffiModel.updateEventListener(""); await parent.target?.invokeMethod("init_service"); - parent.target?.setByName("start_service"); + await bind.mainStartService(); _fetchID(); updateClientState(); if (!Platform.isLinux) { @@ -299,7 +278,7 @@ class ServerModel with ChangeNotifier { // TODO parent.target?.serverModel.closeAll(); await parent.target?.invokeMethod("stop_service"); - parent.target?.setByName("stop_service"); + await bind.mainStopService(); notifyListeners(); if (!Platform.isLinux) { // current linux is not supported @@ -312,9 +291,9 @@ class ServerModel with ChangeNotifier { } Future setPermanentPassword(String newPW) async { - parent.target?.setByName("permanent_password", newPW); + await bind.mainSetPermanentPassword(password: newPW); await Future.delayed(Duration(milliseconds: 500)); - final pw = parent.target?.getByName("permanent_password"); + final pw = await bind.mainGetPermanentPassword(); if (newPW == pw) { return true; } else { @@ -355,10 +334,7 @@ class ServerModel with ChangeNotifier { break; case "input": if (_inputOk != value) { - Map res = Map() - ..["name"] = "enable-keyboard" - ..["value"] = value ? '' : 'N'; - parent.target?.setByName('option', jsonEncode(res)); + bind.mainSetOption(key: "enable-keyboard", value: value ? '' : 'N'); } _inputOk = value; break; @@ -368,8 +344,8 @@ class ServerModel with ChangeNotifier { notifyListeners(); } - updateClientState([String? json]) { - var res = json ?? parent.target?.getByName("clients_state") ?? ""; + updateClientState([String? json]) async { + var res = await bind.mainGetClientsState(); try { final List clientsJson = jsonDecode(res); for (var clientJson in clientsJson) { @@ -451,12 +427,9 @@ class ServerModel with ChangeNotifier { }); } - void sendLoginResponse(Client client, bool res) { - final Map response = Map(); - response["id"] = client.id; - response["res"] = res; + void sendLoginResponse(Client client, bool res) async { if (res) { - parent.target?.setByName("login_res", jsonEncode(response)); + bind.serverLoginRes(connId: client.id, res: res); if (!client.isFileTransfer) { parent.target?.invokeMethod("start_capture"); } @@ -464,7 +437,7 @@ class ServerModel with ChangeNotifier { _clients[client.id]?.authorized = true; notifyListeners(); } else { - parent.target?.setByName("login_res", jsonEncode(response)); + bind.serverLoginRes(connId: client.id, res: res); parent.target?.invokeMethod("cancel_notification", client.id); _clients.remove(client.id); } @@ -496,7 +469,7 @@ class ServerModel with ChangeNotifier { closeAll() { _clients.forEach((id, client) { - parent.target?.setByName("close_conn", id.toString()); + bind.serverCloseConnection(connId: id); }); _clients.clear(); } diff --git a/src/client.rs b/src/client.rs index 7ddfe0969..89d66c6ca 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1280,7 +1280,7 @@ impl LoginConfigHandler { /// Create a [`Message`] for login. fn create_login_msg(&self, password: Vec) -> Message { #[cfg(any(target_os = "android", target_os = "ios"))] - let my_id = Config::get_id_or(crate::common::FLUTTER_INFO1.lock().unwrap().clone()); + let my_id = Config::get_id_or(crate::common::DEVICE_ID.lock().unwrap().clone()); #[cfg(not(any(target_os = "android", target_os = "ios")))] let my_id = Config::get_id(); let mut lr = LoginRequest { diff --git a/src/common.rs b/src/common.rs index 5af811c05..605435956 100644 --- a/src/common.rs +++ b/src/common.rs @@ -28,8 +28,8 @@ lazy_static::lazy_static! { } lazy_static::lazy_static! { - pub static ref FLUTTER_INFO1: Arc> = Default::default(); - pub static ref FLUTTER_INFO2: Arc> = Default::default(); + pub static ref DEVICE_ID: Arc> = Default::default(); + pub static ref DEVICE_NAME: Arc> = Default::default(); } #[inline] @@ -441,7 +441,7 @@ pub fn username() -> String { #[cfg(not(any(target_os = "android", target_os = "ios")))] return whoami::username().trim_end_matches('\0').to_owned(); #[cfg(any(target_os = "android", target_os = "ios"))] - return FLUTTER_INFO2.lock().unwrap().clone(); + return DEVICE_NAME.lock().unwrap().clone(); } #[inline] diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 40f72444a..95cd1abd3 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -26,7 +26,8 @@ use crate::ui_interface::{ get_connect_status, get_fav, get_id, get_lan_peers, get_license, get_local_option, get_option, get_options, get_peer, get_peer_option, get_socks, get_sound_inputs, get_uuid, get_version, has_rendezvous_service, post_request, set_local_option, set_option, set_options, - set_peer_option, set_socks, store_fav, test_if_valid_server, using_public_server, + set_peer_option, set_permanent_password, set_socks, store_fav, test_if_valid_server, + update_temporary_password, using_public_server, }; fn initialize(app_dir: &str) { @@ -235,38 +236,6 @@ pub fn session_send_chat(id: String, text: String) { } } -// 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); @@ -426,11 +395,7 @@ pub fn main_set_option(key: String, value: String) { set_option(key, value); #[cfg(target_os = "android")] crate::rendezvous_mediator::RendezvousMediator::restart(); - #[cfg(any( - target_os = "android", - target_os = "ios", - feature = "cli" - ))] + #[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))] crate::common::test_rendezvous_server(); } else { set_option(key, value); @@ -640,6 +605,143 @@ pub fn main_get_last_remote_id() -> String { LocalConfig::get_remote_id() } +pub fn main_get_software_update_url() -> String { + crate::common::SOFTWARE_UPDATE_URL.lock().unwrap().clone() +} + +pub fn main_get_home_dir() -> String { + fs::get_home_as_string() +} + +pub fn main_get_langs() -> String { + crate::lang::LANGS.to_string() +} + +pub fn main_get_temporary_password() -> String { + ui_interface::temporary_password() +} + +pub fn main_get_permanent_password() -> String { + ui_interface::permanent_password() +} + +pub fn main_get_online_statue() -> i64 { + ONLINE.lock().unwrap().values().max().unwrap_or(&0).clone() +} + +pub fn main_get_clients_state() -> String { + get_clients_state() +} + +pub fn main_check_clients_length(length: usize) -> Option { + if length != get_clients_length() { + Some(get_clients_state()) + } else { + None + } +} + +pub fn main_init(app_dir: String) { + initialize(&app_dir); +} + +pub fn main_device_id(id: String) { + *crate::common::DEVICE_ID.lock().unwrap() = id; +} + +pub fn main_device_name(name: String) { + *crate::common::DEVICE_NAME.lock().unwrap() = name; +} + +pub fn main_remove_peer(id: String) { + PeerConfig::remove(&id); +} + +// TODO +pub fn session_send_mouse(id: String, msg: String) { + if let Ok(m) = serde_json::from_str::>(&msg) { + let alt = m.get("alt").is_some(); + let ctrl = m.get("ctrl").is_some(); + let shift = m.get("shift").is_some(); + let command = m.get("command").is_some(); + let x = m + .get("x") + .map(|x| x.parse::().unwrap_or(0)) + .unwrap_or(0); + let y = m + .get("y") + .map(|x| x.parse::().unwrap_or(0)) + .unwrap_or(0); + let mut mask = 0; + 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; + } + if let Some(session) = SESSIONS.read().unwrap().get(&id) { + session.send_mouse(mask, x, y, alt, ctrl, shift, command); + } + } +} + +pub fn session_restart_remote_device(id: String) { + // TODO + // Session::restart_remote_device(); +} + +pub fn main_set_home_dir(home: String) { + *config::APP_HOME_DIR.write().unwrap() = home; +} + +pub fn main_stop_service() { + #[cfg(target_os = "android")] + { + Config::set_option("stop-service".into(), "Y".into()); + crate::rendezvous_mediator::RendezvousMediator::restart(); + } +} + +pub fn main_start_service() { + #[cfg(target_os = "android")] + { + Config::set_option("stop-service".into(), "".into()); + crate::rendezvous_mediator::RendezvousMediator::restart(); + } + #[cfg(not(target_os = "android"))] + std::thread::spawn(move || start_server(true)); +} + +pub fn main_update_temporary_password() { + update_temporary_password(); +} + +pub fn main_set_permanent_password(password: String) { + set_permanent_password(password); +} + +pub fn server_send_chat(conn_id: i32, msg: String) { + connection_manager::send_chat(conn_id, msg); +} + +pub fn server_login_res(conn_id: i32, res: bool) { + connection_manager::on_login_res(conn_id, res); +} + +pub fn server_close_connection(conn_id: i32) { + connection_manager::close_conn(conn_id); +} + #[no_mangle] unsafe extern "C" fn translate(name: *const c_char, locale: *const c_char) -> *const c_char { let name = CStr::from_ptr(name); @@ -652,241 +754,6 @@ unsafe extern "C" fn translate(name: *const c_char, locale: *const c_char) -> *c CString::from_vec_unchecked(res.into_bytes()).into_raw() } -/// FFI for **get** commands which are idempotent. -/// Return result in c string. -/// -/// # Arguments -/// -/// * `name` - name of the command -/// * `arg` - argument of the command -#[no_mangle] -unsafe extern "C" fn get_by_name(name: *const c_char, arg: *const c_char) -> *const c_char { - let mut res = "".to_owned(); - let arg: &CStr = CStr::from_ptr(arg); - let name: &CStr = CStr::from_ptr(name); - if let Ok(name) = name.to_str() { - match name { - // "peers" => { - // if !config::APP_DIR.read().unwrap().is_empty() { - // let peers: Vec<(String, config::PeerInfoSerde)> = PeerConfig::peers() - // .drain(..) - // .map(|(id, _, p)| (id, p.info)) - // .collect(); - // res = serde_json::ser::to_string(&peers).unwrap_or("".to_owned()); - // } - // } - // "remote_id" => { - // if !config::APP_DIR.read().unwrap().is_empty() { - // res = LocalConfig::get_remote_id(); - // } - // } - // "test_if_valid_server" => { - // if let Ok(arg) = arg.to_str() { - // res = hbb_common::socket_client::test_if_valid_server(arg); - // } - // } - // "option" => { - // if let Ok(arg) = arg.to_str() { - // res = ui_interface::get_option(arg.to_owned()); - // } - // } - "software_update_url" => { - res = crate::common::SOFTWARE_UPDATE_URL.lock().unwrap().clone() - } - // File Action - "get_home_dir" => { - res = fs::get_home_as_string(); - } - // Server Side - "langs" => { - res = crate::lang::LANGS.to_string(); - } - "temporary_password" => { - res = ui_interface::temporary_password(); - } - "permanent_password" => { - res = ui_interface::permanent_password(); - } - "connect_statue" => { - res = ONLINE - .lock() - .unwrap() - .values() - .max() - .unwrap_or(&0) - .clone() - .to_string(); - } - #[cfg(not(any(target_os = "ios")))] - "clients_state" => { - res = get_clients_state(); - } - #[cfg(not(any(target_os = "ios")))] - "check_clients_length" => { - if let Ok(value) = arg.to_str() { - if value.parse::().unwrap_or(usize::MAX) != get_clients_length() { - res = get_clients_state() - } - } - } - _ => { - log::error!("Unknown name of get_by_name: {}", name); - } - } - } - CString::from_vec_unchecked(res.into_bytes()).into_raw() -} - -/// FFI for **set** commands which are not idempotent. -/// -/// # Arguments -/// -/// * `name` - name of the command -/// * `arg` - argument of the command -#[no_mangle] -unsafe extern "C" fn set_by_name(name: *const c_char, value: *const c_char) { - let value: &CStr = CStr::from_ptr(value); - if let Ok(value) = value.to_str() { - let name: &CStr = CStr::from_ptr(name); - if let Ok(name) = name.to_str() { - match name { - "init" => { - initialize(value); - } - "info1" => { - *crate::common::FLUTTER_INFO1.lock().unwrap() = value.to_owned(); - } - "info2" => { - *crate::common::FLUTTER_INFO2.lock().unwrap() = value.to_owned(); - } - "remove" => { - PeerConfig::remove(value); - } - - // TODO - "send_mouse" => { - if let Ok(m) = serde_json::from_str::>(value) { - let id = m.get("id"); - if id.is_none() { - return; - } - let id = id.unwrap(); - let alt = m.get("alt").is_some(); - let ctrl = m.get("ctrl").is_some(); - let shift = m.get("shift").is_some(); - let command = m.get("command").is_some(); - let x = m - .get("x") - .map(|x| x.parse::().unwrap_or(0)) - .unwrap_or(0); - let y = m - .get("y") - .map(|x| x.parse::().unwrap_or(0)) - .unwrap_or(0); - let mut mask = 0; - 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; - } - if let Some(session) = SESSIONS.read().unwrap().get(id) { - session.send_mouse(mask, x, y, alt, ctrl, shift, command); - } - } - } - // "option" => { - // if let Ok(m) = serde_json::from_str::>(value) { - // if let Some(name) = m.get("name") { - // if let Some(value) = m.get("value") { - // ui_interface::set_option(name.to_owned(), value.to_owned()); - // if name == "custom-rendezvous-server" { - // #[cfg(target_os = "android")] - // crate::rendezvous_mediator::RendezvousMediator::restart(); - // #[cfg(any( - // target_os = "android", - // target_os = "ios", - // feature = "cli" - // ))] - // crate::common::test_rendezvous_server(); - // } - // } - // } - // } - // } - "restart_remote_device" => { - // TODO - // Session::restart_remote_device(); - } - #[cfg(target_os = "android")] - "chat_server_mode" => { - if let Ok(m) = serde_json::from_str::>(value) { - if let (Some(Value::Number(id)), Some(Value::String(text))) = - (m.get("id"), m.get("text")) - { - let id = id.as_i64().unwrap_or(0); - connection_manager::send_chat(id as i32, text.to_owned()); - } - } - } - "home_dir" => { - *config::APP_HOME_DIR.write().unwrap() = value.to_owned(); - } - #[cfg(target_os = "android")] - "login_res" => { - if let Ok(m) = serde_json::from_str::>(value) { - if let (Some(Value::Number(id)), Some(Value::Bool(res))) = - (m.get("id"), m.get("res")) - { - let id = id.as_i64().unwrap_or(0); - connection_manager::on_login_res(id as i32, *res); - } - } - } - #[cfg(target_os = "android")] - "stop_service" => { - Config::set_option("stop-service".into(), "Y".into()); - crate::rendezvous_mediator::RendezvousMediator::restart(); - } - "start_service" => { - #[cfg(target_os = "android")] - { - Config::set_option("stop-service".into(), "".into()); - crate::rendezvous_mediator::RendezvousMediator::restart(); - } - #[cfg(not(target_os = "android"))] - std::thread::spawn(move || start_server(true)); - } - #[cfg(target_os = "android")] - "close_conn" => { - if let Ok(id) = value.parse::() { - connection_manager::close_conn(id); - }; - } - "temporary_password" => { - ui_interface::update_temporary_password(); - } - "permanent_password" => { - ui_interface::set_permanent_password(value.to_owned()); - } - _ => { - log::error!("Unknown name of set_by_name: {}", name); - } - } - } - } -} - fn handle_query_onlines(onlines: Vec, offlines: Vec) { if let Some(s) = flutter::GLOBAL_EVENT_STREAM .read() diff --git a/src/server/connection.rs b/src/server/connection.rs index 7d12dce45..346477851 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -5,7 +5,7 @@ use crate::clipboard_file::*; use crate::common::update_clipboard; use crate::video_service; #[cfg(any(target_os = "android", target_os = "ios"))] -use crate::{common::FLUTTER_INFO2, flutter::connection_manager::start_channel}; +use crate::{common::DEVICE_NAME, flutter::connection_manager::start_channel}; use crate::{ipc, VERSION}; use hbb_common::{ config::Config, @@ -643,7 +643,7 @@ impl Connection { } #[cfg(target_os = "android")] { - pi.hostname = FLUTTER_INFO2.lock().unwrap().clone(); + pi.hostname = DEVICE_NAME.lock().unwrap().clone(); pi.platform = "Android".into(); } #[cfg(feature = "hwcodec")]