br_addon/
lib.rs

1/// 功能
2pub mod action;
3/// 插件
4pub mod addon;
5/// 模块
6pub mod module;
7/// 请求数据
8pub mod request;
9/// api清单
10pub mod swagger;
11/// 工具
12pub mod tools;
13use crate::action::Action;
14use crate::addon::Addon;
15use crate::module::Module;
16use crate::request::Request;
17use crate::tools::{Tools, ToolsConfig};
18#[cfg(any(feature = "mysql", feature = "sqlite", feature = "mssql", feature = "pgsql"))]
19use br_db::types::TableOptions;
20use json::{array, object, JsonValue};
21use lazy_static::lazy_static;
22use log::{error, info};
23use std::collections::HashMap;
24use std::path::PathBuf;
25use std::sync::{Mutex, OnceLock};
26use std::{fs, thread};
27use std::cell::RefCell;
28use std::sync::LazyLock;
29
30lazy_static! {
31    /// 工具集合
32    static ref PLUGIN_TOOLS: Mutex<HashMap<String,Tools>> =Mutex::new(HashMap::new());
33    static ref CONFIG: Mutex<HashMap<String,JsonValue>> =Mutex::new(HashMap::new());
34}
35/// 全局监听线程
36static GLOBAL_HANDLE: LazyLock<Mutex<HashMap<String, String>>> = LazyLock::new(|| Mutex::new(HashMap::new()));
37/// 全局加载的插件清单
38pub static GLOBAL_ADDONS: OnceLock<Vec<String>> = OnceLock::new();
39/// 全局加载的模块清单
40pub static GLOBAL_MODULE: OnceLock<Vec<String>> = OnceLock::new();
41/// 全局加载的动作清单
42pub static GLOBAL_ACTION: OnceLock<Vec<String>> = OnceLock::new();
43
44thread_local! {
45    /// 单线程全局变量
46    static GLOBAL_DATA: RefCell<JsonValue> = RefCell::new(object!{});
47}
48/// 插件接口
49pub trait Plugin {
50    /// 加载插件
51    fn addon(name: &str) -> Result<Box<dyn Addon>, String>;
52    /// 加载模型
53    fn module(name: &str) -> Result<Box<dyn Module>, String> {
54        let (addon_name, module_name) = Self::split2(name)?;
55        Self::addon(addon_name)?.module(module_name)
56    }
57    /// 加载动作
58    fn action(name: &str) -> Result<Box<dyn Action>, String> {
59        let (addon_name, module_name, action_name) = Self::split3(name)?;
60        Self::addon(addon_name)?.module(module_name)?.action(action_name)
61    }
62    /// 内部api
63    fn api_run(name: &str, request: Request) -> Result<JsonValue, String> {
64        let (addon_name, module_name, action_name) = Self::split3(name)?;
65        match Self::addon(addon_name)?.module(module_name)?.action(action_name)?.run(request) {
66            Ok(e) => Ok(e.data),
67            Err(e) => Err(e.message),
68        }
69    }
70    /// 加载工具装置
71    /// * path 配置文件路径
72    fn load_tools(config: ToolsConfig) -> Result<(), String> {
73        if PLUGIN_TOOLS.lock().unwrap().get("tools").is_none() {
74            PLUGIN_TOOLS.lock().unwrap().insert("tools".into(), Tools::new(config)?);
75        }
76        Ok(())
77    }
78    /// 获取工具
79    fn get_tools() -> Tools {
80        let tools = PLUGIN_TOOLS.lock().unwrap();
81        let tools = tools.get("tools").unwrap().clone();
82        tools
83    }
84    /// 加载全局配置文件
85    fn load_config(name: &str, config: JsonValue) {
86        CONFIG.lock().unwrap().insert(name.into(), config.clone());
87    }
88    /// 根据API清单初始化数据库
89    ///
90    /// * path 插件目录
91    #[cfg(any(feature = "mysql", feature = "sqlite", feature = "mssql", feature = "pgsql"))]
92    fn init_db() -> Result<(), String> {
93        info!("=============数据库更新开始=============");
94        let mut tables = HashMap::new();
95        // 生成数据库文件
96        let sql = PathBuf::from("sql");
97
98        // 删除目录
99        match fs::remove_dir_all(sql.to_str().unwrap()) {
100            Ok(_) => {}
101            Err(e) => {
102                #[cfg(any(feature = "mysql", feature = "sqlite", feature = "mssql",feature = "pgsql"))]
103                error!("目录删除失败: {e}");
104            }
105        }
106
107        // 创建目录
108        match fs::create_dir_all(sql.to_str().unwrap()) {
109            Ok(_) => {}
110            Err(e) => error!("目录创建失败: {e}"),
111        }
112
113        let sql_file = sql.join("sql.json");
114        let mut db_install = array![];
115
116        for api_name in GLOBAL_MODULE.wait() {
117            let module = match Self::module(api_name) {
118                Ok(e) => e,
119                Err(e) => {
120                    error!("加载模型错误: {}",e);
121                    continue;
122                }
123            };
124            if !module.table() {
125                continue;
126            }
127            if !tables.contains_key(module._table_name()) {
128                tables.insert(module._table_name(), module);
129            }
130        }
131
132        for (_, module) in tables.iter_mut() {
133            let mut opt = TableOptions::default();
134
135            let unique = module.table_unique().iter().map(|x| (*x).to_string()).collect::<Vec<String>>();
136            let unique = unique.iter().map(|x| x.as_str()).collect::<Vec<&str>>();
137
138            let index = module.table_index().iter().map(|x| x.iter().map(|&y| y.to_string()).collect::<Vec<String>>()).collect::<Vec<Vec<String>>>();
139            let index = index.iter().map(|x| x.iter().map(|y| y.as_str()).collect::<Vec<&str>>()).collect::<Vec<Vec<&str>>>();
140
141
142            opt.set_table_name(module._table_name());
143            opt.set_table_title(module.title());
144            opt.set_table_key(module.table_key());
145            opt.set_table_fields(module.fields().clone());
146            opt.set_table_unique(unique.clone());
147            opt.set_table_index(index.clone());
148            opt.set_table_partition(module.table_partition());
149            opt.set_table_partition_columns(module.table_partition_columns());
150            // 生成sql安装文件
151            let sql = Self::get_tools().db.table(module._table_name()).fetch_sql().table_create(opt.clone());
152            let update_sql = Self::get_tools().db.table(module._table_name()).fetch_sql().table_update(opt.clone());
153            db_install.push(object! {
154                    table:module._table_name(),
155                    field:module.fields().clone(),
156                    key:module.table_key(),
157                    index:index.clone(),
158                    unique:unique.clone(),
159                    sql:sql,
160                    update_sql:update_sql
161                 }).unwrap();
162            fs::write(sql_file.clone(), db_install.to_string()).unwrap();
163
164            if Self::get_tools().db.table_is_exist(module._table_name()) {
165                let res = Self::get_tools().db.table_update(opt);
166                match res.as_i32().unwrap() {
167                    -1 => {}
168                    0 => {
169                        info!("数据库更新情况: {} 失败", module._table_name());
170                    }
171                    1 => {
172                        info!("数据库更新情况: {} 成功", module._table_name());
173                    }
174                    _ => {}
175                }
176            } else {
177                let res = Self::get_tools().db.table_create(opt);
178                info!("安装完成情况: {} {}", module._table_name(), res);
179            }
180        }
181        info!("=============数据库更新完成=============");
182        Ok(())
183    }
184
185    /// 全局插件监听入口
186    fn handles() {
187        let mut map = GLOBAL_HANDLE.lock().unwrap();
188        for api in GLOBAL_MODULE.wait() {
189            let mut module_name = match Self::module(api.as_str()) {
190                Ok(e) => e,
191                Err(e) => {
192                    error!("插件: {api} 加载错误 {e}");
193                    continue;
194                }
195            };
196            if map.get(module_name.module_name()).is_none() {
197                map.insert(module_name.module_name().to_string(), module_name.module_name().to_string());
198                thread::spawn(move || module_name.handle());
199            }
200        }
201    }
202    /// 生成Swagger
203    fn swagger(
204        title: &str,
205        description: &str,
206        version: &str,
207        uaturl: &str,
208        produrl: &str,
209        tags: JsonValue,
210        paths: JsonValue,
211    ) -> JsonValue {
212        let info = object! {
213            openapi:"3.0.0",
214            info:{
215                title:title,
216                description:description,
217                version:version
218            },
219            components: {
220                securitySchemes: {
221                    BearerToken: {
222                        "type": "http",
223                        "scheme": "bearer",
224                        "bearerFormat": "Token"
225                    }
226                }
227            },
228            tags:tags,
229            security: [
230                {
231                    "BearerToken": []
232                }
233            ],
234            servers:[
235                {
236                    "url":uaturl,
237                    "description": "测试地址"
238                },
239                {
240                    "url":produrl,
241                    "description": "正式地址"
242                }
243            ],
244            paths:paths
245        };
246        info
247    }
248    /// 生成 api 列表
249    fn generate_api_list(apipath: PathBuf, path: PathBuf, index: usize) -> Result<Vec<String>, String> {
250        #[cfg(debug_assertions)]
251        {
252            let mut plugin_list = Vec::new();
253            if path.is_dir() {
254                let res = fs::read_dir(path);
255                match res {
256                    Ok(entries) => {
257                        for entry in entries {
258                            let entry = match entry {
259                                Ok(e) => e,
260                                Err(e) => {
261                                    return Err(e.to_string())
262                                }
263                            };
264                            let path = entry.path();
265                            if path.is_dir() {
266                                let res = Self::generate_api_list(
267                                    apipath.clone(),
268                                    path.to_str().unwrap().parse().unwrap(),
269                                    index + 1,
270                                )?;
271                                plugin_list.extend(res);
272                            } else if path.is_file() {
273                                if path.to_str().unwrap().ends_with("mod.rs") {
274                                    continue;
275                                }
276                                let addon = path.parent().unwrap().parent().unwrap().file_name().unwrap().to_str().unwrap();
277                                let model = path.parent().unwrap().file_name().unwrap().to_str().unwrap();
278                                let action = path.file_name().unwrap().to_str().unwrap().trim_end_matches(".rs");
279                                let api = format!("{addon}.{model}.{action}");
280                                match Self::action(api.as_str()) {
281                                    Ok(e) => plugin_list.push(e.api()),
282                                    Err(_) => continue
283                                }
284                            }
285                        }
286                    }
287                    Err(e) => return Err(e.to_string())
288                }
289            }
290            if index == 0 {
291                fs::create_dir_all(apipath.clone().parent().unwrap()).unwrap();
292                fs::write(apipath, JsonValue::from(plugin_list.clone()).to_string()).unwrap();
293                info!("=============API数量: {} 条=============", plugin_list.len());
294                Self::_load_apis(plugin_list.clone())?;
295            }
296            Ok(plugin_list)
297        }
298        #[cfg(not(debug_assertions))]
299        {
300            let apis = fs::read_to_string(apipath).unwrap();
301            let apis = json::parse(&apis).unwrap();
302            let apis = apis.members().map(|x| x.as_str().unwrap().to_string()).collect::<Vec<String>>();
303            info!("=============API数量: {} 条=============", apis.len());
304            Self::_load_apis(apis.clone())?;
305            Ok(apis)
306        }
307    }
308    /// 加载api清单
309    fn _load_apis(apis: Vec<String>) -> Result<(), String> {
310        let mut action_list = vec![];
311        let mut module_list = vec![];
312        let mut addons_list = vec![];
313        for api in apis {
314            let action = Self::action(api.as_str())?;
315            action_list.push(action.api());
316            if !module_list.contains(&action.module_name()) {
317                module_list.push(action.module_name());
318            }
319            if !addons_list.contains(&action.addon_name()) {
320                addons_list.push(action.addon_name());
321            }
322        }
323        let _ = GLOBAL_ACTION.set(action_list);
324        let _ = GLOBAL_MODULE.set(module_list);
325        let _ = GLOBAL_ADDONS.set(addons_list);
326        Ok(())
327    }
328    /// 设置全局变量
329    fn set_global_data(key: &str, value: JsonValue) {
330        GLOBAL_DATA.with(|data| {
331            data.borrow_mut()[key] = value;
332        });
333    }
334    /// 获取全局变量数据
335    fn get_global_data() -> JsonValue {
336        GLOBAL_DATA.with(|data| {
337            data.borrow().clone()
338        })
339    }
340    /// 获取全局变量指定字段数据
341    fn get_global_data_key(key: &str) -> JsonValue {
342        GLOBAL_DATA.with(|data| {
343            data.borrow()[key].clone()
344        })
345    }
346    /// 解析 "addon.module"(零分配)
347    #[inline]
348    fn split2(name: &str) -> Result<(&str, &str), String> {
349        let t = name.split(".").collect::<Vec<&str>>();
350        if t.len() < 2 {
351            return Err(format!("模型格式不正确: {name}"));
352        }
353        Ok((t[0], t[1]))
354    }
355
356    /// 解析 "addon.module.action"(零分配)
357    #[inline]
358    fn split3(name: &str) -> Result<(&str, &str, &str), String> {
359        if let Some((a, rest)) = name.split_once('.') {
360            if let Some((b, c)) = rest.split_once('.') {
361                if !a.is_empty() && !b.is_empty() && !c.is_empty() {
362                    Ok((a, b, c))
363                } else {
364                    Err("动作格式不正确".to_string())
365                }
366            } else {
367                Err("动作格式不正确".to_string())
368            }
369        } else {
370            Err("动作格式不正确".to_string())
371        }
372    }
373}
374/// API 错误响应
375#[derive(Debug, Clone)]
376pub struct ApiResponse {
377    pub types: ApiType,
378    pub code: i32,
379    pub message: String,
380    pub data: JsonValue,
381    pub success: bool,
382    pub timestamp: i64,
383}
384impl ApiResponse {
385    pub fn json(self) -> JsonValue {
386        match self.types {
387            ApiType::Json => object! {
388                code: self.code,
389                message: self.message,
390                data: self.data,
391                success: self.success
392            },
393            ApiType::Redirect => self.data,
394            ApiType::Download => self.data,
395            ApiType::Preview => self.data,
396            ApiType::Txt => self.data,
397            ApiType::Html => self.data,
398        }
399    }
400    pub fn swagger(&mut self) -> JsonValue {
401        let mut content = object! {};
402        content[self.types.str().as_str()] = object! {};
403        content[self.types.str().as_str()]["schema"]["type"] = if self.data.is_array() {
404            "array"
405        } else {
406            "object"
407        }.into();
408        content[self.types.str().as_str()]["schema"]["properties"] = self.data.clone();
409
410        content[self.types.str().as_str()]["schema"]["type"] = match content[self.types.str().as_str()]["schema"]["type"].as_str().unwrap() {
411            "int" => "integer".into(),
412            _ => content[self.types.str().as_str()]["schema"]["type"].clone(),
413        };
414        let data = object! {
415            "description":self.message.clone(),
416            "content":content
417        };
418        data
419    }
420    pub fn success(data: JsonValue, mut message: &str) -> Self {
421        if message.is_empty() {
422            message = "success";
423        }
424        Self {
425            success: true,
426            types: ApiType::Json,
427            code: 0,
428            message: message.to_string(),
429            data,
430            timestamp: br_fields::datetime::Timestamp::timestamp(),
431        }
432    }
433    pub fn fail(code: i32, message: &str) -> Self {
434        Self {
435            types: ApiType::Json,
436            code,
437            message: message.to_string(),
438            data: JsonValue::Null,
439            success: false,
440            timestamp: br_fields::datetime::Timestamp::timestamp(),
441        }
442    }
443    pub fn error(data: JsonValue, message: &str) -> Self {
444        Self {
445            types: ApiType::Json,
446            code: -1,
447            message: message.to_string(),
448            data,
449            success: false,
450            timestamp: br_fields::datetime::Timestamp::timestamp(),
451        }
452    }
453    /// 重定向
454    pub fn redirect(url: &str) -> Self {
455        Self {
456            types: ApiType::Redirect,
457            code: 0,
458            message: "".to_string(),
459            data: url.into(),
460            success: true,
461            timestamp: br_fields::datetime::Timestamp::timestamp(),
462        }
463    }
464    /// 下载
465    pub fn download(filename: &str) -> Self {
466        Self {
467            types: ApiType::Download,
468            code: 0,
469            message: "".to_string(),
470            data: filename.into(),
471            success: true,
472            timestamp: br_fields::datetime::Timestamp::timestamp(),
473        }
474    }
475    /// 预览
476    pub fn preview(filename: &str) -> Self {
477        Self {
478            types: ApiType::Preview,
479            code: 0,
480            message: "".to_string(),
481            data: filename.into(),
482            success: true,
483            timestamp: br_fields::datetime::Timestamp::timestamp(),
484        }
485    }
486    /// 文本
487    pub fn txt(txt: &str) -> Self {
488        Self {
489            types: ApiType::Txt,
490            code: 0,
491            message: "".to_string(),
492            data: txt.into(),
493            success: true,
494            timestamp: br_fields::datetime::Timestamp::timestamp(),
495        }
496    }
497    pub fn html(data: &str) -> Self {
498        Self {
499            types: ApiType::Html,
500            code: 0,
501            message: "".to_string(),
502            data: data.into(),
503            success: true,
504            timestamp: br_fields::datetime::Timestamp::timestamp(),
505        }
506    }
507}
508impl Default for ApiResponse {
509    fn default() -> Self {
510        Self {
511            types: ApiType::Json,
512            code: 0,
513            message: "".to_string(),
514            data: JsonValue::Null,
515            success: false,
516            timestamp: br_fields::datetime::Timestamp::timestamp(),
517        }
518    }
519}
520/// API 响应
521#[derive(Debug, Clone)]
522pub enum ApiType {
523    /// JSON类型
524    Json,
525    /// 重定向
526    /// (重定向地址: http://xxxxxx)
527    Redirect,
528    /// 下载
529    /// (文件地址: 文件绝对地址)
530    Download,
531    /// 预览
532    /// (文件地址: 文件绝对地址)
533    Preview,
534    /// TXT格式
535    Txt,
536    /// 返回网页
537    Html,
538}
539impl ApiType {
540    pub fn str(&mut self) -> String {
541        match self {
542            ApiType::Json => "application/json",
543            ApiType::Redirect | ApiType::Download | ApiType::Preview => "text/html",
544            ApiType::Txt => "text/plain",
545            ApiType::Html => "text/html",
546        }.to_string()
547    }
548}