use crate::{
adapter::Adapter,
bot::Bot,
context::{Context, state::EventSystemSharedState},
error::FrameworkResult,
plugin::Plugin,
};
use shirabe_utils::log;
use std::sync::{Arc, RwLock};
use tokio::runtime::Runtime;
pub struct App {
config: config::Config,
adapters: Vec<Arc<dyn Adapter>>,
plugins: Vec<Box<dyn Plugin>>,
shared_state: Arc<RwLock<EventSystemSharedState>>,
}
impl App {
pub fn new() -> Self {
App {
config: config::Config::default(),
adapters: Vec::new(),
plugins: Vec::new(),
shared_state: Arc::new(RwLock::new(EventSystemSharedState::default())),
}
}
pub fn context(&self) -> Context {
Context::new_root(Arc::clone(&self.shared_state))
}
pub fn load_adapter(&mut self, adapter: impl Adapter + 'static) -> &mut Self {
self.adapters.push(Arc::new(adapter));
self
}
pub fn load_plugin(&mut self, plugin: impl Plugin + 'static) -> &mut Self {
self.plugins.push(Box::new(plugin));
self
}
pub fn run(&mut self) -> FrameworkResult<()> {
log::init_logger();
tracing::info!("启动应用……");
let rt = Runtime::new().unwrap();
self.config = config::Config::builder()
.add_source(config::File::new("config", config::FileFormat::Toml))
.build()?;
let app_root_context = Arc::new(self.context());
rt.block_on(async {
if !self.plugins.is_empty() {
tracing::info!("开始加载插件 (on_load)...");
for plugin in &self.plugins {
let ctx_clone = Arc::clone(&app_root_context);
tracing::debug!("调用插件 '{}' 的 on_load 方法", plugin.name());
if let Err(e) = plugin.on_load().await {
tracing::error!("插件 '{}' 的 on_load 方法执行失败: {}", plugin.name(), e);
}
match plugin.apply(ctx_clone).await {
Ok(_) => {}
Err(e) => {
tracing::error!("插件{}启动失败: {:?}", plugin.name(), e)
}
}
}
tracing::debug!("所有插件启动完成。");
}
let mut bot_handlers = vec![];
if self.adapters.is_empty() {
tracing::warn!("没有加载任何适配器。应用将不会启动任何 Bot 或处理事件。");
}
for adapter_arc in &self.adapters {
let bot_context = Arc::clone(&app_root_context); let current_adapter_instance = Arc::clone(adapter_arc);
let bot = Arc::new(Bot::new(bot_context, current_adapter_instance));
{
let bots_arc_mutex = Arc::clone(&app_root_context.bots);
let mut bots_guard = bots_arc_mutex.lock().unwrap();
bots_guard.push(Arc::clone(&bot));
}
let bot_for_task = Arc::clone(&bot);
let platform = bot_for_task.platform.clone();
tracing::info!(
"使用 {} 适配器启动机器人 (Platform: {})",
adapter_arc.get_name(),
platform
);
let handle = tokio::spawn(async move {
if let Err(e) = bot_for_task.start().await {
tracing::error!("Bot {} 启动失败:{}", platform, e);
} else {
tracing::info!("Bot {} 已停止", platform);
}
});
bot_handlers.push(handle);
}
if !bot_handlers.is_empty() {
tracing::info!("所有 Bot 任务已派生,应用正在运行。等待 Bot 任务完成...");
for handle in bot_handlers {
if let Err(e) = handle.await {
tracing::error!("一个 Bot 任务执行时发生错误: {:?}", e);
}
}
tracing::info!("所有 Bot 任务已完成。");
} else if self.adapters.is_empty() {
tracing::info!("由于没有加载适配器,所以没有 Bot 启动。");
} else {
tracing::info!("适配器已加载,但没有 Bot 任务被创建或成功启动。");
}
});
tracing::info!("应用已关闭");
Ok(())
}
}
impl Default for App {
fn default() -> Self {
Self::new()
}
}