mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Merge branch 'rustdesk:master' into master
This commit is contained in:
@@ -104,6 +104,17 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
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")))]
|
||||
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 {
|
||||
hbb_common::allow_err!(crate::plugin::load_plugins());
|
||||
}
|
||||
}
|
||||
if args.is_empty() {
|
||||
std::thread::spawn(move || crate::start_server(false));
|
||||
} else {
|
||||
|
||||
@@ -1436,11 +1436,11 @@ pub fn plugin_set_session_option(_id: String, _peer: String, _key: String, _valu
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn plugin_get_local_option(_id: String, _key: String) -> SyncReturn<Option<String>> {
|
||||
pub fn plugin_get_shared_option(_id: String, _key: String) -> SyncReturn<Option<String>> {
|
||||
#[cfg(feature = "plugin_framework")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
SyncReturn(crate::plugin::LocalConfig::get(&_id, &_key))
|
||||
SyncReturn(crate::plugin::ipc::get_config(&_id, &_key).unwrap_or(None))
|
||||
}
|
||||
#[cfg(any(
|
||||
not(feature = "plugin_framework"),
|
||||
@@ -1453,11 +1453,11 @@ pub fn plugin_get_local_option(_id: String, _key: String) -> SyncReturn<Option<S
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn plugin_set_local_option(_id: String, _key: String, _value: String) {
|
||||
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")))]
|
||||
{
|
||||
let _res = crate::plugin::LocalConfig::set(&_id, &_key, &_value);
|
||||
allow_err!(crate::plugin::ipc::set_config(&_id, &_key, _value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1466,21 +1466,31 @@ pub fn plugin_reload(_id: String) {
|
||||
#[cfg(feature = "plugin_framework")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
// to-do:
|
||||
// reload plugin
|
||||
allow_err!(crate::plugin::reload_plugin(&_id));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn plugin_id_uninstall(_id: String) {
|
||||
#[cfg(feature = "plugin_framework")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
// to-do: uninstall plugin
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn plugin_id_enable(_id: String, v: bool) {
|
||||
pub fn plugin_id_enable(_id: String, _v: bool) {
|
||||
#[cfg(feature = "plugin_framework")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
if v {
|
||||
allow_err!(crate::plugin::ManagerConfig::set_plugin_enabled(&_id, true));
|
||||
allow_err!(crate::plugin::ipc::set_manager_plugin_config(
|
||||
&_id,
|
||||
"enable",
|
||||
_v.to_string()
|
||||
));
|
||||
if _v {
|
||||
allow_err!(crate::plugin::reload_plugin(&_id));
|
||||
} else {
|
||||
allow_err!(crate::plugin::ManagerConfig::set_plugin_enabled(&_id, false));
|
||||
crate::plugin::unload_plugin(&_id);
|
||||
}
|
||||
}
|
||||
@@ -1491,7 +1501,10 @@ pub fn plugin_id_is_enabled(_id: String) -> SyncReturn<bool> {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
SyncReturn(
|
||||
crate::plugin::ManagerConfig::get_plugin_status(&_id, |s| s.enabled).unwrap_or(false),
|
||||
match crate::plugin::ipc::get_manager_plugin_config(&_id, "enabled") {
|
||||
Ok(Some(enabled)) => bool::from_str(&enabled).unwrap_or(false),
|
||||
_ => false,
|
||||
},
|
||||
)
|
||||
}
|
||||
#[cfg(any(
|
||||
@@ -1504,12 +1517,15 @@ pub fn plugin_id_is_enabled(_id: String) -> SyncReturn<bool> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn plugin_enable(v: bool) {
|
||||
pub fn plugin_enable(_v: bool) {
|
||||
#[cfg(feature = "plugin_framework")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
allow_err!(crate::plugin::ManagerConfig::set_enabled(v));
|
||||
if v {
|
||||
allow_err!(crate::plugin::ipc::set_manager_config(
|
||||
"enable",
|
||||
_v.to_string()
|
||||
));
|
||||
if _v {
|
||||
allow_err!(crate::plugin::load_plugins());
|
||||
} else {
|
||||
crate::plugin::unload_plugins();
|
||||
@@ -1517,11 +1533,35 @@ pub fn plugin_enable(v: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn plugin_is_enabled() -> SyncReturn<bool> {
|
||||
pub fn plugin_is_enabled() -> SyncReturn<Option<bool>> {
|
||||
#[cfg(feature = "plugin_framework")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
SyncReturn(crate::plugin::ManagerConfig::is_enabled())
|
||||
let r = match crate::plugin::ipc::get_manager_config("enabled") {
|
||||
Ok(Some(enabled)) => Some(bool::from_str(&enabled).unwrap_or(false)),
|
||||
_ => None,
|
||||
};
|
||||
SyncReturn(r)
|
||||
}
|
||||
#[cfg(any(
|
||||
not(feature = "plugin_framework"),
|
||||
target_os = "android",
|
||||
target_os = "ios"
|
||||
))]
|
||||
{
|
||||
SyncReturn(Some(false))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn plugin_feature_is_enabled() -> SyncReturn<bool> {
|
||||
#[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"),
|
||||
@@ -1533,19 +1573,13 @@ pub fn plugin_is_enabled() -> SyncReturn<bool> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn plugin_feature_is_enabled() -> SyncReturn<bool> {
|
||||
pub fn plugin_sync_ui() {
|
||||
#[cfg(feature = "plugin_framework")]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
{
|
||||
SyncReturn(true)
|
||||
}
|
||||
#[cfg(any(
|
||||
not(feature = "plugin_framework"),
|
||||
target_os = "android",
|
||||
target_os = "ios"
|
||||
))]
|
||||
{
|
||||
SyncReturn(false)
|
||||
if plugin_feature_is_enabled().0 {
|
||||
crate::plugin::sync_ui();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ use parity_tokio_ipc::{
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
use crate::plugin::ipc::Plugin;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
pub use clipboard::ClipboardFile;
|
||||
use hbb_common::{
|
||||
@@ -215,6 +218,9 @@ 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),
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
@@ -453,6 +459,9 @@ 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,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,8 +110,8 @@ pub fn callback_msg(
|
||||
// No need to merge the msgs. Handling the msg one by one is ok.
|
||||
if let Ok(msg) = serde_json::from_str::<MsgToConfig>(s) {
|
||||
match &msg.r#type as _ {
|
||||
config::CONFIG_TYPE_LOCAL => {
|
||||
match config::LocalConfig::set(&msg.id, &msg.key, &msg.value) {
|
||||
config::CONFIG_TYPE_SHARED => {
|
||||
match config::SharedConfig::set(&msg.id, &msg.key, &msg.value) {
|
||||
Ok(_) => {
|
||||
if let Some(ui) = &msg.ui {
|
||||
// No need to set the peer id for location config.
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
use crate::plugins::Plugin;
|
||||
|
||||
use super::desc::ConfigItem;
|
||||
use hbb_common::{bail, config::Config as HbbConfig, lazy_static, ResultType};
|
||||
use hbb_common::{allow_err, bail, config::Config as HbbConfig, lazy_static, log, ResultType};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
str::FromStr,
|
||||
sync::{Arc, Mutex},
|
||||
{collections::HashMap, path::PathBuf},
|
||||
};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref CONFIG_LOCAL: Arc<Mutex<HashMap<String, LocalConfig>>> = Default::default();
|
||||
static ref CONFIG_LOCAL_ITEMS: Arc<Mutex<HashMap<String, Vec<ConfigItem>>>> = Default::default();
|
||||
static ref CONFIG_SHARED: Arc<Mutex<HashMap<String, SharedConfig>>> = Default::default();
|
||||
static ref CONFIG_SHARED_ITEMS: Arc<Mutex<HashMap<String, Vec<ConfigItem>>>> = Default::default();
|
||||
static ref CONFIG_PEERS: Arc<Mutex<HashMap<String, PeersConfig>>> = Default::default();
|
||||
static ref CONFIG_PEER_ITEMS: Arc<Mutex<HashMap<String, Vec<ConfigItem>>>> = Default::default();
|
||||
static ref CONFIG_MANAGER: Arc<Mutex<ManagerConfig>> = {
|
||||
@@ -20,11 +19,11 @@ lazy_static::lazy_static! {
|
||||
};
|
||||
}
|
||||
|
||||
pub(super) const CONFIG_TYPE_LOCAL: &str = "local";
|
||||
pub(super) const CONFIG_TYPE_SHARED: &str = "shared";
|
||||
pub(super) const CONFIG_TYPE_PEER: &str = "peer";
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct LocalConfig(HashMap<String, String>);
|
||||
pub struct SharedConfig(HashMap<String, String>);
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct PeerConfig(HashMap<String, String>);
|
||||
type PeersConfig = HashMap<String, PeerConfig>;
|
||||
@@ -34,7 +33,7 @@ fn path_plugins(id: &str) -> PathBuf {
|
||||
HbbConfig::path("plugins").join(id)
|
||||
}
|
||||
|
||||
impl Deref for LocalConfig {
|
||||
impl Deref for SharedConfig {
|
||||
type Target = HashMap<String, String>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@@ -42,7 +41,7 @@ impl Deref for LocalConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for LocalConfig {
|
||||
impl DerefMut for SharedConfig {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
@@ -62,32 +61,32 @@ impl DerefMut for PeerConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalConfig {
|
||||
impl SharedConfig {
|
||||
#[inline]
|
||||
fn path(id: &str) -> PathBuf {
|
||||
path_plugins(id).join("local.toml")
|
||||
path_plugins(id).join("shared.toml")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn load(id: &str) {
|
||||
let mut conf = hbb_common::config::load_path::<LocalConfig>(Self::path(id));
|
||||
if let Some(items) = CONFIG_LOCAL_ITEMS.lock().unwrap().get(id) {
|
||||
let mut conf = hbb_common::config::load_path::<SharedConfig>(Self::path(id));
|
||||
if let Some(items) = CONFIG_SHARED_ITEMS.lock().unwrap().get(id) {
|
||||
for item in items {
|
||||
if !conf.contains_key(&item.key) {
|
||||
conf.insert(item.key.to_owned(), item.default.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
CONFIG_LOCAL.lock().unwrap().insert(id.to_owned(), conf);
|
||||
CONFIG_SHARED.lock().unwrap().insert(id.to_owned(), conf);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(id: &str, key: &str) -> Option<String> {
|
||||
if let Some(conf) = CONFIG_LOCAL.lock().unwrap().get(id) {
|
||||
if let Some(conf) = CONFIG_SHARED.lock().unwrap().get(id) {
|
||||
return conf.get(key).map(|s| s.to_owned());
|
||||
}
|
||||
Self::load(id);
|
||||
CONFIG_LOCAL
|
||||
CONFIG_SHARED
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(id)?
|
||||
@@ -97,7 +96,7 @@ impl LocalConfig {
|
||||
|
||||
#[inline]
|
||||
pub fn set(id: &str, key: &str, value: &str) -> ResultType<()> {
|
||||
match CONFIG_LOCAL.lock().unwrap().get_mut(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)
|
||||
@@ -170,8 +169,8 @@ impl PeerConfig {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn set_local_items(id: &str, items: &Vec<ConfigItem>) {
|
||||
CONFIG_LOCAL_ITEMS
|
||||
pub(super) fn set_shared_items(id: &str, items: &Vec<ConfigItem>) {
|
||||
CONFIG_SHARED_ITEMS
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(id.to_owned(), items.clone());
|
||||
@@ -196,14 +195,18 @@ const MANAGER_VERSION: &str = "0.1.0";
|
||||
pub struct ManagerConfig {
|
||||
pub version: String,
|
||||
pub enabled: bool,
|
||||
#[serde(default)]
|
||||
pub options: HashMap<String, String>,
|
||||
#[serde(default)]
|
||||
pub plugins: HashMap<String, PluginStatus>,
|
||||
}
|
||||
|
||||
impl Default for ManagerConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
version: "0.1.0".to_owned(),
|
||||
version: MANAGER_VERSION.to_owned(),
|
||||
enabled: true,
|
||||
options: HashMap::new(),
|
||||
plugins: HashMap::new(),
|
||||
}
|
||||
}
|
||||
@@ -217,31 +220,65 @@ impl ManagerConfig {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_enabled() -> bool {
|
||||
CONFIG_MANAGER.lock().unwrap().enabled
|
||||
pub fn get_option(key: &str) -> Option<String> {
|
||||
if key == "enabled" {
|
||||
Some(CONFIG_MANAGER.lock().unwrap().enabled.to_string())
|
||||
} else {
|
||||
CONFIG_MANAGER
|
||||
.lock()
|
||||
.unwrap()
|
||||
.options
|
||||
.get(key)
|
||||
.map(|s| s.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_enabled(enabled: bool) -> ResultType<()> {
|
||||
pub fn set_option(key: &str, value: &str) -> ResultType<()> {
|
||||
let mut lock = CONFIG_MANAGER.lock().unwrap();
|
||||
lock.enabled = enabled;
|
||||
if key == "enabled" {
|
||||
let enabled = bool::from_str(value).unwrap_or(false);
|
||||
lock.enabled = enabled;
|
||||
if enabled {
|
||||
allow_err!(super::load_plugins());
|
||||
} else {
|
||||
super::unload_plugins();
|
||||
}
|
||||
} else {
|
||||
lock.options.insert(key.to_owned(), value.to_owned());
|
||||
}
|
||||
hbb_common::config::store_path(Self::path(), &*lock)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_plugin_status<T>(id: &str, f: fn(&PluginStatus) -> T) -> Option<T> {
|
||||
pub fn get_plugin_option(id: &str, key: &str) -> Option<String> {
|
||||
let lock = CONFIG_MANAGER.lock().unwrap();
|
||||
lock.plugins.get(id).map(f)
|
||||
let status = lock.plugins.get(id)?;
|
||||
match key {
|
||||
"enabled" => Some(status.enabled.to_string()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_plugin_enabled(id: &str, enabled: bool) -> ResultType<()> {
|
||||
pub fn set_plugin_option(id: &str, key: &str, value: &str) -> ResultType<()> {
|
||||
let mut lock = CONFIG_MANAGER.lock().unwrap();
|
||||
if let Some(status) = lock.plugins.get_mut(id) {
|
||||
status.enabled = enabled;
|
||||
hbb_common::config::store_path(Self::path(), &*lock)
|
||||
match key {
|
||||
"enabled" => {
|
||||
let enabled = bool::from_str(value).unwrap_or(false);
|
||||
status.enabled = enabled;
|
||||
if enabled {
|
||||
allow_err!(super::load_plugin(None, Some(id)));
|
||||
} else {
|
||||
super::unload_plugin(id);
|
||||
}
|
||||
}
|
||||
_ => bail!("No such option {}", key),
|
||||
}
|
||||
} else {
|
||||
bail!("No such plugin {}", id)
|
||||
}
|
||||
hbb_common::config::store_path(Self::path(), &*lock)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -256,6 +293,8 @@ impl ManagerConfig {
|
||||
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)
|
||||
hbb_common::config::store_path(Self::path(), &*lock)?;
|
||||
// to-do: remove plugin config dir
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use std::ffi::{c_char, CStr};
|
||||
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.
|
||||
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.
|
||||
}
|
||||
@@ -43,7 +43,7 @@ pub struct ConfigItem {
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
pub local: Vec<ConfigItem>,
|
||||
pub shared: Vec<ConfigItem>,
|
||||
pub peer: Vec<ConfigItem>,
|
||||
}
|
||||
|
||||
|
||||
184
src/plugin/ipc.rs
Normal file
184
src/plugin/ipc.rs
Normal file
@@ -0,0 +1,184 @@
|
||||
// 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 serde_derive::{Deserialize, Serialize};
|
||||
#[cfg(not(windows))]
|
||||
use std::{fs::File, io::prelude::*};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(tag = "t", content = "c")]
|
||||
pub enum Plugin {
|
||||
Config(String, String, Option<String>),
|
||||
ManagerConfig(String, Option<String>),
|
||||
ManagerPluginConfig(String, String, Option<String>),
|
||||
Reload(String),
|
||||
Uninstall,
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
pub async fn get_config(id: &str, name: &str) -> ResultType<Option<String>> {
|
||||
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<Option<String>> {
|
||||
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<Option<String>> {
|
||||
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
|
||||
}
|
||||
|
||||
async fn get_config_async(id: &str, name: &str, ms_timeout: u64) -> ResultType<Option<String>> {
|
||||
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<Option<String>> {
|
||||
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<Option<String>> {
|
||||
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 handle_plugin(plugin: Plugin, stream: &mut Connection) {
|
||||
match plugin {
|
||||
Plugin::Config(id, name, value) => match value {
|
||||
None => {
|
||||
let value = crate::plugin::SharedConfig::get(&id, &name);
|
||||
allow_err!(
|
||||
stream
|
||||
.send(&Data::Plugin(Plugin::Config(id, name, value)))
|
||||
.await
|
||||
);
|
||||
}
|
||||
Some(value) => {
|
||||
allow_err!(crate::plugin::SharedConfig::set(&id, &name, &value));
|
||||
}
|
||||
},
|
||||
Plugin::ManagerConfig(name, value) => match value {
|
||||
None => {
|
||||
let value = crate::plugin::ManagerConfig::get_option(&name);
|
||||
allow_err!(
|
||||
stream
|
||||
.send(&Data::Plugin(Plugin::ManagerConfig(name, value)))
|
||||
.await
|
||||
);
|
||||
}
|
||||
Some(value) => {
|
||||
allow_err!(crate::plugin::ManagerConfig::set_option(&name, &value));
|
||||
}
|
||||
},
|
||||
Plugin::ManagerPluginConfig(id, name, value) => match value {
|
||||
None => {
|
||||
let value = crate::plugin::ManagerConfig::get_plugin_option(&id, &name);
|
||||
allow_err!(
|
||||
stream
|
||||
.send(&Data::Plugin(Plugin::ManagerPluginConfig(id, name, value)))
|
||||
.await
|
||||
);
|
||||
}
|
||||
Some(value) => {
|
||||
allow_err!(crate::plugin::ManagerConfig::set_plugin_option(
|
||||
&id, &name, &value
|
||||
));
|
||||
}
|
||||
},
|
||||
Plugin::Reload(id) => {
|
||||
allow_err!(crate::plugin::reload_plugin(&id));
|
||||
}
|
||||
Plugin::Uninstall => {
|
||||
// to-do: uninstall plugin
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,12 @@ mod callback_msg;
|
||||
mod config;
|
||||
pub mod desc;
|
||||
mod errno;
|
||||
pub mod ipc;
|
||||
mod plugins;
|
||||
|
||||
pub use plugins::{
|
||||
handle_client_event, handle_server_event, handle_ui_event, load_plugin, load_plugins,
|
||||
reload_plugin, unload_plugin, unload_plugins,
|
||||
reload_plugin, sync_ui, unload_plugin, unload_plugins,
|
||||
};
|
||||
|
||||
const MSG_TO_UI_TYPE_PLUGIN_DESC: &str = "plugin_desc";
|
||||
@@ -17,7 +18,7 @@ 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";
|
||||
|
||||
pub use config::{LocalConfig, ManagerConfig, PeerConfig};
|
||||
pub use config::{ManagerConfig, PeerConfig, SharedConfig};
|
||||
|
||||
#[inline]
|
||||
fn cstr_to_string(cstr: *const c_char) -> ResultType<String> {
|
||||
|
||||
@@ -104,7 +104,7 @@ macro_rules! make_plugin {
|
||||
|
||||
$(let $field = match unsafe { lib.symbol::<$tp>(stringify!($field)) } {
|
||||
Ok(m) => {
|
||||
log::info!("method found {}", stringify!($field));
|
||||
log::debug!("{} method found {}", path, stringify!($field));
|
||||
*m
|
||||
},
|
||||
Err(e) => {
|
||||
@@ -132,6 +132,13 @@ make_plugin!(
|
||||
set_cb_get_id: PluginFuncGetIdCallback
|
||||
);
|
||||
|
||||
#[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 fn load_plugins() -> ResultType<()> {
|
||||
let exe = std::env::current_exe()?.to_string_lossy().to_string();
|
||||
match PathBuf::from(&exe).parent() {
|
||||
@@ -141,10 +148,12 @@ pub fn load_plugins() -> ResultType<()> {
|
||||
Ok(entry) => {
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
let path = path.to_str().unwrap_or("");
|
||||
if path.ends_with(".so") {
|
||||
if let Err(e) = load_plugin(Some(path), None) {
|
||||
log::error!("{e}");
|
||||
let filename = entry.file_name();
|
||||
let filename = filename.to_str().unwrap_or("");
|
||||
if filename.starts_with("plugin_") && filename.ends_with(DYLIB_SUFFIX) {
|
||||
if let Err(e) = load_plugin(Some(path.to_str().unwrap_or("")), None)
|
||||
{
|
||||
log::error!("Failed to load plugin {}, {}", filename, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,18 +223,28 @@ fn load_plugin_path(path: &str) -> ResultType<()> {
|
||||
// to-do check the plugin id (make sure it does not use another plugin's id)
|
||||
(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_config(&desc);
|
||||
// Ui may be not ready now, so we need to reload again once ui is ready.
|
||||
reload_ui(&desc);
|
||||
let plugin_info = PluginInfo {
|
||||
path: path.to_string(),
|
||||
desc,
|
||||
};
|
||||
PLUGIN_INFO.write().unwrap().insert(id.clone(), plugin_info);
|
||||
PLUGINS.write().unwrap().insert(id, plugin);
|
||||
PLUGINS.write().unwrap().insert(id.clone(), plugin);
|
||||
log::info!("Plugin {} loaded", id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sync_ui() {
|
||||
for plugin in PLUGIN_INFO.read().unwrap().values() {
|
||||
update_ui_plugin_desc(&plugin.desc);
|
||||
reload_ui(&plugin.desc);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_plugin(path: Option<&str>, id: Option<&str>) -> ResultType<()> {
|
||||
match (path, id) {
|
||||
(Some(path), _) => load_plugin_path(path),
|
||||
@@ -346,7 +365,7 @@ fn make_plugin_response(id: &str, name: &str, msg: &str) -> Message {
|
||||
}
|
||||
|
||||
fn update_config(desc: &Desc) {
|
||||
super::config::set_local_items(desc.id(), &desc.config().local);
|
||||
super::config::set_shared_items(desc.id(), &desc.config().shared);
|
||||
super::config::set_peer_items(desc.id(), &desc.config().peer);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user