1use serde::{Deserialize, Serialize};
8use std::fs;
9use std::path::Path;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct LegacyModuleInfo {
14 pub name: String,
16 pub order: i32,
18}
19
20#[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 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 self.modules.push(LegacyModuleInfo { name, order: 0 });
47 }
48 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
58pub 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}
65use crate::config::ModuleConfig;
69use crate::error::CoolResult;
70use parking_lot::RwLock;
71use salvo::prelude::*;
72use std::collections::HashMap;
73use std::sync::Arc;
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct ModuleInfo {
78 pub name: String,
80 pub description: String,
82 pub prefix: String,
84 pub order: i32,
86 pub enabled: bool,
88}
89
90pub trait Module: Send + Sync {
92 fn config(&self) -> ModuleConfig;
94
95 fn router(&self) -> Router;
97
98 fn init(&self) -> CoolResult<()> {
100 Ok(())
101 }
102
103 fn destroy(&self) -> CoolResult<()> {
105 Ok(())
106 }
107}
108
109pub 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 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 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 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 pub fn get(&self, name: &str) -> Option<Arc<dyn Module>> {
163 let modules = self.modules.read();
164 modules.get(name).cloned()
165 }
166
167 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 pub fn init_all(&self) -> CoolResult<()> {
186 for module in self.get_all() {
187 module.init()?;
188 }
189 Ok(())
190 }
191
192 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 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
224static GLOBAL_MODULE_REGISTRY: once_cell::sync::Lazy<ModuleRegistry> =
226 once_cell::sync::Lazy::new(ModuleRegistry::new);
227
228pub fn global_module_registry() -> &'static ModuleRegistry {
230 &GLOBAL_MODULE_REGISTRY
231}
232
233#[derive(Debug, Clone, Serialize, Deserialize)]
235pub struct MenuItem {
236 pub name: String,
238 pub path: Option<String>,
240 pub icon: Option<String>,
242 pub order_num: i32,
244 pub is_show: bool,
246 #[serde(default)]
248 pub children: Vec<MenuItem>,
249}
250
251#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct MenuConfig {
254 pub menus: Vec<MenuItem>,
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize)]
260pub struct DbConfig {
261 pub data: Vec<serde_json::Value>,
263}