cool_core/module/
mod.rs

1//! 模块管理(简化版)
2//!
3//! - 收集 `modules/` 目录下的模块名
4//! - 读取模块内的 `config.{ts,js}`(本实现仅占位,不执行 JS)
5//! - 提供模块列表给菜单导入使用
6
7use serde::{Deserialize, Serialize};
8use std::fs;
9use std::path::Path;
10
11/// 模块信息(扫描模块用,避免与运行时模块信息冲突)
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct LegacyModuleInfo {
14    /// 模块名
15    pub name: String,
16    /// 模块顺序,默认为 0,越大越靠前
17    pub order: i32,
18}
19
20/// 模块配置管理
21#[derive(Default)]
22pub struct ModuleManager {
23    modules: Vec<LegacyModuleInfo>,
24}
25
26impl ModuleManager {
27    pub fn new() -> Self {
28        Self {
29            modules: Vec::new(),
30        }
31    }
32
33    /// 从指定路径扫描模块(默认 `modules/`)
34    pub fn scan_modules(&mut self, base_path: &str) -> Result<(), std::io::Error> {
35        let dir = Path::new(base_path);
36        if !dir.exists() {
37            return Ok(());
38        }
39        for entry in fs::read_dir(dir)? {
40            let entry = entry?;
41            if !entry.file_type()?.is_dir() {
42                continue;
43            }
44            let name = entry.file_name().to_string_lossy().to_string();
45            // 简化:顺序为 0;如果需要可读模块内某个配置文件决定顺序
46            self.modules.push(LegacyModuleInfo { name, order: 0 });
47        }
48        // 降序排序(与 TS 保持 “order 越大越优先”)
49        self.modules.sort_by(|a, b| b.order.cmp(&a.order));
50        Ok(())
51    }
52
53    pub fn modules(&self) -> Vec<LegacyModuleInfo> {
54        self.modules.clone()
55    }
56}
57
58/// 便捷函数:使用默认路径 `modules/` 扫描
59pub fn scan_default_modules(run_path: &str) -> Result<ModuleManager, std::io::Error> {
60    let mut mm = ModuleManager::new();
61    let base = Path::new(run_path).join("modules");
62    mm.scan_modules(base.to_string_lossy().as_ref())?;
63    Ok(mm)
64}
65/// 模块管理
66///
67/// 对应 TypeScript 版本的 `module/`
68use crate::config::ModuleConfig;
69use crate::error::CoolResult;
70use parking_lot::RwLock;
71use salvo::prelude::*;
72use std::collections::HashMap;
73use std::sync::Arc;
74
75/// 模块信息
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct ModuleInfo {
78    /// 模块名称
79    pub name: String,
80    /// 模块描述
81    pub description: String,
82    /// 模块路由前缀
83    pub prefix: String,
84    /// 模块加载顺序
85    pub order: i32,
86    /// 是否启用
87    pub enabled: bool,
88}
89
90/// 模块 trait
91pub trait Module: Send + Sync {
92    /// 获取模块配置
93    fn config(&self) -> ModuleConfig;
94
95    /// 获取模块路由
96    fn router(&self) -> Router;
97
98    /// 模块初始化
99    fn init(&self) -> CoolResult<()> {
100        Ok(())
101    }
102
103    /// 模块销毁
104    fn destroy(&self) -> CoolResult<()> {
105        Ok(())
106    }
107}
108
109/// 模块注册表
110pub struct ModuleRegistry {
111    modules: RwLock<HashMap<String, Arc<dyn Module>>>,
112    order: RwLock<Vec<String>>,
113}
114
115impl ModuleRegistry {
116    pub fn new() -> Self {
117        Self {
118            modules: RwLock::new(HashMap::new()),
119            order: RwLock::new(Vec::new()),
120        }
121    }
122
123    /// 注册模块
124    pub fn register<M: Module + 'static>(&self, module: M) -> &Self {
125        let config = module.config();
126        let name = config.name.clone();
127        let order = config.order;
128
129        let mut modules = self.modules.write();
130        let mut order_list = self.order.write();
131
132        modules.insert(name.clone(), Arc::new(module));
133
134        // 按 order 排序插入
135        let pos = order_list
136            .iter()
137            .position(|n| {
138                modules
139                    .get(n)
140                    .map(|m| m.config().order < order)
141                    .unwrap_or(true)
142            })
143            .unwrap_or(order_list.len());
144
145        order_list.insert(pos, name);
146
147        self
148    }
149
150    /// 获取所有模块(按顺序)
151    pub fn get_all(&self) -> Vec<Arc<dyn Module>> {
152        let modules = self.modules.read();
153        let order = self.order.read();
154
155        order
156            .iter()
157            .filter_map(|name| modules.get(name).cloned())
158            .collect()
159    }
160
161    /// 获取指定模块
162    pub fn get(&self, name: &str) -> Option<Arc<dyn Module>> {
163        let modules = self.modules.read();
164        modules.get(name).cloned()
165    }
166
167    /// 构建所有模块的路由
168    pub fn build_router(&self, prefix: &str) -> Router {
169        let mut router = Router::with_path(prefix);
170
171        for module in self.get_all() {
172            let config = module.config();
173            router = router.push(module.router());
174            tracing::info!(
175                "模块 [{}] 已加载,路由前缀: {}",
176                config.name,
177                config.description
178            );
179        }
180
181        router
182    }
183
184    /// 初始化所有模块
185    pub fn init_all(&self) -> CoolResult<()> {
186        for module in self.get_all() {
187            module.init()?;
188        }
189        Ok(())
190    }
191
192    /// 销毁所有模块
193    pub fn destroy_all(&self) -> CoolResult<()> {
194        for module in self.get_all().into_iter().rev() {
195            module.destroy()?;
196        }
197        Ok(())
198    }
199
200    /// 获取模块信息列表
201    pub fn info_list(&self) -> Vec<ModuleInfo> {
202        self.get_all()
203            .iter()
204            .map(|m| {
205                let config = m.config();
206                ModuleInfo {
207                    name: config.name,
208                    description: config.description,
209                    prefix: String::new(),
210                    order: config.order,
211                    enabled: true,
212                }
213            })
214            .collect()
215    }
216}
217
218impl Default for ModuleRegistry {
219    fn default() -> Self {
220        Self::new()
221    }
222}
223
224/// 全局模块注册表
225static GLOBAL_MODULE_REGISTRY: once_cell::sync::Lazy<ModuleRegistry> =
226    once_cell::sync::Lazy::new(ModuleRegistry::new);
227
228/// 获取全局模块注册表
229pub fn global_module_registry() -> &'static ModuleRegistry {
230    &GLOBAL_MODULE_REGISTRY
231}
232
233/// 菜单项
234#[derive(Debug, Clone, Serialize, Deserialize)]
235pub struct MenuItem {
236    /// 菜单名称
237    pub name: String,
238    /// 菜单路径
239    pub path: Option<String>,
240    /// 菜单图标
241    pub icon: Option<String>,
242    /// 排序号
243    pub order_num: i32,
244    /// 是否显示
245    pub is_show: bool,
246    /// 子菜单
247    #[serde(default)]
248    pub children: Vec<MenuItem>,
249}
250
251/// 模块菜单配置
252#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct MenuConfig {
254    /// 菜单列表
255    pub menus: Vec<MenuItem>,
256}
257
258/// 数据库初始化配置
259#[derive(Debug, Clone, Serialize, Deserialize)]
260pub struct DbConfig {
261    /// 初始化数据
262    pub data: Vec<serde_json::Value>,
263}