diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index bd026874b..625744dc1 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -123,6 +123,7 @@ class _RemotePageState extends State }); } _ffi.ffiModel.updateEventListener(widget.id); + bind.pluginSyncUi(syncTo: kAppTypeDesktopRemote); _ffi.qualityMonitorModel.checkShowQualityMonitor(widget.id); // Session option should be set after models.dart/FFI.start _showRemoteCursor.value = bind.sessionGetToggleOptionSync( diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 27987d776..9daa69865 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -124,6 +124,7 @@ void runMainApp(bool startService) async { if (startService) { // await windowManager.ensureInitialized(); gFFI.serverModel.startService(); + bind.pluginSyncUi(syncTo: kAppTypeMain); } gFFI.userModel.refreshCurrentUser(); runApp(App()); diff --git a/flutter/lib/mobile/pages/file_manager_page.dart b/flutter/lib/mobile/pages/file_manager_page.dart index 30e0661f6..bfc24364c 100644 --- a/flutter/lib/mobile/pages/file_manager_page.dart +++ b/flutter/lib/mobile/pages/file_manager_page.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_breadcrumb/flutter_breadcrumb.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/models/file_model.dart'; import 'package:get/get.dart'; import 'package:toggle_switch/toggle_switch.dart'; diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart index 31a95b8fb..216814cf6 100644 --- a/flutter/lib/models/server_model.dart +++ b/flutter/lib/models/server_model.dart @@ -341,7 +341,6 @@ class ServerModel with ChangeNotifier { _isStart = true; notifyListeners(); parent.target?.ffiModel.updateEventListener(""); - bind.pluginSyncUi(); await parent.target?.invokeMethod("init_service"); // ugly is here, because for desktop, below is useless await bind.mainStartService(); diff --git a/flutter/lib/plugin/widget.dart b/flutter/lib/plugin/widget.dart index b6bdbe16f..ae1482860 100644 --- a/flutter/lib/plugin/widget.dart +++ b/flutter/lib/plugin/widget.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hbb/models/model.dart'; @@ -198,7 +200,14 @@ void handleReloading(Map evt, String peer) { if (evt['id'] == null || evt['location'] == null) { return; } - addLocationUi(evt['location']!, evt['id']!, UiType.fromJson(evt)); + try { + final ui = UiType.create(json.decode(evt['ui'] as String)); + if (ui != null) { + addLocationUi(evt['location']!, evt['id']!, ui); + } + } catch (e) { + debugPrint('Failed handleReloading, json decode of ui, $e '); + } } void handleOption(Map evt, String peer) { diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index e52d446cb..0e16e7353 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1573,12 +1573,12 @@ pub fn plugin_feature_is_enabled() -> SyncReturn { } } -pub fn plugin_sync_ui() { +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(); + crate::plugin::sync_ui(_sync_to); } } } diff --git a/src/plugin/config.rs b/src/plugin/config.rs index 1f9267f0c..bce60dbc9 100644 --- a/src/plugin/config.rs +++ b/src/plugin/config.rs @@ -69,7 +69,8 @@ impl SharedConfig { #[inline] pub fn load(id: &str) { - let mut conf = hbb_common::config::load_path::(Self::path(id)); + let conf = hbb_common::config::load_path::>(Self::path(id)); + let mut conf = SharedConfig(conf); if let Some(items) = CONFIG_SHARED_ITEMS.lock().unwrap().get(id) { for item in items { if !conf.contains_key(&item.key) { @@ -116,7 +117,8 @@ impl PeerConfig { #[inline] pub fn load(id: &str, peer: &str) { - let mut conf = hbb_common::config::load_path::(Self::path(id, peer)); + let conf = hbb_common::config::load_path::>(Self::path(id, peer)); + let mut conf = PeerConfig(conf); if let Some(items) = CONFIG_PEER_ITEMS.lock().unwrap().get(id) { for item in items { if !conf.contains_key(&item.key) { @@ -124,16 +126,15 @@ impl PeerConfig { } } } - match CONFIG_PEERS.lock().unwrap().get_mut(id) { - Some(peers) => { - peers.insert(peer.to_owned(), conf); - } - None => { - let mut peers = HashMap::new(); - peers.insert(peer.to_owned(), conf); - CONFIG_PEERS.lock().unwrap().insert(id.to_owned(), peers); - } + + if let Some(peers) = CONFIG_PEERS.lock().unwrap().get_mut(id) { + peers.insert(peer.to_owned(), conf); + return; } + + let mut peers = HashMap::new(); + peers.insert(peer.to_owned(), conf); + CONFIG_PEERS.lock().unwrap().insert(id.to_owned(), peers); } #[inline] diff --git a/src/plugin/desc.rs b/src/plugin/desc.rs index a0bb5949f..553185010 100644 --- a/src/plugin/desc.rs +++ b/src/plugin/desc.rs @@ -36,7 +36,6 @@ pub struct Location { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ConfigItem { pub key: String, - pub value: String, pub default: String, pub description: String, } diff --git a/src/plugin/ipc.rs b/src/plugin/ipc.rs index 71807bb6b..501a4d8eb 100644 --- a/src/plugin/ipc.rs +++ b/src/plugin/ipc.rs @@ -1,6 +1,6 @@ // to-do: Interdependence(This mod and crate::ipc) is not good practice here. use crate::ipc::{connect, Connection, Data}; -use hbb_common::{allow_err, bail, bytes, log, tokio, ResultType}; +use hbb_common::{allow_err, log, tokio, ResultType}; use serde_derive::{Deserialize, Serialize}; #[cfg(not(windows))] use std::{fs::File, io::prelude::*}; diff --git a/src/plugin/plugins.rs b/src/plugin/plugins.rs index ab15287cf..1ee6a74cc 100644 --- a/src/plugin/plugins.rs +++ b/src/plugin/plugins.rs @@ -224,10 +224,10 @@ fn load_plugin_path(path: &str) -> ResultType<()> { (plugin.set_cb_msg)(callback_msg::callback_msg); (plugin.set_cb_get_id)(get_local_peer_id as _); // Ui may be not ready now, so we need to update again once ui is ready. - update_ui_plugin_desc(&desc); + update_ui_plugin_desc(&desc, None); update_config(&desc); // Ui may be not ready now, so we need to reload again once ui is ready. - reload_ui(&desc); + reload_ui(&desc, None); let plugin_info = PluginInfo { path: path.to_string(), desc, @@ -238,10 +238,10 @@ fn load_plugin_path(path: &str) -> ResultType<()> { Ok(()) } -pub fn sync_ui() { +pub fn sync_ui(sync_to: String) { for plugin in PLUGIN_INFO.read().unwrap().values() { - update_ui_plugin_desc(&plugin.desc); - reload_ui(&plugin.desc); + update_ui_plugin_desc(&plugin.desc, Some(&sync_to)); + reload_ui(&plugin.desc, Some(&sync_to)); } } @@ -369,44 +369,70 @@ fn update_config(desc: &Desc) { super::config::set_peer_items(desc.id(), &desc.config().peer); } -fn reload_ui(desc: &Desc) { +fn reload_ui(desc: &Desc, sync_to: Option<&str>) { for (location, ui) in desc.location().ui.iter() { - 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 = vec![ - flutter::APP_TYPE_MAIN, - flutter::APP_TYPE_DESKTOP_REMOTE, - flutter::APP_TYPE_CM, - flutter::APP_TYPE_DESKTOP_FILE_TRANSFER, - flutter::APP_TYPE_DESKTOP_PORT_FORWARD, - ]; - if available_channels.contains(&v[1]) { - if let Ok(ui) = serde_json::to_string(&ui) { - let mut m = HashMap::new(); - m.insert("name", MSG_TO_UI_TYPE_PLUGIN_RELOAD); - m.insert("id", desc.id()); - m.insert("location", &location); - m.insert("ui", &ui); - flutter::push_global_event(v[1], serde_json::to_string(&m).unwrap()); + 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.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 = vec![ + flutter::APP_TYPE_MAIN, + flutter::APP_TYPE_DESKTOP_REMOTE, + flutter::APP_TYPE_CM, + flutter::APP_TYPE_DESKTOP_FILE_TRANSFER, + flutter::APP_TYPE_DESKTOP_PORT_FORWARD, + ]; + if available_channels.contains(&v[1]) { + let _res = flutter::push_global_event(v[1], make_event(&ui)); + } + } } } } } } -fn update_ui_plugin_desc(desc: &Desc) { +fn update_ui_plugin_desc(desc: &Desc, sync_to: Option<&str>) { // This function is rarely used. There's no need to care about serialization efficiency here. if let Ok(desc_str) = serde_json::to_string(desc) { let mut m = HashMap::new(); m.insert("name", MSG_TO_UI_TYPE_PLUGIN_DESC); m.insert("desc", &desc_str); - flutter::push_global_event(flutter::APP_TYPE_MAIN, serde_json::to_string(&m).unwrap()); - flutter::push_global_event( - flutter::APP_TYPE_DESKTOP_REMOTE, - serde_json::to_string(&m).unwrap(), - ); - flutter::push_global_event(flutter::APP_TYPE_CM, serde_json::to_string(&m).unwrap()); + let event = serde_json::to_string(&m).unwrap_or("".to_owned()); + match sync_to { + Some(channel) => { + let _res = flutter::push_global_event(channel, serde_json::to_string(&m).unwrap()); + } + None => { + let _res = flutter::push_global_event( + flutter::APP_TYPE_MAIN, + serde_json::to_string(&m).unwrap(), + ); + let _res = flutter::push_global_event( + flutter::APP_TYPE_DESKTOP_REMOTE, + serde_json::to_string(&m).unwrap(), + ); + let _res = flutter::push_global_event( + flutter::APP_TYPE_CM, + serde_json::to_string(&m).unwrap(), + ); + } + } } }