br-addon 0.2.20

This is an addon
Documentation
use crate::module::Module;
use crate::Tools;
use crate::PLUGIN_TOOLS;
use std::any::type_name;
use std::fs;
use std::fs::create_dir_all;
use std::path::PathBuf;

#[must_use]
pub fn to_pascal_case(s: &str) -> String {
    s.split('_')
        .filter(|part| !part.is_empty())
        .map(|part| {
            let mut chars = part.chars();
            match chars.next() {
                Some(first) => first
                    .to_uppercase()
                    .chain(chars.flat_map(|c| c.to_lowercase()))
                    .collect(),
                None => String::new(),
            }
        })
        .collect()
}

/// 插件接口
pub trait Addon: Send + Sync + 'static {
    /// 插件名称
    /// NOTE: 使用 Box::leak 返回 'static str,每个类型只会泄漏一次
    fn name(&self) -> &'static str {
        let name = type_name::<Self>()
            .split("::")
            .last()
            .unwrap_or_default()
            .to_lowercase();
        Box::leak(name.into_boxed_str())
    }
    /// 插件标题
    fn title(&self) -> &'static str;
    /// 插件图标
    fn icon(&self) -> &'static str {
        ""
    }
    /// 功能描述
    fn description(&self) -> &'static str {
        ""
    }
    /// 前端指定页面
    fn pages(&self) -> &'static str {
        ""
    }
    /// 插件排序
    fn sort(&self) -> usize {
        99
    }
    /// 插件分类
    fn category(&self) -> &'static str {
        ""
    }
    /// 模型分流
    fn module(&mut self, name: &str) -> Result<Box<dyn Module>, String>;
    /// 使用工具
    fn tools(&mut self) -> Tools {
        PLUGIN_TOOLS.get().expect("tools not initialized").clone()
    }
    /// 监听
    fn handle(&mut self) {}
}

pub fn addon_create(
    path: &str,
    plugin: &str,
    plugin_title: &str,
    model: &str,
    model_title: &str,
    action: &str,
    action_title: &str,
) {
    let root_path = PathBuf::from(path);
    let plugin_path = root_path.join("plugin");
    let plugin_path = plugin_path.join(plugin);
    create_dir_all(plugin_path.as_os_str()).expect("创建目录失败");

    let plugin_mod_path = plugin_path.join("mod.rs");
    if !plugin_mod_path.is_file() {
        let temp_plugin_mod_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        let temp_plugin_mod_path = temp_plugin_mod_path.join("temp").join("plugin");
        let temp_plugin_mod_data =
            fs::read_to_string(temp_plugin_mod_path).expect("读取插件模板失败");
        let addon_1 = plugin.to_lowercase();
        let plugin_1 = plugin[0..=0].to_uppercase();
        let plugin_2 = plugin[1..].to_lowercase();
        let temp_plugin_mod_data = temp_plugin_mod_data.replace("{{addon}}", &addon_1.to_string());
        let temp_plugin_mod_data =
            temp_plugin_mod_data.replace("{{plugin}}", &format!("{plugin_1}{plugin_2}"));
        let temp_plugin_mod_data = temp_plugin_mod_data.replace("{{title}}", plugin_title);
        fs::write(plugin_mod_path, temp_plugin_mod_data).expect("写入插件mod错误");
    }

    if !model.is_empty() {
        let model_path = plugin_path.join(model);
        create_dir_all(model_path.as_os_str()).expect("创建模型目录失败");

        let plugin_d = to_pascal_case(plugin);
        let model_d = to_pascal_case(model);

        let model_mod_path = model_path.join("mod.rs");
        if !model_mod_path.is_file() {
            let temp_plugin_mod_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            let temp_model_mod_path = temp_plugin_mod_path.join("temp").join("model");
            let mut temp_model_mod_data =
                fs::read_to_string(temp_model_mod_path).expect("读取模型模板失败");
            temp_model_mod_data = temp_model_mod_data.replace("{{addon}}", &plugin_d.to_string());
            temp_model_mod_data =
                temp_model_mod_data.replace("{{model}}", &format!("{plugin_d}{model_d}"));
            temp_model_mod_data =
                temp_model_mod_data.replace("{{addon::model}}", &format!("{plugin}::{model}"));
            temp_model_mod_data =
                temp_model_mod_data.replace("{{plugin_model}}", &format!("{plugin}_{model}"));
            temp_model_mod_data = temp_model_mod_data.replace("{{model_name}}", model);
            let temp_model_mod_data = temp_model_mod_data.replace("{{title}}", model_title);
            fs::write(model_mod_path, temp_model_mod_data).expect("写入模型mod错误");
        }

        if !action.is_empty() {
            let action_path = model_path.join(format!("{action}.rs"));
            if !action_path.is_file() {
                let temp_action_mod_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
                let temp_action_mod_path = {
                    if action.contains("table") {
                        temp_action_mod_path.join("temp").join("action_table")
                    } else if action.contains("add") {
                        temp_action_mod_path.join("temp").join("action_add")
                    } else if action.contains("del") {
                        temp_action_mod_path.join("temp").join("action_del")
                    } else if action.contains("put") {
                        temp_action_mod_path.join("temp").join("action_put")
                    } else if action.contains("select_tree") {
                        temp_action_mod_path.join("temp").join("action_select_tree")
                    } else if action.contains("select") {
                        temp_action_mod_path.join("temp").join("action_select")
                    } else if action.contains("get") {
                        temp_action_mod_path.join("temp").join("action_get")
                    } else if action.contains("menu") {
                        temp_action_mod_path.join("temp").join("action_menu")
                    } else if action.contains("down") {
                        temp_action_mod_path.join("temp").join("action_down")
                    } else if action.contains("tree") {
                        temp_action_mod_path.join("temp").join("action_tree")
                    } else if action.contains("import") {
                        temp_action_mod_path.join("temp").join("action_import")
                    } else {
                        temp_action_mod_path.join("temp").join("action")
                    }
                };

                let temp_action_mod_data =
                    fs::read_to_string(temp_action_mod_path).expect("读取动作模板失败");

                let action_d = to_pascal_case(action);

                let temp_action_mod_data = temp_action_mod_data
                    .replace("{{action}}", &format!("{plugin_d}{model_d}{action_d}"));
                let temp_action_mod_data =
                    temp_action_mod_data.replace("{{api}}", &format!("{plugin}.{model}.{action}"));
                let temp_action_mod_data =
                    temp_action_mod_data.replace("{{model}}", &format!("{plugin_d}{model_d}"));
                let temp_action_mod_data =
                    temp_action_mod_data.replace("{{addon::model}}", &format!("{plugin}::{model}"));
                let temp_action_mod_data = temp_action_mod_data.replace("{{model_a}}", model);
                let temp_action_mod_data = temp_action_mod_data.replace("{{plugin}}", plugin);
                let temp_action_mod_data = temp_action_mod_data.replace("{{title}}", action_title);
                fs::write(action_path, temp_action_mod_data).expect("写入动作文件错误");
            }
        }
    }
}