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            let init_data = module.init_data();
181            if !init_data.is_empty() {
182                let count = Self::get_tools().db.table(module._table_name()).count();
183                if count.is_empty() {
184                    let r = Self::get_tools().db.table(module._table_name()).insert_all(init_data);
185                    info!("初始化【{}】数据 {} 条",module._table_name(),r.len());
186                }
187            }
188        }
189        info!("=============数据库更新完成=============");
190        Ok(())
191    }
192
193    /// 全局插件监听入口
194    fn handles() {
195        let mut map = GLOBAL_HANDLE.lock().unwrap();
196        for api in GLOBAL_MODULE.wait() {
197            let mut module_name = match Self::module(api.as_str()) {
198                Ok(e) => e,
199                Err(e) => {
200                    error!("插件: {api} 加载错误 {e}");
201                    continue;
202                }
203            };
204            if map.get(module_name.module_name()).is_none() {
205                map.insert(module_name.module_name().to_string(), module_name.module_name().to_string());
206                thread::spawn(move || module_name.handle());
207            }
208        }
209    }
210    /// 生成Swagger
211    fn swagger(
212        title: &str,
213        description: &str,
214        version: &str,
215        uaturl: &str,
216        produrl: &str,
217        tags: JsonValue,
218        paths: JsonValue,
219    ) -> JsonValue {
220        let info = object! {
221            openapi:"3.0.0",
222            info:{
223                title:title,
224                description:description,
225                version:version
226            },
227            components: {
228                securitySchemes: {
229                    BearerToken: {
230                        "type": "http",
231                        "scheme": "bearer",
232                        "bearerFormat": "Token"
233                    }
234                }
235            },
236            tags:tags,
237            security: [
238                {
239                    "BearerToken": []
240                }
241            ],
242            servers:[
243                {
244                    "url":uaturl,
245                    "description": "测试地址"
246                },
247                {
248                    "url":produrl,
249                    "description": "正式地址"
250                }
251            ],
252            paths:paths
253        };
254        info
255    }
256    /// 生成 api 列表
257    fn generate_api_list(apipath: PathBuf, path: PathBuf, index: usize) -> Result<Vec<String>, String> {
258        #[cfg(debug_assertions)]
259        {
260            let mut plugin_list = Vec::new();
261            if path.is_dir() {
262                let res = fs::read_dir(path);
263                match res {
264                    Ok(entries) => {
265                        for entry in entries {
266                            let entry = match entry {
267                                Ok(e) => e,
268                                Err(e) => {
269                                    return Err(e.to_string())
270                                }
271                            };
272                            let path = entry.path();
273                            if path.is_dir() {
274                                let res = Self::generate_api_list(
275                                    apipath.clone(),
276                                    path.to_str().unwrap().parse().unwrap(),
277                                    index + 1,
278                                )?;
279                                plugin_list.extend(res);
280                            } else if path.is_file() {
281                                if path.to_str().unwrap().ends_with("mod.rs") {
282                                    continue;
283                                }
284                                let addon = path.parent().unwrap().parent().unwrap().file_name().unwrap().to_str().unwrap();
285                                let model = path.parent().unwrap().file_name().unwrap().to_str().unwrap();
286                                let action = path.file_name().unwrap().to_str().unwrap().trim_end_matches(".rs");
287                                let api = format!("{addon}.{model}.{action}");
288                                match Self::action(api.as_str()) {
289                                    Ok(e) => plugin_list.push(e.api()),
290                                    Err(_) => continue
291                                }
292                            }
293                        }
294                    }
295                    Err(e) => return Err(e.to_string())
296                }
297            }
298            if index == 0 {
299                fs::create_dir_all(apipath.clone().parent().unwrap()).unwrap();
300                fs::write(apipath, JsonValue::from(plugin_list.clone()).to_string()).unwrap();
301                info!("=============API数量: {} 条=============", plugin_list.len());
302                Self::_load_apis(plugin_list.clone())?;
303            }
304            Ok(plugin_list)
305        }
306        #[cfg(not(debug_assertions))]
307        {
308            let apis = fs::read_to_string(apipath).unwrap();
309            let apis = json::parse(&apis).unwrap();
310            let apis = apis.members().map(|x| x.as_str().unwrap().to_string()).collect::<Vec<String>>();
311            info!("=============API数量: {} 条=============", apis.len());
312            Self::_load_apis(apis.clone())?;
313            Ok(apis)
314        }
315    }
316    /// 加载api清单
317    fn _load_apis(apis: Vec<String>) -> Result<(), String> {
318        let mut action_list = vec![];
319        let mut module_list = vec![];
320        let mut addons_list = vec![];
321        for api in apis {
322            let action = Self::action(api.as_str())?;
323            action_list.push(action.api());
324            if !module_list.contains(&action.module_name()) {
325                module_list.push(action.module_name());
326            }
327            if !addons_list.contains(&action.addon_name()) {
328                addons_list.push(action.addon_name());
329            }
330        }
331        let _ = GLOBAL_ACTION.set(action_list);
332        let _ = GLOBAL_MODULE.set(module_list);
333        let _ = GLOBAL_ADDONS.set(addons_list);
334        Ok(())
335    }
336    /// 设置全局变量
337    fn set_global_data(key: &str, value: JsonValue) {
338        GLOBAL_DATA.with(|data| {
339            data.borrow_mut()[key] = value;
340        });
341    }
342    /// 获取全局变量数据
343    fn get_global_data() -> JsonValue {
344        GLOBAL_DATA.with(|data| {
345            data.borrow().clone()
346        })
347    }
348    /// 获取全局变量指定字段数据
349    fn get_global_data_key(key: &str) -> JsonValue {
350        GLOBAL_DATA.with(|data| {
351            data.borrow()[key].clone()
352        })
353    }
354    /// 解析 "addon.module"(零分配)
355    #[inline]
356    fn split2(name: &str) -> Result<(&str, &str), String> {
357        let t = name.split(".").collect::<Vec<&str>>();
358        if t.len() < 2 {
359            return Err(format!("模型格式不正确: {name}"));
360        }
361        Ok((t[0], t[1]))
362    }
363
364    /// 解析 "addon.module.action"(零分配)
365    #[inline]
366    fn split3(name: &str) -> Result<(&str, &str, &str), String> {
367        if let Some((a, rest)) = name.split_once('.') {
368            if let Some((b, c)) = rest.split_once('.') {
369                if !a.is_empty() && !b.is_empty() && !c.is_empty() {
370                    Ok((a, b, c))
371                } else {
372                    Err("动作格式不正确".to_string())
373                }
374            } else {
375                Err("动作格式不正确".to_string())
376            }
377        } else {
378            Err("动作格式不正确".to_string())
379        }
380    }
381}
382/// API 错误响应
383#[derive(Debug, Clone)]
384pub struct ApiResponse {
385    pub types: ApiType,
386    pub code: i32,
387    pub message: String,
388    pub data: JsonValue,
389    pub success: bool,
390    pub timestamp: i64,
391}
392impl ApiResponse {
393    pub fn json(self) -> JsonValue {
394        match self.types {
395            ApiType::Json => object! {
396                code: self.code,
397                message: self.message,
398                data: self.data,
399                success: self.success
400            },
401            ApiType::Redirect => self.data,
402            ApiType::Download => self.data,
403            ApiType::Preview => self.data,
404            ApiType::Txt => self.data,
405            ApiType::Html => self.data,
406        }
407    }
408    pub fn swagger(&mut self) -> JsonValue {
409        let mut content = object! {};
410        content[self.types.str().as_str()] = object! {};
411        content[self.types.str().as_str()]["schema"]["type"] = if self.data.is_array() {
412            "array"
413        } else {
414            "object"
415        }.into();
416        content[self.types.str().as_str()]["schema"]["properties"] = self.data.clone();
417
418        content[self.types.str().as_str()]["schema"]["type"] = match content[self.types.str().as_str()]["schema"]["type"].as_str().unwrap() {
419            "int" => "integer".into(),
420            _ => content[self.types.str().as_str()]["schema"]["type"].clone(),
421        };
422        let data = object! {
423            "description":self.message.clone(),
424            "content":content
425        };
426        data
427    }
428    pub fn success(data: JsonValue, mut message: &str) -> Self {
429        if message.is_empty() {
430            message = "success";
431        }
432        Self {
433            success: true,
434            types: ApiType::Json,
435            code: 0,
436            message: message.to_string(),
437            data,
438            timestamp: br_fields::datetime::Timestamp::timestamp(),
439        }
440    }
441    pub fn fail(code: i32, message: &str) -> Self {
442        Self {
443            types: ApiType::Json,
444            code,
445            message: message.to_string(),
446            data: JsonValue::Null,
447            success: false,
448            timestamp: br_fields::datetime::Timestamp::timestamp(),
449        }
450    }
451    pub fn error(data: JsonValue, message: &str) -> Self {
452        Self {
453            types: ApiType::Json,
454            code: -1,
455            message: message.to_string(),
456            data,
457            success: false,
458            timestamp: br_fields::datetime::Timestamp::timestamp(),
459        }
460    }
461    /// 重定向
462    pub fn redirect(url: &str) -> Self {
463        Self {
464            types: ApiType::Redirect,
465            code: 0,
466            message: "".to_string(),
467            data: url.into(),
468            success: true,
469            timestamp: br_fields::datetime::Timestamp::timestamp(),
470        }
471    }
472    /// 下载
473    pub fn download(filename: &str) -> Self {
474        Self {
475            types: ApiType::Download,
476            code: 0,
477            message: "".to_string(),
478            data: filename.into(),
479            success: true,
480            timestamp: br_fields::datetime::Timestamp::timestamp(),
481        }
482    }
483    /// 预览
484    pub fn preview(filename: &str) -> Self {
485        Self {
486            types: ApiType::Preview,
487            code: 0,
488            message: "".to_string(),
489            data: filename.into(),
490            success: true,
491            timestamp: br_fields::datetime::Timestamp::timestamp(),
492        }
493    }
494    /// 文本
495    pub fn txt(txt: &str) -> Self {
496        Self {
497            types: ApiType::Txt,
498            code: 0,
499            message: "".to_string(),
500            data: txt.into(),
501            success: true,
502            timestamp: br_fields::datetime::Timestamp::timestamp(),
503        }
504    }
505    pub fn html(data: &str) -> Self {
506        Self {
507            types: ApiType::Html,
508            code: 0,
509            message: "".to_string(),
510            data: data.into(),
511            success: true,
512            timestamp: br_fields::datetime::Timestamp::timestamp(),
513        }
514    }
515}
516impl Default for ApiResponse {
517    fn default() -> Self {
518        Self {
519            types: ApiType::Json,
520            code: 0,
521            message: "".to_string(),
522            data: JsonValue::Null,
523            success: false,
524            timestamp: br_fields::datetime::Timestamp::timestamp(),
525        }
526    }
527}
528/// API 响应
529#[derive(Debug, Clone)]
530pub enum ApiType {
531    /// JSON类型
532    Json,
533    /// 重定向
534    /// (重定向地址: http://xxxxxx)
535    Redirect,
536    /// 下载
537    /// (文件地址: 文件绝对地址)
538    Download,
539    /// 预览
540    /// (文件地址: 文件绝对地址)
541    Preview,
542    /// TXT格式
543    Txt,
544    /// 返回网页
545    Html,
546}
547impl ApiType {
548    pub fn str(&mut self) -> String {
549        match self {
550            ApiType::Json => "application/json",
551            ApiType::Redirect | ApiType::Download | ApiType::Preview => "text/html",
552            ApiType::Txt => "text/plain",
553            ApiType::Html => "text/html",
554        }.to_string()
555    }
556}