Skip to main content

br_addon/
addon.rs

1use crate::module::Module;
2use crate::Tools;
3use crate::PLUGIN_TOOLS;
4use std::any::type_name;
5use std::fs;
6use std::fs::create_dir_all;
7use std::path::PathBuf;
8
9#[must_use]
10pub fn to_pascal_case(s: &str) -> String {
11    s.split('_')
12        .filter(|part| !part.is_empty())
13        .map(|part| {
14            let mut chars = part.chars();
15            match chars.next() {
16                Some(first) => first
17                    .to_uppercase()
18                    .chain(chars.flat_map(|c| c.to_lowercase()))
19                    .collect(),
20                None => String::new(),
21            }
22        })
23        .collect()
24}
25
26/// 插件接口
27pub trait Addon: Send + Sync + 'static {
28    /// 插件名称
29    /// NOTE: 使用 Box::leak 返回 'static str,每个类型只会泄漏一次
30    fn name(&self) -> &'static str {
31        let name = type_name::<Self>()
32            .split("::")
33            .last()
34            .unwrap_or_default()
35            .to_lowercase();
36        Box::leak(name.into_boxed_str())
37    }
38    /// 插件标题
39    fn title(&self) -> &'static str;
40    /// 插件图标
41    fn icon(&self) -> &'static str {
42        ""
43    }
44    /// 功能描述
45    fn description(&self) -> &'static str {
46        ""
47    }
48    /// 前端指定页面
49    fn pages(&self) -> &'static str {
50        ""
51    }
52    /// 插件排序
53    fn sort(&self) -> usize {
54        99
55    }
56    /// 插件分类
57    fn category(&self) -> &'static str {
58        ""
59    }
60    /// 模型分流
61    fn module(&mut self, name: &str) -> Result<Box<dyn Module>, String>;
62    /// 使用工具
63    fn tools(&mut self) -> Tools {
64        let tools = PLUGIN_TOOLS.lock().expect("PLUGIN_TOOLS lock failed");
65        tools.get("tools").expect("tools not initialized").clone()
66    }
67    /// 监听
68    fn handle(&mut self) {}
69}
70
71pub fn addon_create(
72    path: &str,
73    plugin: &str,
74    plugin_title: &str,
75    model: &str,
76    model_title: &str,
77    action: &str,
78    action_title: &str,
79) {
80    let root_path = PathBuf::from(path);
81    let plugin_path = root_path.join("plugin");
82    let plugin_path = plugin_path.join(plugin);
83    create_dir_all(plugin_path.as_os_str()).expect("创建目录失败");
84
85    let plugin_mod_path = plugin_path.join("mod.rs");
86    if !plugin_mod_path.is_file() {
87        let temp_plugin_mod_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
88        let temp_plugin_mod_path = temp_plugin_mod_path.join("temp").join("plugin");
89        let temp_plugin_mod_data =
90            fs::read_to_string(temp_plugin_mod_path).expect("读取插件模板失败");
91        let addon_1 = plugin.to_lowercase();
92        let plugin_1 = plugin[0..=0].to_uppercase();
93        let plugin_2 = plugin[1..].to_lowercase();
94        let temp_plugin_mod_data = temp_plugin_mod_data.replace("{{addon}}", &addon_1.to_string());
95        let temp_plugin_mod_data =
96            temp_plugin_mod_data.replace("{{plugin}}", &format!("{plugin_1}{plugin_2}"));
97        let temp_plugin_mod_data = temp_plugin_mod_data.replace("{{title}}", plugin_title);
98        fs::write(plugin_mod_path, temp_plugin_mod_data).expect("写入插件mod错误");
99    }
100
101    if !model.is_empty() {
102        let model_path = plugin_path.join(model);
103        create_dir_all(model_path.as_os_str()).expect("创建模型目录失败");
104
105        let plugin_d = to_pascal_case(plugin);
106        let model_d = to_pascal_case(model);
107
108        let model_mod_path = model_path.join("mod.rs");
109        if !model_mod_path.is_file() {
110            let temp_plugin_mod_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
111            let temp_model_mod_path = temp_plugin_mod_path.join("temp").join("model");
112            let mut temp_model_mod_data =
113                fs::read_to_string(temp_model_mod_path).expect("读取模型模板失败");
114            temp_model_mod_data = temp_model_mod_data.replace("{{addon}}", &plugin_d.to_string());
115            temp_model_mod_data =
116                temp_model_mod_data.replace("{{model}}", &format!("{plugin_d}{model_d}"));
117            temp_model_mod_data =
118                temp_model_mod_data.replace("{{addon::model}}", &format!("{plugin}::{model}"));
119            temp_model_mod_data =
120                temp_model_mod_data.replace("{{plugin_model}}", &format!("{plugin}_{model}"));
121            temp_model_mod_data = temp_model_mod_data.replace("{{model_name}}", model);
122            let temp_model_mod_data = temp_model_mod_data.replace("{{title}}", model_title);
123            fs::write(model_mod_path, temp_model_mod_data).expect("写入模型mod错误");
124        }
125
126        if !action.is_empty() {
127            let action_path = model_path.join(format!("{action}.rs"));
128            if !action_path.is_file() {
129                let temp_action_mod_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
130                let temp_action_mod_path = {
131                    if action.contains("table") {
132                        temp_action_mod_path.join("temp").join("action_table")
133                    } else if action.contains("add") {
134                        temp_action_mod_path.join("temp").join("action_add")
135                    } else if action.contains("del") {
136                        temp_action_mod_path.join("temp").join("action_del")
137                    } else if action.contains("put") {
138                        temp_action_mod_path.join("temp").join("action_put")
139                    } else if action.contains("select_tree") {
140                        temp_action_mod_path.join("temp").join("action_select_tree")
141                    } else if action.contains("select") {
142                        temp_action_mod_path.join("temp").join("action_select")
143                    } else if action.contains("get") {
144                        temp_action_mod_path.join("temp").join("action_get")
145                    } else if action.contains("menu") {
146                        temp_action_mod_path.join("temp").join("action_menu")
147                    } else if action.contains("down") {
148                        temp_action_mod_path.join("temp").join("action_down")
149                    } else if action.contains("tree") {
150                        temp_action_mod_path.join("temp").join("action_tree")
151                    } else if action.contains("import") {
152                        temp_action_mod_path.join("temp").join("action_import")
153                    } else {
154                        temp_action_mod_path.join("temp").join("action")
155                    }
156                };
157
158                let temp_action_mod_data =
159                    fs::read_to_string(temp_action_mod_path).expect("读取动作模板失败");
160
161                let action_d = to_pascal_case(action);
162
163                let temp_action_mod_data = temp_action_mod_data
164                    .replace("{{action}}", &format!("{plugin_d}{model_d}{action_d}"));
165                let temp_action_mod_data =
166                    temp_action_mod_data.replace("{{api}}", &format!("{plugin}.{model}.{action}"));
167                let temp_action_mod_data =
168                    temp_action_mod_data.replace("{{model}}", &format!("{plugin_d}{model_d}"));
169                let temp_action_mod_data =
170                    temp_action_mod_data.replace("{{addon::model}}", &format!("{plugin}::{model}"));
171                let temp_action_mod_data = temp_action_mod_data.replace("{{model_a}}", model);
172                let temp_action_mod_data = temp_action_mod_data.replace("{{plugin}}", plugin);
173                let temp_action_mod_data = temp_action_mod_data.replace("{{title}}", action_title);
174                fs::write(action_path, temp_action_mod_data).expect("写入动作文件错误");
175            }
176        }
177    }
178}