plugin_framework, handle plugin list

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2023-05-09 22:59:38 +08:00
parent db71dd039d
commit 4eb6bd82a4
8 changed files with 57 additions and 33 deletions

View File

@ -126,6 +126,7 @@ void runMainApp(bool startService) async {
// await windowManager.ensureInitialized(); // await windowManager.ensureInitialized();
gFFI.serverModel.startService(); gFFI.serverModel.startService();
bind.pluginSyncUi(syncTo: kAppTypeMain); bind.pluginSyncUi(syncTo: kAppTypeMain);
bind.pluginListReload();
} }
gFFI.userModel.refreshCurrentUser(); gFFI.userModel.refreshCurrentUser();
runApp(App()); runApp(App());

View File

@ -231,6 +231,7 @@ class FfiModel with ChangeNotifier {
} else if (name == 'fingerprint') { } else if (name == 'fingerprint') {
FingerprintState.find(peerId).value = evt['fingerprint'] ?? ''; FingerprintState.find(peerId).value = evt['fingerprint'] ?? '';
} else if (name == 'plugin_manager') { } else if (name == 'plugin_manager') {
debugPrint('REMOVE ME ==================== plugin_manager $evt');
pluginManager.handleEvent(evt); pluginManager.handleEvent(evt);
} else if (name == 'plugin_event') { } else if (name == 'plugin_event') {
handlePluginEvent( handlePluginEvent(

View File

@ -1,6 +1,7 @@
// The plugin manager is a singleton class that manages the plugins. // The plugin manager is a singleton class that manages the plugins.
// 1. It merge metadata and the desc of plugins. // 1. It merge metadata and the desc of plugins.
import 'dart:convert';
import 'dart:collection'; import 'dart:collection';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -211,17 +212,19 @@ class PluginManager with ChangeNotifier {
} }
} }
void _handlePluginList(List<dynamic> evt) { void _handlePluginList(String pluginList) {
_plugins.clear(); _plugins.clear();
try {
for (var p in evt) { for (var p in json.decode(pluginList) as List<dynamic>) {
final plugin = _getPluginFromEvent(p); final plugin = _getPluginFromEvent(p);
if (plugin == null) { if (plugin == null) {
continue; continue;
}
_plugins.add(plugin);
} }
_plugins.add(plugin); } catch (e) {
debugPrint('Failed to decode plugin list \'$pluginList\'');
} }
notifyListeners(); notifyListeners();
} }

View File

@ -35,6 +35,7 @@ chrono = "0.4"
backtrace = "0.3" backtrace = "0.3"
libc = "0.2" libc = "0.2"
dlopen = "0.1" dlopen = "0.1"
toml = "0.7"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
mac_address = "1.1" mac_address = "1.1"
@ -55,5 +56,4 @@ winapi = { version = "0.3", features = ["winuser"] }
osascript = "0.3" osascript = "0.3"
[dev-dependencies] [dev-dependencies]
toml = "0.7"
serde_json = "1.0" serde_json = "1.0"

View File

@ -46,6 +46,7 @@ pub mod keyboard;
pub use sysinfo; pub use sysinfo;
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
pub use dlopen; pub use dlopen;
pub use toml;
#[cfg(feature = "quic")] #[cfg(feature = "quic")]
pub type Stream = quic::Connection; pub type Stream = quic::Connection;

View File

@ -1570,7 +1570,7 @@ pub fn plugin_list_reload() {
#[cfg(feature = "plugin_framework")] #[cfg(feature = "plugin_framework")]
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
{ {
crate::plugin::load_plugin_list(false); crate::plugin::load_plugin_list();
} }
} }

View File

