#![allow(unsafe_code)]
#![allow(clippy::non_send_fields_in_send_ty)]
#![allow(improper_ctypes_definitions)]
use secra_plugins::{
manager::{PluginManager, PluginManagerConfig},
};
use std::path::Path;
use std::sync::{Arc};
use actix_web::{post, App, HttpResponse, HttpServer, Responder};
use tokio::signal;
use secra_logger::{init_logger, LoggerConfig, LogOutput};
use tracing::Level;
fn detect_target_triple() -> String {
let arch = std::env::consts::ARCH;
let os = std::env::consts::OS;
match (arch, os) {
("aarch64", "macos") => "aarch64-apple-darwin".to_string(),
("x86_64", "macos") => "x86_64-apple-darwin".to_string(),
("aarch64", "linux") => "aarch64-unknown-linux-musl".to_string(),
("x86_64", "linux") => "x86_64-unknown-linux-musl".to_string(),
("x86_64", "windows") => "x86_64-pc-windows-gnu".to_string(),
_ => {
if let Ok(target) = std::env::var("TARGET") {
target
} else {
format!("{}-unknown-{}", arch, os)
}
}
}
}
#[post("/echo")]
async fn echo(req_body: String) -> impl Responder {
HttpResponse::Ok().body(req_body)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let log_level = std::env::var("RUST_LOG")
.ok()
.and_then(|s| {
match s.to_lowercase().as_str() {
"trace" => Some(Level::TRACE),
"debug" => Some(Level::DEBUG),
"info" => Some(Level::INFO),
"warn" => Some(Level::WARN),
"error" => Some(Level::ERROR),
_ => None,
}
})
.unwrap_or(Level::INFO);
let config = LoggerConfig::new(
log_level, LogOutput::File, "./logs/app.log", 100 * 1024 * 1024, Some(7), "secra-plugins", );
init_logger(config)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("初始化日志失败: {}", e)))?;
println!("=== 插件系统示例 ===");
let library_path = detect_target_triple();
println!("检测到系统架构: {}", library_path);
let config = PluginManagerConfig::builder()
.library_path(library_path) .plugin_dir("/Users/xiaowenli/lowcode/Secra/code/secra-plugins/plugins".to_string()) .temp_dir("/Users/xiaowenli/lowcode/Secra/code/secra-plugins/temp".to_string()) .timeout_secs(30) .enable_plugin_dir_watch(true) .ed25519_public_key("/Users/xiaowenli/lowcode/Secra/code/secra-plugins/keys/ed25519_public_key.pem".to_string()) .rsa_private_key("/Users/xiaowenli/lowcode/Secra/code/secra-plugins/keys/rsa_private_key.pem".to_string()) .build()
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("配置构建失败: {}", e)))?;
let manager = Arc::new(PluginManager::new(config).await
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("创建插件管理器失败: {}", e)))?);
let plugin_dir = manager.plugin_dir.clone();
if !Path::new(&plugin_dir).exists() {
println!("创建插件目录: {}", plugin_dir);
tokio::fs::create_dir_all(&plugin_dir).await?;
}
println!("\n--- 步骤 1: 加载插件 ---");
match manager.load_all_plugins().await {
Ok(_) => {
println!("插件加载完成");
match manager.get_all_plugins().await {
Ok(plugins) => {
println!("实际加载的插件数量: {}", plugins.len());
if plugins.is_empty() {
println!("警告: 没有插件被成功加载,可能加载过程中出现了错误");
println!("请检查日志输出以获取更多信息");
}
}
Err(e) => {
eprintln!("查询插件失败: {}", e);
}
}
}
Err(e) => {
eprintln!("插件加载失败: {}", e);
println!("提示: 如果这是第一次运行,请确保插件目录中有插件包");
return Ok(());
}
}
println!("\n--- 步骤 2: 初始化插件 ---");
match manager.initialize_all_plugins().await {
Ok(_) => {
println!("插件初始化完成");
}
Err(e) => {
eprintln!("插件初始化失败: {}", e);
}
}
println!("\n--- 步骤 3: 启动插件 ---");
match manager.start_all_plugins().await {
Ok(_) => {
println!("插件启动完成");
}
Err(e) => {
eprintln!("插件启动失败: {}", e);
}
}
let (restart_tx, mut restart_rx) = tokio::sync::mpsc::channel::<()>(1);
let restart_tx_clone = restart_tx.clone();
if let Some(watch_rx) = manager.watch_rx.clone() {
let manager_clone = manager.clone();
tokio::task::spawn_blocking(move || {
let handle = tokio::runtime::Handle::current();
loop {
match watch_rx.lock().unwrap().recv() {
Ok(event) => {
println!("event: {:?}", event);
println!("检测到文件变化,准备重启服务...");
if let Err(e) = handle.block_on(manager_clone.reload_plugin_directory()) {
eprintln!("重新加载插件目录失败: {}", e);
} else {
if let Err(e) = handle.block_on(manager_clone.initialize_all_plugins()) {
eprintln!("初始化插件失败: {}", e);
} else {
if let Err(e) = handle.block_on(manager_clone.start_all_plugins()) {
eprintln!("启动插件失败: {}", e);
} else {
println!("插件重新加载、初始化和启动完成");
}
}
}
let _ = restart_tx_clone.try_send(());
}
Err(std::sync::mpsc::RecvError) => {
println!("文件监听器已关闭");
break;
}
}
}
});
}
loop {
let manager_clone = manager.clone();
let server = HttpServer::new(move || {
let manager = manager_clone.clone();
App::new()
.service(echo)
.configure(move |cfg|{
if let Err(e) = manager.register_all_plugin_routes_sync(cfg) {
eprintln!("注册插件路由失败: {}", e);
}
})
})
.bind(("127.0.0.1", 8080))?
.run();
let handle = server.handle();
println!("服务已启动,监听在 http://127.0.0.1:8080");
let mut server_task_handle = tokio::spawn(async move {
server.await
});
tokio::select! {
result = &mut server_task_handle => {
match result {
Ok(Ok(())) => {
println!("服务器正常停止");
return Ok(());
}
Ok(Err(e)) => {
eprintln!("服务器运行错误: {}", e);
return Err(e);
}
Err(e) => {
eprintln!("服务器任务错误: {}", e);
return Err(std::io::Error::new(std::io::ErrorKind::Other, format!("服务器任务错误: {}", e)));
}
}
}
_ = signal::ctrl_c() => {
println!("\n收到 Ctrl+C 信号,正在优雅地停止服务器...");
let _ = handle.stop(true);
match server_task_handle.await {
Ok(Ok(())) | Ok(Err(_)) | Err(_) => {
}
}
println!("服务器已停止");
return Ok(());
}
restart_signal = restart_rx.recv() => {
match restart_signal {
Some(_) => {
println!("收到重启信号,正在停止服务器...");
let _ = handle.stop(true);
match server_task_handle.await {
Ok(Ok(())) | Ok(Err(_)) | Err(_) => {
}
}
println!("服务器已停止,准备重启...");
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
}
None => {
println!("重启 channel 已关闭,退出服务循环");
let _ = handle.stop(true);
match server_task_handle.await {
Ok(Ok(())) | Ok(Err(_)) | Err(_) => {
}
}
return Ok(());
}
}
}
}
}
}