mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
plugin_framework, test plugin manager, uninstall is not fully tested
Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
parent
4ee0fd9676
commit
095ac46255
@ -1466,15 +1466,22 @@ class _PluginState extends State<_Plugin> {
|
|||||||
return ListView(
|
return ListView(
|
||||||
physics: DraggableNeverScrollableScrollPhysics(),
|
physics: DraggableNeverScrollableScrollPhysics(),
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
children: model.plugins
|
children: model.plugins.map((entry) => pluginCard(entry)).toList(),
|
||||||
.map((entry) => DesktopSettingsCard(plugin: entry))
|
|
||||||
.toList(),
|
|
||||||
).marginOnly(bottom: _kListViewBottomMargin);
|
).marginOnly(bottom: _kListViewBottomMargin);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget pluginCard(PluginInfo plugin) {
|
||||||
|
return ChangeNotifierProvider.value(
|
||||||
|
value: plugin,
|
||||||
|
child: Consumer<PluginInfo>(
|
||||||
|
builder: (context, model, child) => DesktopSettingsCard(plugin: model),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget accountAction() {
|
Widget accountAction() {
|
||||||
return Obx(() => _Button(
|
return Obx(() => _Button(
|
||||||
gFFI.userModel.userName.value.isEmpty ? 'Login' : 'Logout',
|
gFFI.userModel.userName.value.isEmpty ? 'Login' : 'Logout',
|
||||||
|
|||||||
@ -144,17 +144,20 @@ class PluginInfo with ChangeNotifier {
|
|||||||
SourceInfo sourceInfo;
|
SourceInfo sourceInfo;
|
||||||
Meta meta;
|
Meta meta;
|
||||||
String installedVersion; // It is empty if not installed.
|
String installedVersion; // It is empty if not installed.
|
||||||
DateTime installTime;
|
String failedMsg;
|
||||||
String invalidReason; // It is empty if valid.
|
String invalidReason; // It is empty if valid.
|
||||||
|
|
||||||
PluginInfo({
|
PluginInfo({
|
||||||
required this.sourceInfo,
|
required this.sourceInfo,
|
||||||
required this.meta,
|
required this.meta,
|
||||||
required this.installedVersion,
|
required this.installedVersion,
|
||||||
required this.installTime,
|
|
||||||
required this.invalidReason,
|
required this.invalidReason,
|
||||||
|
this.failedMsg = '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bool get installed => installedVersion.isNotEmpty;
|
||||||
|
bool get needUpdate => installed && installedVersion != meta.version;
|
||||||
|
|
||||||
void update(PluginInfo plugin) {
|
void update(PluginInfo plugin) {
|
||||||
assert(plugin.meta.id == meta.id, 'Plugin id not match');
|
assert(plugin.meta.id == meta.id, 'Plugin id not match');
|
||||||
if (plugin.meta.id != meta.id) {
|
if (plugin.meta.id != meta.id) {
|
||||||
@ -164,10 +167,28 @@ class PluginInfo with ChangeNotifier {
|
|||||||
sourceInfo = plugin.sourceInfo;
|
sourceInfo = plugin.sourceInfo;
|
||||||
meta = plugin.meta;
|
meta = plugin.meta;
|
||||||
installedVersion = plugin.installedVersion;
|
installedVersion = plugin.installedVersion;
|
||||||
installTime = plugin.installTime;
|
|
||||||
invalidReason = plugin.invalidReason;
|
invalidReason = plugin.invalidReason;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
class PluginManager with ChangeNotifier {
|
||||||
@ -194,11 +215,27 @@ class PluginManager with ChangeNotifier {
|
|||||||
_handlePluginList(evt['plugin_list']);
|
_handlePluginList(evt['plugin_list']);
|
||||||
} else if (evt['plugin_update'] != null) {
|
} else if (evt['plugin_update'] != null) {
|
||||||
_handlePluginUpdate(evt['plugin_update']);
|
_handlePluginUpdate(evt['plugin_update']);
|
||||||
|
} 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 {
|
} else {
|
||||||
debugPrint('Failed to handle manager event: $evt');
|
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 _handlePluginUpdate(Map<String, dynamic> evt) {
|
void _handlePluginUpdate(Map<String, dynamic> evt) {
|
||||||
final plugin = _getPluginFromEvent(evt);
|
final plugin = _getPluginFromEvent(evt);
|
||||||
if (plugin == null) {
|
if (plugin == null) {
|
||||||
@ -207,6 +244,8 @@ class PluginManager with ChangeNotifier {
|
|||||||
for (var i = 0; i < _plugins.length; i++) {
|
for (var i = 0; i < _plugins.length; i++) {
|
||||||
if (_plugins[i].meta.id == plugin.meta.id) {
|
if (_plugins[i].meta.id == plugin.meta.id) {
|
||||||
_plugins[i].update(plugin);
|
_plugins[i].update(plugin);
|
||||||
|
_sortPlugins();
|
||||||
|
notifyListeners();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,9 +264,32 @@ class PluginManager with ChangeNotifier {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Failed to decode $e, plugin list \'$pluginList\'');
|
debugPrint('Failed to decode $e, plugin list \'$pluginList\'');
|
||||||
}
|
}
|
||||||
|
_sortPlugins();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handlePluginInstall(String id, String 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) {
|
||||||
|
for (var i = 0; i < _plugins.length; i++) {
|
||||||
|
if (_plugins[i].meta.id == id) {
|
||||||
|
_plugins[i].setUninstall(msg);
|
||||||
|
_sortPlugins();
|
||||||
|
notifyListeners();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PluginInfo? _getPluginFromEvent(Map<String, dynamic> evt) {
|
PluginInfo? _getPluginFromEvent(Map<String, dynamic> evt) {
|
||||||
final s = evt['source'];
|
final s = evt['source'];
|
||||||
assert(s != null, 'Source is null');
|
assert(s != null, 'Source is null');
|
||||||
@ -273,19 +335,10 @@ class PluginManager with ChangeNotifier {
|
|||||||
publishInfo:
|
publishInfo:
|
||||||
PublishInfo(lastReleased: lastReleased, published: published),
|
PublishInfo(lastReleased: lastReleased, published: published),
|
||||||
);
|
);
|
||||||
|
|
||||||
late DateTime installTime;
|
|
||||||
try {
|
|
||||||
installTime =
|
|
||||||
DateTime.parse(evt['install_time'] ?? '1970-01-01T00+00:00');
|
|
||||||
} catch (e) {
|
|
||||||
installTime = DateTime.utc(1970);
|
|
||||||
}
|
|
||||||
return PluginInfo(
|
return PluginInfo(
|
||||||
sourceInfo: source,
|
sourceInfo: source,
|
||||||
meta: meta,
|
meta: meta,
|
||||||
installedVersion: evt['installed_version'],
|
installedVersion: evt['installed_version'],
|
||||||
installTime: installTime,
|
|
||||||
invalidReason: evt['invalid_reason'] ?? '',
|
invalidReason: evt['invalid_reason'] ?? '',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,10 +28,13 @@ class DesktopSettingsCard extends StatefulWidget {
|
|||||||
|
|
||||||
class _DesktopSettingsCardState extends State<DesktopSettingsCard> {
|
class _DesktopSettingsCardState extends State<DesktopSettingsCard> {
|
||||||
PluginInfo get plugin => widget.plugin;
|
PluginInfo get plugin => widget.plugin;
|
||||||
bool get installed => plugin.installedVersion.isNotEmpty;
|
bool get installed => plugin.installed;
|
||||||
|
|
||||||
|
bool isEnabled = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
isEnabled = bind.pluginIsEnabled(id: plugin.meta.id);
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Flexible(
|
Flexible(
|
||||||
@ -70,7 +73,7 @@ class _DesktopSettingsCardState extends State<DesktopSettingsCard> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
translate(widget.plugin.meta.name),
|
widget.plugin.meta.name,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: _kTitleFontSize,
|
fontSize: _kTitleFontSize,
|
||||||
@ -95,24 +98,25 @@ class _DesktopSettingsCardState extends State<DesktopSettingsCard> {
|
|||||||
return Container(
|
return Container(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
child: Text(label),
|
child: Text(translate(label)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget headerInstallEnable() {
|
Widget headerInstallEnable() {
|
||||||
final installButton = headerButton(installed ? 'uninstall' : 'install', () {
|
final installButton = headerButton(
|
||||||
bind.pluginInstall(
|
installed ? 'Uninstall' : 'Install',
|
||||||
id: plugin.meta.id,
|
() {
|
||||||
b: !installed,
|
bind.pluginInstall(
|
||||||
);
|
id: plugin.meta.id,
|
||||||
});
|
b: !installed,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (installed) {
|
if (installed) {
|
||||||
final needUpdate =
|
final updateButton = plugin.needUpdate
|
||||||
plugin.installedVersion.compareTo(plugin.meta.version) < 0;
|
? headerButton('Update', () {
|
||||||
final updateButton = needUpdate
|
|
||||||
? headerButton('update', () {
|
|
||||||
bind.pluginInstall(
|
bind.pluginInstall(
|
||||||
id: plugin.meta.id,
|
id: plugin.meta.id,
|
||||||
b: !installed,
|
b: !installed,
|
||||||
@ -120,10 +124,9 @@ class _DesktopSettingsCardState extends State<DesktopSettingsCard> {
|
|||||||
})
|
})
|
||||||
: Container();
|
: Container();
|
||||||
|
|
||||||
final isEnabled = bind.pluginIsEnabled(id: plugin.meta.id);
|
|
||||||
final enableButton = !installed
|
final enableButton = !installed
|
||||||
? Container()
|
? Container()
|
||||||
: headerButton(isEnabled ? 'disable' : 'enable', () {
|
: headerButton(isEnabled ? 'Disable' : 'Enable', () {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
clearPlugin(plugin.meta.id);
|
clearPlugin(plugin.meta.id);
|
||||||
}
|
}
|
||||||
@ -175,7 +178,7 @@ class _DesktopSettingsCardState extends State<DesktopSettingsCard> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget more() {
|
Widget more() {
|
||||||
if (!installed) {
|
if (!(installed && isEnabled)) {
|
||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
future::Future,
|
future::Future,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
@ -61,6 +61,7 @@ lazy_static::lazy_static! {
|
|||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref IS_SERVER: bool = std::env::args().nth(1) == Some("--server".to_owned());
|
static ref IS_SERVER: bool = std::env::args().nth(1) == Some("--server".to_owned());
|
||||||
|
static ref SERVER_RUNNING: Arc<RwLock<bool>> = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
@ -93,9 +94,14 @@ pub fn global_init() -> bool {
|
|||||||
|
|
||||||
pub fn global_clean() {}
|
pub fn global_clean() {}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_server_running(b: bool) {
|
||||||
|
*SERVER_RUNNING.write().unwrap() = b;
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_server() -> bool {
|
pub fn is_server() -> bool {
|
||||||
*IS_SERVER
|
*IS_SERVER || *SERVER_RUNNING.read().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
@ -245,7 +245,7 @@ pub fn core_main() -> Option<Vec<String>> {
|
|||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
if args[0] == "--plugin-install" {
|
if args[0] == "--plugin-install" {
|
||||||
if args.len() == 3 {
|
if args.len() == 3 {
|
||||||
crate::plugin::privileged_install_plugin(&args[1], &args[2]);
|
crate::plugin::install_plugin_with_url(&args[1], &args[2]);
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
} else if args[0] == "--plugin-uninstall" {
|
} else if args[0] == "--plugin-uninstall" {
|
||||||
|
|||||||
@ -1580,12 +1580,11 @@ pub fn plugin_install(id: String, b: bool) {
|
|||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
{
|
{
|
||||||
if b {
|
if b {
|
||||||
allow_err!(crate::plugin::user_install_plugin(&id));
|
if let Err(e) = crate::plugin::install_plugin(&id) {
|
||||||
|
log::error!("Failed to install plugin '{}': {}", id, e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// to-do: uninstall plugin
|
crate::plugin::uninstall_plugin(&id, true);
|
||||||
// 1. unload 2. remove configs 3. remove config files
|
|
||||||
// allow_err!(super::unload_plugin(&id));
|
|
||||||
crate::plugin::uninstall_plugin(&id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,16 @@ fn path_plugins(id: &str) -> PathBuf {
|
|||||||
HbbConfig::path("plugins").join(id)
|
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 {
|
impl Deref for SharedConfig {
|
||||||
type Target = HashMap<String, String>;
|
type Target = HashMap<String, String>;
|
||||||
|
|
||||||
@ -207,6 +217,7 @@ impl PeerConfig {
|
|||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct PluginStatus {
|
pub struct PluginStatus {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
|
pub uninstalled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
const MANAGER_VERSION: &str = "0.1.0";
|
const MANAGER_VERSION: &str = "0.1.0";
|
||||||
@ -269,7 +280,13 @@ impl ManagerConfig {
|
|||||||
if let Some(status) = lock.plugins.get_mut(id) {
|
if let Some(status) = lock.plugins.get_mut(id) {
|
||||||
status.enabled = enabled;
|
status.enabled = enabled;
|
||||||
} else {
|
} else {
|
||||||
lock.plugins.insert(id.to_owned(), PluginStatus { enabled });
|
lock.plugins.insert(
|
||||||
|
id.to_owned(),
|
||||||
|
PluginStatus {
|
||||||
|
enabled,
|
||||||
|
uninstalled: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
hbb_common::config::store_path(Self::path(), &*lock)
|
hbb_common::config::store_path(Self::path(), &*lock)
|
||||||
}
|
}
|
||||||
@ -292,29 +309,50 @@ impl ManagerConfig {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn add_plugin(id: &str) -> ResultType<()> {
|
pub fn add_plugin(id: &str) -> ResultType<()> {
|
||||||
let mut lock = CONFIG_MANAGER.lock().unwrap();
|
let mut lock = CONFIG_MANAGER.lock().unwrap();
|
||||||
lock.plugins
|
lock.plugins.insert(
|
||||||
.insert(id.to_owned(), PluginStatus { enabled: true });
|
id.to_owned(),
|
||||||
|
PluginStatus {
|
||||||
|
enabled: true,
|
||||||
|
uninstalled: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
hbb_common::config::store_path(Self::path(), &*lock)
|
hbb_common::config::store_path(Self::path(), &*lock)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn remove_plugin(id: &str, uninstall: bool) -> ResultType<()> {
|
pub fn remove_plugin(id: &str) -> ResultType<()> {
|
||||||
let mut lock = CONFIG_MANAGER.lock().unwrap();
|
let mut lock = CONFIG_MANAGER.lock().unwrap();
|
||||||
lock.plugins.remove(id);
|
lock.plugins.remove(id);
|
||||||
hbb_common::config::store_path(Self::path(), &*lock)?;
|
hbb_common::config::store_path(Self::path(), &*lock)
|
||||||
if uninstall {
|
|
||||||
allow_err!(fs::remove_dir_all(path_plugins(id)));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_plugins(uninstall: bool) {
|
#[inline]
|
||||||
|
pub fn is_uninstalled(id: &str) -> bool {
|
||||||
|
CONFIG_MANAGER
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.plugins
|
||||||
|
.get(id)
|
||||||
|
.map(|p| p.uninstalled)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_uninstall(id: &str, uninstall: bool) -> ResultType<()> {
|
||||||
let mut lock = CONFIG_MANAGER.lock().unwrap();
|
let mut lock = CONFIG_MANAGER.lock().unwrap();
|
||||||
lock.plugins.clear();
|
if let Some(status) = lock.plugins.get_mut(id) {
|
||||||
allow_err!(hbb_common::config::store_path(Self::path(), &*lock));
|
status.uninstalled = uninstall;
|
||||||
if uninstall {
|
} else {
|
||||||
allow_err!(fs::remove_dir_all(HbbConfig::path("plugins")));
|
lock.plugins.insert(
|
||||||
|
id.to_owned(),
|
||||||
|
PluginStatus {
|
||||||
|
enabled: true,
|
||||||
|
uninstalled: uninstall,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
hbb_common::config::store_path(Self::path(), &*lock)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,7 @@ pub enum Plugin {
|
|||||||
Load(String),
|
Load(String),
|
||||||
Reload(String),
|
Reload(String),
|
||||||
InstallStatus((String, InstallStatus)),
|
InstallStatus((String, InstallStatus)),
|
||||||
|
Uninstall(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
@ -66,6 +67,11 @@ pub async fn reload_plugin(id: &str) -> ResultType<()> {
|
|||||||
reload_plugin_async(id).await
|
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<Option<String>> {
|
async fn get_config_async(id: &str, name: &str, ms_timeout: u64) -> ResultType<Option<String>> {
|
||||||
let mut c = connect(ms_timeout, "").await?;
|
let mut c = connect(ms_timeout, "").await?;
|
||||||
c.send(&Data::Plugin(Plugin::Config(
|
c.send(&Data::Plugin(Plugin::Config(
|
||||||
@ -164,6 +170,13 @@ async fn reload_plugin_async(id: &str) -> ResultType<()> {
|
|||||||
Ok(())
|
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) {
|
pub async fn handle_plugin(plugin: Plugin, stream: &mut Connection) {
|
||||||
match plugin {
|
match plugin {
|
||||||
Plugin::Config(id, name, value) => match value {
|
Plugin::Config(id, name, value) => match value {
|
||||||
@ -206,11 +219,15 @@ pub async fn handle_plugin(plugin: Plugin, stream: &mut Connection) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Plugin::Load(id) => {
|
Plugin::Load(id) => {
|
||||||
|
allow_err!(super::config::ManagerConfig::set_uninstall(&id, false));
|
||||||
allow_err!(super::load_plugin(&id));
|
allow_err!(super::load_plugin(&id));
|
||||||
}
|
}
|
||||||
Plugin::Reload(id) => {
|
Plugin::Reload(id) => {
|
||||||
allow_err!(super::reload_plugin(&id));
|
allow_err!(super::reload_plugin(&id));
|
||||||
}
|
}
|
||||||
|
Plugin::Uninstall(id) => {
|
||||||
|
super::manager::uninstall_plugin(&id, false);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,12 +8,14 @@ use serde_derive::{Deserialize, Serialize};
|
|||||||
use serde_json;
|
use serde_json;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
fs,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
const MSG_TO_UI_PLUGIN_MANAGER_LIST: &str = "plugin_list";
|
const MSG_TO_UI_PLUGIN_MANAGER_LIST: &str = "plugin_list";
|
||||||
const MSG_TO_UI_PLUGIN_MANAGER_UPDATE: &str = "plugin_update";
|
const MSG_TO_UI_PLUGIN_MANAGER_UPDATE: &str = "plugin_update";
|
||||||
const MSG_TO_UI_PLUGIN_MANAGER_INSTALL: &str = "plugin_install";
|
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";
|
const IPC_PLUGIN_POSTFIX: &str = "_plugin";
|
||||||
|
|
||||||
@ -40,7 +42,6 @@ pub struct PluginInfo {
|
|||||||
pub source: PluginSource,
|
pub source: PluginSource,
|
||||||
pub meta: PluginMeta,
|
pub meta: PluginMeta,
|
||||||
pub installed_version: String,
|
pub installed_version: String,
|
||||||
pub install_time: String,
|
|
||||||
pub invalid_reason: String,
|
pub invalid_reason: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +79,6 @@ fn get_source_plugins() -> HashMap<String, PluginInfo> {
|
|||||||
source: source.clone(),
|
source: source.clone(),
|
||||||
meta: meta.clone(),
|
meta: meta.clone(),
|
||||||
installed_version: "".to_string(),
|
installed_version: "".to_string(),
|
||||||
install_time: "".to_string(),
|
|
||||||
invalid_reason: "".to_string(),
|
invalid_reason: "".to_string(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -110,9 +110,18 @@ fn send_plugin_list_event(plugins: &HashMap<String, PluginInfo>) {
|
|||||||
pub fn load_plugin_list() {
|
pub fn load_plugin_list() {
|
||||||
let mut plugin_info_lock = PLUGIN_INFO.lock().unwrap();
|
let mut plugin_info_lock = PLUGIN_INFO.lock().unwrap();
|
||||||
let mut plugins = get_source_plugins();
|
let mut plugins = get_source_plugins();
|
||||||
for (id, info) in super::plugins::get_plugin_infos().read().unwrap().iter() {
|
|
||||||
|
// 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) {
|
if let Some(p) = plugins.get_mut(id) {
|
||||||
p.install_time = info.install_time.clone();
|
|
||||||
p.installed_version = info.desc.meta().version.clone();
|
p.installed_version = info.desc.meta().version.clone();
|
||||||
p.invalid_reason = "".to_string();
|
p.invalid_reason = "".to_string();
|
||||||
} else {
|
} else {
|
||||||
@ -126,7 +135,6 @@ pub fn load_plugin_list() {
|
|||||||
},
|
},
|
||||||
meta: info.desc.meta().clone(),
|
meta: info.desc.meta().clone(),
|
||||||
installed_version: info.desc.meta().version.clone(),
|
installed_version: info.desc.meta().version.clone(),
|
||||||
install_time: info.install_time.clone(),
|
|
||||||
invalid_reason: "".to_string(),
|
invalid_reason: "".to_string(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -139,14 +147,34 @@ pub fn load_plugin_list() {
|
|||||||
pub fn install_plugin(id: &str) -> ResultType<()> {
|
pub fn install_plugin(id: &str) -> ResultType<()> {
|
||||||
match PLUGIN_INFO.lock().unwrap().get(id) {
|
match PLUGIN_INFO.lock().unwrap().get(id) {
|
||||||
Some(plugin) => {
|
Some(plugin) => {
|
||||||
let _plugin_url = format!(
|
|
||||||
"{}/plugins/{}/{}_{}.zip",
|
|
||||||
plugin.source.url, plugin.meta.id, plugin.meta.id, plugin.meta.version
|
|
||||||
);
|
|
||||||
// to-do: Support args with space in quotes. 'arg 1' and "arg 2"
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let _res =
|
{
|
||||||
crate::platform::elevate(&format!("--plugin-install {} {}", id, _plugin_url))?;
|
let mut same_plugin_exists = false;
|
||||||
|
if let Some(version) = super::plugins::get_version(id) {
|
||||||
|
if version == plugin.meta.version {
|
||||||
|
same_plugin_exists = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// to-do: Support args with space in quotes. 'arg 1' and "arg 2"
|
||||||
|
let plugin_url = format!(
|
||||||
|
"{}/plugins/{}/{}_{}.zip",
|
||||||
|
plugin.source.url, plugin.meta.id, plugin.meta.id, plugin.meta.version
|
||||||
|
);
|
||||||
|
let args = if same_plugin_exists {
|
||||||
|
format!("--plugin-install {}", id)
|
||||||
|
} else {
|
||||||
|
format!("--plugin-install {} {}", id, plugin_url)
|
||||||
|
};
|
||||||
|
let allowed = crate::platform::elevate(&args)?;
|
||||||
|
|
||||||
|
if allowed && 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -155,26 +183,93 @@ pub fn install_plugin(id: &str) -> ResultType<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn remove_plugins() {}
|
fn get_uninstalled_plugins() -> ResultType<Vec<String>> {
|
||||||
|
let plugins_dir = super::get_plugins_dir()?;
|
||||||
// 1. Add to uninstall list.
|
let mut plugins = Vec::new();
|
||||||
// 2. Try remove.
|
if plugins_dir.exists() {
|
||||||
// 2. Remove on the next start.
|
for entry in std::fs::read_dir(plugins_dir)? {
|
||||||
pub fn uninstall_plugin(id: &str) {
|
match entry {
|
||||||
// to-do: add to uninstall list.
|
Ok(entry) => {
|
||||||
super::plugins::unload_plugin(id);
|
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 super::config::ManagerConfig::is_uninstalled(id) {
|
||||||
|
plugins.push(id.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to read plugins dir entry, {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(plugins)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_install_event(id: &str, msg: &str) {
|
pub(super) fn remove_plugins() -> ResultType<()> {
|
||||||
|
for id in get_uninstalled_plugins()?.iter() {
|
||||||
|
super::config::remove(id as _);
|
||||||
|
if let Ok(dir) = super::get_plugin_dir(id as _) {
|
||||||
|
allow_err!(fs::remove_dir_all(dir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uninstall_plugin(id: &str, called_by_ui: bool) {
|
||||||
|
if called_by_ui {
|
||||||
|
match crate::platform::elevate(&format!("--plugin-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 '{}': {}", id, e);
|
||||||
|
push_uninstall_event(id, "failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_server() {
|
||||||
|
super::plugins::unload_plugin(&id);
|
||||||
|
// allow_err is Ok here.
|
||||||
|
allow_err!(super::config::ManagerConfig::set_uninstall(&id, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_event(id: &str, r#type: &str, msg: &str) {
|
||||||
let mut m = HashMap::new();
|
let mut m = HashMap::new();
|
||||||
m.insert("name", MSG_TO_UI_TYPE_PLUGIN_MANAGER);
|
m.insert("name", MSG_TO_UI_TYPE_PLUGIN_MANAGER);
|
||||||
m.insert("id", id);
|
m.insert("id", id);
|
||||||
m.insert(MSG_TO_UI_PLUGIN_MANAGER_INSTALL, msg);
|
m.insert(r#type, msg);
|
||||||
if let Ok(event) = serde_json::to_string(&m) {
|
if let Ok(event) = serde_json::to_string(&m) {
|
||||||
let _res = flutter::push_global_event(flutter::APP_TYPE_MAIN, event.clone());
|
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) {
|
async fn handle_conn(mut stream: crate::ipc::Connection) {
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
@ -197,7 +292,7 @@ async fn handle_conn(mut stream: crate::ipc::Connection) {
|
|||||||
InstallStatus::Finished => {
|
InstallStatus::Finished => {
|
||||||
allow_err!(super::plugins::load_plugin(&id));
|
allow_err!(super::plugins::load_plugin(&id));
|
||||||
allow_err!(super::ipc::load_plugin_async(id).await);
|
allow_err!(super::ipc::load_plugin_async(id).await);
|
||||||
load_plugin_list();
|
std::thread::spawn(load_plugin_list);
|
||||||
push_install_event(&id, "finished");
|
push_install_event(&id, "finished");
|
||||||
}
|
}
|
||||||
InstallStatus::FailedCreating => {
|
InstallStatus::FailedCreating => {
|
||||||
@ -329,7 +424,7 @@ pub(super) mod install {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install_plugin(id: &str, url: &str) {
|
pub fn install_plugin_with_url(id: &str, url: &str) {
|
||||||
let plugin_dir = match super::super::get_plugin_dir(id) {
|
let plugin_dir = match super::super::get_plugin_dir(id) {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use hbb_common::{allow_err, libc, log, ResultType};
|
use hbb_common::{libc, log, ResultType};
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
ffi::{c_char, c_int, c_void, CStr},
|
ffi::{c_char, c_int, c_void, CStr},
|
||||||
@ -19,12 +19,11 @@ mod plog;
|
|||||||
mod plugins;
|
mod plugins;
|
||||||
|
|
||||||
pub use manager::{
|
pub use manager::{
|
||||||
install::install_plugin as privileged_install_plugin, install_plugin as user_install_plugin,
|
install::install_plugin_with_url, install_plugin, load_plugin_list, uninstall_plugin,
|
||||||
load_plugin_list, uninstall_plugin,
|
|
||||||
};
|
};
|
||||||
pub use plugins::{
|
pub use plugins::{
|
||||||
handle_client_event, handle_listen_event, handle_server_event, handle_ui_event, load_plugin,
|
handle_client_event, handle_listen_event, handle_server_event, handle_ui_event, load_plugin,
|
||||||
reload_plugin, sync_ui, unload_plugin, unload_plugins,
|
reload_plugin, sync_ui, unload_plugin,
|
||||||
};
|
};
|
||||||
|
|
||||||
const MSG_TO_UI_TYPE_PLUGIN_EVENT: &str = "plugin_event";
|
const MSG_TO_UI_TYPE_PLUGIN_EVENT: &str = "plugin_event";
|
||||||
@ -92,9 +91,13 @@ pub fn init() {
|
|||||||
if !is_server() {
|
if !is_server() {
|
||||||
std::thread::spawn(move || manager::start_ipc());
|
std::thread::spawn(move || manager::start_ipc());
|
||||||
} else {
|
} else {
|
||||||
manager::remove_plugins();
|
if let Err(e) = manager::remove_plugins() {
|
||||||
|
log::error!("Failed to remove plugins: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Err(e) = plugins::load_plugins() {
|
||||||
|
log::error!("Failed to load plugins: {}", e);
|
||||||
}
|
}
|
||||||
allow_err!(plugins::load_plugins());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use super::{desc::Desc, errno::*, *};
|
|||||||
use crate::common::is_server;
|
use crate::common::is_server;
|
||||||
use crate::flutter;
|
use crate::flutter;
|
||||||
use hbb_common::{
|
use hbb_common::{
|
||||||
allow_err, bail,
|
bail,
|
||||||
dlopen::symbor::Library,
|
dlopen::symbor::Library,
|
||||||
lazy_static, log,
|
lazy_static, log,
|
||||||
message_proto::{Message, Misc, PluginFailure, PluginRequest},
|
message_proto::{Message, Misc, PluginFailure, PluginRequest},
|
||||||
@ -15,7 +15,6 @@ use std::{
|
|||||||
ffi::{c_char, c_void},
|
ffi::{c_char, c_void},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
time::SystemTime,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const METHOD_HANDLE_UI: &[u8; 10] = b"handle_ui\0";
|
const METHOD_HANDLE_UI: &[u8; 10] = b"handle_ui\0";
|
||||||
@ -29,7 +28,7 @@ lazy_static::lazy_static! {
|
|||||||
|
|
||||||
pub(super) struct PluginInfo {
|
pub(super) struct PluginInfo {
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub install_time: String,
|
pub uninstalled: bool,
|
||||||
pub desc: Desc,
|
pub desc: Desc,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +306,7 @@ fn load_plugin_dir(dir: &PathBuf) {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!(
|
log::error!(
|
||||||
"Failed to read '{}' dir entry, {}",
|
"Failed to read '{}' dir entry, {}",
|
||||||
dir.file_stem().and_then(|f| f.to_str()).unwrap_or(""),
|
dir.file_name().and_then(|f| f.to_str()).unwrap_or(""),
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -316,20 +315,18 @@ fn load_plugin_dir(dir: &PathBuf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unload_plugins() {
|
|
||||||
log::info!("Plugins unloaded");
|
|
||||||
PLUGINS.write().unwrap().clear();
|
|
||||||
if change_manager() {
|
|
||||||
super::config::ManagerConfig::remove_plugins(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unload_plugin(id: &str) {
|
pub fn unload_plugin(id: &str) {
|
||||||
log::info!("Plugin {} unloaded", id);
|
log::info!("Plugin {} unloaded", id);
|
||||||
PLUGINS.write().unwrap().remove(id);
|
PLUGINS.write().unwrap().remove(id);
|
||||||
if change_manager() {
|
}
|
||||||
allow_err!(super::config::ManagerConfig::remove_plugin(id, false));
|
|
||||||
}
|
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<()> {
|
pub fn reload_plugin(id: &str) -> ResultType<()> {
|
||||||
@ -364,7 +361,7 @@ fn load_plugin_path(path: &str) -> ResultType<()> {
|
|||||||
};
|
};
|
||||||
plugin.init(&init_data, path)?;
|
plugin.init(&init_data, path)?;
|
||||||
|
|
||||||
if change_manager() {
|
if is_server() {
|
||||||
super::config::ManagerConfig::add_plugin(&desc.meta().id)?;
|
super::config::ManagerConfig::add_plugin(&desc.meta().id)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,18 +369,11 @@ fn load_plugin_path(path: &str) -> ResultType<()> {
|
|||||||
// Ui may be not ready now, so we need to update again once ui is ready.
|
// Ui may be not ready now, so we need to update again once ui is ready.
|
||||||
reload_ui(&desc, None);
|
reload_ui(&desc, None);
|
||||||
|
|
||||||
let install_time = PathBuf::from(path)
|
|
||||||
.metadata()
|
|
||||||
.and_then(|d| d.created())
|
|
||||||
.unwrap_or(SystemTime::UNIX_EPOCH);
|
|
||||||
let install_time = chrono::DateTime::<chrono::Local>::from(install_time)
|
|
||||||
.format("%Y-%m-%d %H:%M:%S")
|
|
||||||
.to_string();
|
|
||||||
// add plugins
|
// add plugins
|
||||||
let id = desc.meta().id.clone();
|
let id = desc.meta().id.clone();
|
||||||
let plugin_info = PluginInfo {
|
let plugin_info = PluginInfo {
|
||||||
path: path.to_string(),
|
path: path.to_string(),
|
||||||
install_time,
|
uninstalled: false,
|
||||||
desc,
|
desc,
|
||||||
};
|
};
|
||||||
PLUGIN_INFO.write().unwrap().insert(id.clone(), plugin_info);
|
PLUGIN_INFO.write().unwrap().insert(id.clone(), plugin_info);
|
||||||
@ -582,15 +572,6 @@ fn make_plugin_failure(id: &str, name: &str, msg: &str) -> Message {
|
|||||||
msg_out
|
msg_out
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn change_manager() -> bool {
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
let change_manager = true;
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
let change_manager = is_server();
|
|
||||||
change_manager
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reload_ui(desc: &Desc, sync_to: Option<&str>) {
|
fn reload_ui(desc: &Desc, sync_to: Option<&str>) {
|
||||||
for (location, ui) in desc.location().ui.iter() {
|
for (location, ui) in desc.location().ui.iter() {
|
||||||
if let Ok(ui) = serde_json::to_string(&ui) {
|
if let Ok(ui) = serde_json::to_string(&ui) {
|
||||||
@ -641,3 +622,11 @@ pub(super) fn get_desc_conf(id: &str) -> Option<super::desc::Config> {
|
|||||||
.get(id)
|
.get(id)
|
||||||
.map(|info| info.desc.config().clone())
|
.map(|info| info.desc.config().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn get_version(id: &str) -> Option<String> {
|
||||||
|
PLUGIN_INFO
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get(id)
|
||||||
|
.map(|info| info.desc.meta().version.clone())
|
||||||
|
}
|
||||||
|
|||||||
@ -394,6 +394,7 @@ pub async fn start_server(is_server: bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if is_server {
|
if is_server {
|
||||||
|
crate::common::set_server_running(true);
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
if let Err(err) = crate::ipc::start("") {
|
if let Err(err) = crate::ipc::start("") {
|
||||||
log::error!("Failed to start ipc: {}", err);
|
log::error!("Failed to start ipc: {}", err);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user