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", feature = "pgsql"))]
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<(), 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 tables = HashMap::new();
109
110
111        for api_name in list.members() {
112            let api_info = api_name.as_str().unwrap_or("").split(".").collect::<Vec<&str>>();
113            let mut addon = match Self::addon(api_info[0]) {
114                Ok(e) => e,
115                Err(_) => {
116                    continue;
117                }
118            };
119            let module = match addon.module(api_info[1]) {
120                Ok(e) => e,
121                Err(_) => {
122                    continue;
123                }
124            };
125            if !module.table() {
126                continue;
127            }
128            if !tables.contains_key(module._table_name()) {
129                tables.insert(module._table_name(), module);
130            }
131        }
132
133        for (_, module) in tables.iter_mut() {
134            let mut opt = TableOptions::default();
135
136            let unique = module.table_unique().iter().map(|x| (*x).to_string()).collect::<Vec<String>>();
137            let unique = unique.iter().map(|x| x.as_str()).collect::<Vec<&str>>();
138
139            let index = module.table_index().iter().map(|x| x.iter().map(|&y| y.to_string()).collect::<Vec<String>>()).collect::<Vec<Vec<String>>>();
140            let index = index.iter().map(|x| x.iter().map(|y| y.as_str()).collect::<Vec<&str>>()).collect::<Vec<Vec<&str>>>();
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);
147            opt.set_table_index(index);
148            opt.set_table_partition(module.table_partition());
149            opt.set_table_partition_columns(module.table_partition_columns());
150
151            if Self::get_tools().db.table_is_exist(module._table_name()) {
152                let res = Self::get_tools().db.table_update(opt);
153                match res.as_i32().unwrap() {
154                    -1 => {}
155                    0 => {
156                        info!("数据库更新情况: {} 失败", module._table_name());
157                    }
158                    1 => {
159                        info!("数据库更新情况: {} 成功", module._table_name());
160                    }
161                    _ => {}
162                }
163            } else {
164                let res = Self::get_tools().db.table_create(opt);
165                info!("安装完成情况: {} {}", module._table_name(), res);
166            }
167        }
168        info!("=============数据库更新完成=============");
169        Ok(())
170    }
171    /// 生成Swagger
172    fn swagger(
173        title: &str,
174        description: &str,
175        version: &str,
176        uaturl: &str,
177        produrl: &str,
178        tags: JsonValue,
179        paths: JsonValue,
180    ) -> JsonValue {
181        let info = object! {
182            openapi:"3.0.0",
183            info:{
184                title:title,
185                description:description,
186                version:version
187            },
188            components: {
189                securitySchemes: {
190                    BearerToken: {
191                        "type": "http",
192                        "scheme": "bearer",
193                        "bearerFormat": "Token"
194                    }
195                }
196            },
197            tags:tags,
198            security: [
199                {
200                    "BearerToken": []
201                }
202            ],
203            servers:[
204                {
205                    "url":uaturl,
206                    "description": "测试地址"
207                },
208                {
209                    "url":produrl,
210                    "description": "正式地址"
211                }
212            ],
213            paths:paths
214        };
215        info
216    }
217    /// 生成 api 列表
218    fn generate_api_list(apipath: PathBuf, path: PathBuf, index: usize) -> io::Result<Vec<String>> {
219        #[cfg(debug_assertions)]
220        {
221            let mut plugin_list = Vec::new();
222            if path.is_dir() {
223                let res = fs::read_dir(path);
224                match res {
225                    Ok(entries) => {
226                        for entry in entries {
227                            let entry = entry.unwrap();
228                            let path = entry.path();
229                            if path.is_dir() {
230                                let res = Self::generate_api_list(
231                                    apipath.clone(),
232                                    path.to_str().unwrap().parse().unwrap(),
233                                    index + 1,
234                                )?;
235                                plugin_list.extend(res);
236                            } else if path.is_file() {
237                                if path.to_str().unwrap().ends_with("mod.rs") {
238                                    continue;
239                                }
240                                let addon = path.parent().unwrap().parent().unwrap().file_name().unwrap().to_str().unwrap();
241                                let model = path.parent().unwrap().file_name().unwrap().to_str().unwrap();
242                                let action = path.file_name().unwrap().to_str().unwrap().trim_end_matches(".rs");
243                                let api = format!("{addon}.{model}.{action}");
244                                match Self::api(api.as_str()) {
245                                    Ok(e) => plugin_list.push(e.api()),
246                                    Err(_) => continue
247                                }
248                            }
249                        }
250                    }
251                    Err(e) => return Err(io::Error::other(e.to_string()))
252                }
253            }
254            if index == 0 {
255                fs::create_dir_all(apipath.clone().parent().unwrap()).unwrap();
256                fs::write(apipath, JsonValue::from(plugin_list.clone()).to_string()).unwrap();
257                info!("=============API数量: {} 条=============", plugin_list.len());
258            }
259            Ok(plugin_list)
260        }
261        #[cfg(not(debug_assertions))]
262        {
263            let apis = fs::read_to_string(apipath).unwrap();
264            let apis = json::parse(&apis).unwrap();
265            let apis = apis.members().map(|x| x.as_str().unwrap().to_string()).collect::<Vec<String>>();
266            info!("=============API数量: {} 条=============", apis.len());
267            Ok(apis)
268        }
269    }
270
271    /// 设置全局变量
272    fn set_global_data(key: &str, value: JsonValue) {
273        GLOBAL_DATA.with(|data| {
274            data.borrow_mut()[key] = value;
275        });
276    }
277    /// 获取全局变量数据
278    fn get_global_data() -> JsonValue {
279        GLOBAL_DATA.with(|data| {
280            data.borrow().clone()
281        })
282    }
283    /// 获取全局变量指定字段数据
284    fn get_global_data_key(key: &str) -> JsonValue {
285        GLOBAL_DATA.with(|data| {
286            data.borrow()[key].clone()
287        })
288    }
289}
290/// API 错误响应
291#[derive(Debug, Clone)]
292pub struct ApiResponse {
293    pub types: ApiType,
294    pub code: i32,
295    pub message: String,
296    pub data: JsonValue,
297    pub success: bool,
298}
299impl ApiResponse {
300    pub fn json(self) -> JsonValue {
301        match self.types {
302            ApiType::Json => object! {
303                code: self.code,
304                message: self.message,
305                data: self.data,
306                success: self.success
307            },
308            ApiType::Redirect => self.data,
309            ApiType::Download => self.data,
310            ApiType::Preview => self.data,
311            ApiType::Txt => self.data,
312            ApiType::Html => self.data,
313        }
314    }
315    pub fn swagger(&mut self) -> JsonValue {
316        let mut content = object! {};
317        content[self.types.str().as_str()] = object! {};
318        content[self.types.str().as_str()]["schema"]["type"] = if self.data.is_array() {
319            "array"
320        } else {
321            "object"
322        }.into();
323        content[self.types.str().as_str()]["schema"]["properties"] = self.data.clone();
324
325        content[self.types.str().as_str()]["schema"]["type"] = match content[self.types.str().as_str()]["schema"]["type"].as_str().unwrap() {
326            "int" => "integer".into(),
327            _ => content[self.types.str().as_str()]["schema"]["type"].clone(),
328        };
329        let data = object! {
330            "description":self.message.clone(),
331            "content":content
332        };
333        data
334    }
335    pub fn success(data: JsonValue, mut message: &str) -> Self {
336        if message.is_empty() {
337            message = "success";
338        }
339        Self {
340            success: true,
341            types: ApiType::Json,
342            code: 0,
343            message: message.to_string(),
344            data,
345        }
346    }
347    pub fn fail(code: i32, message: &str) -> Self {
348        Self {
349            types: ApiType::Json,
350            code,
351            message: message.to_string(),
352            data: JsonValue::Null,
353            success: false,
354        }
355    }
356    pub fn error(data: JsonValue, message: &str) -> Self {
357        Self {
358            types: ApiType::Json,
359            code: -1,
360            message: message.to_string(),
361            data,
362            success: false,
363        }
364    }
365    /// 重定向
366    pub fn redirect(url: &str) -> Self {
367        Self {
368            types: ApiType::Redirect,
369            code: 0,
370            message: "".to_string(),
371            data: url.into(),
372            success: true,
373        }
374    }
375    /// 下载
376    pub fn download(filename: &str) -> Self {
377        Self {
378            types: ApiType::Download,
379            code: 0,
380            message: "".to_string(),
381            data: filename.into(),
382            success: true,
383        }
384    }
385    /// 预览
386    pub fn preview(filename: &str) -> Self {
387        Self {
388            types: ApiType::Preview,
389            code: 0,
390            message: "".to_string(),
391            data: filename.into(),
392            success: true,
393        }
394    }
395    /// 文本
396    pub fn txt(txt: &str) -> Self {
397        Self {
398            types: ApiType::Txt,
399            code: 0,
400            message: "".to_string(),
401            data: txt.into(),
402            success: true,
403        }
404    }
405    pub fn html(data: &str) -> Self {
406        Self {
407            types: ApiType::Html,
408            code: 0,
409            message: "".to_string(),
410            data: data.into(),
411            success: true,
412        }
413    }
414}
415impl Default for ApiResponse {
416    fn default() -> Self {
417        Self {
418            types: ApiType::Json,
419            code: 0,
420            message: "".to_string(),
421            data: JsonValue::Null,
422            success: false,
423        }
424    }
425}
426/// API 响应
427#[derive(Debug, Clone)]
428pub enum ApiType {
429    /// JSON类型
430    Json,
431    /// 重定向
432    /// (重定向地址: http://xxxxxx)
433    Redirect,
434    /// 下载
435    /// (文件地址: 文件绝对地址)
436    Download,
437    /// 预览
438    /// (文件地址: 文件绝对地址)
439    Preview,
440    /// TXT格式
441    Txt,
442    /// 返回网页
443    Html,
444}
445impl ApiType {
446    pub fn str(&mut self) -> String {
447        match self {
448            ApiType::Json => "application/json",
449            ApiType::Redirect | ApiType::Download | ApiType::Preview => "text/html",
450            ApiType::Txt => "text/plain",
451            ApiType::Html => "text/html",
452        }.to_string()
453    }
454}