df_plugin/
lib.rs

1use std::{env, fs};
2use std::fs::{create_dir_all, File};
3use std::io::Write;
4use std::path::{Path, PathBuf};
5use df_cache::Cache;
6use df_db::{Db, Mode, Table};
7use df_fields::Field;
8use df_kafka::Kafka;
9use json::{array, JsonValue, object};
10
11pub mod test;
12
13use lazy_static::lazy_static;
14use std::sync::Mutex;
15use std::collections::HashMap;
16use df_email::smtp::Smtp;
17use crate::test::Test;
18use crate::test::test::table::TestTestTable;
19use crate::test::test::TestTest;
20lazy_static! {
21    /// 工具集合
22    pub static ref TOOLS: Mutex<HashMap<String,Tools>> =Mutex::new(HashMap::new());
23}
24
25/// 内部插件入口
26pub fn plugins(name: &str) -> Box<dyn Plugin> {
27    match name {
28        _ => Box::new(Test {})
29    }
30}
31
32/// 内部模型入口
33pub fn models(name: &str) -> Box<dyn Model> {
34    match name {
35        _ => Box::new(TestTest {})
36    }
37}
38
39/// 内部动作入口
40pub fn actions(name: &str) -> Box<dyn Action> {
41    match name {
42        _ => Box::new(TestTestTable { model: TestTest {} })
43    }
44}
45
46/// 创建 插件
47pub fn plugin_create(path: &str, plugin: &str, plugin_title: &str, model: &str, model_title: &str, action: &str, action_title: &str) {
48    let root_path = PathBuf::from(path);
49    let plugin_path = root_path.join("plugin");
50    let plugin_path = plugin_path.join(plugin);
51    create_dir_all(plugin_path.as_os_str()).expect("创建目录失败");
52
53    let plugin_mod_path = plugin_path.join("mod.rs");
54    if !plugin_mod_path.is_file() {
55        let temp_plugin_mod_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
56        let temp_plugin_mod_path = temp_plugin_mod_path.join("temp").join("plugin");
57        let temp_plugin_mod_data = fs::read_to_string(temp_plugin_mod_path).unwrap();
58        let plugin_1 = plugin[0..=0].to_uppercase();
59        let plugin_2 = plugin[1..].to_lowercase();
60        let temp_plugin_mod_data = temp_plugin_mod_data.replace("{{plugin}}", &*format!("{}{}", plugin_1, plugin_2));
61        let temp_plugin_mod_data = temp_plugin_mod_data.replace("{{title}}", plugin_title);
62        fs::write(plugin_mod_path, temp_plugin_mod_data).expect("写入插件mod错误");
63    }
64
65    if model != "" {
66        let model_path = plugin_path.join(model);
67        create_dir_all(model_path.as_os_str()).expect("创建模型目录失败");
68
69
70        let plugin_d = {
71            let t: Vec<String> = plugin.split("_").map(|x| {
72                let x1 = x[0..=0].to_uppercase();
73                let x2 = x[1..].to_lowercase();
74                format!("{}{}", x1.clone(), x2.clone())
75            }).collect();
76            t.join("")
77        };
78        let model_d = {
79            let t: Vec<String> = model.split("_").map(|x| {
80                let x1 = x[0..=0].to_uppercase();
81                let x2 = x[1..].to_lowercase();
82                format!("{}{}", x1.clone(), x2.clone())
83            }).collect();
84            t.join("")
85        };
86
87        let model_mod_path = model_path.join("mod.rs");
88        if !model_mod_path.is_file() {
89            let temp_plugin_mod_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
90            let temp_model_mod_path = temp_plugin_mod_path.join("temp").join("model");
91            let mut temp_model_mod_data = fs::read_to_string(temp_model_mod_path).unwrap();
92            temp_model_mod_data = temp_model_mod_data.replace("{{model}}", &*format!("{}{}", plugin_d, model_d));
93            temp_model_mod_data = temp_model_mod_data.replace("{{plugin_model}}", &*format!("{}_{}", plugin, model));
94            let temp_model_mod_data = temp_model_mod_data.replace("{{title}}", model_title);
95            fs::write(model_mod_path, temp_model_mod_data).expect("写入模型mod错误");
96        }
97
98        if action != "" {
99            let action_path = model_path.join(format!("{}.rs", action));
100            if !action_path.is_file() {
101                let temp_action_mod_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
102                let temp_action_mod_path = {
103                    match action {
104                        "table" => {
105                            temp_action_mod_path.join("temp").join("action_table")
106                        }
107                        "add" => {
108                            temp_action_mod_path.join("temp").join("action_add")
109                        }
110                        "delete" => {
111                            temp_action_mod_path.join("temp").join("action_delete")
112                        }
113                        "put" => {
114                            temp_action_mod_path.join("temp").join("action_put")
115                        }
116                        "select" => {
117                            temp_action_mod_path.join("temp").join("action_select")
118                        }
119                        "get" => {
120                            temp_action_mod_path.join("temp").join("action_get")
121                        }
122                        _ => {
123                            temp_action_mod_path.join("temp").join("action")
124                        }
125                    }
126                };
127
128                let temp_action_mod_data = fs::read_to_string(temp_action_mod_path).unwrap();
129
130
131                let action_d = {
132                    let t: Vec<String> = action.split("_").map(|x| {
133                        let x1 = x[0..=0].to_uppercase();
134                        let x2 = x[1..].to_lowercase();
135                        format!("{}{}", x1.clone(), x2.clone())
136                    }).collect();
137                    t.join("")
138                };
139
140                let temp_action_mod_data = temp_action_mod_data.replace("{{action}}", &*format!("{}{}{}", plugin_d, model_d, action_d));
141                let temp_action_mod_data = temp_action_mod_data.replace("{{api}}", &*format!("{}.{}.{}", plugin, model, action));
142                let temp_action_mod_data = temp_action_mod_data.replace("{{model}}", &*format!("{}{}", plugin_d, model_d));
143                let temp_action_mod_data = temp_action_mod_data.replace("{{model_a}}", &*format!("{}", model));
144                let temp_action_mod_data = temp_action_mod_data.replace("{{plugin}}", &*format!("{}", plugin));
145                let temp_action_mod_data = temp_action_mod_data.replace("{{title}}", action_title);
146                fs::write(action_path, temp_action_mod_data).expect("写入动作文件错误");
147            }
148        }
149    }
150}
151
152
153/// 插件
154pub trait Plugin {
155    fn model(&mut self, name: &str) -> Box<dyn Model>;
156    /// 模型名称
157    fn title(&mut self) -> &'static str;
158    /// 插件描述
159    fn describe(&mut self) -> &'static str { return ""; }
160}
161
162/// 模型
163pub trait Model {
164    /// 版本号
165    fn version(&mut self) -> &'static str {
166        "0.0.1"
167    }
168    /// 数据库表名称
169    fn table(&mut self) -> &'static str;
170    /// 模型名称
171    fn title(&mut self) -> &'static str;
172    /// 模型描述
173    fn describe(&mut self) -> &'static str { return ""; }
174    /// 字段列表
175    fn fields(&mut self) -> JsonValue;
176
177    /// 数据库唯一约束
178    fn unique(&mut self) -> Vec<&'static str> {
179        return vec![];
180    }
181    /// 查询索引
182    fn index(&mut self) -> Vec<Vec<&'static str>> {
183        return vec![];
184    }
185    /// 主键
186    fn primary_key(&mut self) -> &'static str {
187        return "id";
188    }
189    /// 自动ID值
190    fn auto(&mut self) -> bool {
191        return false;
192    }
193    /// 创建安装json
194    fn json(&mut self) -> Table {
195        Table {
196            version: self.version().parse().unwrap(),
197            table: self.table().parse().unwrap(),
198            title: self.title().parse().unwrap(),
199            primary_key: self.primary_key().parse().unwrap(),
200            auto: self.auto(),
201            unique: self.unique().iter().map(|x| x.to_string()).collect(),
202            index: self.index().iter().map(|x| x.iter().map(|y| y.to_string()).collect()).collect(),
203            fields: self.fields(),
204        }
205    }
206    /// 创建安装文件
207    fn create_json_file(&mut self, path: &str) -> bool {
208        let json = self.json();
209        let o = Path::new(path);
210        if !o.is_dir() {
211            fs::create_dir(path).unwrap();
212        }
213        env::set_current_dir(path).unwrap();
214        let dir = env::current_dir().unwrap();
215        let version = self.version();
216        let version = version.replace(".", "_");
217        let dir = dir.join(format!("{}_{}.json", self.table(), version));
218        let mut f = File::create(dir.to_str().unwrap()).unwrap();
219        match f.write_all(json.to_string().as_bytes()) {
220            Ok(_) => true,
221            Err(_) => false
222        }
223    }
224    /// 模型动作
225    fn action(&mut self, name: &str) -> Box<dyn Action>;
226    /// 前端搜索字段
227    fn table_fields(&mut self) -> JsonValue {
228        let mut params = object! {};
229        params["load"] = df_fields::select::Radio::new(false, "load", "加载内容", vec!["col", "data"], "data").field();
230        params["page"] = df_fields::int::Int::new(false, "page", "页数", 15, 1).field();
231        params["limit"] = df_fields::int::Int::new(false, "limit", "记录数", 10, 25).field();
232        params["where"] = df_fields::text::Json::new(false, "where", "条件", object! {}).field();
233        params["filter"] = df_fields::text::Text::new(false, "filter", "模糊搜索", "").field();
234        params["order"] = df_fields::text::Json::new(false, "order", "排序", array![]).field();
235        return params;
236    }
237
238    fn tools(&mut self) -> Tools {
239        let db = TOOLS.lock().unwrap();
240        let db = db.get("tools").unwrap().clone();
241        db
242    }
243    /// 前端-数据表
244    fn tables(&mut self, header: JsonValue, request: JsonValue, fields: Vec<&str>, query_fields: Vec<&str>, filter_fields: Vec<&str>) -> JsonValue {
245        let load = request["load"].as_str().unwrap();
246        let page = request["page"].as_i32().unwrap();
247        let limit = request["limit"].as_i32().unwrap();
248        let wheres = request["where"].clone();
249        let filter = request["filter"].to_string();
250        let order = request["order"].clone();
251        let columns = self.columns(fields.clone());
252        // 查询到的数据
253        let mut data = {
254            let mut db = self.tools().db;
255            let db = db.table(self.table());
256            // 整合搜索字段
257            if filter_fields.len() > 0 && filter != "" {
258                db.where_or(filter_fields.join("|").as_str(), "like", format!("%{}%", filter).into());
259            }
260            if fields.len() > 0 {
261                db.field(fields.join(",").as_str().clone());
262            }
263            for item in wheres.members() {
264                db.where_and(item[0].as_str().unwrap(), item[1].as_str().unwrap(), item[2].clone());
265            }
266            if order.len() > 0 {
267                db.order(order[0].as_str().unwrap(), order[1].as_bool().unwrap());
268            }
269            db.page(page.clone(), limit.clone()).select()
270        };
271
272        // 总记录数
273        let total = {
274            let mut db = self.tools().db;
275            let db = db.table(self.table());
276            if filter_fields.len() > 0 && filter != "" {
277                db.where_or(filter_fields.join("|").as_str(), "like", format!("%{}%", filter).into());
278            }
279            for item in wheres.members() {
280                db.where_and(item[0].as_str().unwrap(), item[1].as_str().unwrap(), item[2].clone());
281            }
282            db.count().as_i32().unwrap()
283        };
284
285
286        let mut fields_table = false;
287        let mut fields_list = object! {};
288        for field in columns.members() {
289            fields_list[field["field"].as_str().unwrap()] = field.clone();
290            match field["mode"].as_str().unwrap() {
291                "table" | "file" => {
292                    fields_table = true;
293                }
294                _ => {}
295            }
296        }
297        if fields_table {
298            let mut fields_table_ids = object! {};
299            for item in data.members_mut() {
300                for (key, field) in fields_list.entries() {
301                    match field["mode"].as_str().unwrap() {
302                        "table" => {
303                            let id = item[key].clone();
304                            if id.is_empty() {
305                                continue;
306                            }
307                            if fields_table_ids[id.as_str().unwrap()].is_null() {
308                                let table = field["table"].as_str().unwrap();
309                                let field: Vec<&str> = field["fields"].members().map(|x| x.as_str().unwrap()).collect();
310                                let find = self.tools().db.table(table)
311                                    .where_and("id", "=", id.clone())
312                                    .field(format!("id,{}", field.join(",")).as_str().clone())
313                                    .find();
314                                let mut row = object! {};
315                                if !find.is_empty() {
316                                    row["id"] = find["id"].clone();
317                                    for field in field.iter() {
318                                        if row["value"].is_null() {
319                                            row["value"] = format!("{}", find[field.clone()]).into();
320                                        } else {
321                                            row["value"] = format!("{} | {}", row["value"], find[field.clone()]).into();
322                                        }
323                                    }
324                                    fields_table_ids[id.as_str().unwrap()] = row;
325                                } else {
326                                    fields_table_ids[id.as_str().unwrap()] = object! {};
327                                }
328                            }
329                            item[key] = fields_table_ids[id.as_str().unwrap()].clone();
330                        }
331                        "file" => {
332                            let id = item[key].clone();
333                            if id.is_empty() {
334                                item[key] = array![];
335                                continue;
336                            }
337                            let mut files = self.tools().db.table("file_file")
338                                .where_and("id", "in", id.clone())
339                                .select();
340
341                            let domain = header["domain"].clone();
342                            for file in files.members_mut() {
343                                file["url"] = format!("{}/file/{}/{}.{}", domain.clone(), file["mode"], file["id"], file["mode"]).into();
344                            }
345                            item[key] = files;
346                        }
347                        _ => {}
348                    }
349                }
350            }
351        }
352
353        let mut table = object! {};
354        table["total_page"] = JsonValue::from((total as f64 / limit as f64).ceil() as i64);
355        table["total_data"] = total.into();
356        table["data"] = data.clone();
357        match load {
358            "col" => {
359                table["col"] = columns.clone();
360                table["query_fields"] = self.query_fields(query_fields.clone());
361                table["filter_title"] = self.filter_title(filter_fields.clone()).into();
362            }
363            _ => {}
364        }
365        table
366    }
367
368    /// 前端-列数据
369    fn columns(&mut self, fields: Vec<&str>) -> JsonValue {
370        let columns = self.fields();
371        let mut data = array![];
372        for (key, field) in columns.entries() {
373            if fields.contains(&key) || fields.len() == 0 {
374                let mut row = field.clone();
375                row["name"] = field["field"].clone();
376                row["label"] = field["title"].clone();
377                row["align"] = "center".into();
378                row["sortable"] = match field["mode"].as_str().unwrap() {
379                    "int" | "float" => {
380                        true.into()
381                    }
382                    _ => {
383                        false.into()
384                    }
385                };
386                data.push(row.clone()).unwrap();
387            }
388        }
389        data
390    }
391    /// 前端-高级查询条件字段
392    fn query_fields(&mut self, fields: Vec<&str>) -> JsonValue {
393        let columns = self.fields();
394        let mut data = array![];
395        for (key, field) in columns.entries() {
396            if fields.contains(&key) {
397                let mut row = field.clone();
398                row["require"] = JsonValue::from(false);
399                data.push(row.clone()).unwrap();
400            }
401        }
402        data
403    }
404    /// 前端-模糊查询标题
405    fn filter_title(&mut self, fields: Vec<&str>) -> String {
406        let columns = self.fields();
407        let mut data = vec![];
408        for (key, field) in columns.entries() {
409            if fields.contains(&key) {
410                data.push(field["title"].as_str().unwrap());
411            }
412        }
413        format!("搜索 {}", data.join(" "))
414    }
415
416    /// 前端-按钮数据
417    fn btn_data(&mut self, title: &str, mut action: Box<dyn Action>, mode: BtnMode, color: BtnColor, match_condition: Vec<Vec<&str>>) -> JsonValue {
418        let mut btn = object! {};
419        if title.is_empty() {
420            btn["title"] = action.title().into();
421        } else {
422            btn["title"] = title.into();
423        }
424        btn["api"] = action.name().into();
425        let mut params = array![];
426        for (_, item) in action.params().entries() {
427            params.push(item.clone()).unwrap();
428        }
429        btn["params"] = JsonValue::from(params);
430        btn["color"] = JsonValue::from(color.from());
431        btn["mode"] = JsonValue::from(mode.from());
432        btn["match_condition"] = match_condition.into();
433        return btn;
434    }
435
436
437    /// 前端-按钮-指定页面
438    fn btn_path_data(&mut self, title: &str, path: &str, color: BtnColor, match_condition: Vec<Vec<&str>>) -> JsonValue {
439        let mut btn = object! {};
440        btn["title"] = title.into();
441        btn["path"] = JsonValue::from(path);
442        btn["color"] = JsonValue::from(color.from());
443        btn["mode"] = JsonValue::from("path");
444        btn["match_condition"] = match_condition.into();
445        return btn;
446    }
447
448    /// 前端 关联搜索字段
449    fn table_select_fields(&mut self) -> JsonValue {
450        let mut fields = object! {};
451        fields[self.primary_key()] = df_fields::str::Key::new(true, self.primary_key(), "ID", 20).field();
452        fields["filter"] = df_fields::text::Text::new(true, "filter", "模糊搜索", "").field();
453        return fields;
454    }
455    /// 前端-select
456    fn table_select(&mut self, request: JsonValue, fields: Vec<&str>, filter: Vec<Vec<&str>>) -> JsonValue {
457        let id = request["id"].as_str().unwrap();
458        let wheres = request["filter"].as_str().unwrap();
459
460        let mut db = self.tools().db;
461        let db = db.table(self.table());
462
463        db.field(format!("id,{}", fields.join(",")).as_str().clone());
464
465        for item in filter.iter() {
466            db.where_and(item[0], item[1], item[2].into());
467        }
468        if wheres != "" {
469            if id != "" {
470                db.where_or("id", "=", id.into());
471            }
472            db.where_or(fields.join("|").as_str(), "like", format!("%{}%", wheres).into());
473        } else {
474            if id != "" {
475                db.where_or("id", "=", id.into()).where_or("id", "!=", id.into());
476            }
477        }
478
479        let data = db.select();
480        let mut list = array![];
481        for item in data.members() {
482            let mut row = object! {};
483            row["id"] = item["id"].clone();
484            for field in fields.iter() {
485                if row["value"].is_null() {
486                    row["value"] = format!("{}", item[field.clone()]).into();
487                } else {
488                    row["value"] = format!("{} | {}", row["value"], item[field.clone()]).into();
489                }
490            }
491            list.push(row).unwrap();
492        }
493        list
494    }
495}
496
497/// 按钮颜色
498pub enum BtnColor {
499    Red,
500    Blue,
501    Yellow,
502}
503
504impl BtnColor {
505    fn from(self) -> &'static str {
506        match self {
507            BtnColor::Red => "red",
508            BtnColor::Blue => "blue",
509            BtnColor::Yellow => "yellow",
510        }
511    }
512}
513
514/// 按钮模式
515pub enum BtnMode {
516    Form,
517    Url,
518    Api,
519    Download,
520    Path,
521}
522
523impl BtnMode {
524    fn from(self) -> &'static str {
525        match self {
526            BtnMode::Form => "form",
527            BtnMode::Url => "url",
528            BtnMode::Api => "api",
529            BtnMode::Download => "download",
530            BtnMode::Path => "path",
531        }
532    }
533}
534
535/// 动作
536pub trait Action {
537    /// 标题
538    fn title(&mut self) -> &'static str;
539    /// api名称
540    fn name(&mut self) -> &'static str;
541    /// 是否使用密钥
542    fn token(&mut self) -> bool { true }
543    /// API描述
544    fn describe(&mut self) -> &'static str { return ""; }
545    /// 是否公开
546    fn public(&mut self) -> bool { true }
547    /// 接口类型 btn menu
548    fn interface_type(&mut self) -> &'static str {
549        ""
550    }
551    /// 依赖接口
552    fn dependent(&mut self) -> Vec<&'static str> {
553        return vec![];
554    }
555    /// 请求参数入口
556    fn params(&mut self) -> JsonValue { object! {} }
557    /// 检测
558    fn _check(&mut self, mut request: JsonValue) -> (bool, String, JsonValue) {
559        let params = self.params();
560        let mut new_request = object! {};
561        for (key, field) in params.entries() {
562            if request[key].is_null() && field["require"].as_bool().unwrap() {
563                return (false, format!("缺少参数 {}:{}", key, field["title"]), request);
564            }
565            if request[key].is_empty() && field["require"].as_bool().unwrap() {
566                request[key] = field["def"].clone().into();
567            }
568            if request[key].is_null() && !field["require"].as_bool().unwrap() {
569                request[key] = field["def"].clone().into();
570            }
571            if request[key] == JsonValue::from("null") {
572                request[key] = field["def"].clone().into();
573            }
574            new_request[key] = request[key].clone();
575        }
576        return (true, "验证通过".to_string(), new_request);
577    }
578    /// 执行参数入口
579    fn run(&mut self, header: JsonValue, request: JsonValue) -> Response {
580        let (state, msg, request) = self._check(request.clone());
581        if !state {
582            return self.fail(&*msg);
583        }
584        return self.index(header.clone(), request.clone());
585    }
586    fn index(&mut self, header: JsonValue, request: JsonValue) -> Response;
587    fn success(&mut self, data: JsonValue, msg: &str) -> Response {
588        Response::success(data, msg)
589    }
590    fn fail(&mut self, msg: &str) -> Response {
591        Response::fail(msg)
592    }
593    fn login(&mut self, msg: &str) -> Response {
594        Response::login(msg)
595    }
596    fn download(&mut self, filename: &str) -> Response {
597        Response::download(filename)
598    }
599    fn redirect(&mut self, url: &str) -> Response {
600        Response::redirect(url)
601    }
602    /// 获取工具集合
603    fn tools(&mut self) -> Tools {
604        TOOLS.lock().unwrap().get("tools").unwrap().clone()
605    }
606}
607
608/// 集合工具
609#[derive(Clone)]
610pub struct Tools {
611    pub db: Db,
612    pub cache: Cache,
613    pub kafka: Kafka,
614    pub email: Smtp,
615}
616
617#[derive(Clone, Debug)]
618pub struct Response(i32, &'static str, JsonValue);
619
620impl Response {
621    pub fn into(self) -> (i32, &'static str, JsonValue) {
622        return (self.0, self.1, self.2);
623    }
624    /// 成功
625    pub fn success(data: JsonValue, msg: &str) -> Self {
626        let data = object! {code: 0,data:data,msg: msg.to_string()};
627        Self(200, "json", data)
628    }
629    /// 失败
630    pub fn fail(msg: &str) -> Self {
631        let data = object! {
632            code: -1,
633            msg: msg.to_string()
634        };
635        Self(200, "json", data)
636    }
637    /// 登陆
638    pub fn login(msg: &str) -> Self {
639        let data = object! {code: 1000,msg: msg.to_string(),};
640        Self(200, "json", data)
641    }
642    /// 下载
643    pub fn download(filename: &str) -> Self {
644        Self(200, "download", filename.into())
645    }
646    /// 重定向
647    pub fn redirect(url: &str) -> Self {
648        Self(301, "url", url.into())
649    }
650}
651
652pub struct ApiModel {}
653
654impl ApiModel {
655    pub fn run(args_new: Vec<String>) -> (bool, String, String, String, String, JsonValue) {
656        let mut args: Vec<String> = env::args().collect();
657        if args_new.len() > 0 {
658            args = args_new.clone();
659        }
660        if args.len() <= 1 {
661            return (false, "参数错误".to_string(), "".to_string(), "".to_string(), "".to_string(), object! {});
662        }
663        let mode = args[1].as_str();
664        let api = args[2].as_str();
665        if api.is_empty() {
666            return (false, "无API参数".to_string(), "".to_string(), "".to_string(), "".to_string(), object! {});
667        }
668        let api: Vec<&str> = api.split(".").collect();
669        if api.len() != 3 {
670            return (false, "API参数错误".to_string(), "".to_string(), "".to_string(), "".to_string(), object! {});
671        }
672        let data = args[3].as_str();
673        if data.is_empty() {
674            return (false, "请求参数无效".to_string(), "".to_string(), "".to_string(), "".to_string(), object! {});
675        }
676        let data = json::parse(data).unwrap();
677        return (true, mode.to_string(), api[0].to_string(), api[1].to_string(), api[2].to_string(), data);
678    }
679    pub fn fail(msg: &str) -> JsonValue {
680        let data = object! {code:-1,msg:msg};
681        return data;
682    }
683}
684
685