@ -3,7 +3,7 @@
use super::{desc::Meta as PluginMeta, ipc::InstallStatus, *}; use super::{desc::Meta as PluginMeta, ipc::InstallStatus, *};
use crate::{common::is_server, flutter}; use crate::{common::is_server, flutter};
use hbb_common::{allow_err, bail, log, tokio}; use hbb_common::{allow_err, bail, config::load_path, log, tokio, toml};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use serde_json; use serde_json;
use std::{ use std::{
@ -21,7 +21,7 @@ lazy_static::lazy_static! {
static ref PLUGIN_INFO: Arc<Mutex<HashMap<String, PluginInfo>>> = Arc::new(Mutex::new(HashMap::new())); static ref PLUGIN_INFO: Arc<Mutex<HashMap<String, PluginInfo>>> = Arc::new(Mutex::new(HashMap::new()));
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Default, Serialize, Deserialize)]
pub struct ManagerMeta { pub struct ManagerMeta {
pub version: String, pub version: String,
pub description: String, pub description: String,
@ -45,24 +45,47 @@ pub struct PluginInfo {
} }
static PLUGIN_SOURCE_LOCAL: &str = "local"; static PLUGIN_SOURCE_LOCAL: &str = "local";
pub(super) static PLUGIN_SOURCE_LOCAL_URL: &str = "plugins";
#[cfg(not(debug_assertions))]
fn get_plugin_source_list() -> Vec<PluginSource> { fn get_plugin_source_list() -> Vec<PluginSource> {
// Only one source for now. // Only one source for now.
vec![PluginSource { vec![PluginSource {
name: "rustdesk".to_string(), name: "rustdesk".to_string(),
#[cfg(debug_assertions)]
url: PLUGIN_SOURCE_LOCAL_URL.to_string(),
#[cfg(not(debug_assertions))]
url: "https://github.com/fufesou/rustdesk-plugins".to_string(), url: "https://github.com/fufesou/rustdesk-plugins".to_string(),
description: "".to_string(), description: "".to_string(),
}] }]
} }
#[cfg(debug_assertions)]
fn get_source_plugins() -> HashMap<String, PluginInfo> {
let meta_file = super::get_plugins_dir().unwrap().join("meta.toml");
let mut plugins = HashMap::new();
let meta = load_path::<ManagerMeta>(meta_file);
let source = PluginSource {
name: "rustdesk".to_string(),
url: "https://github.com/fufesou/rustdesk-plugins".to_string(),
description: "".to_string(),
};
for plugin in meta.plugins.iter() {
plugins.insert(
plugin.id.clone(),
PluginInfo {
source: source.clone(),
plugin: plugin.clone(),
installed_version: "".to_string(),
install_time: "".to_string(),
invalid_reason: "".to_string(),
},
);
}
plugins
}
#[cfg(not(debug_assertions))]
fn get_source_plugins() -> HashMap<String, PluginInfo> { fn get_source_plugins() -> HashMap<String, PluginInfo> {
let mut plugins = HashMap::new(); let mut plugins = HashMap::new();
for source in get_plugin_source_list().into_iter() { for source in get_plugin_source_list().into_iter() {
let url = format!("{}/meta.json", source.url); let url = format!("{}/meta.toml", source.url);
match reqwest::blocking::get(&url) { match reqwest::blocking::get(&url) {
Ok(resp) => { Ok(resp) => {
if !resp.status().is_success() { if !resp.status().is_success() {
@ -109,16 +132,8 @@ fn send_plugin_list_event(plugins: &HashMap<String, PluginInfo>) {
} }
} }
pub fn load_plugin_list(load_local: bool) { pub fn load_plugin_list() {
let mut plugin_info_lock = PLUGIN_INFO.lock().unwrap(); let mut plugin_info_lock = PLUGIN_INFO.lock().unwrap();
if load_local {
if is_server() {
allow_err!(super::plugins::load_plugins());
return;
}
}
let mut plugins = get_source_plugins(); let mut plugins = get_source_plugins();
for (id, info) in super::plugins::get_plugin_infos().read().unwrap().iter() { for (id, info) in super::plugins::get_plugin_infos().read().unwrap().iter() {
if let Some(p) = plugins.get_mut(id) { if let Some(p) = plugins.get_mut(id) {
@ -130,7 +145,7 @@ pub fn load_plugin_list(load_local: bool) {
PluginInfo { PluginInfo {
source: PluginSource { source: PluginSource {
name: PLUGIN_SOURCE_LOCAL.to_string(), name: PLUGIN_SOURCE_LOCAL.to_string(),
url: PLUGIN_SOURCE_LOCAL_URL.to_string(), url: PLUGIN_SOURCE_LOCAL_DIR.to_string(),
description: "".to_string(), description: "".to_string(),
}, },
plugin: info.desc.meta().clone(), plugin: info.desc.meta().clone(),
@ -163,9 +178,7 @@ pub fn install_plugin(id: &str) -> ResultType<()> {
} }
} }
pub(super) fn remove_plugins() { pub(super) fn remove_plugins() {}
}
// 1. Add to uninstall list. // 1. Add to uninstall list.
// 2. Try remove. // 2. Try remove.

View File

@ -1,4 +1,4 @@
use hbb_common::{libc, tokio, ResultType}; use hbb_common::{libc, tokio, ResultType, allow_err, log};
use std::{ use std::{
env, env,
ffi::{c_char, c_int, c_void, CStr}, ffi::{c_char, c_int, c_void, CStr},
@ -38,6 +38,8 @@ 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_CLIENT: &str = "on_conn_close_client";
pub const EVENT_ON_CONN_CLOSE_SERVER: &str = "on_conn_close_server"; 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}; pub use config::{ManagerConfig, PeerConfig, SharedConfig};
use crate::common::is_server; use crate::common::is_server;
@ -91,14 +93,17 @@ pub fn init() {
std::thread::spawn(move || manager::start_ipc()); std::thread::spawn(move || manager::start_ipc());
if is_server() { if is_server() {
manager::remove_plugins(); manager::remove_plugins();
allow_err!(plugins::load_plugins());
} }
load_plugin_list(true); load_plugin_list();
} }
#[inline] #[inline]
fn get_plugins_dir() -> ResultType<PathBuf> { fn get_plugins_dir() -> ResultType<PathBuf> {
// to-do: linux and macos // to-do: linux and macos
Ok(PathBuf::from(env::var("ProgramData")?).join(manager::PLUGIN_SOURCE_LOCAL_URL)) Ok(PathBuf::from(env::var("ProgramData")?)
.join("RustDesk")
.join(PLUGIN_SOURCE_LOCAL_DIR))
} }
#[inline] #[inline]