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
14use crate::action::Action;
15use crate::addon::Addon;
16use crate::module::Module;
17use crate::request::Request;
18use crate::tools::{Tools, ToolsConfig};
19#[cfg(any(feature = "mysql", feature = "sqlite", feature = "mssql"))]
20use br_db::types::TableOptions;
21use json::{array, object, JsonValue};
22use lazy_static::lazy_static;
23use log::info;
24use std::collections::HashMap;
25use std::path::PathBuf;
26use std::sync::Mutex;
27use std::{fs, io};
28use std::cell::RefCell;
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
36thread_local! {
37    /// 单线程全局变量
38    static GLOBAL_DATA: RefCell<JsonValue> = RefCell::new(object!{});
39}
40/// 插件接口
41pub trait Plugin {
42    /// 加载插件
43    fn addon(name: &str) -> Result<Box<dyn Addon>, String>;
44    /// 加载模型
45    fn module(name: &str) -> Result<Box<dyn Module>, String> {
46        let res = name.split(".").collect::<Vec<&str>>();
47        if res.len() < 2 {
48            return Err("模型格式不正确".to_string());
49        }
50        Self::addon(res[0])?.module(res[1])
51    }
52    /// 加载动作
53    fn action(name: &str) -> Result<Box<dyn Action>, String> {
54        let res = name.split(".").collect::<Vec<&str>>();
55        if res.len() < 3 {
56            return Err("动作格式不正确".to_string());
57        }
58        Self::addon(res[0])?.module(res[1])?.action(res[2])
59    }
60    /// 内部api
61    fn api_run(name: &str, request: Request) -> Result<JsonValue, String> {
62        let res = name.split(".").collect::<Vec<&str>>();
63        if res.len() != 3 {
64            return Err("action格式不正确".to_string());
65        }
66        match Self::addon(res[0])?.module(res[1])?.action(res[2])?.run(request) {
67            Ok(e) => Ok(e.data),
68            Err(e) => Err(e.message),
69        }
70    }
71    /// 加载api
72    fn api(name: &str) -> Result<Box<dyn Action>, String> {
73        let res = name.split(".").collect::<Vec<&str>>();
74        if res.len() != 3 {
75            return Err("api 格式不正确".to_string());
76        }
77        Self::addon(res[0])?.module(res[1])?.action(res[2])
78    }
79    /// 加载工具装置
80    /// * path 配置文件路径
81    fn load_tools(config: ToolsConfig) -> Result<(), String> {
82        if PLUGIN_TOOLS.lock().unwrap().get("tools").is_none() {
83            let res = Tools::new(config)?;
84            PLUGIN_TOOLS.lock().unwrap().insert("tools".into(), res.clone());
85        }
86        Ok(())
87    }
88    /// 获取工具
89    fn get_tools() -> Tools {
90        let tools = PLUGIN_TOOLS.lock().unwrap();
91        let tools = tools.get("tools").unwrap().clone();
92        tools
93    }
94    /// 加载全局配置文件
95    fn load_config(name: &str, config: JsonValue) {
96        CONFIG.lock().unwrap().insert(name.into(), config.clone());
97    }
98    /// 根据API清单初始化数据库
99    ///
100    /// * path 插件目录
101    #[cfg(any(feature = "mysql", feature = "sqlite", feature = "mssql"))]
102    fn init_db(file_path: PathBuf) -> Result<Vec<String>, String> {
103        info!("=============数据库更新开始=============");
104        let list = match fs::read_to_string(file_path.clone()) {
105            Ok(e) => json::parse(&e).unwrap_or(array![]),
106            Err(e) => return Err(format!("加载API清单失败: {}", e)),
107        };
108        let mut api_list = vec![];
109        let mut table_name_list = vec![];
110        for api_name in list.members() {
111            let api_info = api_name.as_str().unwrap_or("").split(".").collect::<Vec<&str>>();
112            let mut addon = match Self::addon(api_info[0]) {
113                Ok(e) => e,
114                Err(_) => {
115                    continue;
116                }
117            };
118            let mut module = match addon.module(api_info[1]) {
119                Ok(e) => e,
120                Err(_) => {
121                    continue;
122                }
123            };
124            let action = match module.action(api_info[2]) {
125                Ok(e) => e,
126                Err(_) => {
127                    continue;
128                }
129            };
130
131            if action.auth() || action.public() {
132                api_list.push(api_name.to_string().clone());
133            }
134
135            if !module.table() {
136                continue;
137            }
138            let mut opt = TableOptions::default();
139
140            let unique = module.table_unique().iter().map(|x| x.to_string()).collect::<Vec<String>>();
141            let unique = unique.iter().map(|x| x.as_str()).collect::<Vec<&str>>();
142
143            let index = module.table_index().iter().map(|x| x.iter().map(|&y| y.to_string()).collect::<Vec<String>>()).collect::<Vec<Vec<String>>>();
144            let index = index.iter().map(|x| x.iter().map(|y| y.as_str()).collect::<Vec<&str>>()).collect::<Vec<Vec<&str>>>();
145
146            opt.set_table_name(module._table_name());
147            opt.set_table_title(module.title());
148            opt.set_table_key(module.table_key());
149            opt.set_table_fields(module.fields().clone());
150            opt.set_table_unique(unique);
151            opt.set_table_index(index);
152            opt.set_table_partition(module.table_partition());
153            opt.set_table_partition_columns(module.table_partition_columns());
154
155            if table_name_list.contains(&module._table_name()) {
156                continue;
157            }
158            table_name_list.push(module._table_name());
159            if Self::get_tools().db.table_is_exist(module._table_name()) {
160                let res = Self::get_tools().db.table_update_new(opt);
161                match res.as_i32().unwrap() {
162                    -1 => {}
163                    0 => {
164                        info!("数据库更新情况: {} 失败", module._table_name());
165                    }
166                    1 => {
167                        info!("数据库更新情况: {} 成功", module._table_name());
168                    }
169                    _ => {}
170                }
171            } else {
172                let res = Self::get_tools().db.table_create_new(opt);
173                info!("安装完成情况: {} {}", module._table_name(), res);
174            }
175        }
176        info!("=============数据库更新完成=============");
177        info!("=============API数量: {} 条=============", api_list.len());
178        fs::write(file_path, JsonValue::from(api_list.clone()).to_string()).unwrap();
179        Ok(api_list)
180    }
181    /// 生成Swagger
182    fn swagger(
183        title: &str,
184        description: &str,
185        version: &str,
186        uaturl: &str,
187        produrl: &str,
188        tags: JsonValue,
189        paths: JsonValue,
190    ) -> JsonValue {
191        let info = object! {
192            openapi:"3.0.0",
193            info:{
194                title:title,
195                description:description,
196                version:version
197            },
198            components: {
199                securitySchemes: {
200                    BearerToken: {
201                        "type": "http",
202                        "scheme": "bearer",
203                        "bearerFormat": "Token"
204                    }
205                }
206            },
207            tags:tags,
208            security: [
209                {
210                    "BearerToken": []
211                }
212            ],
213            servers:[
214                {
215                    "url":uaturl,
216                    "description": "测试地址"
217                },
218                {
219                    "url":produrl,
220                    "description": "正式地址"
221                }
222            ],
223            paths:paths
224        };
225        info
226    }
227    /// 生成 api 列表
228    fn generate_api_list(apipath: PathBuf, path: PathBuf, index: usize) -> io::Result<Vec<String>> {
229        #[cfg(debug_assertions)]
230        {
231            let mut plugin_list = vec![];
232            if path.is_dir() {
233                let res = fs::read_dir(path);
234                match res {
235                    Ok(entries) => {
236                        for entry in entries {
237                            let entry = entry.unwrap();
238                            let path = entry.path();
239                            if path.is_dir() {
240                                let res = Self::generate_api_list(
241                                    apipath.clone(),
242                                    path.to_str().unwrap().parse().unwrap(),
243                                    index + 1,
244                                )?;
245                                plugin_list.extend(res);
246                            } else if path.is_file() {
247                                if path.to_str().unwrap().ends_with("mod.rs") {
248                                    continue;
249                                }
250                                let addon = path.parent().unwrap().parent().unwrap().file_name().unwrap().to_str().unwrap();
251                                let model = path.parent().unwrap().file_name().unwrap().to_str().unwrap();
252                                let action = path.file_name().unwrap().to_str().unwrap().trim_end_matches(".rs");
253                                plugin_list.push(format!("{}.{}.{}", addon, model, action));
254                            }
255                        }
256                    }
257                    Err(e) => {
258                        return Err(std::io::Error::new(
259                            std::io::ErrorKind::Other,
260                            e.to_string(),
261                        ))
262                    }
263                }
264            }
265            if index == 0 {
266                fs::create_dir_all(apipath.clone().parent().unwrap()).unwrap();
267                fs::write(apipath, JsonValue::from(plugin_list.clone()).to_string()).unwrap();
268            }
269            Ok(plugin_list)
270        }
271        #[cfg(not(debug_assertions))]
272        {
273            let apis = fs::read_to_string(apipath).unwrap();
274            let apis = json::parse(&apis).unwrap();
275            let mut apis = apis.members().map(|x| x.as_str().unwrap().to_string()).collect::<Vec<String>>();
276            Ok(apis)
277        }
278    }
279
280    /// 设置全局变量
281    fn set_global_data(key: &str, value: JsonValue) {
282        GLOBAL_DATA.with(|data| {
283            data.borrow_mut()[key] = value;
284        });
285    }
286    /// 获取全局变量数据
287    fn get_global_data() -> JsonValue {
288        GLOBAL_DATA.with(|data| {
289            data.borrow().clone()
290        })
291    }
292    /// 获取全局变量指定字段数据
293    fn get_global_data_key(key: &str) -> JsonValue {
294        GLOBAL_DATA.with(|data| {
295            data.borrow()[key].clone()
296        })
297    }
298}
299/// API 错误响应
300#[derive(Debug, Clone)]
301pub struct ApiResponse {
302    pub types: ApiType,
303    pub code: i32,
304    pub message: String,
305    pub data: JsonValue,
306    pub success: bool,
307}
308impl ApiResponse {
309    pub fn json(self) -> JsonValue {
310        match self.types {
311            ApiType::Json => object! {
312                code: self.code,
313                message: self.message,
314                data: self.data,
315                success: self.success
316            },
317            ApiType::Redirect => self.data,
318            ApiType::Download => self.data,
319            ApiType::Preview => self.data,
320            ApiType::Txt => self.data,
321        }
322    }
323    pub fn swagger(&mut self) -> JsonValue {
324        let mut content = object! {};
325        content[self.types.str().as_str()] = object! {};
326        content[self.types.str().as_str()]["schema"]["type"] = if self.data.is_array() {
327            "array"
328        } else {
329            "object"
330        }.into();
331        content[self.types.str().as_str()]["schema"]["properties"] = self.data.clone();
332
333        content[self.types.str().as_str()]["schema"]["type"] = match content[self.types.str().as_str()]["schema"]["type"].as_str().unwrap() {
334            "int" => "integer".into(),
335            _ => content[self.types.str().as_str()]["schema"]["type"].clone(),
336        };
337        let data = object! {
338            "description":self.message.clone(),
339            "content":content
340        };
341        data
342    }
343    pub fn success(data: JsonValue, mut message: &str) -> Self {
344        if message.is_empty() {
345            message = "success";
346        }
347        Self {
348            success: true,
349            types: ApiType::Json,
350            code: 0,
351            message: message.to_string(),
352            data,
353        }
354    }
355    pub fn fail(code: i32, message: &str) -> Self {
356        Self {
357            types: ApiType::Json,
358            code,
359            message: message.to_string(),
360            data: JsonValue::Null,
361            success: false,
362        }
363    }
364    pub fn error(data: JsonValue, message: &str) -> Self {
365        Self {
366            types: ApiType::Json,
367            code: -1,
368            message: message.to_string(),
369            data,
370            success: false,
371        }
372    }
373    /// 重定向
374    pub fn redirect(url: &str) -> Self {
375        Self {
376            types: ApiType::Redirect,
377            code: 0,
378            message: "".to_string(),
379            data: url.into(),
380            success: true,
381        }
382    }
383    /// 下载
384    pub fn download(filename: &str) -> Self {
385        Self {
386            types: ApiType::Download,
387            code: 0,
388            message: "".to_string(),
389            data: filename.into(),
390            success: true,
391        }
392    }
393    /// 预览
394    pub fn preview(filename: &str) -> Self {
395        Self {
396            types: ApiType::Preview,
397            code: 0,
398            message: "".to_string(),
399            data: filename.into(),
400            success: true,
401        }
402    }
403    /// 文本
404    pub fn txt(txt: &str) -> Self {
405        Self {
406            types: ApiType::Txt,
407            code: 0,
408            message: "".to_string(),
409            data: txt.into(),
410            success: true,
411        }
412    }
413}
414impl Default for ApiResponse {
415    fn default() -> Self {
416        Self {
417            types: ApiType::Json,
418            code: 0,
419            message: "".to_string(),
420            data: JsonValue::Null,
421            success: false,
422        }
423    }
424}
425/// API 响应
426#[derive(Debug, Clone)]
427pub enum ApiType {
428    /// JSON类型
429    Json,
430    /// 重定向
431    /// (重定向地址: http://xxxxxx)
432    Redirect,
433    /// 下载
434    /// (文件地址: 文件绝对地址)
435    Download,
436    /// 预览
437    /// (文件地址: 文件绝对地址)
438    Preview,
439    /// TXT格式
440    Txt,
441}
442impl ApiType {
443    pub fn str(&mut self) -> String {
444        match self {
445            ApiType::Json => "application/json",
446            ApiType::Redirect | ApiType::Download | ApiType::Preview => "text/html",
447            ApiType::Txt => "text/plain",
448        }.to_string()
449    }
450}