feat: 实现动态插件系统 (6阶段完成)
- 阶段1: 消息类型序列化 (Serialize/Deserialize, &'static str → String) - 阶段2: FFI 边界类型 + Plugin SDK (plugin_abi, showen-plugin-sdk crate) - 阶段3: PluginLoader + DynamicPlugin (libloading 动态加载 .so) - 阶段4: 版本管理 + 错误策略 (VersionManager, PluginState, 自动回退) - 阶段5: 远程仓库客户端 (HTTP 下载 + tar.gz 安装) - 阶段6: 示例插件 + HTTP 管理 API + 全目录 README 文档 54/54 测试通过,0 warnings。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,8 @@ pub(crate) struct HttpState {
|
||||
player_status: Mutex<crate::core::message::PlayerStatusData>,
|
||||
ble_ready: AtomicBool,
|
||||
ws_events: broadcast::Sender<String>,
|
||||
/// 动态插件管理状态(由 Custom 消息更新)
|
||||
plugin_states: Mutex<Vec<crate::core::service_manager::PluginStateInfo>>,
|
||||
}
|
||||
|
||||
impl HttpState {
|
||||
@@ -68,6 +70,7 @@ impl HttpState {
|
||||
player_status: Mutex::new(player_status),
|
||||
ble_ready: AtomicBool::new(false),
|
||||
ws_events,
|
||||
plugin_states: Mutex::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,6 +182,21 @@ impl HttpState {
|
||||
self.publish_ws(payload);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn plugin_states(&self) -> Vec<crate::core::service_manager::PluginStateInfo> {
|
||||
self.plugin_states
|
||||
.lock()
|
||||
.map(|s| s.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn update_plugin_states(&self, json: &str) {
|
||||
if let Ok(states) = serde_json::from_str::<Vec<crate::core::service_manager::PluginStateInfo>>(json) {
|
||||
if let Ok(mut current) = self.plugin_states.lock() {
|
||||
*current = states;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HttpPlugin {
|
||||
@@ -202,21 +220,21 @@ impl Default for HttpPlugin {
|
||||
}
|
||||
|
||||
impl Plugin for HttpPlugin {
|
||||
fn id(&self) -> &'static str {
|
||||
fn id(&self) -> &str {
|
||||
"http"
|
||||
}
|
||||
|
||||
fn info(&self) -> PluginInfo {
|
||||
PluginInfo {
|
||||
name: "HTTP API",
|
||||
version: "0.2.0",
|
||||
description: "Web UI + REST API (warp)",
|
||||
name: "HTTP API".to_string(),
|
||||
version: "0.2.0".to_string(),
|
||||
description: "Web UI + REST API (warp)".to_string(),
|
||||
platform: Platform::Any,
|
||||
}
|
||||
}
|
||||
|
||||
fn dependencies(&self) -> Vec<&'static str> {
|
||||
vec!["video"]
|
||||
fn dependencies(&self) -> Vec<String> {
|
||||
vec!["video".to_string()]
|
||||
}
|
||||
|
||||
fn init(&mut self, ctx: PluginContext) -> Result<()> {
|
||||
@@ -268,9 +286,9 @@ impl Plugin for HttpPlugin {
|
||||
};
|
||||
|
||||
if let Err(error) = tx.send(Envelope {
|
||||
from: "http",
|
||||
from: "http".to_string(),
|
||||
to: crate::core::message::Destination::Manager,
|
||||
message: Message::PluginReady("http"),
|
||||
message: Message::PluginReady("http".to_string()),
|
||||
}) {
|
||||
eprintln!("[HttpPlugin] failed to report ready state: {error}");
|
||||
}
|
||||
@@ -314,8 +332,11 @@ impl Plugin for HttpPlugin {
|
||||
state.publish_ws(payload);
|
||||
}
|
||||
}
|
||||
Message::PluginReady("ble") => state.set_ble_ready(true),
|
||||
Message::PluginReady(ref id) if id == "ble" => state.set_ble_ready(true),
|
||||
Message::Shutdown => state.set_ble_ready(false),
|
||||
Message::Custom { ref kind, ref payload } if kind == "plugin_states" => {
|
||||
state.update_plugin_states(payload);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user