diff --git a/Cargo.lock b/Cargo.lock index cb08cdad2..9272b562a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -986,27 +986,6 @@ dependencies = [ "serde 1.0.228", ] -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "cacao" version = "0.4.0-beta2" @@ -1477,8 +1456,8 @@ dependencies = [ "compression-core", "flate2", "memchr", - "zstd 0.13.1", - "zstd-safe 7.1.0", + "zstd", + "zstd-safe", ] [[package]] @@ -1549,12 +1528,6 @@ dependencies = [ "unicode-xid 0.2.4", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "constant_time_eq" version = "0.2.6" @@ -3825,7 +3798,7 @@ dependencies = [ "whoami", "winapi 0.3.9", "x11 2.21.0", - "zstd 0.13.1", + "zstd", ] [[package]] @@ -6057,35 +6030,12 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest", - "hmac", - "password-hash", - "sha2", -] - [[package]] name = "peeking_take_while" version = "0.1.2" @@ -7365,7 +7315,6 @@ dependencies = [ "wol-rs", "x11-clipboard 0.8.1", "x11rb 0.12.0", - "zip", ] [[package]] @@ -8907,7 +8856,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c4ae9724c5888c0417d2396037ed3b60665925624766416e3e342b6ba5dbd3f" dependencies = [ "base32", - "constant_time_eq 0.2.6", + "constant_time_eq", "hmac", "rand 0.8.5", "sha1", @@ -11157,52 +11106,13 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq 0.1.5", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2", - "sha1", - "time 0.3.36", - "zstd 0.11.2+zstd.1.5.2", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe 5.0.2+zstd.1.5.2", -] - [[package]] name = "zstd" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" dependencies = [ - "zstd-safe 7.1.0", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", + "zstd-safe", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2fac88c00..588cbd96a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,6 @@ drm = ["scrap/drm"] # kind of operation and deserves a switch that can remove it from the binary entirely, without # giving up DRM capture: `--features drm` builds the capture path with no wake code compiled in. drm-wake = ["drm"] -plugin_framework = [] linux-pkg-config = ["magnum-opus/linux-pkg-config", "scrap/linux-pkg-config"] unix-file-copy-paste = [ "dep:x11-clipboard", @@ -81,7 +80,6 @@ hex = "0.4" chrono = "0.4" cidr-utils = "0.5" fon = "0.6" -zip = "0.6" shutdown_hooks = "0.1" totp-rs = { version = "5.4", default-features = false, features = ["gen_secret", "otpauth"] } stunclient = "0.4" @@ -212,7 +210,7 @@ android-wakelock = { git = "https://github.com/rustdesk-org/android-wakelock" } [workspace] members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/virtual_display/dylib", "libs/portable", "libs/remote_printer"] -exclude = ["vdi/host", "examples/custom_plugin"] +exclude = ["vdi/host"] # Patch libxdo-sys to use a stub implementation that doesn't require libxdo # This allows building and running on systems without libxdo installed (e.g., Wayland-only) diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 42ec10032..76d464198 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -16,7 +16,6 @@ import 'package:flutter_hbb/desktop/widgets/update_progress.dart'; import 'package:flutter_hbb/models/platform_model.dart'; import 'package:flutter_hbb/models/server_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; -import 'package:flutter_hbb/plugin/ui_manager.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:flutter_hbb/utils/platform_channel.dart'; import 'package:get/get.dart'; @@ -111,7 +110,6 @@ class _DesktopHomePageState extends State } }, ), - buildPluginEntry(), ]; if (isIncomingOnly) { children.addAll([ @@ -890,21 +888,6 @@ class _DesktopHomePageState extends State shouldBeBlocked(_block, canBeBlocked); } } - - Widget buildPluginEntry() { - final entries = PluginUiManager.instance.entries.entries; - return Offstage( - offstage: entries.isEmpty, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ...entries.map((entry) { - return entry.value; - }) - ], - ), - ); - } } void setPasswordDialog({VoidCallback? notEmptyCallback}) async { diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index b2aab1cfb..a2eb94e42 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -17,8 +17,6 @@ import 'package:flutter_hbb/models/platform_model.dart'; import 'package:flutter_hbb/models/printer_model.dart'; import 'package:flutter_hbb/models/server_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; -import 'package:flutter_hbb/plugin/manager.dart'; -import 'package:flutter_hbb/plugin/widgets/desktop_settings.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -55,7 +53,6 @@ enum SettingsTabKey { safety, network, display, - plugin, account, printer, about, @@ -74,8 +71,6 @@ class DesktopSettingPage extends StatefulWidget { bind.mainGetBuildinOption(key: kOptionHideNetworkSetting) != 'Y') SettingsTabKey.network, if (!bind.isIncomingOnly()) SettingsTabKey.display, - if (!isWeb && !bind.isIncomingOnly() && bind.pluginFeatureIsEnabled()) - SettingsTabKey.plugin, if (!bind.isDisableAccount()) SettingsTabKey.account, if (isWindows && bind.mainGetBuildinOption(key: kOptionHideRemotePrinterSetting) != 'Y') @@ -171,7 +166,7 @@ class _DesktopSettingPageState extends State void dispose() { super.dispose(); Get.delete(tag: _kSettingPageControllerTag); - Get.delete(tag: _kSettingPageTabKeyTag); + Get.delete>(tag: _kSettingPageTabKeyTag); WidgetsBinding.instance.removeObserver(this); _videoConnTimer?.cancel(); } @@ -196,10 +191,6 @@ class _DesktopSettingPageState extends State settingTabs.add(_TabInfo(tab, 'Display', Icons.desktop_windows_outlined, Icons.desktop_windows)); break; - case SettingsTabKey.plugin: - settingTabs.add(_TabInfo( - tab, 'Plugin', Icons.extension_outlined, Icons.extension)); - break; case SettingsTabKey.account: settingTabs.add( _TabInfo(tab, 'Account', Icons.person_outline, Icons.person)); @@ -233,9 +224,6 @@ class _DesktopSettingPageState extends State case SettingsTabKey.display: children.add(const _Display()); break; - case SettingsTabKey.plugin: - children.add(const _Plugin()); - break; case SettingsTabKey.account: children.add(const _Account()); break; @@ -2255,51 +2243,6 @@ class _CheckboxState extends State<_Checkbox> { } } -class _Plugin extends StatefulWidget { - const _Plugin({Key? key}) : super(key: key); - - @override - State<_Plugin> createState() => _PluginState(); -} - -class _PluginState extends State<_Plugin> { - @override - Widget build(BuildContext context) { - bind.pluginListReload(); - final scrollController = ScrollController(); - return ChangeNotifierProvider.value( - value: pluginManager, - child: Consumer(builder: (context, model, child) { - return ListView( - controller: scrollController, - children: model.plugins.map((entry) => pluginCard(entry)).toList(), - ).marginOnly(bottom: _kListViewBottomMargin); - }), - ); - } - - Widget pluginCard(PluginInfo plugin) { - return ChangeNotifierProvider.value( - value: plugin, - child: Consumer( - builder: (context, model, child) => DesktopSettingsCard(plugin: model), - ), - ); - } - - Widget accountAction() { - return Obx(() => _Button( - gFFI.userModel.userName.value.isEmpty - ? 'Login' - : '${translate('Logout')} (${gFFI.userModel.accountLabelWithHandle})', - () => { - gFFI.userModel.userName.value.isEmpty - ? loginDialog() - : logOutConfirmDialog() - })); - } -} - class _Printer extends StatefulWidget { const _Printer({super.key}); diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index a9185d6a3..79f382249 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -182,7 +182,6 @@ class _RemotePageState extends State WakelockManager.enable(_uniqueKey); _ffi.ffiModel.updateEventListener(sessionId, widget.id); - if (!isWeb) bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote); _ffi.qualityMonitorModel.checkShowQualityMonitor(sessionId); _ffi.dialogManager.loadMobileActionsOverlayVisible(); WidgetsBinding.instance.addPostFrameCallback((_) { diff --git a/flutter/lib/desktop/pages/view_camera_page.dart b/flutter/lib/desktop/pages/view_camera_page.dart index c45ec4d86..6eb65b11d 100644 --- a/flutter/lib/desktop/pages/view_camera_page.dart +++ b/flutter/lib/desktop/pages/view_camera_page.dart @@ -127,7 +127,6 @@ class _ViewCameraPageState extends State WakelockManager.enable(_uniqueKey); _ffi.ffiModel.updateEventListener(sessionId, widget.id); - if (!isWeb) bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote); _ffi.qualityMonitorModel.checkShowQualityMonitor(sessionId); _ffi.dialogManager.loadMobileActionsOverlayVisible(); DesktopMultiWindow.addListener(this); diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 2373d016a..0516608cd 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -10,8 +10,6 @@ import 'package:flutter_hbb/models/chat_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; -import 'package:flutter_hbb/plugin/widgets/desc_ui.dart'; -import 'package:flutter_hbb/plugin/common.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; @@ -1478,20 +1476,13 @@ class _DisplayMenu extends StatefulWidget { final FFI ffi; final ToolbarState state; final Function(bool) setFullscreen; - final Widget pluginItem; _DisplayMenu( {Key? key, required this.id, required this.ffi, required this.state, required this.setFullscreen}) - : pluginItem = LocationItem.createLocationItem( - id, - ffi, - kLocationClientRemoteToolbarDisplay, - true, - ), - super(key: key); + : super(key: key); @override State<_DisplayMenu> createState() => _DisplayMenuState(); @@ -1582,9 +1573,6 @@ class _DisplayMenuState extends State<_DisplayMenu> { ]); } } - if (ffi.connType == ConnType.defaultConn) { - menuChildren.add(widget.pluginItem); - } return menuChildren; } diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 7e0a8cb2b..5f234cb69 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -30,9 +30,6 @@ import 'mobile/pages/server_page.dart'; import 'mobile/widgets/deploy_dialog.dart'; import 'models/platform_model.dart'; -import 'package:flutter_hbb/plugin/handlers.dart' - if (dart.library.html) 'package:flutter_hbb/web/plugin/handlers.dart'; - /// Basic window and launch properties. int? kWindowId; WindowType? kWindowType; @@ -141,8 +138,6 @@ void runMainApp(bool startService) async { await bind.mainCheckConnectStatus(); if (startService) { gFFI.serverModel.startService(); - bind.pluginSyncUi(syncTo: kAppTypeMain); - bind.pluginListReload(); } await Future.wait([gFFI.abModel.loadCache(), gFFI.groupModel.loadCache()]); gFFI.userModel.refreshCurrentUser(); @@ -570,12 +565,6 @@ _registerEventHandler() { reloadAllWindows(); }); } - // Register native handlers. - if (isDesktop) { - platformFFI.registerEventHandler('native_ui', 'native_ui', (evt) async { - NativeUiHandler.instance.onEvent(evt); - }); - } if (isAndroid) { platformFFI.registerEventHandler( 'android_needs_deploy', 'android_needs_deploy', (_) async { diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 4a6088bd3..68ec58cc3 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -25,9 +25,6 @@ import 'package:flutter_hbb/models/user_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; import 'package:flutter_hbb/models/desktop_render_texture.dart'; import 'package:flutter_hbb/models/terminal_model.dart'; -import 'package:flutter_hbb/plugin/event.dart'; -import 'package:flutter_hbb/plugin/manager.dart'; -import 'package:flutter_hbb/plugin/widgets/desc_ui.dart'; import 'package:flutter_hbb/common/shared_state.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:flutter_hbb/utils/http_service.dart' as http; @@ -437,15 +434,6 @@ class FfiModel with ChangeNotifier { parent.target?.serverModel.updateVoiceCallState(evt); } else if (name == 'fingerprint') { FingerprintState.find(peerId).value = evt['fingerprint'] ?? ''; - } else if (name == 'plugin_manager') { - pluginManager.handleEvent(evt); - } else if (name == 'plugin_event') { - handlePluginEvent(evt, - (Map e) => handleMsgBox(e, sessionId, peerId)); - } else if (name == 'plugin_reload') { - handleReloading(evt); - } else if (name == 'plugin_option') { - handleOption(evt); } else if (name == "sync_peer_hash_password_to_personal_ab") { if (desktopType == DesktopType.main || isWeb || isMobile) { final id = evt['id']; diff --git a/flutter/lib/plugin/common.dart b/flutter/lib/plugin/common.dart deleted file mode 100644 index d984c68ea..000000000 --- a/flutter/lib/plugin/common.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'dart:convert'; - -typedef PluginId = String; - -// ui location -const String kLocationHostMainPlugin = 'host|main|settings|plugin'; -const String kLocationClientRemoteToolbarDisplay = - 'client|remote|toolbar|display'; - -class MsgFromUi { - String id; - String name; - String location; - String key; - String value; - String action; - - MsgFromUi({ - required this.id, - required this.name, - required this.location, - required this.key, - required this.value, - required this.action, - }); - - Map toJson() { - return { - 'id': id, - 'name': name, - 'location': location, - 'key': key, - 'value': value, - 'action': action, - }; - } - - @override - String toString() { - return jsonEncode(toJson()); - } -} diff --git a/flutter/lib/plugin/event.dart b/flutter/lib/plugin/event.dart deleted file mode 100644 index 29a2ae44c..000000000 --- a/flutter/lib/plugin/event.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; - -void handlePluginEvent( - Map evt, - Function(Map e) handleMsgBox, -) { - Map? content; - try { - content = json.decode(evt['content']); - } catch (e) { - debugPrint( - 'Json decode plugin event content failed: $e, ${evt['content']}'); - } - if (content?['t'] == 'MsgBox') { - handleMsgBox(content?['c']); - } -} diff --git a/flutter/lib/plugin/handlers.dart b/flutter/lib/plugin/handlers.dart deleted file mode 100644 index c85f4dfca..000000000 --- a/flutter/lib/plugin/handlers.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'dart:convert'; -import 'dart:ffi'; - -import 'package:ffi/ffi.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hbb/plugin/ui_manager.dart'; -import 'package:flutter_hbb/plugin/utils/dialogs.dart'; - -abstract class NativeHandler { - bool onEvent(Map evt); -} - -typedef OnSelectPeersCallback = Bool Function(Int returnCode, - Pointer data, Uint64 dataLength, Pointer userData); -typedef OnSelectPeersCallbackDart = bool Function( - int returnCode, Pointer data, int dataLength, Pointer userData); - -class NativeUiHandler extends NativeHandler { - NativeUiHandler._(); - - static NativeUiHandler instance = NativeUiHandler._(); - - @override - bool onEvent(Map evt) { - final name = evt['name']; - final action = evt['action']; - if (name != "native_ui") { - return false; - } - switch (action) { - case "select_peers": - int cb = evt['cb']; - int userData = evt['user_data'] ?? 0; - final cbFuncNative = Pointer.fromAddress(cb) - .cast>(); - final cbFuncDart = cbFuncNative.asFunction(); - onSelectPeers(cbFuncDart, userData); - break; - case "register_ui_entry": - int cb = evt['on_tap_cb']; - int userData = evt['user_data'] ?? 0; - String title = evt['title'] ?? ""; - final cbFuncNative = Pointer.fromAddress(cb) - .cast>(); - final cbFuncDart = cbFuncNative.asFunction(); - onRegisterUiEntry(title, cbFuncDart, userData); - break; - default: - return false; - } - return true; - } - - void onSelectPeers(OnSelectPeersCallbackDart cb, int userData) async { - showPeerSelectionDialog(onPeersCallback: (peers) { - String json = jsonEncode( { - "peers": peers - }); - final native = json.toNativeUtf8(); - cb(0, native.cast(), native.length, Pointer.fromAddress(userData)); - malloc.free(native); - }); - } - - void onRegisterUiEntry(String title, OnSelectPeersCallbackDart cbFuncDart, int userData) { - Widget widget = InkWell( - child: Container( - height: 25.0, - child: Row( - children: [ - Expanded(child: Text(title)), - Icon(Icons.chevron_right_rounded, size: 12.0,) - ], - ), - ), - ); - PluginUiManager.instance.registerEntry(title, widget); - } -} diff --git a/flutter/lib/plugin/manager.dart b/flutter/lib/plugin/manager.dart deleted file mode 100644 index f58a1a54e..000000000 --- a/flutter/lib/plugin/manager.dart +++ /dev/null @@ -1,319 +0,0 @@ -// The plugin manager is a singleton class that manages the plugins. -// 1. It merge metadata and the desc of plugins. - -import 'dart:convert'; -import 'dart:collection'; -import 'package:flutter/material.dart'; - -const String kValueTrue = '1'; -const String kValueFalse = '0'; - -class ConfigItem { - String key; - String description; - String defaultValue; - - ConfigItem(this.key, this.defaultValue, this.description); - ConfigItem.fromJson(Map json) - : key = json['key'] ?? '', - description = json['description'] ?? '', - defaultValue = json['default'] ?? ''; - - static String get trueValue => kValueTrue; - static String get falseValue => kValueFalse; - static bool isTrue(String value) => value == kValueTrue; - static bool isFalse(String value) => value == kValueFalse; -} - -class UiType { - String key; - String text; - String tooltip; - String action; - - UiType(this.key, this.text, this.tooltip, this.action); - - UiType.fromJson(Map json) - : key = json['key'] ?? '', - text = json['text'] ?? '', - tooltip = json['tooltip'] ?? '', - action = json['action'] ?? ''; - - static UiType? create(Map json) { - if (json['t'] == 'Button') { - return UiButton.fromJson(json['c']); - } else if (json['t'] == 'Checkbox') { - return UiCheckbox.fromJson(json['c']); - } else { - return null; - } - } -} - -class UiButton extends UiType { - String icon; - - UiButton( - {required String key, - required String text, - required this.icon, - required String tooltip, - required String action}) - : super(key, text, tooltip, action); - - UiButton.fromJson(Map json) - : icon = json['icon'] ?? '', - super.fromJson(json); -} - -class UiCheckbox extends UiType { - UiCheckbox( - {required String key, - required String text, - required String tooltip, - required String action}) - : super(key, text, tooltip, action); - - UiCheckbox.fromJson(Map json) : super.fromJson(json); -} - -class Location { - // location key: - // host|main|settings|plugin - // client|remote|toolbar|display - HashMap ui; - - Location(this.ui); - Location.fromJson(Map json) : ui = HashMap() { - (json['ui'] as Map).forEach((key, value) { - var ui = UiType.create(value); - if (ui != null) { - this.ui[ui.key] = ui; - } - }); - } -} - -class PublishInfo { - PublishInfo({ - required this.lastReleased, - required this.published, - }); - - final DateTime lastReleased; - final DateTime published; -} - -class Meta { - Meta({ - required this.id, - required this.name, - required this.version, - required this.description, - required this.author, - required this.home, - required this.license, - required this.publishInfo, - required this.source, - }); - - final String id; - final String name; - final String version; - final String description; - final String author; - final String home; - final String license; - final PublishInfo publishInfo; - final String source; -} - -class SourceInfo { - String name; // 1. RustDesk github 2. Local - String url; - String description; - - SourceInfo({ - required this.name, - required this.url, - required this.description, - }); -} - -class PluginInfo with ChangeNotifier { - SourceInfo sourceInfo; - Meta meta; - String installedVersion; // It is empty if not installed. - String failedMsg; - String invalidReason; // It is empty if valid. - - PluginInfo({ - required this.sourceInfo, - required this.meta, - required this.installedVersion, - required this.invalidReason, - this.failedMsg = '', - }); - - bool get installed => installedVersion.isNotEmpty; - bool get needUpdate => installed && installedVersion != meta.version; - - void setInstall(String msg) { - if (msg == "finished") { - msg = ''; - } - failedMsg = msg; - if (msg.isEmpty) { - installedVersion = meta.version; - } - notifyListeners(); - } - - void setUninstall(String msg) { - failedMsg = msg; - if (msg.isEmpty) { - installedVersion = ''; - } - notifyListeners(); - } -} - -class PluginManager with ChangeNotifier { - String failedReason = ''; // The reason of failed to load plugins. - final List _plugins = []; - - PluginManager._(); - static final PluginManager _instance = PluginManager._(); - static PluginManager get instance => _instance; - - List get plugins => _plugins; - - PluginInfo? getPlugin(String id) { - for (var p in _plugins) { - if (p.meta.id == id) { - return p; - } - } - return null; - } - - void handleEvent(Map evt) { - if (evt['plugin_list'] != null) { - _handlePluginList(evt['plugin_list']); - } else if (evt['plugin_install'] != null && evt['id'] != null) { - _handlePluginInstall(evt['id'], evt['plugin_install']); - } else if (evt['plugin_uninstall'] != null && evt['id'] != null) { - _handlePluginUninstall(evt['id'], evt['plugin_uninstall']); - } else { - debugPrint('Failed to handle manager event: $evt'); - } - } - - void _sortPlugins() { - plugins.sort((a, b) { - if (a.installed) { - return -1; - } else if (b.installed) { - return 1; - } else { - return 0; - } - }); - } - - void _handlePluginList(String pluginList) { - _plugins.clear(); - try { - for (var p in json.decode(pluginList) as List) { - final plugin = _getPluginFromEvent(p); - if (plugin == null) { - continue; - } - _plugins.add(plugin); - } - } catch (e) { - debugPrint('Failed to decode $e, plugin list \'$pluginList\''); - } - _sortPlugins(); - notifyListeners(); - } - - void _handlePluginInstall(String id, String msg) { - debugPrint('Plugin \'$id\' install msg $msg'); - for (var i = 0; i < _plugins.length; i++) { - if (_plugins[i].meta.id == id) { - _plugins[i].setInstall(msg); - _sortPlugins(); - notifyListeners(); - return; - } - } - } - - void _handlePluginUninstall(String id, String msg) { - debugPrint('Plugin \'$id\' uninstall msg $msg'); - for (var i = 0; i < _plugins.length; i++) { - if (_plugins[i].meta.id == id) { - _plugins[i].setUninstall(msg); - _sortPlugins(); - notifyListeners(); - return; - } - } - } - - PluginInfo? _getPluginFromEvent(Map evt) { - final s = evt['source']; - assert(s != null, 'Source is null'); - if (s == null) { - return null; - } - final source = SourceInfo( - name: s['name'], - url: s['url'] ?? '', - description: s['description'] ?? '', - ); - - final m = evt['meta']; - assert(m != null, 'Meta is null'); - if (m == null) { - return null; - } - - late DateTime lastReleased; - late DateTime published; - try { - lastReleased = DateTime.parse( - m['publish_info']?['last_released'] ?? '1970-01-01T00+00:00'); - } catch (e) { - lastReleased = DateTime.utc(1970); - } - try { - published = DateTime.parse( - m['publish_info']?['published'] ?? '1970-01-01T00+00:00'); - } catch (e) { - published = DateTime.utc(1970); - } - - final meta = Meta( - id: m['id'], - name: m['name'], - version: m['version'], - description: m['description'] ?? '', - author: m['author'], - home: m['home'] ?? '', - license: m['license'] ?? '', - source: m['source'] ?? '', - publishInfo: - PublishInfo(lastReleased: lastReleased, published: published), - ); - return PluginInfo( - sourceInfo: source, - meta: meta, - installedVersion: evt['installed_version'], - invalidReason: evt['invalid_reason'] ?? '', - ); - } -} - -PluginManager get pluginManager => PluginManager.instance; diff --git a/flutter/lib/plugin/model.dart b/flutter/lib/plugin/model.dart deleted file mode 100644 index 4fc024e4c..000000000 --- a/flutter/lib/plugin/model.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'package:flutter/material.dart'; -import './common.dart'; -import './manager.dart'; - -final Map _locationModels = {}; -final Map _optionModels = {}; - -class OptionModel with ChangeNotifier { - String? v; - - String? get value => v; - set value(String? v) { - this.v = v; - notifyListeners(); - } - - static String key(String location, PluginId id, String peer, String k) => - '$location|$id|$peer|$k'; -} - -class PluginModel with ChangeNotifier { - final List uiList = []; - final Map opts = {}; - - void add(List uiList) { - bool found = false; - for (var ui in uiList) { - for (int i = 0; i < this.uiList.length; i++) { - if (this.uiList[i].key == ui.key) { - this.uiList[i] = ui; - found = true; - } - } - if (!found) { - this.uiList.add(ui); - } - } - notifyListeners(); - } - - String? getOpt(String key) => opts.remove(key); - - bool get isEmpty => uiList.isEmpty; -} - -class LocationModel with ChangeNotifier { - final Map pluginModels = {}; - - void add(PluginId id, List uiList) { - if (pluginModels[id] != null) { - pluginModels[id]!.add(uiList); - } else { - var model = PluginModel(); - model.add(uiList); - pluginModels[id] = model; - notifyListeners(); - } - } - - void clear() { - pluginModels.clear(); - notifyListeners(); - } - - void remove(PluginId id) { - pluginModels.remove(id); - notifyListeners(); - } - - bool get isEmpty => pluginModels.isEmpty; -} - -void addLocationUi(String location, PluginId id, List uiList) { - if (_locationModels[location] == null) { - _locationModels[location] = LocationModel(); - } - _locationModels[location]?.add(id, uiList); -} - -LocationModel? getLocationModel(String location) => _locationModels[location]; - -PluginModel? getPluginModel(String location, PluginId id) => - _locationModels[location]?.pluginModels[id]; - -void clearPlugin(PluginId pluginId) { - for (var element in _locationModels.values) { - element.remove(pluginId); - } -} - -void clearLocations() { - for (var element in _locationModels.values) { - element.clear(); - } -} - -OptionModel getOptionModel( - String location, PluginId pluginId, String peer, String key) { - final k = OptionModel.key(location, pluginId, peer, key); - if (_optionModels[k] == null) { - _optionModels[k] = OptionModel(); - } - return _optionModels[k]!; -} - -void updateOption( - String location, PluginId id, String peer, String key, String value) { - final k = OptionModel.key(location, id, peer, key); - _optionModels[k]?.value = value; -} diff --git a/flutter/lib/plugin/ui_manager.dart b/flutter/lib/plugin/ui_manager.dart deleted file mode 100644 index 45accf650..000000000 --- a/flutter/lib/plugin/ui_manager.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter/material.dart'; - -class PluginUiManager { - PluginUiManager._(); - - static PluginUiManager instance = PluginUiManager._(); - - Map entries = {}; - - void registerEntry(String key, Widget widget) { - entries[key] = widget; - } - - void unregisterEntry(String key) { - entries.remove(key); - } -} \ No newline at end of file diff --git a/flutter/lib/plugin/utils/dialogs.dart b/flutter/lib/plugin/utils/dialogs.dart deleted file mode 100644 index 6fdb86ab4..000000000 --- a/flutter/lib/plugin/utils/dialogs.dart +++ /dev/null @@ -1,86 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:flutter_hbb/common.dart'; - -void showPeerSelectionDialog( - {bool singleSelection = false, - required Function(List) onPeersCallback}) async { - // load recent peers, we can directly use the peers in `gFFI.recentPeersModel`. - // The plugin is not used for now, so just left it empty here. - final peers = ''; - if (peers.isEmpty) { - // debugPrint("load recent peers failed."); - return; - } - - Map map = jsonDecode(peers); - List peersList = map['peers'] ?? []; - final selected = List.empty(growable: true); - - submit() async { - onPeersCallback.call(selected); - } - - gFFI.dialogManager.show((setState, close, context) { - return CustomAlertDialog( - title: - Text(translate(singleSelection ? "Select peers" : "Select a peer")), - content: SizedBox( - height: 300.0, - child: ListView.builder( - itemBuilder: (context, index) { - final Map peer = peersList[index]; - final String platform = peer['platform'] ?? ""; - final String id = peer['id'] ?? ""; - final String alias = peer['alias'] ?? ""; - return GestureDetector( - onTap: () { - setState(() { - if (selected.contains(id)) { - selected.remove(id); - } else { - selected.add(id); - } - }); - }, - child: Container( - key: ValueKey(index), - height: 50.0, - decoration: BoxDecoration( - color: Theme.of(context).highlightColor, - borderRadius: BorderRadius.circular(12.0)), - padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0), - margin: EdgeInsets.symmetric(vertical: 4.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - // platform - SizedBox( - width: 8.0, - ), - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - getPlatformImage(platform, size: 34.0), - ], - ), - SizedBox( - width: 8.0, - ), - // id/alias - Expanded(child: Text(alias.isEmpty ? id : alias)), - ], - ), - ), - ); - }, - itemCount: peersList.length, - itemExtent: 50.0, - ), - ), - onSubmit: submit, - ); - }); -} diff --git a/flutter/lib/plugin/widgets/desc_ui.dart b/flutter/lib/plugin/widgets/desc_ui.dart deleted file mode 100644 index 10c231f98..000000000 --- a/flutter/lib/plugin/widgets/desc_ui.dart +++ /dev/null @@ -1,301 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_hbb/common.dart'; -import 'package:flutter_hbb/models/model.dart'; -import 'package:provider/provider.dart'; -import 'package:get/get.dart'; -// to-do: do not depend on desktop -import 'package:flutter_hbb/desktop/widgets/remote_toolbar.dart'; -import 'package:flutter_hbb/models/platform_model.dart'; - -import '../manager.dart'; -import '../model.dart'; -import '../common.dart'; - -// dup to flutter\lib\desktop\pages\desktop_setting_page.dart -const double _kCheckBoxLeftMargin = 10; - -class LocationItem extends StatelessWidget { - final String peerId; - final FFI ffi; - final String location; - final LocationModel locationModel; - final bool isMenu; - - LocationItem({ - Key? key, - required this.peerId, - required this.ffi, - required this.location, - required this.locationModel, - required this.isMenu, - }) : super(key: key); - - bool get isEmpty => locationModel.isEmpty; - - static Widget createLocationItem( - String peerId, FFI ffi, String location, bool isMenu) { - final model = getLocationModel(location); - return model == null - ? Container() - : LocationItem( - peerId: peerId, - ffi: ffi, - location: location, - locationModel: model, - isMenu: isMenu, - ); - } - - @override - Widget build(BuildContext context) { - return ChangeNotifierProvider.value( - value: locationModel, - child: Consumer(builder: (context, model, child) { - return Column( - children: model.pluginModels.entries - .map((entry) => _buildPluginItem(entry.key, entry.value)) - .toList(), - ); - }), - ); - } - - Widget _buildPluginItem(PluginId id, PluginModel model) => PluginItem( - pluginId: id, - peerId: peerId, - ffi: ffi, - location: location, - pluginModel: model, - isMenu: isMenu, - ); -} - -class PluginItem extends StatelessWidget { - final PluginId pluginId; - final String peerId; - final FFI? ffi; - final String location; - final PluginModel pluginModel; - final bool isMenu; - - PluginItem({ - Key? key, - required this.pluginId, - required this.peerId, - this.ffi, - required this.location, - required this.pluginModel, - required this.isMenu, - }) : super(key: key); - - bool get isEmpty => pluginModel.isEmpty; - - @override - Widget build(BuildContext context) { - return ChangeNotifierProvider.value( - value: pluginModel, - child: Consumer( - builder: (context, pluginModel, child) { - return Column( - children: pluginModel.uiList.map((ui) => _buildItem(ui)).toList(), - ); - }, - ), - ); - } - - Widget _buildItem(UiType ui) { - Widget? child; - switch (ui.runtimeType) { - case UiButton: - if (isMenu) { - if (ffi != null) { - child = _buildMenuButton(ui as UiButton, ffi!); - } - } else { - child = _buildButton(ui as UiButton); - } - break; - case UiCheckbox: - if (isMenu) { - if (ffi != null) { - child = _buildCheckboxMenuButton(ui as UiCheckbox, ffi!); - } - } else { - child = _buildCheckbox(ui as UiCheckbox); - } - break; - default: - break; - } - // to-do: add plugin icon and tooltip - return child ?? Container(); - } - - Widget _buildButton(UiButton ui) { - return TextButton( - onPressed: () => bind.pluginEvent( - id: pluginId, - peer: peerId, - event: _makeEvent(ui.key), - ), - child: Text(ui.text), - ); - } - - Widget _buildCheckbox(UiCheckbox ui) { - getChild(OptionModel model) { - final v = _getOption(model, ui.key); - if (v == null) { - // session or plugin not found - return Container(); - } - - onChanged(bool value) { - bind.pluginEvent( - id: pluginId, - peer: peerId, - event: _makeEvent(ui.key, v: value), - ); - } - - final value = ConfigItem.isTrue(v); - return GestureDetector( - child: Row( - children: [ - Checkbox( - value: value, - onChanged: (_) => onChanged(!value), - ).marginOnly(right: 5), - Expanded( - child: Text(translate(ui.text)), - ) - ], - ).marginOnly(left: _kCheckBoxLeftMargin), - onTap: () => onChanged(!value), - ); - } - - return ChangeNotifierProvider.value( - value: getOptionModel(location, pluginId, peerId, ui.key), - child: Consumer( - builder: (context, model, child) => getChild(model), - ), - ); - } - - Widget _buildCheckboxMenuButton(UiCheckbox ui, FFI ffi) { - getChild(OptionModel model) { - final v = _getOption(model, ui.key); - if (v == null) { - // session or plugin not found - return Container(); - } - return CkbMenuButton( - value: ConfigItem.isTrue(v), - onChanged: (v) { - if (v != null) { - bind.pluginEvent( - id: pluginId, - peer: peerId, - event: _makeEvent(ui.key, v: v), - ); - } - }, - // to-do: RustDesk translate or plugin translate ? - child: Text(ui.text), - ffi: ffi, - ); - } - - return ChangeNotifierProvider.value( - value: getOptionModel(location, pluginId, peerId, ui.key), - child: Consumer( - builder: (context, model, child) => getChild(model), - ), - ); - } - - Widget _buildMenuButton(UiButton ui, FFI ffi) { - return MenuButton( - onPressed: () => bind.pluginEvent( - id: pluginId, - peer: peerId, - event: _makeEvent(ui.key), - ), - // to-do: support trailing icon, but it will cause tree shake error. - // ``` - // This application cannot tree shake icons fonts. It has non-constant instances of IconData at the following locations: - // Target release_macos_bundle_flutter_assets failed: Exception: Avoid non-constant invocations of IconData or try to build again with --no-tree-shake-icons. - // ``` - // - // trailingIcon: Icon( - // IconData(int.parse(ui.icon, radix: 16), fontFamily: 'MaterialIcons')), - // - // to-do: RustDesk translate or plugin translate ? - child: Text(ui.text), - ffi: ffi, - ); - } - - Uint8List _makeEvent( - String key, { - bool? v, - }) { - final event = MsgFromUi( - id: pluginId, - name: pluginManager.getPlugin(pluginId)?.meta.name ?? '', - location: location, - key: key, - value: - v != null ? (v ? ConfigItem.trueValue : ConfigItem.falseValue) : '', - action: '', - ); - return Uint8List.fromList(event.toString().codeUnits); - } - - String? _getOption(OptionModel model, String key) { - var v = model.value; - if (v == null) { - try { - if (peerId.isEmpty) { - v = bind.pluginGetSharedOption(id: pluginId, key: key); - } else { - v = bind.pluginGetSessionOption(id: pluginId, peer: peerId, key: key); - } - } catch (e) { - debugPrint('Failed to get option "$key", $e'); - v = null; - } - } - return v; - } -} - -void handleReloading(Map evt) { - if (evt['id'] == null || evt['location'] == null) { - return; - } - try { - final uiList = []; - for (var e in json.decode(evt['ui'] as String)) { - final ui = UiType.create(e); - if (ui != null) { - uiList.add(ui); - } - } - if (uiList.isNotEmpty) { - addLocationUi(evt['location']!, evt['id']!, uiList); - } - } catch (e) { - debugPrint('Failed handleReloading, json decode of ui, $e '); - } -} - -void handleOption(Map evt) { - updateOption( - evt['location'], evt['id'], evt['peer'] ?? '', evt['key'], evt['value']); -} diff --git a/flutter/lib/plugin/widgets/desktop_settings.dart b/flutter/lib/plugin/widgets/desktop_settings.dart deleted file mode 100644 index 232df001f..000000000 --- a/flutter/lib/plugin/widgets/desktop_settings.dart +++ /dev/null @@ -1,202 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hbb/common.dart'; -import 'package:flutter_hbb/models/platform_model.dart'; -import 'package:flutter_hbb/plugin/model.dart'; -import 'package:flutter_hbb/plugin/common.dart'; -import 'package:get/get.dart'; - -import '../manager.dart'; -import './desc_ui.dart'; - -// to-do: use settings from desktop_setting_page.dart -const double _kCardFixedWidth = 540; -const double _kCardLeftMargin = 15; -const double _kContentHMargin = 15; -const double _kTitleFontSize = 20; -const double _kVersionFontSize = 12; - -class DesktopSettingsCard extends StatefulWidget { - final PluginInfo plugin; - DesktopSettingsCard({ - Key? key, - required this.plugin, - }) : super(key: key); - - @override - State createState() => _DesktopSettingsCardState(); -} - -class _DesktopSettingsCardState extends State { - PluginInfo get plugin => widget.plugin; - bool get installed => plugin.installed; - - bool isEnabled = false; - - @override - Widget build(BuildContext context) { - isEnabled = bind.pluginIsEnabled(id: plugin.meta.id); - return Row( - children: [ - Flexible( - child: SizedBox( - width: _kCardFixedWidth, - child: Card( - child: Column( - children: [ - header(), - body(), - ], - ).marginOnly(bottom: 10), - ).marginOnly(left: _kCardLeftMargin, top: 15), - ), - ), - ], - ); - } - - Widget header() { - return Row( - children: [ - headerNameVersion(), - headerInstallEnable(), - ], - ).marginOnly( - left: _kContentHMargin, - top: 10, - bottom: 10, - right: _kContentHMargin, - ); - } - - Widget headerNameVersion() { - return Expanded( - child: Row( - children: [ - Text( - widget.plugin.meta.name, - textAlign: TextAlign.start, - style: const TextStyle( - fontSize: _kTitleFontSize, - ), - ), - SizedBox( - width: 5, - ), - Text( - plugin.meta.version, - textAlign: TextAlign.start, - style: const TextStyle( - fontSize: _kVersionFontSize, - ), - ) - ], - ), - ); - } - - Widget headerButton(String label, VoidCallback onPressed) { - return Container( - child: ElevatedButton( - onPressed: onPressed, - child: Text(translate(label)), - ), - ); - } - - Widget headerInstallEnable() { - final installButton = headerButton( - installed ? 'Uninstall' : 'Install', - () { - bind.pluginInstall( - id: plugin.meta.id, - b: !installed, - ); - }, - ); - - if (installed) { - final updateButton = plugin.needUpdate - ? headerButton('Update', () { - bind.pluginInstall( - id: plugin.meta.id, - b: !installed, - ); - }) - : Container(); - - final enableButton = !installed - ? Container() - : headerButton(isEnabled ? 'Disable' : 'Enable', () { - if (isEnabled) { - clearPlugin(plugin.meta.id); - } - bind.pluginEnable(id: plugin.meta.id, v: !isEnabled); - setState(() {}); - }); - return Row( - children: [ - updateButton, - SizedBox( - width: 10, - ), - installButton, - SizedBox( - width: 10, - ), - enableButton, - ], - ); - } else { - return installButton; - } - } - - Widget body() { - return Column(children: [ - author(), - description(), - more(), - ]).marginOnly( - left: _kCardLeftMargin, - top: 4, - right: _kContentHMargin, - ); - } - - Widget author() { - return Align( - alignment: Alignment.centerLeft, - child: Text(plugin.meta.author), - ); - } - - Widget description() { - return Align( - alignment: Alignment.centerLeft, - child: Text(plugin.meta.description), - ); - } - - Widget more() { - if (!(installed && isEnabled)) { - return Container(); - } - - final List children = []; - final model = getPluginModel(kLocationHostMainPlugin, plugin.meta.id); - if (model != null) { - children.add(PluginItem( - pluginId: plugin.meta.id, - peerId: '', - location: kLocationHostMainPlugin, - pluginModel: model, - isMenu: false, - )); - } - return ExpansionTile( - title: Text('Options'), - controlAffinity: ListTileControlAffinity.leading, - children: children, - ); - } -} diff --git a/flutter/lib/web/bridge.dart b/flutter/lib/web/bridge.dart index ac48dfb0f..b59c769da 100644 --- a/flutter/lib/web/bridge.dart +++ b/flutter/lib/web/bridge.dart @@ -1644,78 +1644,6 @@ class RustdeskImpl { throw UnimplementedError("sendUrlScheme"); } - Future pluginEvent( - {required String id, - required String peer, - required Uint8List event, - dynamic hint}) { - throw UnimplementedError("pluginEvent"); - } - - Stream pluginRegisterEventStream( - {required String id, dynamic hint}) { - throw UnimplementedError("pluginRegisterEventStream"); - } - - String? pluginGetSessionOption( - {required String id, - required String peer, - required String key, - dynamic hint}) { - throw UnimplementedError("pluginGetSessionOption"); - } - - Future pluginSetSessionOption( - {required String id, - required String peer, - required String key, - required String value, - dynamic hint}) { - throw UnimplementedError("pluginSetSessionOption"); - } - - String? pluginGetSharedOption( - {required String id, required String key, dynamic hint}) { - throw UnimplementedError("pluginGetSharedOption"); - } - - Future pluginSetSharedOption( - {required String id, - required String key, - required String value, - dynamic hint}) { - throw UnimplementedError("pluginSetSharedOption"); - } - - Future pluginReload({required String id, dynamic hint}) { - throw UnimplementedError("pluginReload"); - } - - void pluginEnable({required String id, required bool v, dynamic hint}) { - throw UnimplementedError("pluginEnable"); - } - - bool pluginIsEnabled({required String id, dynamic hint}) { - throw UnimplementedError("pluginIsEnabled"); - } - - bool pluginFeatureIsEnabled({dynamic hint}) { - throw UnimplementedError("pluginFeatureIsEnabled"); - } - - Future pluginSyncUi({required String syncTo, dynamic hint}) { - throw UnimplementedError("pluginSyncUi"); - } - - Future pluginListReload({dynamic hint}) { - throw UnimplementedError("pluginListReload"); - } - - Future pluginInstall( - {required String id, required bool b, dynamic hint}) { - throw UnimplementedError("pluginInstall"); - } - bool isSupportMultiUiSession({required String version, dynamic hint}) { return versionToNumber(v: version) > versionToNumber(v: '1.2.4'); } diff --git a/flutter/lib/web/plugin/handlers.dart b/flutter/lib/web/plugin/handlers.dart deleted file mode 100644 index f159ce9dd..000000000 --- a/flutter/lib/web/plugin/handlers.dart +++ /dev/null @@ -1,14 +0,0 @@ -abstract class NativeHandler { - bool onEvent(Map evt); -} - -class NativeUiHandler extends NativeHandler { - NativeUiHandler._(); - - static NativeUiHandler instance = NativeUiHandler._(); - - @override - bool onEvent(Map evt) { - throw UnimplementedError(); - } -} diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 1af691429..bc1828fd8 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -1437,14 +1437,6 @@ impl Remote { #[cfg(all(feature = "flutter", feature = "unix-file-copy-paste"))] crate::flutter::update_file_clipboard_required(); - - // on connection established client - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - crate::plugin::handle_listen_event( - crate::plugin::EVENT_ON_CONN_CLIENT.to_owned(), - self.handler.get_id(), - ); } if self.handler.is_file_transfer() { @@ -1988,26 +1980,6 @@ impl Remote { ); } } - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - Some(misc::Union::PluginRequest(p)) => { - allow_err!(crate::plugin::handle_server_event( - &p.id, - &self.handler.get_id(), - &p.content - )); - // to-do: show message box on UI when error occurs? - } - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - Some(misc::Union::PluginFailure(p)) => { - let name = if p.name.is_empty() { - "plugin".to_string() - } else { - p.name - }; - self.handler.msgbox("custom-nocancel", &name, &p.msg, ""); - } Some(misc::Union::SupportedEncoding(e)) => { log::info!("update supported encoding:{:?}", e); self.handler.lc.write().unwrap().supported_encoding = e; diff --git a/src/core_main.rs b/src/core_main.rs index b20ecd92b..3a190f114 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -190,9 +190,6 @@ pub fn core_main() -> Option> { crate::platform::elevate_or_run_as_system(click_setup, _is_elevate, _is_run_as_system); return None; } - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - init_plugins(&args); if args.is_empty() || crate::common::is_empty_uni_link(&args[0]) { #[cfg(target_os = "macos")] { @@ -737,22 +734,6 @@ pub fn core_main() -> Option> { crate::platform::gtk_sudo::exec(); } return None; - } else { - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - if args[0] == "--plugin-install" { - if args.len() == 2 { - crate::plugin::change_uninstall_plugin(&args[1], false); - } else if args.len() == 3 { - crate::plugin::install_plugin_with_url(&args[1], &args[2]); - } - return None; - } else if args[0] == "--plugin-uninstall" { - if args.len() == 2 { - crate::plugin::change_uninstall_plugin(&args[1], true); - } - return None; - } } } //_async_logger_holder.map(|x| x.flush()); @@ -762,23 +743,6 @@ pub fn core_main() -> Option> { return Some(args); } -#[inline] -#[cfg(all(feature = "flutter", feature = "plugin_framework"))] -#[cfg(not(any(target_os = "android", target_os = "ios")))] -fn init_plugins(args: &Vec) { - if args.is_empty() || "--server" == (&args[0] as &str) { - #[cfg(debug_assertions)] - let load_plugins = true; - #[cfg(not(debug_assertions))] - let load_plugins = crate::platform::is_installed(); - if load_plugins { - crate::plugin::init(); - } - } else if "--service" == (&args[0] as &str) { - hbb_common::allow_err!(crate::plugin::remove_uninstalled()); - } -} - fn import_config(path: &str) { use hbb_common::{config::*, get_exe_time, get_modified_time}; let path2 = path.replace(".toml", "2.toml"); diff --git a/src/flutter.rs b/src/flutter.rs index f6e3d3edd..87c9c02af 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -225,8 +225,6 @@ pub struct FlutterHandler { session_handlers: Arc>>, display_rgbas: Arc>>, peer_info: Arc>, - #[cfg(not(any(target_os = "android", target_os = "ios")))] - hooks: Arc>>, use_texture_render: Arc, } @@ -236,8 +234,6 @@ impl Default for FlutterHandler { session_handlers: Default::default(), display_rgbas: Default::default(), peer_info: Default::default(), - #[cfg(not(any(target_os = "android", target_os = "ios")))] - hooks: Default::default(), use_texture_render: Arc::new( AtomicBool::new(crate::ui_interface::use_texture_render()), ), @@ -636,30 +632,6 @@ impl FlutterHandler { serde_json::ser::to_string(&msg_vec).unwrap_or("".to_owned()) } - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - pub(crate) fn add_session_hook(&self, key: String, hook: SessionHook) -> bool { - let mut hooks = self.hooks.write().unwrap(); - if hooks.contains_key(&key) { - // Already has the hook with this key. - return false; - } - let _ = hooks.insert(key, hook); - true - } - - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - pub(crate) fn remove_session_hook(&self, key: &String) -> bool { - let mut hooks = self.hooks.write().unwrap(); - if !hooks.contains_key(key) { - // The hook with this key does not found. - return false; - } - let _ = hooks.remove(key); - true - } - pub fn update_use_texture_render(&self) { self.use_texture_render .store(crate::ui_interface::use_texture_render(), Ordering::Relaxed); @@ -1194,15 +1166,6 @@ impl InvokeUiSession for FlutterHandler { impl FlutterHandler { #[inline] fn on_rgba_soft_render(&self, display: usize, rgba: &mut scrap::ImageRgb) { - // Give a chance for plugins or etc to hook a rgba data. - #[cfg(not(any(target_os = "android", target_os = "ios")))] - for (key, hook) in self.hooks.read().unwrap().iter() { - match hook { - SessionHook::OnSessionRgba(cb) => { - cb(key.to_owned(), rgba); - } - } - } // If the current rgba is not fetched by flutter, i.e., is valid. // We give up sending a new event to flutter. let mut rgba_write_lock = self.display_rgbas.write().unwrap(); @@ -1963,12 +1926,6 @@ pub fn session_on_waiting_for_image_dialog_show(session_id: SessionID) { } } -/// Hooks for session. -#[derive(Clone)] -pub enum SessionHook { - OnSessionRgba(fn(String, &mut scrap::ImageRgb)), -} - #[inline] pub fn get_cur_session() -> Option { sessions::get_session_by_session_id(&*CUR_SESSION_ID.read().unwrap()) diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 9b73c4cd4..091fcef25 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -12,9 +12,6 @@ use crate::{ ui_interface::{self, *}, }; use flutter_rust_bridge::{StreamSink, SyncReturn}; -#[cfg(feature = "plugin_framework")] -#[cfg(not(any(target_os = "android", target_os = "ios")))] -use hbb_common::allow_err; use hbb_common::{ config::{self, LocalConfig, PeerConfig, PeerInfoSerde}, fs, lazy_static, log, @@ -2522,180 +2519,6 @@ pub fn send_url_scheme(_url: String) { std::thread::spawn(move || crate::handle_url_scheme(_url)); } -#[inline] -pub fn plugin_event(_id: String, _peer: String, _event: Vec) { - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - allow_err!(crate::plugin::handle_ui_event(&_id, &_peer, &_event)); - } -} - -pub fn plugin_register_event_stream(_id: String, _event2ui: StreamSink) { - #[cfg(feature = "plugin_framework")] - { - crate::plugin::native_handlers::session::session_register_event_stream(_id, _event2ui); - } -} - -#[inline] -pub fn plugin_get_session_option( - _id: String, - _peer: String, - _key: String, -) -> SyncReturn> { - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - SyncReturn(crate::plugin::PeerConfig::get(&_id, &_peer, &_key)) - } - #[cfg(any( - not(feature = "plugin_framework"), - target_os = "android", - target_os = "ios" - ))] - { - SyncReturn(None) - } -} - -#[inline] -pub fn plugin_set_session_option(_id: String, _peer: String, _key: String, _value: String) { - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - let _res = crate::plugin::PeerConfig::set(&_id, &_peer, &_key, &_value); - } -} - -#[inline] -pub fn plugin_get_shared_option(_id: String, _key: String) -> SyncReturn> { - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - SyncReturn(crate::plugin::ipc::get_config(&_id, &_key).unwrap_or(None)) - } - #[cfg(any( - not(feature = "plugin_framework"), - target_os = "android", - target_os = "ios" - ))] - { - SyncReturn(None) - } -} - -#[inline] -pub fn plugin_set_shared_option(_id: String, _key: String, _value: String) { - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - allow_err!(crate::plugin::ipc::set_config(&_id, &_key, _value)); - } -} - -#[inline] -pub fn plugin_reload(_id: String) { - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - allow_err!(crate::plugin::ipc::reload_plugin(&_id,)); - allow_err!(crate::plugin::reload_plugin(&_id)); - } -} - -#[inline] -pub fn plugin_enable(_id: String, _v: bool) -> SyncReturn<()> { - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - allow_err!(crate::plugin::ipc::set_manager_plugin_config( - &_id, - "enabled", - _v.to_string() - )); - if _v { - allow_err!(crate::plugin::load_plugin(&_id)); - } else { - crate::plugin::unload_plugin(&_id); - } - } - SyncReturn(()) -} - -pub fn plugin_is_enabled(_id: String) -> SyncReturn { - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - SyncReturn( - match crate::plugin::ipc::get_manager_plugin_config(&_id, "enabled") { - Ok(Some(enabled)) => bool::from_str(&enabled).unwrap_or(false), - _ => false, - }, - ) - } - #[cfg(any( - not(feature = "plugin_framework"), - target_os = "android", - target_os = "ios" - ))] - { - SyncReturn(false) - } -} - -pub fn plugin_feature_is_enabled() -> SyncReturn { - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - #[cfg(debug_assertions)] - let enabled = true; - #[cfg(not(debug_assertions))] - let enabled = is_installed(); - SyncReturn(enabled) - } - #[cfg(any( - not(feature = "plugin_framework"), - target_os = "android", - target_os = "ios" - ))] - { - SyncReturn(false) - } -} - -pub fn plugin_sync_ui(_sync_to: String) { - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - if plugin_feature_is_enabled().0 { - crate::plugin::sync_ui(_sync_to); - } - } -} - -pub fn plugin_list_reload() { - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - crate::plugin::load_plugin_list(); - } -} - -pub fn plugin_install(_id: String, _b: bool) { - #[cfg(feature = "plugin_framework")] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - if _b { - if let Err(e) = crate::plugin::install_plugin(&_id) { - log::error!("Failed to install plugin '{}': {}", _id, e); - } - } else { - crate::plugin::uninstall_plugin(&_id, true); - } - } -} - pub fn is_support_multi_ui_session(version: String) -> SyncReturn { SyncReturn(crate::common::is_support_multi_ui_session(&version)) } diff --git a/src/ipc.rs b/src/ipc.rs index 52e79955d..9e3faab63 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -19,9 +19,6 @@ pub(crate) use ipc_drm::DrmConn; #[cfg(all(target_os = "linux", feature = "drm"))] pub(crate) use ipc_drm::connect_drm; -#[cfg(all(feature = "flutter", feature = "plugin_framework"))] -#[cfg(not(any(target_os = "android", target_os = "ios")))] -use crate::plugin::ipc::Plugin; use crate::{ common::{is_server, CheckTestNatType}, privacy_mode, @@ -404,9 +401,6 @@ pub enum Data { StartVoiceCall, VoiceCallResponse(bool), CloseVoiceCall(String), - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - Plugin(Plugin), #[cfg(windows)] SyncWinCpuUsage(Option), FileTransferLog((String, String)), @@ -1076,9 +1070,6 @@ async fn handle(data: Data, stream: &mut Connection) { .await ); } - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - Data::Plugin(plugin) => crate::plugin::ipc::handle_plugin(plugin, stream).await, #[cfg(windows)] Data::ControlledSessionCount(_) => { allow_err!( diff --git a/src/lang/ar.rs b/src/lang/ar.rs index 2189648d9..bc9ea67d8 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "البصمة"), ("Copy Fingerprint", "نسخ البصمة"), ("no fingerprints", "لا توجد بصمات اصابع"), - ("Select a peer", "اختر قرين"), - ("Select peers", "اختر الاقران"), - ("Plugins", "الاضافات"), ("Uninstall", "الغاء التثبيت"), ("Update", "تحديث"), ("Enable", "تفعيل"), diff --git a/src/lang/be.rs b/src/lang/be.rs index ac302f3af..3dd0ef75e 100644 --- a/src/lang/be.rs +++ b/src/lang/be.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Адбітак"), ("Copy Fingerprint", "Капіяваць адбітак"), ("no fingerprints", "адбіткі адсутнічаюць"), - ("Select a peer", "Выберыце абанента"), - ("Select peers", "Выберыце абанентаў"), - ("Plugins", "Убудовы"), ("Uninstall", "Выдаліць"), ("Update", "Абнавіць"), ("Enable", "Уключыць"), diff --git a/src/lang/bg.rs b/src/lang/bg.rs index c339270c0..0d926db31 100644 --- a/src/lang/bg.rs +++ b/src/lang/bg.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Пръстов отпечатък"), ("Copy Fingerprint", "Копиране на пръстов отпечатък"), ("no fingerprints", "Няма пръстови отпечатъци"), - ("Select a peer", "Избери отдалечена страна"), - ("Select peers", "Избери отдалечени страни"), - ("Plugins", "Плъгини"), ("Uninstall", "Премахни"), ("Update", "Обновяване"), ("Enable", "Позволяване"), diff --git a/src/lang/ca.rs b/src/lang/ca.rs index d3b0ae7e0..17f5817b2 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Empremta"), ("Copy Fingerprint", "Copia l'empremta"), ("no fingerprints", "Cap empremta"), - ("Select a peer", "Seleccioneu un client"), - ("Select peers", "Seleccioneu els clients"), - ("Plugins", "Complements"), ("Uninstall", "Desinstal·la"), ("Update", "Actualitza"), ("Enable", "Activa"), diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 7423cceb3..d1ada573b 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "指纹"), ("Copy Fingerprint", "复制指纹"), ("no fingerprints", "没有指纹"), - ("Select a peer", "选择一个被控端"), - ("Select peers", "选择被控"), - ("Plugins", "插件"), ("Uninstall", "卸载"), ("Update", "更新"), ("Enable", "启用"), diff --git a/src/lang/cs.rs b/src/lang/cs.rs index abd4e60aa..3bb59ecfb 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Otisk"), ("Copy Fingerprint", "Kopírovat otisk"), ("no fingerprints", "žádný otisk"), - ("Select a peer", "Výběr protistrany"), - ("Select peers", "Vybrat protistrany"), - ("Plugins", "Pluginy"), ("Uninstall", "Odinstalovat"), ("Update", "Aktualizovat"), ("Enable", "Povolit"), diff --git a/src/lang/da.rs b/src/lang/da.rs index 0ecab9098..823a58a6b 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Fingeraftryk"), ("Copy Fingerprint", "Kopiér fingeraftryk"), ("no fingerprints", "Ingen fingeraftryk"), - ("Select a peer", "Vælg en peer"), - ("Select peers", "Vælg peers"), - ("Plugins", "Plugins"), ("Uninstall", "Afinstallér"), ("Update", "Opdatér"), ("Enable", "Aktivér"), diff --git a/src/lang/de.rs b/src/lang/de.rs index d71dfa6ce..7f30d1051 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Fingerabdruck"), ("Copy Fingerprint", "Fingerabdruck kopieren"), ("no fingerprints", "Keine Fingerabdrücke"), - ("Select a peer", "Gegenstelle auswählen"), - ("Select peers", "Gegenstellen auswählen"), - ("Plugins", "Plugins"), ("Uninstall", "Deinstallieren"), ("Update", "Update"), ("Enable", "Aktivieren"), diff --git a/src/lang/el.rs b/src/lang/el.rs index deca79aa6..e6c4ab6fe 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Δακτυλικό αποτύπωμα"), ("Copy Fingerprint", "Αντιγραφή δακτυλικού αποτυπώματος"), ("no fingerprints", "χωρίς δακτυλικά αποτυπώματα"), - ("Select a peer", "Επιλέξτε έναν σταθμό"), - ("Select peers", "Επιλέξτε σταθμούς"), - ("Plugins", "Επεκτάσεις"), ("Uninstall", "Κατάργηση εγκατάστασης"), ("Update", "Ενημέρωση"), ("Enable", "Ενεργοποίηση"), diff --git a/src/lang/eo.rs b/src/lang/eo.rs index e6cc0cae5..5e5c19d64 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Fingrospuro"), ("Copy Fingerprint", "Kopii fingrospuron"), ("no fingerprints", "Neniuj fingrospuroj"), - ("Select a peer", "Elekti samulon"), - ("Select peers", "Elekti samulojn"), - ("Plugins", "Kromprogramoj"), ("Uninstall", "Malinstali"), ("Update", "Ĝisdatigi"), ("Enable", "Ebligi"), diff --git a/src/lang/es.rs b/src/lang/es.rs index 2e7ace9cf..7f12ef41e 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Huella digital"), ("Copy Fingerprint", "Copiar huella digital"), ("no fingerprints", "sin huellas digitales"), - ("Select a peer", "Seleccionar un par"), - ("Select peers", "Seleccionar pares"), - ("Plugins", "Complementos"), ("Uninstall", "Desinstalar"), ("Update", "Actualizar"), ("Enable", "Habilitar"), diff --git a/src/lang/et.rs b/src/lang/et.rs index 238c84c88..d8cd510bb 100644 --- a/src/lang/et.rs +++ b/src/lang/et.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Sõrmejälg"), ("Copy Fingerprint", "Kopeeri sõrmejälg"), ("no fingerprints", "Sõrmejäljed puuduvad"), - ("Select a peer", "Vali partner"), - ("Select peers", "Vali partnerid"), - ("Plugins", "Pluginad"), ("Uninstall", "Desinstalli"), ("Update", "Uuenda"), ("Enable", "Luba"), diff --git a/src/lang/eu.rs b/src/lang/eu.rs index 3fd38eb55..838b26353 100644 --- a/src/lang/eu.rs +++ b/src/lang/eu.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Hatz-marka"), ("Copy Fingerprint", "Kopiatu hatz-marka"), ("no fingerprints", "hatz-markarik ez"), - ("Select a peer", "Hautatu parekidea"), - ("Select peers", "Hautatu parekideak"), - ("Plugins", "Pluginak"), ("Uninstall", "Desinstalatu"), ("Update", "Eguneratu"), ("Enable", "Gaitu"), diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 1e4039be7..08dc9f568 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "\n اثر انگشت"), ("Copy Fingerprint", "کپی کردن اثر انگشت"), ("no fingerprints", "بدون اثر انگشت"), - ("Select a peer", "یک همتا را انتخاب کنید"), - ("Select peers", "همتایان را انتخاب کنید"), - ("Plugins", "پلاگین ها"), ("Uninstall", "حذف نصب"), ("Update", "به روز رسانی"), ("Enable", "فعال کردن"), diff --git a/src/lang/fi.rs b/src/lang/fi.rs index 2a21ba049..d86cad0c7 100644 --- a/src/lang/fi.rs +++ b/src/lang/fi.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Sormenjälki"), ("Copy Fingerprint", "Kopioi sormenjälki"), ("no fingerprints", "Ei sormenjälkiä"), - ("Select a peer", "Valitse vastapää"), - ("Select peers", "Valitse useita vastapään laitteita"), - ("Plugins", "Laajennukset"), ("Uninstall", "Poista asennus"), ("Update", "Päivitä"), ("Enable", "Ota käyttöön"), diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 8359587a2..a20c0e41b 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Empreinte numérique"), ("Copy Fingerprint", "Copier l’empreinte numérique"), ("no fingerprints", "Aucune empreinte numérique"), - ("Select a peer", "Sélectionnez l’appareil distant"), - ("Select peers", "Sélectionnez les appareils distants"), - ("Plugins", "Plugins"), ("Uninstall", "Désinstaller"), ("Update", "Mettre à jour"), ("Enable", "Activer"), diff --git a/src/lang/ge.rs b/src/lang/ge.rs index 97c3e9171..ce6e89bb4 100644 --- a/src/lang/ge.rs +++ b/src/lang/ge.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "ანაბეჭდი"), ("Copy Fingerprint", "ანაბეჭდის კოპირება"), ("no fingerprints", "ანაბეჭდები არ არის"), - ("Select a peer", "აირჩიეთ დისტანციური კვანძი"), - ("Select peers", "აირჩიეთ დისტანციური კვანძები"), - ("Plugins", "დანამატები"), ("Uninstall", "წაშლა"), ("Update", "განახლება"), ("Enable", "ჩართვა"), diff --git a/src/lang/gu.rs b/src/lang/gu.rs index c9c2c9177..31e905ea7 100644 --- a/src/lang/gu.rs +++ b/src/lang/gu.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "ફિંગરપ્રિન્ટ"), ("Copy Fingerprint", "ફિંગરપ્રિન્ટ કોપી કરો"), ("no fingerprints", "કોઈ ફિંગરપ્રિન્ટ નથી"), - ("Select a peer", "એક પીઅર પસંદ કરો"), - ("Select peers", "પીઅર્સ પસંદ કરો"), - ("Plugins", "પ્લગઇન્સ"), ("Uninstall", "અનઇન્સ્ટોલ કરો"), ("Update", "અપડેટ કરો"), ("Enable", "સક્ષમ કરો"), diff --git a/src/lang/he.rs b/src/lang/he.rs index 3ea0d7626..b82f66dab 100644 --- a/src/lang/he.rs +++ b/src/lang/he.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "טביעת אצבע"), ("Copy Fingerprint", "העתק טביעת אצבע"), ("no fingerprints", "אין טביעות אצבע"), - ("Select a peer", "בחר עמית"), - ("Select peers", "בחר עמיתים"), - ("Plugins", "תוספים"), ("Uninstall", "הסר"), ("Update", "עדכן"), ("Enable", "פועל"), diff --git a/src/lang/hi.rs b/src/lang/hi.rs index e3851a0d8..1e5d3a0b5 100644 --- a/src/lang/hi.rs +++ b/src/lang/hi.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "फिंगरप्रिंट"), ("Copy Fingerprint", "फिंगरप्रिंट कॉपी करें"), ("no fingerprints", "कोई फिंगरप्रिंट नहीं"), - ("Select a peer", "एक पीयर (Peer) चुनें"), - ("Select peers", "पीयर्स चुनें"), - ("Plugins", "प्लगइन्स"), ("Uninstall", "अनइंस्टॉल करें"), ("Update", "अपडेट करें"), ("Enable", "सक्षम करें"), diff --git a/src/lang/hr.rs b/src/lang/hr.rs index ee894b0e7..a05462292 100644 --- a/src/lang/hr.rs +++ b/src/lang/hr.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Otisak"), ("Copy Fingerprint", "Kopirat otisak"), ("no fingerprints", "nema otiska"), - ("Select a peer", "Izbor druge strane"), - ("Select peers", "Odaberite druge strane"), - ("Plugins", "Dodaci"), ("Uninstall", "Deinstaliraj"), ("Update", "Ažuriraj"), ("Enable", "Dopustiti"), diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 14a85f1f7..68d26c389 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Ujjlenyomat"), ("Copy Fingerprint", "Ujjlenyomat másolása"), ("no fingerprints", "nincsenek ujjlenyomatok"), - ("Select a peer", "Egy távoli állomás kiválasztása"), - ("Select peers", "Távoli állomások kiválasztása"), - ("Plugins", "Beépülő modulok"), ("Uninstall", "Eltávolítás"), ("Update", "Frissítés"), ("Enable", "Engedélyezés"), diff --git a/src/lang/id.rs b/src/lang/id.rs index 7ba387e48..c51c908a4 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Sidik jari"), ("Copy Fingerprint", "Salin sidik jari"), ("no fingerprints", "Tidak ada sidik jari"), - ("Select a peer", "Pilih rekan"), - ("Select peers", "Pilih rekan-rekan"), - ("Plugins", "Plugin"), ("Uninstall", "Hapus instalasi"), ("Update", "Perbarui"), ("Enable", "Aktifkan"), diff --git a/src/lang/it.rs b/src/lang/it.rs index 1297972df..939048e3b 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Firma digitale"), ("Copy Fingerprint", "Copia firma digitale"), ("no fingerprints", "Nessuna firma digitale"), - ("Select a peer", "Seleziona dispositivo remoto"), - ("Select peers", "Seleziona dispositivi remoti"), - ("Plugins", "Plugin"), ("Uninstall", "Disinstalla"), ("Update", "Aggiorna"), ("Enable", "Abilita"), diff --git a/src/lang/ja.rs b/src/lang/ja.rs index ba6e6cb09..2d944bf8f 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "フィンガープリント"), ("Copy Fingerprint", "フィンガープリントをコピー"), ("no fingerprints", "フィンガープリントがありません"), - ("Select a peer", "リモートコンピューターを選択"), - ("Select peers", "複数のリモートコンピューターを選択"), - ("Plugins", "プラグイン"), ("Uninstall", "アンインストール"), ("Update", "更新"), ("Enable", "有効"), diff --git a/src/lang/ko.rs b/src/lang/ko.rs index f60af542b..d46c327d3 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "지문"), ("Copy Fingerprint", "지문 복사"), ("no fingerprints", "지문이 없습니다"), - ("Select a peer", "피어 선택"), - ("Select peers", "피어 선택"), - ("Plugins", "플러그인"), ("Uninstall", "설치 제거"), ("Update", "업데이트"), ("Enable", "허용"), diff --git a/src/lang/kz.rs b/src/lang/kz.rs index fc59efde3..b73b8dac0 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Саусақ ізі"), ("Copy Fingerprint", "Саусақ ізін көшіру"), ("no fingerprints", "Саусақ іздері жоқ"), - ("Select a peer", "Пир таңдау"), - ("Select peers", "Пирлерді таңдау"), - ("Plugins", "Плагиндер"), ("Uninstall", "Жою"), ("Update", "Жаңарту"), ("Enable", "Қосу"), diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 3589a2fb3..5c26e3119 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Kontrolinis kodas"), ("Copy Fingerprint", "Kopijuoti kontrolinį kodą"), ("no fingerprints", "Nėra kontrolinių kodų"), - ("Select a peer", "Pasirinkite įrenginį"), - ("Select peers", "Pasirinkite įrenginius"), - ("Plugins", "Papildiniai"), ("Uninstall", "Pašalinti"), ("Update", "Atnaujinti"), ("Enable", "Įgalinti"), diff --git a/src/lang/lv.rs b/src/lang/lv.rs index d4101d6db..7ae317893 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Pirkstu nospiedums"), ("Copy Fingerprint", "Kopēt pirkstu nospiedumu"), ("no fingerprints", "nav pirkstu nospiedumu"), - ("Select a peer", "Atlasīt līdzīgu"), - ("Select peers", "Atlasīt līdzīgus"), - ("Plugins", "Spraudņi"), ("Uninstall", "Atinstalēt"), ("Update", "Atjaunināt"), ("Enable", "Iespējot"), diff --git a/src/lang/ml.rs b/src/lang/ml.rs index d93760b50..69394909b 100644 --- a/src/lang/ml.rs +++ b/src/lang/ml.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "ഫിംഗർപ്രിന്റ്"), ("Copy Fingerprint", "ഫിംഗർപ്രിന്റ് കോപ്പി ചെയ്യുക"), ("no fingerprints", "ഫിംഗർപ്രിന്റുകൾ ഇല്ല"), - ("Select a peer", "ഒരാളെ തിരഞ്ഞെടുക്കുക"), - ("Select peers", "തിരഞ്ഞെടുക്കുക"), - ("Plugins", "പ്ലഗിനുകൾ"), ("Uninstall", "അൺഇൻസ്റ്റാൾ ചെയ്യുക"), ("Update", "അപ്ഡേറ്റ് ചെയ്യുക"), ("Enable", "പ്രവർത്തനക്ഷമമാക്കുക"), diff --git a/src/lang/nb.rs b/src/lang/nb.rs index 3cc71a96b..cf0009314 100644 --- a/src/lang/nb.rs +++ b/src/lang/nb.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Fingeravtrykk"), ("Copy Fingerprint", "Kopier fingeravtrykk"), ("no fingerprints", "Ingen fingeravtrykk"), - ("Select a peer", "Velg en motpart"), - ("Select peers", "Velg motparter"), - ("Plugins", "Programtillegg"), ("Uninstall", "Avinstaller"), ("Update", "Oppdater"), ("Enable", "Aktiver"), diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 61a5306c9..68206f0d6 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Vingerafdruk"), ("Copy Fingerprint", "Vingerafdruk kopiëren"), ("no fingerprints", "geen vingerafdrukken"), - ("Select a peer", "Selecteer een peer"), - ("Select peers", "Selecteer peers"), - ("Plugins", "Plugins"), ("Uninstall", "Verwijderen"), ("Update", "Bijwerken"), ("Enable", "Activeren"), diff --git a/src/lang/pl.rs b/src/lang/pl.rs index df5c53439..0e2e03f02 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Sygnatura"), ("Copy Fingerprint", "Skopiuj sygnaturę"), ("no fingerprints", "brak sygnatur"), - ("Select a peer", "Wybierz zdalne urządzenie"), - ("Select peers", "Wybierz zdalne urządzenia"), - ("Plugins", "Wtyczki"), ("Uninstall", "Odinstaluj"), ("Update", "Aktualizuj"), ("Enable", "Włącz"), diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 79420e73b..a391fcfdc 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Impressão digital"), ("Copy Fingerprint", "Copiar impressão digital"), ("no fingerprints", "Sem impressões digitais"), - ("Select a peer", "Selecionar um destino"), - ("Select peers", "Selecionar destinos"), - ("Plugins", "Plugins"), ("Uninstall", "Desinstalar"), ("Update", "Atualizar"), ("Enable", "Ativar"), diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 61bf5cf48..522b3f8b8 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Impressão Digital"), ("Copy Fingerprint", "Copiar Impressão Digital"), ("no fingerprints", "sem Impressões Digitais"), - ("Select a peer", "Selecione um parceiro"), - ("Select peers", "Selecione parceiros"), - ("Plugins", "Plugins"), ("Uninstall", "Desinstalar"), ("Update", "Atualizar"), ("Enable", "Habilitar"), diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 4499df1bd..cc774057e 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Amprentă digitală"), ("Copy Fingerprint", "Copiază amprenta digitală"), ("no fingerprints", "Nicio amprentă digitală"), - ("Select a peer", "Selectează un dispozitiv pereche"), - ("Select peers", "Selectează dispozitive pereche"), - ("Plugins", "Pluginuri"), ("Uninstall", "Dezinstalează"), ("Update", "Actualizează"), ("Enable", "Activează"), diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 459549f97..2ded4ebf5 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Отпечаток"), ("Copy Fingerprint", "Копировать отпечаток"), ("no fingerprints", "отпечатки отсутствуют"), - ("Select a peer", "Выберите удалённый узел"), - ("Select peers", "Выберите удалённые узлы"), - ("Plugins", "Плагины"), ("Uninstall", "Удалить"), ("Update", "Обновить"), ("Enable", "Включить"), diff --git a/src/lang/sc.rs b/src/lang/sc.rs index 1ccfcf7dc..6bb1190c1 100644 --- a/src/lang/sc.rs +++ b/src/lang/sc.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Firma digitale"), ("Copy Fingerprint", "Còpia firma digitale"), ("no fingerprints", "Peruna firma digitale"), - ("Select a peer", "Seletziona su dispositivu remotu"), - ("Select peers", "Seletziona sos dispositivos remotos"), - ("Plugins", "Cumplementos"), ("Uninstall", "Disinstalla"), ("Update", "Atualiza"), ("Enable", "Abìlita"), diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 3d4993115..96eb423ef 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Odtlačok prsta"), ("Copy Fingerprint", "Kopírovať odtlačok prsta"), ("no fingerprints", "žiadne odtlačky prstov"), - ("Select a peer", "Výber partnera"), - ("Select peers", "Výber partnerov"), - ("Plugins", "Pluginy"), ("Uninstall", "Odinštalovať"), ("Update", "Aktualizovať"), ("Enable", "Povoliť"), diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 10fc5d909..82f177428 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Prstni odtis"), ("Copy Fingerprint", "Kopiraj prstni odtis"), ("no fingerprints", "ni prstnega odtisa"), - ("Select a peer", "Izberite partnerja"), - ("Select peers", "Izberite partnerje"), - ("Plugins", "Vključki"), ("Uninstall", "Odstrani"), ("Update", "Posodobi"), ("Enable", "Omogoči"), diff --git a/src/lang/sq.rs b/src/lang/sq.rs index 91f5d4c7a..103a1bfe9 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Gjurma e gishtit"), ("Copy Fingerprint", "Kopjo gjurmën e gishtit"), ("no fingerprints", "Nuk ka gjurmë gishtash"), - ("Select a peer", "Zgjidh një peer"), - ("Select peers", "Zgjidh peer-at"), - ("Plugins", "Shtojcat"), ("Uninstall", "Çinstalo"), ("Update", "Përditëso"), ("Enable", "Aktivizo"), diff --git a/src/lang/sr.rs b/src/lang/sr.rs index b79eccf5b..c58f7b174 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Otisak"), ("Copy Fingerprint", "Kopiraj otisak"), ("no fingerprints", "Nema otisaka"), - ("Select a peer", "Izaberi klijenta"), - ("Select peers", "Izaberi klijente"), - ("Plugins", "Dodaci"), ("Uninstall", "Deinstaliraj"), ("Update", "Ažuriraj"), ("Enable", "Omogući"), diff --git a/src/lang/sv.rs b/src/lang/sv.rs index 79dd316cd..5075bd6d4 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Fingeravtryck"), ("Copy Fingerprint", "Kopiera fingeravtryck"), ("no fingerprints", "inga fingeravtryck"), - ("Select a peer", "Välj en klient"), - ("Select peers", "Välj klienter"), - ("Plugins", "Plugin"), ("Uninstall", "Avinstallera"), ("Update", "Uppdatera"), ("Enable", "Aktivera"), diff --git a/src/lang/ta.rs b/src/lang/ta.rs index 376af972e..37af3a97d 100644 --- a/src/lang/ta.rs +++ b/src/lang/ta.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "கைரேகை"), ("Copy Fingerprint", "கைரேகை நகல்"), ("no fingerprints", "கைரேகைகள் இல்லை"), - ("Select a peer", "பியர் தேர்வு"), - ("Select peers", "பியர்கள் தேர்வு"), - ("Plugins", "இணைப்புகள்"), ("Uninstall", "நிறுவல் நீக்கு"), ("Update", "புதுப்பி"), ("Enable", "இயக்கு"), diff --git a/src/lang/template.rs b/src/lang/template.rs index f16cf1ebc..e31425369 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", ""), ("Copy Fingerprint", ""), ("no fingerprints", ""), - ("Select a peer", ""), - ("Select peers", ""), - ("Plugins", ""), ("Uninstall", ""), ("Update", ""), ("Enable", ""), diff --git a/src/lang/th.rs b/src/lang/th.rs index bd87cf5a7..8e2c33ebb 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "ลายนิ้วมือ"), ("Copy Fingerprint", "คัดลอกลายนิ้วมือ"), ("no fingerprints", "ไม่มีลายนิ้วมือ"), - ("Select a peer", "เลือกผู้ใช้งาน"), - ("Select peers", "เลือกผู้ใช้งาน"), - ("Plugins", "ปลั๊กอิน"), ("Uninstall", "ถอนการติดตั้ง"), ("Update", "อัปเดต"), ("Enable", "เปิดใช้งาน"), diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 2925ce792..f548e39de 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Parmak İzi"), ("Copy Fingerprint", "Parmak İzini Kopyala"), ("no fingerprints", "parmak izi yok"), - ("Select a peer", "Bir cihaz seçin"), - ("Select peers", "Cihazları seçin"), - ("Plugins", "Eklentiler"), ("Uninstall", "Kaldır"), ("Update", "Güncelle"), ("Enable", "Etkinleştir"), diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 438cb8091..6e22e4d79 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "指紋"), ("Copy Fingerprint", "複製指紋"), ("no fingerprints", "沒有指紋"), - ("Select a peer", "選擇夥伴"), - ("Select peers", "選擇夥伴"), - ("Plugins", "外掛程式"), ("Uninstall", "解除安裝"), ("Update", "更新"), ("Enable", "啟用"), diff --git a/src/lang/uk.rs b/src/lang/uk.rs index 7e55426d1..f03bcb089 100644 --- a/src/lang/uk.rs +++ b/src/lang/uk.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Відбитки пальців"), ("Copy Fingerprint", "Копіювати відбитки пальців"), ("no fingerprints", "немає відбитків пальців"), - ("Select a peer", "Оберіть віддалений пристрій"), - ("Select peers", "Оберіть віддалені пристрої"), - ("Plugins", "Плагіни"), ("Uninstall", "Видалити"), ("Update", "Оновити"), ("Enable", "Увімкнути"), diff --git a/src/lang/vi.rs b/src/lang/vi.rs index af358831e..0b9421ba4 100644 --- a/src/lang/vi.rs +++ b/src/lang/vi.rs @@ -483,9 +483,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Fingerprint", "Dấu vân tay"), ("Copy Fingerprint", "Sao chép fingerprint"), ("no fingerprints", "không có fingerprint"), - ("Select a peer", "Chọn một đối tác"), - ("Select peers", "Chọn các đối tác"), - ("Plugins", "Plugin"), ("Uninstall", "Gỡ cài đặt"), ("Update", "Cập nhật"), ("Enable", "Bật"), diff --git a/src/lib.rs b/src/lib.rs index 49cb2b7e9..20d5d6aab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,10 +46,6 @@ mod lang; #[cfg(not(any(target_os = "android", target_os = "ios")))] mod port_forward; -#[cfg(all(feature = "flutter", feature = "plugin_framework"))] -#[cfg(not(any(target_os = "android", target_os = "ios")))] -pub mod plugin; - #[cfg(not(any(target_os = "android", target_os = "ios")))] mod tray; diff --git a/src/plugin/callback_ext.rs b/src/plugin/callback_ext.rs deleted file mode 100644 index 715f47f7e..000000000 --- a/src/plugin/callback_ext.rs +++ /dev/null @@ -1,44 +0,0 @@ -// External support for callback. -// 1. Support block input for some plugins. -// ----------------------------------------------------------------------------- - -use super::*; - -const EXT_SUPPORT_BLOCK_INPUT: &str = "block-input"; - -pub(super) fn ext_support_callback( - id: &str, - peer: &str, - msg: &super::callback_msg::MsgToExtSupport, -) -> PluginReturn { - match &msg.r#type as _ { - EXT_SUPPORT_BLOCK_INPUT => { - // let supported_plugins = []; - // let supported = supported_plugins.contains(&id); - let supported = true; - if supported { - if msg.data.len() != 1 { - return PluginReturn::new( - errno::ERR_CALLBACK_INVALID_ARGS, - "Invalid data length", - ); - } - let block = msg.data[0] != 0; - if crate::server::plugin_block_input(peer, block) == block { - PluginReturn::success() - } else { - PluginReturn::new(errno::ERR_CALLBACK_FAILED, "") - } - } else { - PluginReturn::new( - errno::ERR_CALLBACK_PLUGIN_ID, - &format!("This operation is not supported for plugin '{}', please contact the RustDesk team for support.", id), - ) - } - } - _ => PluginReturn::new( - errno::ERR_CALLBACK_TARGET_TYPE, - &format!("Unknown target type '{}'", &msg.r#type), - ), - } -} diff --git a/src/plugin/callback_msg.rs b/src/plugin/callback_msg.rs deleted file mode 100644 index 2a23b03dd..000000000 --- a/src/plugin/callback_msg.rs +++ /dev/null @@ -1,411 +0,0 @@ -use super::*; -use crate::hbbs_http::create_http_client; -use crate::{ - flutter::{self, APP_TYPE_CM, APP_TYPE_MAIN, SESSIONS}, - ui_interface::get_api_server, -}; -use hbb_common::{lazy_static, log, message_proto::PluginRequest}; -use serde_derive::{Deserialize, Serialize}; -use serde_json; -use std::{ - collections::HashMap, - ffi::{c_char, c_void}, - sync::Arc, - thread, - time::Duration, -}; - -const MSG_TO_RUSTDESK_TARGET: &str = "rustdesk"; -const MSG_TO_PEER_TARGET: &str = "peer"; -const MSG_TO_UI_TARGET: &str = "ui"; -const MSG_TO_CONFIG_TARGET: &str = "config"; -const MSG_TO_EXT_SUPPORT_TARGET: &str = "ext-support"; - -const MSG_TO_RUSTDESK_SIGNATURE_VERIFICATION: &str = "signature_verification"; - -#[allow(dead_code)] -const MSG_TO_UI_FLUTTER_CHANNEL_MAIN: u16 = 0x01 << 0; -#[allow(dead_code)] -#[cfg(not(any(target_os = "android", target_os = "ios")))] -const MSG_TO_UI_FLUTTER_CHANNEL_CM: u16 = 0x01 << 1; -#[cfg(any(target_os = "android", target_os = "ios"))] -const MSG_TO_UI_FLUTTER_CHANNEL_CM: u16 = 0x01; -const MSG_TO_UI_FLUTTER_CHANNEL_REMOTE: u16 = 0x01 << 2; -#[allow(dead_code)] -const MSG_TO_UI_FLUTTER_CHANNEL_TRANSFER: u16 = 0x01 << 3; -#[allow(dead_code)] -const MSG_TO_UI_FLUTTER_CHANNEL_FORWARD: u16 = 0x01 << 4; - -lazy_static::lazy_static! { - static ref MSG_TO_UI_FLUTTER_CHANNELS: Arc> = { - let channels = HashMap::from([ - (MSG_TO_UI_FLUTTER_CHANNEL_MAIN, APP_TYPE_MAIN.to_string()), - (MSG_TO_UI_FLUTTER_CHANNEL_CM, APP_TYPE_CM.to_string()), - ]); - Arc::new(channels) - }; -} - -#[derive(Deserialize)] -pub struct MsgToRustDesk { - pub r#type: String, - pub data: Vec, -} - -#[derive(Deserialize)] -pub struct SignatureVerification { - pub version: String, - pub data: Vec, -} - -#[derive(Debug, Deserialize)] -struct ConfigToUi { - channel: u16, - location: String, -} - -#[derive(Debug, Deserialize)] -struct MsgToConfig { - r#type: String, - key: String, - value: String, - #[serde(skip_serializing_if = "Option::is_none")] - ui: Option, // If not None, send msg to ui. -} - -#[derive(Debug, Deserialize)] -pub(super) struct MsgToExtSupport { - pub r#type: String, - pub data: Vec, -} - -#[derive(Debug, Serialize)] -struct PluginSignReq { - plugin_id: String, - version: String, - msg: Vec, -} - -#[derive(Debug, Deserialize)] -struct PluginSignResp { - signed_msg: Vec, -} - -macro_rules! cb_msg_field { - ($field: ident) => { - let $field = match cstr_to_string($field) { - Err(e) => { - let msg = format!("Failed to convert {} to string, {}", stringify!($field), e); - log::error!("{}", &msg); - return PluginReturn::new(errno::ERR_CALLBACK_INVALID_ARGS, &msg); - } - Ok(v) => v, - }; - }; -} - -macro_rules! early_return_value { - ($e:expr, $code: ident, $($arg:tt)*) => { - match $e { - Err(e) => return PluginReturn::new( - errno::$code, - &format!("Failed to {} '{}'", format_args!($($arg)*), e), - ), - Ok(v) => v, - } - }; -} - -/// Callback to send message to peer or ui. -/// peer, target, id are utf8 strings(null terminated). -/// -/// peer: The peer id. -/// target: "peer" or "ui". -/// id: The id of this plugin. -/// content: The content. -/// len: The length of the content. -/// -/// Return null ptr if success. -/// Return the error message if failed. `i32-String` without dash, i32 is a signed little-endian number, the String is utf8 string. -/// The plugin allocate memory with `libc::malloc` and return the pointer. -#[no_mangle] -pub(super) extern "C" fn cb_msg( - peer: *const c_char, - target: *const c_char, - id: *const c_char, - content: *const c_void, - len: usize, -) -> PluginReturn { - cb_msg_field!(target); - cb_msg_field!(id); - - match &target as _ { - MSG_TO_PEER_TARGET => { - cb_msg_field!(peer); - if let Some(session) = SESSIONS.write().unwrap().get_mut(&peer) { - let content_slice = - unsafe { std::slice::from_raw_parts(content as *const u8, len) }; - let content_vec = Vec::from(content_slice); - let request = PluginRequest { - id, - content: bytes::Bytes::from(content_vec), - ..Default::default() - }; - session.send_plugin_request(request); - PluginReturn::success() - } else { - PluginReturn::new( - errno::ERR_CALLBACK_PEER_NOT_FOUND, - &format!("Failed to find session for peer '{}'", peer), - ) - } - } - MSG_TO_UI_TARGET => { - cb_msg_field!(peer); - let content_slice = unsafe { std::slice::from_raw_parts(content as *const u8, len) }; - let channel = u16::from_le_bytes([content_slice[0], content_slice[1]]); - let content = std::string::String::from_utf8(content_slice[2..].to_vec()) - .unwrap_or("".to_string()); - push_event_to_ui(channel, &peer, &content); - PluginReturn::success() - } - MSG_TO_CONFIG_TARGET => { - cb_msg_field!(peer); - let s = early_return_value!( - std::str::from_utf8(unsafe { std::slice::from_raw_parts(content as _, len) }), - ERR_CALLBACK_INVALID_MSG, - "parse msg string" - ); - // No need to merge the msgs. Handling the msg one by one is ok. - let msg = early_return_value!( - serde_json::from_str::(s), - ERR_CALLBACK_INVALID_MSG, - "parse msg '{}'", - s - ); - match &msg.r#type as _ { - config::CONFIG_TYPE_SHARED => { - let _r = early_return_value!( - config::SharedConfig::set(&id, &msg.key, &msg.value), - ERR_CALLBACK_INVALID_MSG, - "set local config" - ); - if let Some(ui) = &msg.ui { - // No need to set the peer id for location config. - push_option_to_ui(ui.channel, &id, "", &msg, ui); - } - PluginReturn::success() - } - config::CONFIG_TYPE_PEER => { - let _r = early_return_value!( - config::PeerConfig::set(&id, &peer, &msg.key, &msg.value), - ERR_CALLBACK_INVALID_MSG, - "set peer config" - ); - if let Some(ui) = &msg.ui { - push_option_to_ui(ui.channel, &id, &peer, &msg, ui); - } - PluginReturn::success() - } - _ => PluginReturn::new( - errno::ERR_CALLBACK_TARGET_TYPE, - &format!("Unknown target type '{}'", &msg.r#type), - ), - } - } - MSG_TO_EXT_SUPPORT_TARGET => { - cb_msg_field!(peer); - let s = early_return_value!( - std::str::from_utf8(unsafe { std::slice::from_raw_parts(content as _, len) }), - ERR_CALLBACK_INVALID_MSG, - "parse msg string" - ); - let msg = early_return_value!( - serde_json::from_str::(s), - ERR_CALLBACK_INVALID_MSG, - "parse msg '{}'", - s - ); - super::callback_ext::ext_support_callback(&id, &peer, &msg) - } - MSG_TO_RUSTDESK_TARGET => handle_msg_to_rustdesk(id, content, len), - _ => PluginReturn::new( - errno::ERR_CALLBACK_TARGET, - &format!("Unknown target '{}'", target), - ), - } -} - -#[inline] -fn is_peer_channel(channel: u16) -> bool { - channel & MSG_TO_UI_FLUTTER_CHANNEL_REMOTE != 0 - || channel & MSG_TO_UI_FLUTTER_CHANNEL_TRANSFER != 0 - || channel & MSG_TO_UI_FLUTTER_CHANNEL_FORWARD != 0 -} - -fn handle_msg_to_rustdesk(id: String, content: *const c_void, len: usize) -> PluginReturn { - let s = early_return_value!( - std::str::from_utf8(unsafe { std::slice::from_raw_parts(content as _, len) }), - ERR_CALLBACK_INVALID_MSG, - "parse msg string" - ); - let msg_to_rustdesk = early_return_value!( - serde_json::from_str::(s), - ERR_CALLBACK_INVALID_MSG, - "parse msg '{}'", - s - ); - match &msg_to_rustdesk.r#type as &str { - MSG_TO_RUSTDESK_SIGNATURE_VERIFICATION => request_plugin_sign(id, msg_to_rustdesk), - t => PluginReturn::new( - errno::ERR_CALLBACK_TARGET_TYPE, - &format!( - "Unknown target type '{}' for target {}", - t, MSG_TO_RUSTDESK_TARGET - ), - ), - } -} - -fn request_plugin_sign(id: String, msg_to_rustdesk: MsgToRustDesk) -> PluginReturn { - let signature_data = early_return_value!( - std::str::from_utf8(&msg_to_rustdesk.data), - ERR_CALLBACK_INVALID_MSG, - "parse signature data string" - ); - let signature_data = early_return_value!( - serde_json::from_str::(signature_data), - ERR_CALLBACK_INVALID_MSG, - "parse signature data '{}'", - signature_data - ); - thread::spawn(move || { - let sign_url = format!("{}/lic/web/api/plugin-sign", get_api_server()); - let client = create_http_client(); - let req = PluginSignReq { - plugin_id: id.clone(), - version: signature_data.version, - msg: signature_data.data, - }; - match client - .post(sign_url) - .json(&req) - .timeout(Duration::from_secs(10)) - .send() - { - Ok(response) => match response.json::() { - Ok(sign_resp) => { - match super::plugins::plugin_call( - &id, - super::plugins::METHOD_HANDLE_SIGNATURE_VERIFICATION, - "", - &sign_resp.signed_msg, - ) { - Ok(..) => { - match super::plugins::plugin_call_get_return( - &id, - super::plugins::METHOD_HANDLE_STATUS, - "", - &[], - ) { - Ok(ret) => { - debug_assert!(!ret.msg.is_null(), "msg is null"); - if ret.msg.is_null() { - // unreachable - log::error!( - "The returned message pointer of plugin status is null, plugin id: '{}', code: {}", - id, - ret.code, - ); - return; - } - let msg = cstr_to_string(ret.msg).unwrap_or_default(); - free_c_ptr(ret.msg as _); - if ret.code == super::errno::ERR_SUCCESS { - log::info!("Plugin '{}' status: '{}'", id, msg); - } else { - log::error!( - "Failed to handle plugin event, id: {}, method: {}, code: {}, msg: {}", - id, - std::string::String::from_utf8(super::plugins::METHOD_HANDLE_STATUS.to_vec()).unwrap_or_default(), - ret.code, - msg - ); - } - } - Err(e) => { - log::error!( - "Failed to call status for plugin '{}': {}", - &id, - e - ); - } - } - } - Err(e) => { - log::error!( - "Failed to call signature verification for plugin '{}': {}", - &id, - e - ); - } - } - } - Err(e) => { - log::error!("Failed to decode response for plugin '{}': {}", &id, e); - } - }, - Err(e) => { - log::error!("Failed to request sign for plugin '{}', {}", &id, e); - } - } - }); - PluginReturn::success() -} - -fn push_event_to_ui(channel: u16, peer: &str, content: &str) { - let mut m = HashMap::new(); - m.insert("name", MSG_TO_UI_TYPE_PLUGIN_EVENT); - m.insert("peer", &peer); - m.insert("content", &content); - let event = serde_json::to_string(&m).unwrap_or("".to_string()); - // Send to main and cm - for (k, v) in MSG_TO_UI_FLUTTER_CHANNELS.iter() { - if channel & k != 0 { - let _res = flutter::push_global_event(v as _, event.to_string()); - } - } - if !peer.is_empty() && is_peer_channel(channel) { - let _res = flutter::push_session_event( - &peer, - MSG_TO_UI_TYPE_PLUGIN_EVENT, - vec![("peer", &peer), ("content", &content)], - ); - } -} - -fn push_option_to_ui(channel: u16, id: &str, peer: &str, msg: &MsgToConfig, ui: &ConfigToUi) { - let v = [ - ("id", id), - ("location", &ui.location), - ("key", &msg.key), - ("value", &msg.value), - ]; - - // Send main and cm - let mut m = HashMap::from(v); - m.insert("name", MSG_TO_UI_TYPE_PLUGIN_OPTION); - let event = serde_json::to_string(&m).unwrap_or("".to_string()); - for (k, v) in MSG_TO_UI_FLUTTER_CHANNELS.iter() { - if channel & k != 0 { - let _res = flutter::push_global_event(v as _, event.to_string()); - } - } - - // Send remote, transfer and forward - if !peer.is_empty() && is_peer_channel(channel) { - let mut v = v.to_vec(); - v.push(("peer", &peer)); - let _res = flutter::push_session_event(&peer, MSG_TO_UI_TYPE_PLUGIN_OPTION, v); - } -} diff --git a/src/plugin/config.rs b/src/plugin/config.rs deleted file mode 100644 index 20cd02a88..000000000 --- a/src/plugin/config.rs +++ /dev/null @@ -1,363 +0,0 @@ -use super::{cstr_to_string, str_to_cstr_ret}; -use hbb_common::{allow_err, bail, config::Config as HbbConfig, lazy_static, log, ResultType}; -use serde_derive::{Deserialize, Serialize}; -use std::{ - collections::HashMap, - ffi::c_char, - fs, - ops::{Deref, DerefMut}, - path::PathBuf, - ptr, - str::FromStr, - sync::{Arc, Mutex}, -}; - -lazy_static::lazy_static! { - static ref CONFIG_SHARED: Arc>> = Default::default(); - static ref CONFIG_PEERS: Arc>> = Default::default(); - static ref CONFIG_MANAGER: Arc> = { - let conf = hbb_common::config::load_path::(ManagerConfig::path()); - Arc::new(Mutex::new(conf)) - }; -} -use crate::ui_interface::get_id; - -pub(super) const CONFIG_TYPE_SHARED: &str = "shared"; -pub(super) const CONFIG_TYPE_PEER: &str = "peer"; - -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct SharedConfig(HashMap); -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct PeerConfig(HashMap); -type PeersConfig = HashMap; - -#[inline] -fn path_plugins(id: &str) -> PathBuf { - HbbConfig::path("plugins").join(id) -} - -pub fn remove(id: &str) { - CONFIG_SHARED.lock().unwrap().remove(id); - CONFIG_PEERS.lock().unwrap().remove(id); - // allow_err is Ok here. - allow_err!(ManagerConfig::remove_plugin(id)); - if let Err(e) = fs::remove_dir_all(path_plugins(id)) { - log::error!("Failed to remove plugin '{}' directory: {}", id, e); - } -} - -impl Deref for SharedConfig { - type Target = HashMap; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for SharedConfig { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl Deref for PeerConfig { - type Target = HashMap; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for PeerConfig { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl SharedConfig { - #[inline] - fn path(id: &str) -> PathBuf { - path_plugins(id).join("shared.toml") - } - - #[inline] - fn load(id: &str) { - let mut lock = CONFIG_SHARED.lock().unwrap(); - if lock.contains_key(id) { - return; - } - let conf = hbb_common::config::load_path::>(Self::path(id)); - let mut conf = SharedConfig(conf); - if let Some(desc_conf) = super::plugins::get_desc_conf(id) { - for item in desc_conf.shared.iter() { - if !conf.contains_key(&item.key) { - conf.insert(item.key.to_owned(), item.default.to_owned()); - } - } - } - lock.insert(id.to_owned(), conf); - } - - #[inline] - fn load_if_not_exists(id: &str) { - if CONFIG_SHARED.lock().unwrap().contains_key(id) { - return; - } - Self::load(id); - } - - #[inline] - pub fn get(id: &str, key: &str) -> Option { - Self::load_if_not_exists(id); - CONFIG_SHARED - .lock() - .unwrap() - .get(id)? - .get(key) - .map(|s| s.to_owned()) - } - - #[inline] - pub fn set(id: &str, key: &str, value: &str) -> ResultType<()> { - Self::load_if_not_exists(id); - match CONFIG_SHARED.lock().unwrap().get_mut(id) { - Some(config) => { - config.insert(key.to_owned(), value.to_owned()); - hbb_common::config::store_path(Self::path(id), config) - } - None => { - // unreachable - bail!("No such plugin {}", id) - } - } - } -} - -impl PeerConfig { - #[inline] - fn path(id: &str, peer: &str) -> PathBuf { - path_plugins(id) - .join("peers") - .join(format!("{}.toml", peer)) - } - - #[inline] - fn load(id: &str, peer: &str) { - let mut lock = CONFIG_PEERS.lock().unwrap(); - if let Some(peers) = lock.get(id) { - if peers.contains_key(peer) { - return; - } - } - - let conf = hbb_common::config::load_path::>(Self::path(id, peer)); - let mut conf = PeerConfig(conf); - if let Some(desc_conf) = super::plugins::get_desc_conf(id) { - for item in desc_conf.peer.iter() { - if !conf.contains_key(&item.key) { - conf.insert(item.key.to_owned(), item.default.to_owned()); - } - } - } - - if let Some(peers) = lock.get_mut(id) { - peers.insert(peer.to_owned(), conf); - return; - } - - let mut peers = HashMap::new(); - peers.insert(peer.to_owned(), conf); - lock.insert(id.to_owned(), peers); - } - - #[inline] - fn load_if_not_exists(id: &str, peer: &str) { - if let Some(peers) = CONFIG_PEERS.lock().unwrap().get(id) { - if peers.contains_key(peer) { - return; - } - } - Self::load(id, peer); - } - - #[inline] - pub fn get(id: &str, peer: &str, key: &str) -> Option { - Self::load_if_not_exists(id, peer); - CONFIG_PEERS - .lock() - .unwrap() - .get(id)? - .get(peer)? - .get(key) - .map(|s| s.to_owned()) - } - - #[inline] - pub fn set(id: &str, peer: &str, key: &str, value: &str) -> ResultType<()> { - Self::load_if_not_exists(id, peer); - match CONFIG_PEERS.lock().unwrap().get_mut(id) { - Some(peers) => match peers.get_mut(peer) { - Some(config) => { - config.insert(key.to_owned(), value.to_owned()); - hbb_common::config::store_path(Self::path(id, peer), config) - } - None => { - // unreachable - bail!("No such peer {}", peer) - } - }, - None => { - // unreachable - bail!("No such plugin {}", id) - } - } - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct PluginStatus { - pub enabled: bool, -} - -const MANAGER_VERSION: &str = "0.1.0"; - -#[derive(Debug, Serialize, Deserialize)] -pub struct ManagerConfig { - pub version: String, - #[serde(default)] - pub options: HashMap, - #[serde(default)] - pub plugins: HashMap, -} - -impl Default for ManagerConfig { - fn default() -> Self { - Self { - version: MANAGER_VERSION.to_owned(), - options: HashMap::new(), - plugins: HashMap::new(), - } - } -} - -// Do not care about the `store_path` error, no need to store the old value and restore if failed. -impl ManagerConfig { - #[inline] - fn path() -> PathBuf { - HbbConfig::path("plugins").join("manager.toml") - } - - #[inline] - pub fn get_option(key: &str) -> Option { - CONFIG_MANAGER - .lock() - .unwrap() - .options - .get(key) - .map(|s| s.to_owned()) - } - - #[inline] - pub fn set_option(key: &str, value: &str) { - let mut lock = CONFIG_MANAGER.lock().unwrap(); - lock.options.insert(key.to_owned(), value.to_owned()); - allow_err!(hbb_common::config::store_path(Self::path(), &*lock)); - } - - #[inline] - pub fn get_plugin_option(id: &str, key: &str) -> Option { - let lock = CONFIG_MANAGER.lock().unwrap(); - match key { - "enabled" => { - let enabled = lock - .plugins - .get(id) - .map(|status| status.enabled.to_owned()) - .unwrap_or(true.to_owned()) - .to_string(); - Some(enabled) - } - _ => None, - } - } - - fn set_plugin_option_enabled(id: &str, enabled: bool) -> ResultType<()> { - let mut lock = CONFIG_MANAGER.lock().unwrap(); - if let Some(status) = lock.plugins.get_mut(id) { - status.enabled = enabled; - } else { - lock.plugins.insert(id.to_owned(), PluginStatus { enabled }); - } - hbb_common::config::store_path(Self::path(), &*lock) - } - - pub fn set_plugin_option(id: &str, key: &str, value: &str) { - match key { - "enabled" => { - let enabled = bool::from_str(value).unwrap_or(false); - allow_err!(Self::set_plugin_option_enabled(id, enabled)); - if enabled { - allow_err!(super::load_plugin(id)); - } else { - super::unload_plugin(id); - } - } - _ => log::error!("No such option {}", key), - } - } - - #[inline] - pub fn add_plugin(id: &str) -> ResultType<()> { - let mut lock = CONFIG_MANAGER.lock().unwrap(); - lock.plugins - .insert(id.to_owned(), PluginStatus { enabled: true }); - hbb_common::config::store_path(Self::path(), &*lock) - } - - #[inline] - pub fn remove_plugin(id: &str) -> ResultType<()> { - let mut lock = CONFIG_MANAGER.lock().unwrap(); - lock.plugins.remove(id); - hbb_common::config::store_path(Self::path(), &*lock) - } -} - -pub(super) extern "C" fn cb_get_local_peer_id() -> *const c_char { - str_to_cstr_ret(&get_id()) -} - -// Return shared config if peer is nullptr. -pub(super) extern "C" fn cb_get_conf( - peer: *const c_char, - id: *const c_char, - key: *const c_char, -) -> *const c_char { - match (cstr_to_string(id), cstr_to_string(key)) { - (Ok(id), Ok(key)) => { - if peer.is_null() { - SharedConfig::load_if_not_exists(&id); - if let Some(conf) = CONFIG_SHARED.lock().unwrap().get(&id) { - if let Some(value) = conf.get(&key) { - return str_to_cstr_ret(value); - } - } - } else { - match cstr_to_string(peer) { - Ok(peer) => { - PeerConfig::load_if_not_exists(&id, &peer); - if let Some(conf) = CONFIG_PEERS.lock().unwrap().get(&id) { - if let Some(conf) = conf.get(&peer) { - if let Some(value) = conf.get(&key) { - return str_to_cstr_ret(value); - } - } - } - } - Err(_) => {} - } - } - } - _ => {} - } - ptr::null() -} diff --git a/src/plugin/desc.rs b/src/plugin/desc.rs deleted file mode 100644 index 883f2afd7..000000000 --- a/src/plugin/desc.rs +++ /dev/null @@ -1,100 +0,0 @@ -use hbb_common::ResultType; -use serde_derive::{Deserialize, Serialize}; -use serde_json; -use std::collections::HashMap; -use std::ffi::{c_char, CStr}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct UiButton { - key: String, - text: String, - icon: String, // icon can be int in flutter, but string in other ui framework. And it is flexible to use string. - tooltip: String, - action: String, // The action to be triggered when the button is clicked. -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct UiCheckbox { - key: String, - text: String, - tooltip: String, - action: String, // The action to be triggered when the checkbox is checked or unchecked. -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(tag = "t", content = "c")] -pub enum UiType { - Button(UiButton), - Checkbox(UiCheckbox), -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Location { - pub ui: HashMap>, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ConfigItem { - pub key: String, - pub default: String, - pub description: String, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Config { - pub shared: Vec, - pub peer: Vec, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PublishInfo { - pub published: String, - pub last_released: String, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Meta { - pub id: String, - pub name: String, - pub version: String, - pub description: String, - #[serde(default)] - pub platforms: String, - pub author: String, - pub home: String, - pub license: String, - pub source: String, - pub publish_info: PublishInfo, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Desc { - meta: Meta, - need_reboot: bool, - location: Location, - config: Config, - listen_events: Vec, -} - -impl Desc { - pub fn from_cstr(s: *const c_char) -> ResultType { - let s = unsafe { CStr::from_ptr(s) }; - Ok(serde_json::from_str(s.to_str()?)?) - } - - pub fn meta(&self) -> &Meta { - &self.meta - } - - pub fn location(&self) -> &Location { - &self.location - } - - pub fn config(&self) -> &Config { - &self.config - } - - pub fn listen_events(&self) -> &Vec { - &self.listen_events - } -} diff --git a/src/plugin/errno.rs b/src/plugin/errno.rs deleted file mode 100644 index 6b1e3612d..000000000 --- a/src/plugin/errno.rs +++ /dev/null @@ -1,50 +0,0 @@ -#![allow(dead_code)] - -pub const ERR_SUCCESS: i32 = 0; - -// ====================================================== -// Errors from the plugins, must be handled by RustDesk - -pub const ERR_RUSTDESK_HANDLE_BASE: i32 = 10000; - -// not loaded -pub const ERR_PLUGIN_LOAD: i32 = 10001; -// not initialized -pub const ERR_PLUGIN_MSG_INIT: i32 = 10101; -pub const ERR_PLUGIN_MSG_INIT_INVALID: i32 = 10102; -pub const ERR_PLUGIN_MSG_GET_LOCAL_PEER_ID: i32 = 10103; -pub const ERR_PLUGIN_SIGNATURE_NOT_VERIFIED: i32 = 10104; -pub const ERR_PLUGIN_SIGNATURE_VERIFICATION_FAILED: i32 = 10105; -// invalid -pub const ERR_CALL_UNIMPLEMENTED: i32 = 10201; -pub const ERR_CALL_INVALID_METHOD: i32 = 10202; -pub const ERR_CALL_NOT_SUPPORTED_METHOD: i32 = 10203; -pub const ERR_CALL_INVALID_PEER: i32 = 10204; -// failed on calling -pub const ERR_CALL_INVALID_ARGS: i32 = 10301; -pub const ERR_PEER_ID_MISMATCH: i32 = 10302; -pub const ERR_CALL_CONFIG_VALUE: i32 = 10303; -// no handlers on calling -pub const ERR_NOT_HANDLED: i32 = 10401; - -// ====================================================== -// Errors from RustDesk callbacks. - -pub const ERR_CALLBACK_HANDLE_BASE: i32 = 20000; -pub const ERR_CALLBACK_PLUGIN_ID: i32 = 20001; -pub const ERR_CALLBACK_INVALID_ARGS: i32 = 20002; -pub const ERR_CALLBACK_INVALID_MSG: i32 = 20003; -pub const ERR_CALLBACK_TARGET: i32 = 20004; -pub const ERR_CALLBACK_TARGET_TYPE: i32 = 20005; -pub const ERR_CALLBACK_PEER_NOT_FOUND: i32 = 20006; - -pub const ERR_CALLBACK_FAILED: i32 = 21001; - -// ====================================================== -// Errors from the plugins, should be handled by the plugins. - -pub const ERR_PLUGIN_HANDLE_BASE: i32 = 30000; - -pub const EER_CALL_FAILED: i32 = 30021; -pub const ERR_PEER_ON_FAILED: i32 = 40012; -pub const ERR_PEER_OFF_FAILED: i32 = 40012; diff --git a/src/plugin/ipc.rs b/src/plugin/ipc.rs deleted file mode 100644 index 6a14ab00a..000000000 --- a/src/plugin/ipc.rs +++ /dev/null @@ -1,230 +0,0 @@ -// to-do: Interdependence(This mod and crate::ipc) is not good practice here. -use crate::ipc::{connect, Connection, Data}; -use hbb_common::{allow_err, log, tokio, ResultType}; -use serde_derive::{Deserialize, Serialize}; - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub enum InstallStatus { - Downloading(u8), - Installing, - Finished, - FailedCreating, - FailedDownloading, - FailedInstalling, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(tag = "t", content = "c")] -pub enum Plugin { - Config(String, String, Option), - ManagerConfig(String, Option), - ManagerPluginConfig(String, String, Option), - Load(String), - Reload(String), - InstallStatus((String, InstallStatus)), - Uninstall(String), -} - -#[tokio::main(flavor = "current_thread")] -pub async fn get_config(id: &str, name: &str) -> ResultType> { - get_config_async(id, name, 1_000).await -} - -#[tokio::main(flavor = "current_thread")] -pub async fn set_config(id: &str, name: &str, value: String) -> ResultType<()> { - set_config_async(id, name, value).await -} - -#[tokio::main(flavor = "current_thread")] -pub async fn get_manager_config(name: &str) -> ResultType> { - get_manager_config_async(name, 1_000).await -} - -#[tokio::main(flavor = "current_thread")] -pub async fn set_manager_config(name: &str, value: String) -> ResultType<()> { - set_manager_config_async(name, value).await -} - -#[tokio::main(flavor = "current_thread")] -pub async fn get_manager_plugin_config(id: &str, name: &str) -> ResultType> { - get_manager_plugin_config_async(id, name, 1_000).await -} - -#[tokio::main(flavor = "current_thread")] -pub async fn set_manager_plugin_config(id: &str, name: &str, value: String) -> ResultType<()> { - set_manager_plugin_config_async(id, name, value).await -} - -#[tokio::main(flavor = "current_thread")] -pub async fn load_plugin(id: &str) -> ResultType<()> { - load_plugin_async(id).await -} - -#[tokio::main(flavor = "current_thread")] -pub async fn reload_plugin(id: &str) -> ResultType<()> { - reload_plugin_async(id).await -} - -#[tokio::main(flavor = "current_thread")] -pub async fn uninstall_plugin(id: &str) -> ResultType<()> { - uninstall_plugin_async(id).await -} - -async fn get_config_async(id: &str, name: &str, ms_timeout: u64) -> ResultType> { - let mut c = connect(ms_timeout, "").await?; - c.send(&Data::Plugin(Plugin::Config( - id.to_owned(), - name.to_owned(), - None, - ))) - .await?; - if let Some(Data::Plugin(Plugin::Config(id2, name2, value))) = - c.next_timeout(ms_timeout).await? - { - if id == id2 && name == name2 { - return Ok(value); - } - } - return Ok(None); -} - -async fn set_config_async(id: &str, name: &str, value: String) -> ResultType<()> { - let mut c = connect(1000, "").await?; - c.send(&Data::Plugin(Plugin::Config( - id.to_owned(), - name.to_owned(), - Some(value), - ))) - .await?; - Ok(()) -} - -async fn get_manager_config_async(name: &str, ms_timeout: u64) -> ResultType> { - let mut c = connect(ms_timeout, "").await?; - c.send(&Data::Plugin(Plugin::ManagerConfig(name.to_owned(), None))) - .await?; - if let Some(Data::Plugin(Plugin::ManagerConfig(name2, value))) = - c.next_timeout(ms_timeout).await? - { - if name == name2 { - return Ok(value); - } - } - return Ok(None); -} - -async fn set_manager_config_async(name: &str, value: String) -> ResultType<()> { - let mut c = connect(1000, "").await?; - c.send(&Data::Plugin(Plugin::ManagerConfig( - name.to_owned(), - Some(value), - ))) - .await?; - Ok(()) -} - -async fn get_manager_plugin_config_async( - id: &str, - name: &str, - ms_timeout: u64, -) -> ResultType> { - let mut c = connect(ms_timeout, "").await?; - c.send(&Data::Plugin(Plugin::ManagerPluginConfig( - id.to_owned(), - name.to_owned(), - None, - ))) - .await?; - if let Some(Data::Plugin(Plugin::ManagerPluginConfig(id2, name2, value))) = - c.next_timeout(ms_timeout).await? - { - if id == id2 && name == name2 { - return Ok(value); - } - } - return Ok(None); -} - -async fn set_manager_plugin_config_async(id: &str, name: &str, value: String) -> ResultType<()> { - let mut c = connect(1000, "").await?; - c.send(&Data::Plugin(Plugin::ManagerPluginConfig( - id.to_owned(), - name.to_owned(), - Some(value), - ))) - .await?; - Ok(()) -} - -pub async fn load_plugin_async(id: &str) -> ResultType<()> { - let mut c = connect(1000, "").await?; - c.send(&Data::Plugin(Plugin::Load(id.to_owned()))).await?; - Ok(()) -} - -async fn reload_plugin_async(id: &str) -> ResultType<()> { - let mut c = connect(1000, "").await?; - c.send(&Data::Plugin(Plugin::Reload(id.to_owned()))).await?; - Ok(()) -} - -async fn uninstall_plugin_async(id: &str) -> ResultType<()> { - let mut c = connect(1000, "").await?; - c.send(&Data::Plugin(Plugin::Uninstall(id.to_owned()))) - .await?; - Ok(()) -} - -pub async fn handle_plugin(plugin: Plugin, stream: &mut Connection) { - match plugin { - Plugin::Config(id, name, value) => match value { - None => { - let value = super::SharedConfig::get(&id, &name); - allow_err!( - stream - .send(&Data::Plugin(Plugin::Config(id, name, value))) - .await - ); - } - Some(value) => { - allow_err!(super::SharedConfig::set(&id, &name, &value)); - } - }, - Plugin::ManagerConfig(name, value) => match value { - None => { - let value = super::ManagerConfig::get_option(&name); - allow_err!( - stream - .send(&Data::Plugin(Plugin::ManagerConfig(name, value))) - .await - ); - } - Some(value) => { - super::ManagerConfig::set_option(&name, &value); - } - }, - Plugin::ManagerPluginConfig(id, name, value) => match value { - None => { - let value = super::ManagerConfig::get_plugin_option(&id, &name); - allow_err!( - stream - .send(&Data::Plugin(Plugin::ManagerPluginConfig(id, name, value))) - .await - ); - } - Some(value) => { - super::ManagerConfig::set_plugin_option(&id, &name, &value); - } - }, - Plugin::Load(id) => { - allow_err!(super::load_plugin(&id)); - } - Plugin::Reload(id) => { - allow_err!(super::reload_plugin(&id)); - } - Plugin::Uninstall(id) => { - super::manager::uninstall_plugin(&id, false); - } - _ => {} - } -} diff --git a/src/plugin/manager.rs b/src/plugin/manager.rs deleted file mode 100644 index f59e4c9ff..000000000 --- a/src/plugin/manager.rs +++ /dev/null @@ -1,600 +0,0 @@ -// 1. Check update. -// 2. Install or uninstall. - -use super::{desc::Meta as PluginMeta, ipc::InstallStatus, *}; -use crate::flutter; -use crate::hbbs_http::create_http_client; -use hbb_common::{allow_err, bail, log, tokio, toml}; -use serde_derive::{Deserialize, Serialize}; -use serde_json; -use std::{ - collections::{HashMap, HashSet}, - fs::{read_to_string, remove_dir_all, OpenOptions}, - io::Write, - sync::{Arc, Mutex}, -}; - -const MSG_TO_UI_PLUGIN_MANAGER_LIST: &str = "plugin_list"; -const MSG_TO_UI_PLUGIN_MANAGER_INSTALL: &str = "plugin_install"; -const MSG_TO_UI_PLUGIN_MANAGER_UNINSTALL: &str = "plugin_uninstall"; - -const IPC_PLUGIN_POSTFIX: &str = "_plugin"; - -#[cfg(target_os = "windows")] -const PLUGIN_PLATFORM: &str = "windows"; -#[cfg(target_os = "linux")] -const PLUGIN_PLATFORM: &str = "linux"; -#[cfg(target_os = "macos")] -const PLUGIN_PLATFORM: &str = "macos"; - -lazy_static::lazy_static! { - static ref PLUGIN_INFO: Arc>> = Arc::new(Mutex::new(HashMap::new())); -} - -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct ManagerMeta { - pub version: String, - pub description: String, - pub plugins: Vec, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PluginSource { - pub name: String, - pub url: String, - pub description: String, -} - -#[derive(Debug, Serialize)] -pub struct PluginInfo { - pub source: PluginSource, - pub meta: PluginMeta, - pub installed_version: String, - pub invalid_reason: String, -} - -static PLUGIN_SOURCE_LOCAL: &str = "local"; - -fn get_plugin_source_list() -> Vec { - // Only one source for now. - // vec![PluginSource { - // name: "rustdesk".to_string(), - // url: "https://raw.githubusercontent.com/fufesou/rustdesk-plugins/main".to_string(), - // description: "".to_string(), - // }] - vec![] -} - -fn get_source_plugins() -> HashMap { - let mut plugins = HashMap::new(); - for source in get_plugin_source_list().into_iter() { - let url = format!("{}/meta.toml", source.url); - match create_http_client().get(&url).send() { - Ok(resp) => { - if !resp.status().is_success() { - log::error!( - "Failed to get plugin list from '{}', status code: {}", - url, - resp.status() - ); - } - if let Ok(text) = resp.text() { - match toml::from_str::(&text) { - Ok(manager_meta) => { - for meta in manager_meta.plugins.iter() { - if !meta - .platforms - .to_uppercase() - .contains(&PLUGIN_PLATFORM.to_uppercase()) - { - continue; - } - plugins.insert( - meta.id.clone(), - PluginInfo { - source: source.clone(), - meta: meta.clone(), - installed_version: "".to_string(), - invalid_reason: "".to_string(), - }, - ); - } - } - Err(e) => log::error!("Failed to parse plugin list from '{}', {}", url, e), - } - } - } - Err(e) => log::error!("Failed to get plugin list from '{}', {}", url, e), - } - } - plugins -} - -fn send_plugin_list_event(plugins: &HashMap) { - let mut plugin_list = plugins.values().collect::>(); - plugin_list.sort_by(|a, b| a.meta.name.cmp(&b.meta.name)); - if let Ok(plugin_list) = serde_json::to_string(&plugin_list) { - let mut m = HashMap::new(); - m.insert("name", MSG_TO_UI_TYPE_PLUGIN_MANAGER); - m.insert(MSG_TO_UI_PLUGIN_MANAGER_LIST, &plugin_list); - if let Ok(event) = serde_json::to_string(&m) { - let _res = flutter::push_global_event(flutter::APP_TYPE_MAIN, event.clone()); - } - } -} - -pub fn load_plugin_list() { - let mut plugin_info_lock = PLUGIN_INFO.lock().unwrap(); - let mut plugins = get_source_plugins(); - - // A big read lock is needed to prevent race conditions. - // Loading plugin list may be slow. - // Users may call uninstall plugin in the middle. - let plugin_infos = super::plugins::get_plugin_infos(); - let plugin_infos_read_lock = plugin_infos.read().unwrap(); - for (id, info) in plugin_infos_read_lock.iter() { - if info.uninstalled { - continue; - } - - if let Some(p) = plugins.get_mut(id) { - p.installed_version = info.desc.meta().version.clone(); - p.invalid_reason = "".to_string(); - } else { - plugins.insert( - id.to_string(), - PluginInfo { - source: PluginSource { - name: PLUGIN_SOURCE_LOCAL.to_string(), - url: PLUGIN_SOURCE_LOCAL_DIR.to_string(), - description: "".to_string(), - }, - meta: info.desc.meta().clone(), - installed_version: info.desc.meta().version.clone(), - invalid_reason: "".to_string(), - }, - ); - } - } - send_plugin_list_event(&plugins); - *plugin_info_lock = plugins; -} - -#[cfg(target_os = "windows")] -fn elevate_install( - plugin_id: &str, - plugin_url: &str, - same_plugin_exists: bool, -) -> ResultType { - // to-do: Support args with space in quotes. 'arg 1' and "arg 2" - let args = if same_plugin_exists { - format!("--plugin-install {}", plugin_id) - } else { - format!("--plugin-install {} {}", plugin_id, plugin_url) - }; - crate::platform::elevate(&args) -} - -#[cfg(target_os = "linux")] -fn elevate_install( - plugin_id: &str, - plugin_url: &str, - same_plugin_exists: bool, -) -> ResultType { - let mut args = vec!["--plugin-install", plugin_id]; - if !same_plugin_exists { - args.push(&plugin_url); - } - crate::platform::elevate(args) -} - -#[cfg(target_os = "macos")] -fn elevate_install( - plugin_id: &str, - plugin_url: &str, - same_plugin_exists: bool, -) -> ResultType { - let mut args = vec!["--plugin-install", plugin_id]; - if !same_plugin_exists { - args.push(&plugin_url); - } - crate::platform::elevate(args, "RustDesk wants to install then plugin") -} - -#[inline] -#[cfg(target_os = "windows")] -fn elevate_uninstall(plugin_id: &str) -> ResultType { - crate::platform::elevate(&format!("--plugin-uninstall {}", plugin_id)) -} - -#[inline] -#[cfg(target_os = "linux")] -fn elevate_uninstall(plugin_id: &str) -> ResultType { - crate::platform::elevate(vec!["--plugin-uninstall", plugin_id]) -} - -#[inline] -#[cfg(target_os = "macos")] -fn elevate_uninstall(plugin_id: &str) -> ResultType { - crate::platform::elevate( - vec!["--plugin-uninstall", plugin_id], - "RustDesk wants to uninstall the plugin", - ) -} - -pub fn install_plugin(id: &str) -> ResultType<()> { - match PLUGIN_INFO.lock().unwrap().get(id) { - Some(plugin) => { - let mut same_plugin_exists = false; - if let Some(version) = super::plugins::get_version(id) { - if version == plugin.meta.version { - same_plugin_exists = true; - } - } - let plugin_url = format!( - "{}/plugins/{}/{}/{}_{}.zip", - plugin.source.url, - plugin.meta.id, - PLUGIN_PLATFORM, - plugin.meta.id, - plugin.meta.version - ); - let allowed_install = elevate_install(id, &plugin_url, same_plugin_exists)?; - if allowed_install && same_plugin_exists { - super::ipc::load_plugin(id)?; - super::plugins::load_plugin(id)?; - super::plugins::mark_uninstalled(id, false); - push_install_event(id, "finished"); - } - Ok(()) - } - None => { - bail!("Plugin not found: {}", id); - } - } -} - -fn get_uninstalled_plugins(uninstalled_plugin_set: &HashSet) -> ResultType> { - let plugins_dir = super::get_plugins_dir()?; - let mut plugins = Vec::new(); - if plugins_dir.exists() { - for entry in std::fs::read_dir(plugins_dir)? { - match entry { - Ok(entry) => { - let plugin_dir = entry.path(); - if plugin_dir.is_dir() { - if let Some(id) = plugin_dir.file_name().and_then(|n| n.to_str()) { - if uninstalled_plugin_set.contains(id) { - plugins.push(id.to_string()); - } - } - } - } - Err(e) => { - log::error!("Failed to read plugins dir entry, {}", e); - } - } - } - } - Ok(plugins) -} - -pub fn remove_uninstalled() -> ResultType<()> { - let mut uninstalled_plugin_set = get_uninstall_id_set()?; - for id in get_uninstalled_plugins(&uninstalled_plugin_set)?.iter() { - super::config::remove(id as _); - if let Ok(dir) = super::get_plugin_dir(id as _) { - allow_err!(remove_dir_all(dir.clone())); - if !dir.exists() { - uninstalled_plugin_set.remove(id); - } - } - } - allow_err!(update_uninstall_id_set(uninstalled_plugin_set)); - Ok(()) -} - -pub fn uninstall_plugin(id: &str, called_by_ui: bool) { - if called_by_ui { - match elevate_uninstall(id) { - Ok(true) => { - if let Err(e) = super::ipc::uninstall_plugin(id) { - log::error!("Failed to uninstall plugin '{}': {}", id, e); - push_uninstall_event(id, "failed"); - return; - } - super::plugins::unload_plugin(id); - super::plugins::mark_uninstalled(id, true); - super::config::remove(id); - push_uninstall_event(id, ""); - } - Ok(false) => { - return; - } - Err(e) => { - log::error!( - "Failed to uninstall plugin '{}', check permission error: {}", - id, - e - ); - push_uninstall_event(id, "failed"); - return; - } - } - } - - if super::is_server_running() { - super::plugins::unload_plugin(&id); - } -} - -fn push_event(id: &str, r#type: &str, msg: &str) { - let mut m = HashMap::new(); - m.insert("name", MSG_TO_UI_TYPE_PLUGIN_MANAGER); - m.insert("id", id); - m.insert(r#type, msg); - if let Ok(event) = serde_json::to_string(&m) { - let _res = flutter::push_global_event(flutter::APP_TYPE_MAIN, event.clone()); - } -} - -#[inline] -fn push_uninstall_event(id: &str, msg: &str) { - push_event(id, MSG_TO_UI_PLUGIN_MANAGER_UNINSTALL, msg); -} - -#[inline] -fn push_install_event(id: &str, msg: &str) { - push_event(id, MSG_TO_UI_PLUGIN_MANAGER_INSTALL, msg); -} - -async fn handle_conn(mut stream: crate::ipc::Connection) { - loop { - tokio::select! { - res = stream.next() => { - match res { - Err(err) => { - log::trace!("plugin ipc connection closed: {}", err); - break; - } - Ok(Some(data)) => { - match &data { - crate::ipc::Data::Plugin(super::ipc::Plugin::InstallStatus((id, status))) => { - match status { - InstallStatus::Downloading(n) => { - push_install_event(&id, &format!("downloading-{}", n)); - }, - InstallStatus::Installing => { - push_install_event(&id, "installing"); - } - InstallStatus::Finished => { - allow_err!(super::plugins::load_plugin(&id)); - allow_err!(super::ipc::load_plugin_async(id).await); - std::thread::spawn(load_plugin_list); - push_install_event(&id, "finished"); - } - InstallStatus::FailedCreating => { - push_install_event(&id, "failed-creating"); - } - InstallStatus::FailedDownloading => { - push_install_event(&id, "failed-downloading"); - } - InstallStatus::FailedInstalling => { - push_install_event(&id, "failed-installing"); - } - } - } - _ => {} - } - } - _ => { - } - } - } - } - } -} - -#[cfg(not(any(target_os = "android", target_os = "ios")))] -#[tokio::main] -pub async fn start_ipc() { - match crate::ipc::new_listener(IPC_PLUGIN_POSTFIX).await { - Ok(mut incoming) => { - while let Some(result) = incoming.next().await { - match result { - Ok(stream) => { - log::debug!("Got new connection"); - tokio::spawn(handle_conn(crate::ipc::Connection::new(stream))); - } - Err(err) => { - log::error!("Couldn't get plugin client: {:?}", err); - } - } - } - } - Err(err) => { - log::error!("Failed to start plugin ipc server: {}", err); - } - } -} - -pub(super) fn get_uninstall_id_set() -> ResultType> { - let uninstall_file_path = super::get_uninstall_file_path()?; - if !uninstall_file_path.exists() { - std::fs::create_dir_all(&super::get_plugins_dir()?)?; - return Ok(HashSet::new()); - } - let s = read_to_string(uninstall_file_path)?; - Ok(serde_json::from_str::>(&s)?) -} - -fn update_uninstall_id_set(set: HashSet) -> ResultType<()> { - let content = serde_json::to_string(&set)?; - let file = OpenOptions::new() - .write(true) - .truncate(true) - .create(true) - .open(super::get_uninstall_file_path()?)?; - let mut writer = std::io::BufWriter::new(file); - writer.write_all(content.as_bytes())?; - Ok(()) -} - -// install process -pub(super) mod install { - use super::IPC_PLUGIN_POSTFIX; - use crate::hbbs_http::create_http_client; - use crate::{ - ipc::{connect, Data}, - plugin::ipc::{InstallStatus, Plugin}, - }; - use hbb_common::{allow_err, bail, log, tokio, ResultType}; - use std::{ - fs::File, - io::{BufReader, BufWriter, Write}, - path::Path, - }; - use zip::ZipArchive; - - #[tokio::main(flavor = "current_thread")] - async fn send_install_status(id: &str, status: InstallStatus) { - allow_err!(_send_install_status(id, status).await); - } - - async fn _send_install_status(id: &str, status: InstallStatus) -> ResultType<()> { - let mut c = connect(1_000, IPC_PLUGIN_POSTFIX).await?; - c.send(&Data::Plugin(Plugin::InstallStatus(( - id.to_string(), - status, - )))) - .await?; - Ok(()) - } - - fn download_to_file(url: &str, file: File) -> ResultType<()> { - let resp = match create_http_client().get(url).send() { - Ok(resp) => resp, - Err(e) => { - bail!("get plugin from '{}', {}", url, e); - } - }; - - if !resp.status().is_success() { - bail!("get plugin from '{}', status code: {}", url, resp.status()); - } - - let mut writer = BufWriter::new(file); - writer.write_all(resp.bytes()?.as_ref())?; - Ok(()) - } - - fn download_file(id: &str, url: &str, filename: &Path) -> bool { - let file = match File::create(filename) { - Ok(f) => f, - Err(e) => { - log::error!("Failed to create plugin file: {}", e); - send_install_status(id, InstallStatus::FailedCreating); - return false; - } - }; - if let Err(e) = download_to_file(url, file) { - log::error!("Failed to download plugin '{}', {}", id, e); - send_install_status(id, InstallStatus::FailedDownloading); - return false; - } - true - } - - fn do_install_file(filename: &Path, target_dir: &Path) -> ResultType<()> { - let mut zip = ZipArchive::new(BufReader::new(File::open(filename)?))?; - for i in 0..zip.len() { - let mut file = zip.by_index(i)?; - let file_path = target_dir.join(file.name()); - if file.name().ends_with("/") { - std::fs::create_dir_all(&file_path)?; - } else { - if let Some(p) = file_path.parent() { - if !p.exists() { - std::fs::create_dir_all(&p)?; - } - } - let mut outfile = File::create(&file_path)?; - std::io::copy(&mut file, &mut outfile)?; - } - } - Ok(()) - } - - pub fn change_uninstall_plugin(id: &str, add: bool) { - match super::get_uninstall_id_set() { - Ok(mut set) => { - if add { - set.insert(id.to_string()); - } else { - set.remove(id); - } - if let Err(e) = super::update_uninstall_id_set(set) { - log::error!("Failed to write uninstall list, {}", e); - } - } - Err(e) => log::error!( - "Failed to get plugins dir, unable to read uninstall list, {}", - e - ), - } - } - - pub fn install_plugin_with_url(id: &str, url: &str) { - log::info!("Installing plugin '{}', url: {}", id, url); - let plugin_dir = match super::super::get_plugin_dir(id) { - Ok(d) => d, - Err(e) => { - send_install_status(id, InstallStatus::FailedCreating); - log::error!("Failed to get plugin dir: {}", e); - return; - } - }; - if !plugin_dir.exists() { - if let Err(e) = std::fs::create_dir_all(&plugin_dir) { - send_install_status(id, InstallStatus::FailedCreating); - log::error!("Failed to create plugin dir: {}", e); - return; - } - } - - let filename = match url.rsplit('/').next() { - Some(filename) => plugin_dir.join(filename), - None => { - send_install_status(id, InstallStatus::FailedDownloading); - log::error!("Failed to download plugin file, invalid url: {}", url); - return; - } - }; - - let filename_to_remove = filename.clone(); - let _call_on_ret = crate::common::SimpleCallOnReturn { - b: true, - f: Box::new(move || { - if let Err(e) = std::fs::remove_file(&filename_to_remove) { - log::error!("Failed to remove plugin file: {}", e); - } - }), - }; - - // download - if !download_file(id, url, &filename) { - return; - } - - // install - send_install_status(id, InstallStatus::Installing); - if let Err(e) = do_install_file(&filename, &plugin_dir) { - log::error!("Failed to install plugin: {}", e); - send_install_status(id, InstallStatus::FailedInstalling); - return; - } - - // finished - send_install_status(id, InstallStatus::Finished); - } -} diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs deleted file mode 100644 index bd4b21b67..000000000 --- a/src/plugin/mod.rs +++ /dev/null @@ -1,188 +0,0 @@ -use hbb_common::{bail, libc, log, ResultType}; -#[cfg(target_os = "windows")] -use std::env; -use std::{ - ffi::{c_char, c_int, c_void, CStr}, - path::PathBuf, - ptr::null, -}; - -mod callback_ext; -mod callback_msg; -mod config; -pub mod desc; -mod errno; -pub mod ipc; -mod manager; -pub mod native; -pub mod native_handlers; -mod plog; -mod plugins; - -pub use manager::{ - install::{change_uninstall_plugin, install_plugin_with_url}, - install_plugin, load_plugin_list, remove_uninstalled, uninstall_plugin, -}; -pub use plugins::{ - handle_client_event, handle_listen_event, handle_server_event, handle_ui_event, load_plugin, - reload_plugin, sync_ui, unload_plugin, -}; - -const MSG_TO_UI_TYPE_PLUGIN_EVENT: &str = "plugin_event"; -const MSG_TO_UI_TYPE_PLUGIN_RELOAD: &str = "plugin_reload"; -const MSG_TO_UI_TYPE_PLUGIN_OPTION: &str = "plugin_option"; -const MSG_TO_UI_TYPE_PLUGIN_MANAGER: &str = "plugin_manager"; - -pub const EVENT_ON_CONN_CLIENT: &str = "on_conn_client"; -pub const EVENT_ON_CONN_SERVER: &str = "on_conn_server"; -pub const EVENT_ON_CONN_CLOSE_CLIENT: &str = "on_conn_close_client"; -pub const EVENT_ON_CONN_CLOSE_SERVER: &str = "on_conn_close_server"; - -static PLUGIN_SOURCE_LOCAL_DIR: &str = "plugins"; - -pub use config::{ManagerConfig, PeerConfig, SharedConfig}; - -/// Common plugin return. -/// -/// [Note] -/// The msg must be nullptr if code is errno::ERR_SUCCESS. -/// The msg must be freed by caller if code is not errno::ERR_SUCCESS. -#[repr(C)] -#[derive(Debug)] -pub struct PluginReturn { - pub code: c_int, - pub msg: *const c_char, -} - -impl PluginReturn { - pub fn success() -> Self { - Self { - code: errno::ERR_SUCCESS, - msg: null(), - } - } - - #[inline] - pub fn is_success(&self) -> bool { - self.code == errno::ERR_SUCCESS - } - - pub fn new(code: c_int, msg: &str) -> Self { - Self { - code, - msg: str_to_cstr_ret(msg), - } - } - - pub fn get_code_msg(&mut self, id: &str) -> (i32, String) { - if self.is_success() { - (self.code, "".to_owned()) - } else { - if self.msg.is_null() { - log::warn!( - "The message pointer from the plugin '{}' is null, but the error code is {}", - id, - self.code - ); - return (self.code, "".to_owned()); - } - let msg = cstr_to_string(self.msg).unwrap_or_default(); - free_c_ptr(self.msg as _); - self.msg = null(); - (self.code as _, msg) - } - } -} - -fn is_server_running() -> bool { - crate::common::is_server() || crate::common::is_server_running() -} - -pub fn init() { - if !is_server_running() { - std::thread::spawn(move || manager::start_ipc()); - } else { - if let Err(e) = remove_uninstalled() { - log::error!("Failed to remove plugins: {}", e); - } - } - match manager::get_uninstall_id_set() { - Ok(ids) => { - if let Err(e) = plugins::load_plugins(&ids) { - log::error!("Failed to load plugins: {}", e); - } - } - Err(e) => { - log::error!("Failed to load plugins: {}", e); - } - } -} - -#[inline] -#[cfg(target_os = "windows")] -fn get_share_dir() -> ResultType { - Ok(PathBuf::from(env::var("ProgramData")?)) -} - -#[inline] -#[cfg(target_os = "linux")] -fn get_share_dir() -> ResultType { - Ok(PathBuf::from("/usr/share")) -} - -#[inline] -#[cfg(target_os = "macos")] -fn get_share_dir() -> ResultType { - Ok(PathBuf::from("/Library/Application Support")) -} - -#[inline] -fn get_plugins_dir() -> ResultType { - Ok(get_share_dir()? - .join("RustDesk") - .join(PLUGIN_SOURCE_LOCAL_DIR)) -} - -#[inline] -fn get_plugin_dir(id: &str) -> ResultType { - Ok(get_plugins_dir()?.join(id)) -} - -#[inline] -fn get_uninstall_file_path() -> ResultType { - Ok(get_plugins_dir()?.join("uninstall_list")) -} - -#[inline] -fn cstr_to_string(cstr: *const c_char) -> ResultType { - if cstr.is_null() { - bail!("failed to convert string, the pointer is null"); - } - Ok(String::from_utf8(unsafe { - CStr::from_ptr(cstr).to_bytes().to_vec() - })?) -} - -#[inline] -fn str_to_cstr_ret(s: &str) -> *const c_char { - let mut s = s.as_bytes().to_vec(); - s.push(0); - unsafe { - let r = libc::malloc(s.len()) as *mut c_char; - libc::memcpy( - r as *mut libc::c_void, - s.as_ptr() as *const libc::c_void, - s.len(), - ); - r - } -} - -#[inline] -fn free_c_ptr(p: *mut c_void) { - if !p.is_null() { - unsafe { - libc::free(p); - } - } -} diff --git a/src/plugin/native.rs b/src/plugin/native.rs deleted file mode 100644 index ce885c77c..000000000 --- a/src/plugin/native.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::{ - ffi::{c_char, c_int, c_void}, - os::raw::c_uint, -}; - -use hbb_common::log::error; - -use super::{ - cstr_to_string, - errno::ERR_NOT_HANDLED, - native_handlers::{Callable, NATIVE_HANDLERS_REGISTRAR}, -}; -/// The native returned value from librustdesk native. -/// -/// [Note] -/// The data is owned by librustdesk. -#[repr(C)] -pub struct NativeReturnValue { - pub return_type: c_int, - pub data: *const c_void, -} - -pub(super) extern "C" fn cb_native_data( - method: *const c_char, - json: *const c_char, - raw: *const c_void, - raw_len: usize, -) -> NativeReturnValue { - let ret = match cstr_to_string(method) { - Ok(method) => NATIVE_HANDLERS_REGISTRAR.call(&method, json, raw, raw_len), - Err(err) => { - error!("cb_native_data error: {}", err); - None - } - }; - return ret.unwrap_or(NativeReturnValue { - return_type: ERR_NOT_HANDLED, - data: std::ptr::null(), - }); -} diff --git a/src/plugin/native_handlers/macros.rs b/src/plugin/native_handlers/macros.rs deleted file mode 100644 index 82d7e10a6..000000000 --- a/src/plugin/native_handlers/macros.rs +++ /dev/null @@ -1,27 +0,0 @@ -#[macro_export] -macro_rules! return_if_not_method { - ($call: ident, $prefix: ident) => { - if $call.starts_with($prefix) { - return None; - } - }; -} - -#[macro_export] -macro_rules! call_if_method { - ($call: ident ,$method: literal, $block: block) => { - if ($call != $method) { - $block - } - }; -} - -#[macro_export] -macro_rules! define_method_prefix { - ($prefix: literal) => { - #[inline] - fn method_prefix(&self) -> &'static str { - $prefix - } - }; -} diff --git a/src/plugin/native_handlers/mod.rs b/src/plugin/native_handlers/mod.rs deleted file mode 100644 index 7d590ab1e..000000000 --- a/src/plugin/native_handlers/mod.rs +++ /dev/null @@ -1,126 +0,0 @@ -use std::{ - ffi::c_void, - sync::{Arc, RwLock}, - vec, -}; - -use hbb_common::libc::c_char; -use lazy_static::lazy_static; -use serde_json::Map; - -use crate::return_if_not_method; - -use self::{session::PluginNativeSessionHandler, ui::PluginNativeUIHandler}; - -use super::cstr_to_string; - -mod macros; -pub mod session; -pub mod ui; - -pub type NR = super::native::NativeReturnValue; -pub type PluginNativeHandlerRegistrar = NativeHandlerRegistrar>; - -lazy_static! { - pub static ref NATIVE_HANDLERS_REGISTRAR: Arc = - Arc::new(PluginNativeHandlerRegistrar::default()); -} - -#[derive(Clone)] -pub struct NativeHandlerRegistrar { - handlers: Arc>>, -} - -impl Default for PluginNativeHandlerRegistrar { - fn default() -> Self { - Self { - handlers: Arc::new(RwLock::new(vec![ - // Add prebuilt native handlers here. - Box::new(PluginNativeSessionHandler::default()), - Box::new(PluginNativeUIHandler::default()), - ])), - } - } -} - -pub(self) trait PluginNativeHandler { - /// The method prefix handled by this handler.s - fn method_prefix(&self) -> &'static str; - - /// Try to handle the method with the given data. - /// - /// Returns: None for the message does not be handled by this handler. - fn on_message(&self, method: &str, data: &Map) -> Option; - - /// Try to handle the method with the given data and extra void binary data. - /// - /// Returns: None for the message does not be handled by this handler. - fn on_message_raw( - &self, - method: &str, - data: &Map, - raw: *const c_void, - raw_len: usize, - ) -> Option; -} - -pub trait Callable { - fn call( - &self, - method: &String, - json: *const c_char, - raw: *const c_void, - raw_len: usize, - ) -> Option { - None - } -} - -impl Callable for T -where - T: PluginNativeHandler + Send + Sync, -{ - fn call( - &self, - method: &String, - json: *const c_char, - raw: *const c_void, - raw_len: usize, - ) -> Option { - let prefix = self.method_prefix(); - return_if_not_method!(method, prefix); - match cstr_to_string(json) { - Ok(s) => { - if let Ok(json) = serde_json::from_str(s.as_str()) { - let method_suffix = &method[prefix.len()..]; - if raw != std::ptr::null() && raw_len > 0 { - return self.on_message_raw(method_suffix, &json, raw, raw_len); - } else { - return self.on_message(method_suffix, &json); - } - } else { - return None; - } - } - Err(_) => return None, - } - } -} - -impl Callable for PluginNativeHandlerRegistrar { - fn call( - &self, - method: &String, - json: *const c_char, - raw: *const c_void, - raw_len: usize, - ) -> Option { - for handler in self.handlers.read().unwrap().iter() { - let ret = handler.call(method, json, raw, raw_len); - if ret.is_some() { - return ret; - } - } - None - } -} diff --git a/src/plugin/native_handlers/session.rs b/src/plugin/native_handlers/session.rs deleted file mode 100644 index 3a3f62f8d..000000000 --- a/src/plugin/native_handlers/session.rs +++ /dev/null @@ -1,219 +0,0 @@ -use std::{ - collections::HashMap, - ffi::{c_char, c_void}, - ptr::addr_of_mut, - sync::{Arc, RwLock}, -}; - -use flutter_rust_bridge::StreamSink; - -use crate::{define_method_prefix, flutter_ffi::EventToUI}; - -const MSG_TO_UI_TYPE_SESSION_CREATED: &str = "session_created"; - -use super::PluginNativeHandler; - -pub type OnSessionRgbaCallback = unsafe extern "C" fn( - *const c_char, // Session ID - *mut c_void, // raw data - *mut usize, // width - *mut usize, // height, - *mut usize, // stride, - *mut scrap::ImageFormat, // ImageFormat -); - -#[derive(Default)] -/// Session related handler for librustdesk core. -pub struct PluginNativeSessionHandler { - sessions: Arc>>, - cbs: Arc>>, -} - -lazy_static::lazy_static! { - pub static ref SESSION_HANDLER: Arc = Arc::new(PluginNativeSessionHandler::default()); -} - -impl PluginNativeHandler for PluginNativeSessionHandler { - define_method_prefix!("session_"); - - fn on_message( - &self, - method: &str, - data: &serde_json::Map, - ) -> Option { - match method { - "create_session" => { - if let Some(id) = data.get("id") { - if let Some(id) = id.as_str() { - return Some(super::NR { - return_type: 1, - data: SESSION_HANDLER.create_session(id.to_string()).as_ptr() as _, - }); - } - } - } - "start_session" => { - if let Some(id) = data.get("id") { - if let Some(id) = id.as_str() { - let sessions = SESSION_HANDLER.sessions.read().unwrap(); - for session in sessions.iter() { - if session.id == id { - let round = - session.connection_round_state.lock().unwrap().new_round(); - crate::ui_session_interface::io_loop(session.clone(), round); - } - } - } - } - } - "remove_session_hook" => { - if let Some(id) = data.get("id") { - if let Some(id) = id.as_str() { - SESSION_HANDLER.remove_session_hook(id.to_string()); - return Some(super::NR { - return_type: 0, - data: std::ptr::null(), - }); - } - } - } - "remove_session" => { - if let Some(id) = data.get("id") { - if let Some(id) = id.as_str() { - SESSION_HANDLER.remove_session(id.to_owned()); - return Some(super::NR { - return_type: 0, - data: std::ptr::null(), - }); - } - } - } - _ => {} - } - None - } - - fn on_message_raw( - &self, - method: &str, - data: &serde_json::Map, - raw: *const std::ffi::c_void, - _raw_len: usize, - ) -> Option { - match method { - "add_session_hook" => { - if let Some(id) = data.get("id") { - if let Some(id) = id.as_str() { - let cb: OnSessionRgbaCallback = unsafe { std::mem::transmute(raw) }; - SESSION_HANDLER.add_session_hook(id.to_string(), cb); - return Some(super::NR { - return_type: 0, - data: std::ptr::null(), - }); - } - } - } - _ => {} - } - None - } -} - -impl PluginNativeSessionHandler { - fn create_session(&self, session_id: String) -> String { - let session = - crate::flutter::session_add(&session_id, false, false, false, "", false, "".to_owned()); - if let Ok(session) = session { - let mut sessions = self.sessions.write().unwrap(); - sessions.push(session); - // push a event to notify flutter to bind a event stream for this session. - let mut m = HashMap::new(); - m.insert("name", MSG_TO_UI_TYPE_SESSION_CREATED); - m.insert("session_id", &session_id); - // todo: APP_TYPE_DESKTOP_REMOTE is not used anymore. - // crate::flutter::APP_TYPE_DESKTOP_REMOTE + window id, is used for multi-window support. - crate::flutter::push_global_event( - crate::flutter::APP_TYPE_DESKTOP_REMOTE, - serde_json::to_string(&m).unwrap_or("".to_string()), - ); - return session_id; - } else { - return "".to_string(); - } - } - - fn add_session_hook(&self, session_id: String, cb: OnSessionRgbaCallback) { - let sessions = self.sessions.read().unwrap(); - for session in sessions.iter() { - if session.id == session_id { - self.cbs.write().unwrap().insert(session_id.to_owned(), cb); - session.ui_handler.add_session_hook( - session_id, - crate::flutter::SessionHook::OnSessionRgba(session_rgba_cb), - ); - break; - } - } - } - - fn remove_session_hook(&self, session_id: String) { - let sessions = self.sessions.read().unwrap(); - for session in sessions.iter() { - if session.id == session_id { - session.ui_handler.remove_session_hook(&session_id); - } - } - } - - fn remove_session(&self, session_id: String) { - let _ = self.cbs.write().unwrap().remove(&session_id); - let mut sessions = self.sessions.write().unwrap(); - for i in 0..sessions.len() { - if sessions[i].id == session_id { - sessions[i].close_event_stream(); - sessions[i].close(); - sessions.remove(i); - } - } - } - - #[inline] - // The callback function for rgba data - fn session_rgba_cb(&self, session_id: String, rgb: &mut scrap::ImageRgb) { - let cbs = self.cbs.read().unwrap(); - if let Some(cb) = cbs.get(&session_id) { - unsafe { - cb( - session_id.as_ptr() as _, - rgb.raw.as_mut_ptr() as _, - addr_of_mut!(rgb.w), - addr_of_mut!(rgb.h), - addr_of_mut!(rgb.stride), - addr_of_mut!(rgb.fmt), - ); - } - } - } - - #[inline] - // The callback function for rgba data - fn session_register_event_stream(&self, session_id: String, stream: StreamSink) { - let sessions = self.sessions.read().unwrap(); - for session in sessions.iter() { - if session.id == session_id { - *session.event_stream.write().unwrap() = Some(stream); - break; - } - } - } -} - -#[inline] -fn session_rgba_cb(id: String, rgb: &mut scrap::ImageRgb) { - SESSION_HANDLER.session_rgba_cb(id, rgb); -} - -#[inline] -pub fn session_register_event_stream(id: String, stream: StreamSink) { - SESSION_HANDLER.session_register_event_stream(id, stream); -} diff --git a/src/plugin/native_handlers/ui.rs b/src/plugin/native_handlers/ui.rs deleted file mode 100644 index aec7facd8..000000000 --- a/src/plugin/native_handlers/ui.rs +++ /dev/null @@ -1,143 +0,0 @@ -use std::{collections::HashMap, ffi::c_void, os::raw::c_int}; - -use serde_json::json; - -use crate::{define_method_prefix, flutter::APP_TYPE_MAIN}; - -use super::PluginNativeHandler; - -#[derive(Default)] -pub struct PluginNativeUIHandler; - -/// Callback for UI interface. -/// -/// [Note] -/// We will transfer the native callback to u64 and post it to flutter. -/// The flutter thread will directly call this method. -/// -/// an example of `data` is: -/// ``` -/// { -/// "cb": 0x1234567890 -/// } -/// ``` -/// [Safety] -/// Please make sure the callback u provided is VALID, or memory or calling issues may occur to cause the program crash! -pub type OnUIReturnCallback = - extern "C" fn(return_code: c_int, data: *const c_void, data_len: u64, user_data: *const c_void); - -impl PluginNativeHandler for PluginNativeUIHandler { - define_method_prefix!("ui_"); - - fn on_message( - &self, - method: &str, - data: &serde_json::Map, - ) -> Option { - match method { - "select_peers_async" => { - if let Some(cb) = data.get("cb") { - if let Some(cb) = cb.as_u64() { - let user_data = match data.get("user_data") { - Some(user_data) => user_data.as_u64().unwrap_or(0), - None => 0, - }; - self.select_peers_async(cb, user_data); - return Some(super::NR { - return_type: 0, - data: std::ptr::null(), - }); - } - } - return Some(super::NR { - return_type: -1, - data: "missing cb field message".as_ptr() as _, - }); - } - "register_ui_entry" => { - let title; - if let Some(v) = data.get("title") { - title = v.as_str().unwrap_or(""); - } else { - title = ""; - } - if let Some(on_tap_cb) = data.get("on_tap_cb") { - if let Some(on_tap_cb) = on_tap_cb.as_u64() { - let user_data = match data.get("user_data") { - Some(user_data) => user_data.as_u64().unwrap_or(0), - None => 0, - }; - self.register_ui_entry(title, on_tap_cb, user_data); - return Some(super::NR { - return_type: 0, - data: std::ptr::null(), - }); - } - } - return Some(super::NR { - return_type: -1, - data: "missing cb field message".as_ptr() as _, - }); - } - _ => {} - } - None - } - - fn on_message_raw( - &self, - method: &str, - data: &serde_json::Map, - raw: *const std::ffi::c_void, - _raw_len: usize, - ) -> Option { - None - } -} - -impl PluginNativeUIHandler { - /// Call with method `select_peers_async` and the following json: - /// ```json - /// { - /// "cb": 0, // The function address - /// "user_data": 0 // An opaque pointer value passed to the callback. - /// } - /// ``` - /// - /// [Arguments] - /// @param cb: the function address with type [OnUIReturnCallback]. - /// @param user_data: the function will be called with this value. - fn select_peers_async(&self, cb: u64, user_data: u64) { - let mut param = HashMap::new(); - param.insert("name", json!("native_ui")); - param.insert("action", json!("select_peers")); - param.insert("cb", json!(cb)); - param.insert("user_data", json!(user_data)); - crate::flutter::push_global_event( - APP_TYPE_MAIN, - serde_json::to_string(¶m).unwrap_or("".to_string()), - ); - } - - /// Call with method `register_ui_entry` and the following json: - /// ``` - /// { - /// - /// "on_tap_cb": 0, // The function address - /// "user_data": 0, // An opaque pointer value passed to the callback. - /// "title": "entry name" - /// } - /// ``` - fn register_ui_entry(&self, title: &str, on_tap_cb: u64, user_data: u64) { - let mut param = HashMap::new(); - param.insert("name", json!("native_ui")); - param.insert("action", json!("register_ui_entry")); - param.insert("title", json!(title)); - param.insert("cb", json!(on_tap_cb)); - param.insert("user_data", json!(user_data)); - crate::flutter::push_global_event( - APP_TYPE_MAIN, - serde_json::to_string(¶m).unwrap_or("".to_string()), - ); - } -} diff --git a/src/plugin/plog.rs b/src/plugin/plog.rs deleted file mode 100644 index f1e78d36e..000000000 --- a/src/plugin/plog.rs +++ /dev/null @@ -1,34 +0,0 @@ -use hbb_common::log; -use std::ffi::c_char; - -const LOG_LEVEL_TRACE: &[u8; 6] = b"trace\0"; -const LOG_LEVEL_DEBUG: &[u8; 6] = b"debug\0"; -const LOG_LEVEL_INFO: &[u8; 5] = b"info\0"; -const LOG_LEVEL_WARN: &[u8; 5] = b"warn\0"; -const LOG_LEVEL_ERROR: &[u8; 6] = b"error\0"; - -#[inline] -fn is_level(level: *const c_char, level_bytes: &[u8]) -> bool { - level_bytes == unsafe { std::slice::from_raw_parts(level as *const u8, level_bytes.len()) } -} - -#[no_mangle] -pub(super) extern "C" fn plugin_log(level: *const c_char, msg: *const c_char) { - if level.is_null() || msg.is_null() { - return; - } - - if let Ok(msg) = super::cstr_to_string(msg) { - if is_level(level, LOG_LEVEL_TRACE) { - log::trace!("{}", msg); - } else if is_level(level, LOG_LEVEL_DEBUG) { - log::debug!("{}", msg); - } else if is_level(level, LOG_LEVEL_INFO) { - log::info!("{}", msg); - } else if is_level(level, LOG_LEVEL_WARN) { - log::warn!("{}", msg); - } else if is_level(level, LOG_LEVEL_ERROR) { - log::error!("{}", msg); - } - } -} diff --git a/src/plugin/plugins.rs b/src/plugin/plugins.rs deleted file mode 100644 index bf980ee8c..000000000 --- a/src/plugin/plugins.rs +++ /dev/null @@ -1,659 +0,0 @@ -use super::{desc::Desc, errno::*, *}; -#[cfg(not(debug_assertions))] -use crate::common::is_server; -use crate::flutter; -use hbb_common::{ - bail, - dlopen::symbor::Library, - lazy_static, log, - message_proto::{Message, Misc, PluginFailure, PluginRequest}, - ResultType, -}; -use serde_derive::Serialize; -use std::{ - collections::{HashMap, HashSet}, - ffi::{c_char, c_void}, - path::Path, - sync::{Arc, RwLock}, -}; - -pub const METHOD_HANDLE_STATUS: &[u8; 14] = b"handle_status\0"; -pub const METHOD_HANDLE_SIGNATURE_VERIFICATION: &[u8; 30] = b"handle_signature_verification\0"; -const METHOD_HANDLE_UI: &[u8; 10] = b"handle_ui\0"; -const METHOD_HANDLE_PEER: &[u8; 12] = b"handle_peer\0"; -pub const METHOD_HANDLE_LISTEN_EVENT: &[u8; 20] = b"handle_listen_event\0"; - -lazy_static::lazy_static! { - static ref PLUGIN_INFO: Arc>> = Default::default(); - static ref PLUGINS: Arc>> = Default::default(); -} - -pub(super) struct PluginInfo { - pub path: String, - pub uninstalled: bool, - pub desc: Desc, -} - -/// Initialize the plugins. -/// -/// data: The initialize data. -type PluginFuncInit = extern "C" fn(data: *const InitData) -> PluginReturn; -/// Reset the plugin. -/// -/// data: The initialize data. -type PluginFuncReset = extern "C" fn(data: *const InitData) -> PluginReturn; -/// Clear the plugin. -type PluginFuncClear = extern "C" fn() -> PluginReturn; -/// Get the description of the plugin. -/// Return the description. The plugin allocate memory with `libc::malloc` and return the pointer. -type PluginFuncDesc = extern "C" fn() -> *const c_char; -/// Callback to send message to peer or ui. -/// peer, target, id are utf8 strings(null terminated). -/// -/// peer: The peer id. -/// target: "peer" or "ui". -/// id: The id of this plugin. -/// content: The content. -/// len: The length of the content. -type CallbackMsg = extern "C" fn( - peer: *const c_char, - target: *const c_char, - id: *const c_char, - content: *const c_void, - len: usize, -) -> PluginReturn; -/// Callback to get the config. -/// peer, key are utf8 strings(null terminated). -/// -/// peer: The peer id. -/// id: The id of this plugin. -/// key: The key of the config. -/// -/// The returned string is utf8 string(null terminated) and must be freed by caller. -type CallbackGetConf = - extern "C" fn(peer: *const c_char, id: *const c_char, key: *const c_char) -> *const c_char; -/// Get local peer id. -/// -/// The returned string is utf8 string(null terminated) and must be freed by caller. -type CallbackGetId = extern "C" fn() -> *const c_char; -/// Callback to log. -/// -/// level, msg are utf8 strings(null terminated). -/// level: "error", "warn", "info", "debug", "trace". -/// msg: The message. -type CallbackLog = extern "C" fn(level: *const c_char, msg: *const c_char); - -/// Callback to the librustdesk core. -/// -/// method: the method name of this callback. -/// json: the json data for the parameters. The argument *must* be non-null. -/// raw: the binary data for this call, nullable. -/// raw_len: the length of this binary data, only valid when we pass raw data to `raw`. -type CallbackNative = extern "C" fn( - method: *const c_char, - json: *const c_char, - raw: *const c_void, - raw_len: usize, -) -> super::native::NativeReturnValue; -/// The main function of the plugin. -/// -/// method: The method. "handle_ui" or "handle_peer" -/// peer: The peer id. -/// args: The arguments. -/// len: The length of the arguments. -type PluginFuncCall = extern "C" fn( - method: *const c_char, - peer: *const c_char, - args: *const c_void, - len: usize, -) -> PluginReturn; -/// The main function of the plugin. -/// This function is called mainly for handling messages from the peer, -/// and then send messages back to the peer. -/// -/// method: The method. "handle_ui" or "handle_peer" -/// peer: The peer id. -/// args: The arguments. -/// len: The length of the arguments. -/// out: The output. -/// The plugin allocate memory with `libc::malloc` and return the pointer. -/// out_len: The length of the output. -type PluginFuncCallWithOutData = extern "C" fn( - method: *const c_char, - peer: *const c_char, - args: *const c_void, - len: usize, - out: *mut *mut c_void, - out_len: *mut usize, -) -> PluginReturn; - -/// The plugin callbacks. -/// msg: The callback to send message to peer or ui. -/// get_conf: The callback to get the config. -/// log: The callback to log. -#[repr(C)] -#[derive(Copy, Clone)] -struct Callbacks { - msg: CallbackMsg, - get_conf: CallbackGetConf, - get_id: CallbackGetId, - log: CallbackLog, - native: CallbackNative, -} - -#[derive(Serialize)] -#[repr(C)] -struct InitInfo { - is_server: bool, -} - -/// The plugin initialize data. -/// version: The version of the plugin, can't be nullptr. -/// local_peer_id: The local peer id, can't be nullptr. -/// cbs: The callbacks. -#[repr(C)] -struct InitData { - version: *const c_char, - info: *const c_char, - cbs: Callbacks, -} - -impl Drop for InitData { - fn drop(&mut self) { - free_c_ptr(self.version as _); - free_c_ptr(self.info as _); - } -} - -macro_rules! make_plugin { - ($($field:ident : $tp:ty),+) => { - #[allow(dead_code)] - pub struct Plugin { - _lib: Library, - id: Option, - path: String, - $($field: $tp),+ - } - - impl Plugin { - fn new(path: &str) -> ResultType { - let lib = match Library::open(path) { - Ok(lib) => lib, - Err(e) => { - bail!("Failed to load library {}, {}", path, e); - } - }; - - $(let $field = match unsafe { lib.symbol::<$tp>(stringify!($field)) } { - Ok(m) => { - *m - }, - Err(e) => { - bail!("Failed to load {} func {}, {}", path, stringify!($field), e); - } - } - ;)+ - - Ok(Self { - _lib: lib, - id: None, - path: path.to_string(), - $( $field ),+ - }) - } - - fn desc(&self) -> ResultType { - let desc_ret = (self.desc)(); - let desc = Desc::from_cstr(desc_ret); - free_c_ptr(desc_ret as _); - desc - } - - fn init(&self, data: &InitData, path: &str) -> ResultType<()> { - let mut init_ret = (self.init)(data as _); - if !init_ret.is_success() { - let (code, msg) = init_ret.get_code_msg(path); - bail!( - "Failed to init plugin {}, code: {}, msg: {}", - path, - code, - msg - ); - } - Ok(()) - } - - fn clear(&self, id: &str) { - let mut clear_ret = (self.clear)(); - if !clear_ret.is_success() { - let (code, msg) = clear_ret.get_code_msg(id); - log::error!( - "Failed to clear plugin {}, code: {}, msg: {}", - id, - code, - msg - ); - } - } - } - - impl Drop for Plugin { - fn drop(&mut self) { - let id = self.id.as_ref().unwrap_or(&self.path); - self.clear(id); - } - } - } -} - -make_plugin!( - init: PluginFuncInit, - reset: PluginFuncReset, - clear: PluginFuncClear, - desc: PluginFuncDesc, - call: PluginFuncCall, - call_with_out_data: PluginFuncCallWithOutData -); - -#[derive(Serialize)] -pub struct MsgListenEvent { - pub event: String, -} - -#[cfg(target_os = "windows")] -const DYLIB_SUFFIX: &str = ".dll"; -#[cfg(target_os = "linux")] -const DYLIB_SUFFIX: &str = ".so"; -#[cfg(target_os = "macos")] -const DYLIB_SUFFIX: &str = ".dylib"; - -pub(super) fn load_plugins(uninstalled_ids: &HashSet) -> ResultType<()> { - let plugins_dir = super::get_plugins_dir()?; - if !plugins_dir.exists() { - std::fs::create_dir_all(&plugins_dir)?; - } else { - for entry in std::fs::read_dir(plugins_dir)? { - match entry { - Ok(entry) => { - let plugin_dir = entry.path(); - if plugin_dir.is_dir() { - if let Some(plugin_id) = plugin_dir.file_name().and_then(|f| f.to_str()) { - if uninstalled_ids.contains(plugin_id) { - log::debug!( - "Ignore loading '{}' as it should be uninstalled", - plugin_id - ); - continue; - } - load_plugin_dir(&plugin_dir); - } - } - } - Err(e) => { - log::error!("Failed to read plugins dir entry, {}", e); - } - } - } - } - Ok(()) -} - -fn load_plugin_dir(dir: &Path) { - log::debug!("Begin load plugin dir: {}", dir.display()); - if let Ok(rd) = std::fs::read_dir(dir) { - for entry in rd { - match entry { - Ok(entry) => { - let path = entry.path(); - if path.is_file() { - let filename = entry.file_name(); - let filename = filename.to_str().unwrap_or(""); - if filename.starts_with("plugin_") && filename.ends_with(DYLIB_SUFFIX) { - if let Some(path) = path.to_str() { - if let Err(e) = load_plugin_path(path) { - log::error!("Failed to load plugin {}, {}", filename, e); - } - } - } - } - } - Err(e) => { - log::error!( - "Failed to read '{}' dir entry, {}", - dir.file_name().and_then(|f| f.to_str()).unwrap_or(""), - e - ); - } - } - } - } -} - -pub fn unload_plugin(id: &str) { - log::info!("Plugin {} unloaded", id); - PLUGINS.write().unwrap().remove(id); -} - -pub(super) fn mark_uninstalled(id: &str, uninstalled: bool) { - log::info!("Plugin {} uninstall", id); - PLUGIN_INFO - .write() - .unwrap() - .get_mut(id) - .map(|info| info.uninstalled = uninstalled); -} - -pub fn reload_plugin(id: &str) -> ResultType<()> { - let path = match PLUGIN_INFO.read().unwrap().get(id) { - Some(plugin) => plugin.path.clone(), - None => bail!("Plugin {} not found", id), - }; - unload_plugin(id); - load_plugin_path(&path) -} - -fn load_plugin_path(path: &str) -> ResultType<()> { - log::info!("Begin load plugin {}", path); - - let plugin = Plugin::new(path)?; - let desc = plugin.desc()?; - - // to-do validate plugin - // to-do check the plugin id (make sure it does not use another plugin's id) - - let id = desc.meta().id.clone(); - let plugin_info = PluginInfo { - path: path.to_string(), - uninstalled: false, - desc: desc.clone(), - }; - PLUGIN_INFO.write().unwrap().insert(id.clone(), plugin_info); - - let init_info = serde_json::to_string(&InitInfo { - is_server: super::is_server_running(), - })?; - let init_data = InitData { - version: str_to_cstr_ret(crate::VERSION), - info: str_to_cstr_ret(&init_info) as _, - cbs: Callbacks { - msg: callback_msg::cb_msg, - get_conf: config::cb_get_conf, - get_id: config::cb_get_local_peer_id, - log: super::plog::plugin_log, - native: super::native::cb_native_data, - }, - }; - // If do not load the plugin when init failed, the ui will not show the installed plugin. - if let Err(e) = plugin.init(&init_data, path) { - log::error!("Failed to init plugin '{}', {}", desc.meta().id, e); - } - - if super::is_server_running() { - super::config::ManagerConfig::add_plugin(&desc.meta().id)?; - } - - // update ui - // Ui may be not ready now, so we need to update again once ui is ready. - reload_ui(&desc, None); - - // add plugins - PLUGINS.write().unwrap().insert(id.clone(), plugin); - - log::info!("Plugin {} loaded, {}", id, path); - Ok(()) -} - -pub fn sync_ui(sync_to: String) { - for plugin in PLUGIN_INFO.read().unwrap().values() { - reload_ui(&plugin.desc, Some(&sync_to)); - } -} - -#[inline] -pub fn load_plugin(id: &str) -> ResultType<()> { - load_plugin_dir(&super::get_plugin_dir(id)?); - Ok(()) -} - -#[inline] -fn handle_event(method: &[u8], id: &str, peer: &str, event: &[u8]) -> ResultType<()> { - let mut peer: String = peer.to_owned(); - peer.push('\0'); - plugin_call(id, method, &peer, event) -} - -pub fn plugin_call(id: &str, method: &[u8], peer: &str, event: &[u8]) -> ResultType<()> { - let mut ret = plugin_call_get_return(id, method, peer, event)?; - if ret.is_success() { - Ok(()) - } else { - let (code, msg) = ret.get_code_msg(id); - bail!( - "Failed to handle plugin event, id: {}, method: {}, code: {}, msg: {}", - id, - std::string::String::from_utf8(method.to_vec()).unwrap_or_default(), - code, - msg - ); - } -} - -#[inline] -pub fn plugin_call_get_return( - id: &str, - method: &[u8], - peer: &str, - event: &[u8], -) -> ResultType { - match PLUGINS.read().unwrap().get(id) { - Some(plugin) => Ok((plugin.call)( - method.as_ptr() as _, - peer.as_ptr() as _, - event.as_ptr() as _, - event.len(), - )), - None => bail!("Plugin {} not found", id), - } -} - -#[inline] -pub fn handle_ui_event(id: &str, peer: &str, event: &[u8]) -> ResultType<()> { - handle_event(METHOD_HANDLE_UI, id, peer, event) -} - -#[inline] -pub fn handle_server_event(id: &str, peer: &str, event: &[u8]) -> ResultType<()> { - handle_event(METHOD_HANDLE_PEER, id, peer, event) -} - -fn _handle_listen_event(event: String, peer: String) { - let mut plugins = Vec::new(); - for info in PLUGIN_INFO.read().unwrap().values() { - if info.desc.listen_events().contains(&event.to_string()) { - plugins.push(info.desc.meta().id.clone()); - } - } - - if plugins.is_empty() { - return; - } - - if let Ok(evt) = serde_json::to_string(&MsgListenEvent { - event: event.clone(), - }) { - let mut evt_bytes = evt.as_bytes().to_vec(); - evt_bytes.push(0); - let mut peer: String = peer.to_owned(); - peer.push('\0'); - for id in plugins { - match PLUGINS.read().unwrap().get(&id) { - Some(plugin) => { - let mut ret = (plugin.call)( - METHOD_HANDLE_LISTEN_EVENT.as_ptr() as _, - peer.as_ptr() as _, - evt_bytes.as_ptr() as _, - evt_bytes.len(), - ); - if !ret.is_success() { - let (code, msg) = ret.get_code_msg(&id); - log::error!( - "Failed to handle plugin listen event, id: {}, event: {}, code: {}, msg: {}", - id, - event, - code, - msg - ); - } - } - None => { - log::error!("Plugin {} not found when handle_listen_event", id); - } - } - } - } -} - -#[inline] -pub fn handle_listen_event(event: String, peer: String) { - std::thread::spawn(|| _handle_listen_event(event, peer)); -} - -#[inline] -pub fn handle_client_event(id: &str, peer: &str, event: &[u8]) -> Message { - let mut peer: String = peer.to_owned(); - peer.push('\0'); - match PLUGINS.read().unwrap().get(id) { - Some(plugin) => { - let mut out = std::ptr::null_mut(); - let mut out_len: usize = 0; - let mut ret = (plugin.call_with_out_data)( - METHOD_HANDLE_PEER.as_ptr() as _, - peer.as_ptr() as _, - event.as_ptr() as _, - event.len(), - &mut out as _, - &mut out_len as _, - ); - if ret.is_success() { - let msg = make_plugin_request(id, out, out_len); - free_c_ptr(out as _); - msg - } else { - let (code, msg) = ret.get_code_msg(id); - if code > ERR_RUSTDESK_HANDLE_BASE && code < ERR_PLUGIN_HANDLE_BASE { - log::debug!( - "Plugin {} failed to handle client event, code: {}, msg: {}", - id, - code, - msg - ); - let name = match PLUGIN_INFO.read().unwrap().get(id) { - Some(plugin) => &plugin.desc.meta().name, - None => "???", - } - .to_owned(); - match code { - ERR_CALL_NOT_SUPPORTED_METHOD => { - make_plugin_failure(id, &name, "Plugin method is not supported") - } - ERR_CALL_INVALID_ARGS => { - make_plugin_failure(id, &name, "Plugin arguments is invalid") - } - _ => make_plugin_failure(id, &name, &msg), - } - } else { - log::error!( - "Plugin {} failed to handle client event, code: {}, msg: {}", - id, - code, - msg - ); - let msg = make_plugin_request(id, out, out_len); - free_c_ptr(out as _); - msg - } - } - } - None => make_plugin_failure(id, "", "Plugin not found"), - } -} - -fn make_plugin_request(id: &str, content: *const c_void, len: usize) -> Message { - let mut misc = Misc::new(); - misc.set_plugin_request(PluginRequest { - id: id.to_owned(), - content: unsafe { std::slice::from_raw_parts(content as *const u8, len) } - .clone() - .into(), - ..Default::default() - }); - let mut msg_out = Message::new(); - msg_out.set_misc(misc); - msg_out -} - -fn make_plugin_failure(id: &str, name: &str, msg: &str) -> Message { - let mut misc = Misc::new(); - misc.set_plugin_failure(PluginFailure { - id: id.to_owned(), - name: name.to_owned(), - msg: msg.to_owned(), - ..Default::default() - }); - let mut msg_out = Message::new(); - msg_out.set_misc(misc); - msg_out -} - -fn reload_ui(desc: &Desc, sync_to: Option<&str>) { - for (location, ui) in desc.location().ui.iter() { - if let Ok(ui) = serde_json::to_string(&ui) { - let make_event = |ui: &str| { - let mut m = HashMap::new(); - m.insert("name", MSG_TO_UI_TYPE_PLUGIN_RELOAD); - m.insert("id", &desc.meta().id); - m.insert("location", &location); - // Do not depend on the "location" and plugin desc on the ui side. - // Send the ui field to ensure the ui is valid. - m.insert("ui", ui); - serde_json::to_string(&m).unwrap_or("".to_owned()) - }; - match sync_to { - Some(channel) => { - let _res = flutter::push_global_event(channel, make_event(&ui)); - } - None => { - let v: Vec<&str> = location.split('|').collect(); - // The first element is the "client" or "host". - // The second element is the "main", "remote", "cm", "file transfer", "port forward". - if v.len() >= 2 { - let available_channels = flutter::get_global_event_channels(); - if available_channels.contains(&v[1]) { - let _res = flutter::push_global_event(v[1], make_event(&ui)); - } - } - } - } - } - } -} - -pub(super) fn get_plugin_infos() -> Arc>> { - PLUGIN_INFO.clone() -} - -pub(super) fn get_desc_conf(id: &str) -> Option { - PLUGIN_INFO - .read() - .unwrap() - .get(id) - .map(|info| info.desc.config().clone()) -} - -pub(super) fn get_version(id: &str) -> Option { - PLUGIN_INFO - .read() - .unwrap() - .get(id) - .map(|info| info.desc.meta().version.clone()) -} diff --git a/src/server/connection.rs b/src/server/connection.rs index bf05d56bd..7dc41ecbb 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -163,43 +163,6 @@ pub static CLICK_TIME: AtomicI64 = AtomicI64::new(0); #[cfg(not(any(target_os = "android", target_os = "ios")))] pub static MOUSE_MOVE_TIME: AtomicI64 = AtomicI64::new(0); -#[cfg(all(feature = "flutter", feature = "plugin_framework"))] -#[cfg(not(any(target_os = "android", target_os = "ios")))] -lazy_static::lazy_static! { - static ref PLUGIN_BLOCK_INPUT_TXS: Arc>>> = Default::default(); - static ref PLUGIN_BLOCK_INPUT_TX_RX: (Arc>>, Arc>>) = { - let (tx, rx) = std_mpsc::channel(); - (Arc::new(Mutex::new(tx)), Arc::new(Mutex::new(rx))) - }; -} - -// Block input is required for some special cases, such as privacy mode. -#[cfg(all(feature = "flutter", feature = "plugin_framework"))] -#[cfg(not(any(target_os = "android", target_os = "ios")))] -pub fn plugin_block_input(peer: &str, block: bool) -> bool { - if let Some(tx) = PLUGIN_BLOCK_INPUT_TXS.lock().unwrap().get(peer) { - let _ = tx.send(if block { - MessageInput::BlockOnPlugin(peer.to_string()) - } else { - MessageInput::BlockOffPlugin(peer.to_string()) - }); - match PLUGIN_BLOCK_INPUT_TX_RX - .1 - .lock() - .unwrap() - .recv_timeout(std::time::Duration::from_millis(3_000)) - { - Ok(b) => b == block, - Err(..) => { - log::error!("plugin_block_input timeout"); - false - } - } - } else { - false - } -} - #[derive(Clone, Default)] pub struct ConnInner { id: i32, @@ -225,12 +188,6 @@ enum MessageInput { Pointer((PointerDeviceEvent, i32)), BlockOn, BlockOff, - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - BlockOnPlugin(String), - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - BlockOffPlugin(String), } #[derive(Clone, Debug, Hash, Eq, PartialEq)] @@ -1176,12 +1133,6 @@ impl Connection { let _ = Self::turn_off_privacy_to_msg(id, String::new()); } } - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - crate::plugin::handle_listen_event( - crate::plugin::EVENT_ON_CONN_CLOSE_SERVER.to_owned(), - conn.lr.my_id.clone(), - ); video_service::notify_video_frame_fetched_by_conn_id(id, None); if conn.authorized { password::update_temporary_password(); @@ -1266,32 +1217,6 @@ impl Connection { ); } } - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - MessageInput::BlockOnPlugin(_peer) => { - let (ok, _msg) = crate::platform::block_input(true); - if ok { - block_input_mode = true; - } - let _r = PLUGIN_BLOCK_INPUT_TX_RX - .0 - .lock() - .unwrap() - .send(block_input_mode); - } - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - MessageInput::BlockOffPlugin(_peer) => { - let (ok, _msg) = crate::platform::block_input(false); - if ok { - block_input_mode = false; - } - let _r = PLUGIN_BLOCK_INPUT_TX_RX - .0 - .lock() - .unwrap() - .send(block_input_mode); - } }, Err(err) => { #[cfg(not(any(target_os = "android", target_os = "ios")))] @@ -2032,13 +1957,6 @@ impl Connection { username = "".to_owned(); } } - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - PLUGIN_BLOCK_INPUT_TXS - .lock() - .unwrap() - .insert(self.lr.my_id.clone(), self.tx_input.clone()); - // Terminal feature is supported on desktop only #[allow(unused_mut)] let mut terminal = cfg!(not(any(target_os = "android", target_os = "ios"))); @@ -3904,13 +3822,6 @@ impl Connection { self.change_resolution(Some(dr.display as _), &dr.resolution); } } - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - Some(misc::Union::PluginRequest(p)) => { - let msg = - crate::plugin::handle_client_event(&p.id, &self.lr.my_id, &p.content); - self.send(msg).await; - } Some(misc::Union::AutoAdjustFps(fps)) => video_service::VIDEO_QOS .lock() .unwrap() diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 9e4128dca..03b59a497 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -569,16 +569,6 @@ impl Session { self.send(Data::Message(msg)); } - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] - #[cfg(not(any(target_os = "android", target_os = "ios")))] - pub fn send_plugin_request(&self, request: PluginRequest) { - let mut misc = Misc::new(); - misc.set_plugin_request(request); - let mut msg_out = Message::new(); - msg_out.set_misc(misc); - self.send(Data::Message(msg_out)); - } - pub fn get_audit_server(&self, typ: String) -> String { if LocalConfig::get_option("access_token").is_empty() { return "".to_owned();