use serde::{Deserialize, Serialize};
use std::fs;
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LegacyModuleInfo {
pub name: String,
pub order: i32,
}
#[derive(Default)]
pub struct ModuleManager {
modules: Vec<LegacyModuleInfo>,
}
impl ModuleManager {
pub fn new() -> Self {
Self {
modules: Vec::new(),
}
}
pub fn scan_modules(&mut self, base_path: &str) -> Result<(), std::io::Error> {
let dir = Path::new(base_path);
if !dir.exists() {
return Ok(());
}
for entry in fs::read_dir(dir)? {
let entry = entry?;
if !entry.file_type()?.is_dir() {
continue;
}
let name = entry.file_name().to_string_lossy().to_string();
self.modules.push(LegacyModuleInfo { name, order: 0 });
}
self.modules.sort_by(|a, b| b.order.cmp(&a.order));
Ok(())
}
pub fn modules(&self) -> Vec<LegacyModuleInfo> {
self.modules.clone()
}
}
pub fn scan_default_modules(run_path: &str) -> Result<ModuleManager, std::io::Error> {
let mut mm = ModuleManager::new();
let base = Path::new(run_path).join("modules");
mm.scan_modules(base.to_string_lossy().as_ref())?;
Ok(mm)
}
use crate::config::ModuleConfig;
use crate::error::CoolResult;
use parking_lot::RwLock;
use salvo::prelude::*;
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModuleInfo {
pub name: String,
pub description: String,
pub prefix: String,
pub order: i32,
pub enabled: bool,
}
pub trait Module: Send + Sync {
fn config(&self) -> ModuleConfig;
fn router(&self) -> Router;
fn init(&self) -> CoolResult<()> {
Ok(())
}
fn destroy(&self) -> CoolResult<()> {
Ok(())
}
}
pub struct ModuleRegistry {
modules: RwLock<HashMap<String, Arc<dyn Module>>>,
order: RwLock<Vec<String>>,
}
impl ModuleRegistry {
pub fn new() -> Self {
Self {
modules: RwLock::new(HashMap::new()),
order: RwLock::new(Vec::new()),
}
}
pub fn register<M: Module + 'static>(&self, module: M) -> &Self {
let config = module.config();
let name = config.name.clone();
let order = config.order;
let mut modules = self.modules.write();
let mut order_list = self.order.write();
modules.insert(name.clone(), Arc::new(module));
let pos = order_list
.iter()
.position(|n| {
modules
.get(n)
.map(|m| m.config().order < order)
.unwrap_or(true)
})
.unwrap_or(order_list.len());
order_list.insert(pos, name);
self
}
pub fn get_all(&self) -> Vec<Arc<dyn Module>> {
let modules = self.modules.read();
let order = self.order.read();
order
.iter()
.filter_map(|name| modules.get(name).cloned())
.collect()
}
pub fn get(&self, name: &str) -> Option<Arc<dyn Module>> {
let modules = self.modules.read();
modules.get(name).cloned()
}
pub fn build_router(&self, prefix: &str) -> Router {
let mut router = Router::with_path(prefix);
for module in self.get_all() {
let config = module.config();
router = router.push(module.router());
tracing::info!(
"模块 [{}] 已加载,路由前缀: {}",
config.name,
config.description
);
}
router
}
pub fn init_all(&self) -> CoolResult<()> {
for module in self.get_all() {
module.init()?;
}
Ok(())
}
pub fn destroy_all(&self) -> CoolResult<()> {
for module in self.get_all().into_iter().rev() {
module.destroy()?;
}
Ok(())
}
pub fn info_list(&self) -> Vec<ModuleInfo> {
self.get_all()
.iter()
.map(|m| {
let config = m.config();
ModuleInfo {
name: config.name,
description: config.description,
prefix: String::new(),
order: config.order,
enabled: true,
}
})
.collect()
}
}
impl Default for ModuleRegistry {
fn default() -> Self {
Self::new()
}
}
static GLOBAL_MODULE_REGISTRY: once_cell::sync::Lazy<ModuleRegistry> =
once_cell::sync::Lazy::new(ModuleRegistry::new);
pub fn global_module_registry() -> &'static ModuleRegistry {
&GLOBAL_MODULE_REGISTRY
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MenuItem {
pub name: String,
pub path: Option<String>,
pub icon: Option<String>,
pub order_num: i32,
pub is_show: bool,
#[serde(default)]
pub children: Vec<MenuItem>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MenuConfig {
pub menus: Vec<MenuItem>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DbConfig {
pub data: Vec<serde_json::Value>,
}