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