fix: plugin init problem
This commit is contained in:
1 parent
96ebe74d12
commit
0fe8e4bcbd
4 files changed
+218
-87
No files matched your search
@@ -42,9 +42,17 @@ impl UserData for PluginFileSystem {
|
|||||||
let path = args.0;
|
let path = args.0;
|
||||||
let content = args.1;
|
let content = args.1;
|
||||||
let path = PathBuf::from(path);
|
let path = PathBuf::from(path);
|
||||||
let mut file = std::fs::File::create(path)?;
|
|
||||||
file.write_all(content.as_bytes())?;
|
let file = std::fs::File::create(path);
|
||||||
Ok(())
|
if file.is_err() {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if file.unwrap().write_all(content.as_bytes()).is_err() {
|
||||||
|
return Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
});
|
});
|
||||||
methods.add_function("unzip_file", |_, args: (String, String)| {
|
methods.add_function("unzip_file", |_, args: (String, String)| {
|
||||||
let file = PathBuf::from(args.0);
|
let file = PathBuf::from(args.0);
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ pub struct PluginInfo<'lua> {
|
|||||||
pub author: String,
|
pub author: String,
|
||||||
pub version: String,
|
pub version: String,
|
||||||
|
|
||||||
|
pub inner: PluginInner,
|
||||||
|
|
||||||
pub on_init: Option<Function<'lua>>,
|
pub on_init: Option<Function<'lua>>,
|
||||||
pub build: PluginBuildInfo<'lua>,
|
pub build: PluginBuildInfo<'lua>,
|
||||||
pub serve: PluginServeInfo<'lua>,
|
pub serve: PluginServeInfo<'lua>,
|
||||||
@@ -28,6 +30,8 @@ impl<'lua> FromLua<'lua> for PluginInfo<'lua> {
|
|||||||
author: String::default(),
|
author: String::default(),
|
||||||
version: String::from("0.1.0"),
|
version: String::from("0.1.0"),
|
||||||
|
|
||||||
|
inner: Default::default(),
|
||||||
|
|
||||||
on_init: None,
|
on_init: None,
|
||||||
build: Default::default(),
|
build: Default::default(),
|
||||||
serve: Default::default(),
|
serve: Default::default(),
|
||||||
@@ -46,6 +50,10 @@ impl<'lua> FromLua<'lua> for PluginInfo<'lua> {
|
|||||||
res.version = v;
|
res.version = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Ok(v) = tab.get::<_, PluginInner>("inner") {
|
||||||
|
res.inner = v;
|
||||||
|
}
|
||||||
|
|
||||||
if let Ok(v) = tab.get::<_, Function>("on_init") {
|
if let Ok(v) = tab.get::<_, Function>("on_init") {
|
||||||
res.on_init = Some(v);
|
res.on_init = Some(v);
|
||||||
}
|
}
|
||||||
@@ -72,6 +80,8 @@ impl<'lua> ToLua<'lua> for PluginInfo<'lua> {
|
|||||||
res.set("author", self.author.to_string())?;
|
res.set("author", self.author.to_string())?;
|
||||||
res.set("version", self.version.to_string())?;
|
res.set("version", self.version.to_string())?;
|
||||||
|
|
||||||
|
res.set("inner", self.inner)?;
|
||||||
|
|
||||||
if let Some(e) = self.on_init {
|
if let Some(e) = self.on_init {
|
||||||
res.set("on_init", e)?;
|
res.set("on_init", e)?;
|
||||||
}
|
}
|
||||||
@@ -82,6 +92,42 @@ impl<'lua> ToLua<'lua> for PluginInfo<'lua> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct PluginInner {
|
||||||
|
pub plugin_dir: String,
|
||||||
|
pub from_loader: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> FromLua<'lua> for PluginInner {
|
||||||
|
fn from_lua(lua_value: mlua::Value<'lua>, _lua: &'lua mlua::Lua) -> mlua::Result<Self> {
|
||||||
|
let mut res = Self {
|
||||||
|
plugin_dir: String::new(),
|
||||||
|
from_loader: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let mlua::Value::Table(t) = lua_value {
|
||||||
|
if let Ok(v) = t.get::<_, String>("plugin_dir") {
|
||||||
|
res.plugin_dir = v;
|
||||||
|
}
|
||||||
|
if let Ok(v) = t.get::<_, bool>("from_loader") {
|
||||||
|
res.from_loader = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> ToLua<'lua> for PluginInner {
|
||||||
|
fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
|
||||||
|
let res = lua.create_table()?;
|
||||||
|
|
||||||
|
res.set("plugin_dir", self.plugin_dir)?;
|
||||||
|
res.set("from_loader", self.from_loader)?;
|
||||||
|
|
||||||
|
Ok(mlua::Value::Table(res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct PluginBuildInfo<'lua> {
|
pub struct PluginBuildInfo<'lua> {
|
||||||
pub on_start: Option<Function<'lua>>,
|
pub on_start: Option<Function<'lua>>,
|
||||||
|
|||||||
+121
-58
@@ -4,7 +4,7 @@ use std::{
|
|||||||
sync::Mutex,
|
sync::Mutex,
|
||||||
};
|
};
|
||||||
|
|
||||||
use mlua::{AsChunk, Lua, Table};
|
use mlua::{Lua, Table};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -32,9 +32,17 @@ pub struct PluginManager;
|
|||||||
|
|
||||||
impl PluginManager {
|
impl PluginManager {
|
||||||
pub fn init(config: toml::Value) -> anyhow::Result<()> {
|
pub fn init(config: toml::Value) -> anyhow::Result<()> {
|
||||||
|
let config = PluginConfig::from_toml_value(config);
|
||||||
|
|
||||||
|
if !config.available {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let lua = LUA.lock().unwrap();
|
let lua = LUA.lock().unwrap();
|
||||||
|
|
||||||
let manager = lua.create_table().unwrap();
|
let manager = lua.create_table().unwrap();
|
||||||
|
let name_index = lua.create_table().unwrap();
|
||||||
|
|
||||||
let plugin_dir = Self::init_plugin_dir();
|
let plugin_dir = Self::init_plugin_dir();
|
||||||
|
|
||||||
let api = lua.create_table().unwrap();
|
let api = lua.create_table().unwrap();
|
||||||
@@ -51,18 +59,27 @@ impl PluginManager {
|
|||||||
lua.globals()
|
lua.globals()
|
||||||
.set("library_dir", plugin_dir.to_str().unwrap())
|
.set("library_dir", plugin_dir.to_str().unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let config = PluginConfig::from_toml_value(config);
|
lua.globals().set("config_info", config.clone())?;
|
||||||
lua.globals().set("config_info", config)?;
|
|
||||||
|
|
||||||
let mut index: u32 = 1;
|
let mut index: u32 = 1;
|
||||||
let mut init_list: Vec<(u32, PathBuf, PluginInfo)> = Vec::new();
|
|
||||||
let dirs = std::fs::read_dir(&plugin_dir)?;
|
let dirs = std::fs::read_dir(&plugin_dir)?;
|
||||||
for entry in dirs {
|
|
||||||
if entry.is_err() {
|
let mut path_list = dirs
|
||||||
continue;
|
.filter(|v| v.is_ok())
|
||||||
|
.map(|v| (v.unwrap().path(), false))
|
||||||
|
.collect::<Vec<(PathBuf, bool)>>();
|
||||||
|
for i in &config.loader {
|
||||||
|
let path = PathBuf::from(i);
|
||||||
|
if !path.is_dir() {
|
||||||
|
// for loader dir, we need check first, because we need give a error log.
|
||||||
|
log::error!("Plugin loader: {:?} path is not a exists directory.", path);
|
||||||
}
|
}
|
||||||
let entry = entry.unwrap();
|
path_list.push((path, true));
|
||||||
let plugin_dir = entry.path().to_path_buf();
|
}
|
||||||
|
|
||||||
|
for entry in path_list {
|
||||||
|
let plugin_dir = entry.0.to_path_buf();
|
||||||
|
|
||||||
if plugin_dir.is_dir() {
|
if plugin_dir.is_dir() {
|
||||||
let init_file = plugin_dir.join("init.lua");
|
let init_file = plugin_dir.join("init.lua");
|
||||||
if init_file.is_file() {
|
if init_file.is_file() {
|
||||||
@@ -70,21 +87,78 @@ impl PluginManager {
|
|||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
file.read_to_string(&mut buffer).unwrap();
|
file.read_to_string(&mut buffer).unwrap();
|
||||||
|
|
||||||
|
let current_plugin_dir = plugin_dir.to_str().unwrap().to_string();
|
||||||
|
let from_loader = entry.1;
|
||||||
|
|
||||||
|
lua.globals()
|
||||||
|
.set("_temp_plugin_dir", current_plugin_dir.clone())?;
|
||||||
|
lua.globals().set("_temp_from_loader", from_loader)?;
|
||||||
|
|
||||||
let info = lua.load(&buffer).eval::<PluginInfo>();
|
let info = lua.load(&buffer).eval::<PluginInfo>();
|
||||||
match info {
|
match info {
|
||||||
Ok(info) => {
|
Ok(mut info) => {
|
||||||
let _ = manager.set(index, info.clone());
|
if name_index.contains_key(info.name.clone()).unwrap_or(false)
|
||||||
|
&& !from_loader
|
||||||
let dir_name_str = plugin_dir.name().unwrap().to_string();
|
{
|
||||||
lua.globals().set("current_dir_name", dir_name_str).unwrap();
|
// found same name plugin, intercept load
|
||||||
|
log::warn!(
|
||||||
|
"Plugin {} has been intercepted. [mulit-load]",
|
||||||
|
info.name
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
info.inner.plugin_dir = current_plugin_dir;
|
||||||
|
info.inner.from_loader = from_loader;
|
||||||
|
|
||||||
// call `on_init` if file "dcp.json" not exists
|
// call `on_init` if file "dcp.json" not exists
|
||||||
let dcp_file = plugin_dir.join("dcp.json");
|
let dcp_file = plugin_dir.join("dcp.json");
|
||||||
if !dcp_file.is_file() {
|
if !dcp_file.is_file() {
|
||||||
init_list.push((index, dcp_file, info));
|
if let Some(func) = info.clone().on_init {
|
||||||
}
|
let result = func.call::<_, bool>(());
|
||||||
|
match result {
|
||||||
|
Ok(true) => {
|
||||||
|
// plugin init success, create `dcp.json` file.
|
||||||
|
let mut file = std::fs::File::create(dcp_file).unwrap();
|
||||||
|
let value = json!({
|
||||||
|
"name": info.name,
|
||||||
|
"author": info.author,
|
||||||
|
"repository": info.repository,
|
||||||
|
"version": info.version,
|
||||||
|
"generate_time": chrono::Local::now().timestamp(),
|
||||||
|
});
|
||||||
|
let buffer =
|
||||||
|
serde_json::to_string_pretty(&value).unwrap();
|
||||||
|
let buffer = buffer.as_bytes();
|
||||||
|
file.write_all(buffer).unwrap();
|
||||||
|
|
||||||
index += 1;
|
// insert plugin-info into plugin-manager
|
||||||
|
if let Ok(index) =
|
||||||
|
name_index.get::<_, u32>(info.name.clone())
|
||||||
|
{
|
||||||
|
let _ = manager.set(index, info.clone());
|
||||||
|
} else {
|
||||||
|
let _ = manager.set(index, info.clone());
|
||||||
|
index += 1;
|
||||||
|
let _ = name_index.set(info.name, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(false) => {
|
||||||
|
log::warn!("Plugin init function result is `false`, init failed.");
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Plugin init failed: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Ok(index) = name_index.get::<_, u32>(info.name.clone()) {
|
||||||
|
let _ = manager.set(index, info.clone());
|
||||||
|
} else {
|
||||||
|
let _ = manager.set(index, info.clone());
|
||||||
|
index += 1;
|
||||||
|
let _ = name_index.set(info.name, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
let dir_name = plugin_dir.file_name().unwrap().to_str().unwrap();
|
let dir_name = plugin_dir.file_name().unwrap().to_str().unwrap();
|
||||||
@@ -97,46 +171,6 @@ impl PluginManager {
|
|||||||
|
|
||||||
lua.globals().set("manager", manager).unwrap();
|
lua.globals().set("manager", manager).unwrap();
|
||||||
|
|
||||||
for (idx, path, info) in init_list {
|
|
||||||
let res = lua
|
|
||||||
.load(mlua::chunk! {
|
|
||||||
manager[$idx].on_init()
|
|
||||||
})
|
|
||||||
.eval::<bool>();
|
|
||||||
match res {
|
|
||||||
Ok(true) => {
|
|
||||||
// plugin init success, create `dcp.json` file.
|
|
||||||
let mut file = std::fs::File::create(path).unwrap();
|
|
||||||
let value = json!({
|
|
||||||
"name": info.name,
|
|
||||||
"author": info.author,
|
|
||||||
"repository": info.repository,
|
|
||||||
"version": info.version,
|
|
||||||
"generate_time": chrono::Local::now().timestamp(),
|
|
||||||
});
|
|
||||||
let buffer = serde_json::to_string_pretty(&value).unwrap();
|
|
||||||
let buffer = buffer.as_bytes();
|
|
||||||
file.write_all(buffer).unwrap();
|
|
||||||
}
|
|
||||||
Ok(false) => {
|
|
||||||
log::warn!("Plugin init function result is `false`, init failed.");
|
|
||||||
let _ = lua
|
|
||||||
.load(mlua::chunk! {
|
|
||||||
table.remove(manager, $idx)
|
|
||||||
})
|
|
||||||
.exec();
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// plugin init failed
|
|
||||||
log::warn!("Plugin init failed: {e}");
|
|
||||||
let _ = lua
|
|
||||||
.load(mlua::chunk! {
|
|
||||||
table.remove(manager, $idx)
|
|
||||||
})
|
|
||||||
.exec();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +298,7 @@ impl PluginManager {
|
|||||||
plugin_path
|
plugin_path
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plugin_list() -> Vec<String> {
|
pub fn plugin_list_from_dir() -> Vec<String> {
|
||||||
let mut res = vec![];
|
let mut res = vec![];
|
||||||
|
|
||||||
let app_path = app_path();
|
let app_path = app_path();
|
||||||
@@ -280,6 +314,35 @@ impl PluginManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn plugin_list() -> Vec<String> {
|
||||||
|
let mut res = vec![];
|
||||||
|
|
||||||
|
if let Ok(lua) = LUA.lock() {
|
||||||
|
let list = lua
|
||||||
|
.load(mlua::chunk!(
|
||||||
|
local list = {}
|
||||||
|
for key, value in ipairs(manager) do
|
||||||
|
table.insert(list, {name = value.name, loader = value.inner.from_loader})
|
||||||
|
end
|
||||||
|
return list
|
||||||
|
))
|
||||||
|
.eval::<Vec<Table>>()
|
||||||
|
.unwrap_or_default();
|
||||||
|
for i in list {
|
||||||
|
let name = i.get::<_, String>("name").unwrap();
|
||||||
|
let loader = i.get::<_, bool>("loader").unwrap();
|
||||||
|
|
||||||
|
let text = if loader {
|
||||||
|
format!("{name} [:loader]")
|
||||||
|
} else {
|
||||||
|
name
|
||||||
|
};
|
||||||
|
res.push(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-26
@@ -4,8 +4,9 @@ use mlua::ToLua;
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PluginConfig {
|
pub struct PluginConfig {
|
||||||
available: bool,
|
pub available: bool,
|
||||||
config_info: HashMap<String, HashMap<String, Value>>,
|
pub loader: Vec<String>,
|
||||||
|
pub config_info: HashMap<String, HashMap<String, Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> ToLua<'lua> for PluginConfig {
|
impl<'lua> ToLua<'lua> for PluginConfig {
|
||||||
@@ -13,6 +14,7 @@ impl<'lua> ToLua<'lua> for PluginConfig {
|
|||||||
let table = lua.create_table()?;
|
let table = lua.create_table()?;
|
||||||
|
|
||||||
table.set("available", self.available)?;
|
table.set("available", self.available)?;
|
||||||
|
table.set("loader", self.loader)?;
|
||||||
|
|
||||||
let config_info = lua.create_table()?;
|
let config_info = lua.create_table()?;
|
||||||
|
|
||||||
@@ -34,9 +36,21 @@ impl PluginConfig {
|
|||||||
.unwrap_or(&toml::Value::Boolean(true));
|
.unwrap_or(&toml::Value::Boolean(true));
|
||||||
let available = available.as_bool().unwrap_or(true);
|
let available = available.as_bool().unwrap_or(true);
|
||||||
|
|
||||||
|
let mut loader = vec![];
|
||||||
|
if let Some(origin) = tab.get("loader") {
|
||||||
|
if origin.is_array() {
|
||||||
|
for i in origin.as_array().unwrap() {
|
||||||
|
loader.push(i.as_str().unwrap_or_default().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut config_info = HashMap::new();
|
let mut config_info = HashMap::new();
|
||||||
|
|
||||||
for (name, value) in tab {
|
for (name, value) in tab {
|
||||||
|
if name == "available" || name == "loader" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if let toml::Value::Table(value) = value {
|
if let toml::Value::Table(value) = value {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
for (item, info) in value {
|
for (item, info) in value {
|
||||||
@@ -48,11 +62,13 @@ impl PluginConfig {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
available,
|
available,
|
||||||
|
loader,
|
||||||
config_info,
|
config_info,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Self {
|
Self {
|
||||||
available: false,
|
available: false,
|
||||||
|
loader: vec![],
|
||||||
config_info: HashMap::new(),
|
config_info: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,41 +100,39 @@ impl Value {
|
|||||||
v.push(Value::from_toml(i));
|
v.push(Value::from_toml(i));
|
||||||
}
|
}
|
||||||
Value::Array(v)
|
Value::Array(v)
|
||||||
},
|
}
|
||||||
cargo_toml::Value::Table(t) => {
|
cargo_toml::Value::Table(t) => {
|
||||||
let mut h = HashMap::new();
|
let mut h = HashMap::new();
|
||||||
for (n, v) in t {
|
for (n, v) in t {
|
||||||
h.insert(n, Value::from_toml(v));
|
h.insert(n, Value::from_toml(v));
|
||||||
}
|
}
|
||||||
Value::Table(h)
|
Value::Table(h)
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'lua> ToLua<'lua> for Value {
|
impl<'lua> ToLua<'lua> for Value {
|
||||||
fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
|
fn to_lua(self, lua: &'lua mlua::Lua) -> mlua::Result<mlua::Value<'lua>> {
|
||||||
Ok(
|
Ok(match self {
|
||||||
match self {
|
Value::String(s) => mlua::Value::String(lua.create_string(&s)?),
|
||||||
Value::String(s) => mlua::Value::String(lua.create_string(&s)?),
|
Value::Integer(i) => mlua::Value::Integer(i),
|
||||||
Value::Integer(i) => mlua::Value::Integer(i),
|
Value::Float(f) => mlua::Value::Number(f),
|
||||||
Value::Float(f) => mlua::Value::Number(f),
|
Value::Boolean(b) => mlua::Value::Boolean(b),
|
||||||
Value::Boolean(b) => mlua::Value::Boolean(b),
|
Value::Array(a) => {
|
||||||
Value::Array(a) => {
|
let table = lua.create_table()?;
|
||||||
let table = lua.create_table()?;
|
for (i, v) in a.iter().enumerate() {
|
||||||
for (i, v) in a.iter().enumerate() {
|
table.set(i, v.clone())?;
|
||||||
table.set(i, v.clone())?;
|
}
|
||||||
}
|
mlua::Value::Table(table)
|
||||||
mlua::Value::Table(table)
|
|
||||||
},
|
|
||||||
Value::Table(t) => {
|
|
||||||
let table = lua.create_table()?;
|
|
||||||
for (i, v) in t.iter() {
|
|
||||||
table.set(i.clone(), v.clone())?;
|
|
||||||
}
|
|
||||||
mlua::Value::Table(table)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
)
|
Value::Table(t) => {
|
||||||
|
let table = lua.create_table()?;
|
||||||
|
for (i, v) in t.iter() {
|
||||||
|
table.set(i.clone(), v.clone())?;
|
||||||
|
}
|
||||||
|
mlua::Value::Table(table)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user