feat: M1.1 完成 + M1.2 启动 — 全量更新
M1.1 收尾: - 24项 P0/P1/P2 bug 修复 (Rust 107 tests + Flutter 15 tests) - Flutter App v0.3: cupertino_icons 修复, 单元测试, 调试面板, APK 52.6MB - 示例插件完善: manifest.json + 请求/响应示范 + 7个测试 - API 文档重写 (以 routes.rs 为唯一权威) - MILESTONES.md 更新至 100% M1.2 启动: - P0: 插件管理 API 闭环 (handle_manager_message Custom 分支 + broadcast_plugin_states) - ServiceManager 集成测试 8/8 (tests/m1_2_service_manager.rs) - M1.2 测试计划 (docs/M1.2_TEST_PLAN.md, 18个E2E场景) - 动态插件系统: auto_rollback + version_manager GC + 路径穿越防护 总计: Rust 115/115 测试, Flutter 15/15 测试, 零 warning Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -296,6 +296,15 @@ pub type FfiStr = *const c_char;
|
||||
///
|
||||
/// 主程序从插件取回 JSON 或错误信息时使用该结构体。内存由插件分配,
|
||||
/// 再通过 `PluginVTable::free_string` 释放。
|
||||
///
|
||||
/// 该类型故意不携带 allocator 标识,以保持现有 `repr(C)` ABI 稳定;
|
||||
/// 因此调用方必须通过 API 契约保证“谁分配,谁释放”。
|
||||
///
|
||||
/// # Safety
|
||||
/// - 插件返回给主程序的 `FfiString` 只能由当前插件导出的
|
||||
/// `PluginVTable::free_string` 释放。
|
||||
/// - 主程序分配的字符串绝不能交给插件释放,反之亦然。
|
||||
/// - 跨 allocator 释放会导致未定义行为(可能崩溃或内存损坏)。
|
||||
#[repr(C)]
|
||||
pub struct FfiString {
|
||||
/// 字符串起始指针;为空时表示没有内容。
|
||||
@@ -308,6 +317,7 @@ impl FfiString {
|
||||
/// 从 Rust `String` 构造 FFI 字符串。
|
||||
///
|
||||
/// 如果字符串中包含内部 `NUL` 字节,会返回空字符串表示失败。
|
||||
/// 生成的指针必须由当前插件的 `free_string` 回调释放。
|
||||
pub fn from_string(s: String) -> Self {
|
||||
match CString::new(s) {
|
||||
Ok(cstr) => {
|
||||
@@ -332,7 +342,8 @@ impl FfiString {
|
||||
/// 复制为 Rust String(不释放底层内存)
|
||||
///
|
||||
/// # Safety
|
||||
/// ptr 必须指向有效的 null-terminated C 字符串
|
||||
/// `ptr` 必须指向由当前插件 allocator 创建的有效 null-terminated C 字符串。
|
||||
/// 调用此函数不会转移所有权,原始分配方仍负责释放该内存。
|
||||
pub unsafe fn to_string(&self) -> Option<String> {
|
||||
if self.ptr.is_null() {
|
||||
return None;
|
||||
@@ -376,6 +387,8 @@ impl FfiResult {
|
||||
/// 主程序提供给插件的消息发送回调。
|
||||
///
|
||||
/// 插件通常无需直接调用该类型,而是通过 [`MessageSender`] 使用安全封装。
|
||||
/// 若插件把发送器保存到后台线程,必须在 [`ShowenPlugin::stop`] 返回前终止这些线程,
|
||||
/// 之后不得再继续使用该回调或 `MessageSender`。
|
||||
pub type SendCallback = unsafe extern "C" fn(ctx: *mut c_void, envelope_json: FfiStr);
|
||||
|
||||
/// 插件导出给主程序的函数表。
|
||||
@@ -403,6 +416,9 @@ pub struct PluginVTable {
|
||||
/// 停止插件。
|
||||
pub stop: unsafe extern "C" fn(handle: PluginHandle) -> FfiResult,
|
||||
/// 释放由插件返回的字符串。
|
||||
///
|
||||
/// # Safety
|
||||
/// 只能释放当前插件导出的 `FfiString`。不要将宿主分配的字符串传给这里。
|
||||
pub free_string: unsafe extern "C" fn(s: FfiString),
|
||||
/// 销毁插件实例。
|
||||
pub destroy: unsafe extern "C" fn(handle: PluginHandle),
|
||||
@@ -729,7 +745,8 @@ pub trait ShowenPlugin: Send {
|
||||
/// 停止插件并释放运行期资源。
|
||||
///
|
||||
/// 该方法通常用于停止后台线程、撤销监听、关闭文件句柄或网络连接。执行完成后,
|
||||
/// 主程序可能很快销毁插件实例。
|
||||
/// 主程序可能很快销毁插件实例。所有后台线程必须在该方法返回前退出,并停止使用
|
||||
/// 之前在 `init` 中收到的 `MessageSender`。
|
||||
///
|
||||
/// # Examples
|
||||
/// ```ignore
|
||||
|
||||
Reference in New Issue
Block a user