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