refactor: strip non-kernel code — keep pure geometry engine only
CI / Build & Test (push) Failing after 16m59s
CI / Release Build (push) Failing after 14m49s
Build & Test / build-and-test (push) Has been cancelled
Build & Test / python-bindings (push) Has been cancelled

Removed (application layer, not kernel):
- blender_addon/ — Blender plugin
- dotnet/ — .NET/C# bindings
- viewer/ — Web 3D viewer
- include/vde/ai/ — AI/ML (GNN, generative design)
- include/vde/cloud/ — Cloud-native (OT, sessions)
- include/vde/distributed/ — Cluster computing
- include/vde/kbe/ — Knowledge-based engineering
- include/vde/wasm/ — WASM compilation
- include/vde/digital_twin/ — Digital twin
- include/vde/plugin/ — Plugin system
- include/vde/gpu/ — GPU acceleration
- src/ai/, src/cloud/, src/distributed/, src/kbe/, src/wasm/, src/digital_twin/, src/plugin/, src/gpu/
- tests/ai/, tests/cloud/, tests/distributed/, tests/kbe/, tests/gpu/

Kept (pure geometry kernel):
- brep/ curves/ mesh/ core/ foundation/ spatial/ boolean/ collision/ sdf/ sketch/ capi/
- python/ bindings (kept as thin binding layer)

Rationale: Parasolid/ACIS/CGM are pure kernels. AI, cloud, WASM, digital twin,
Blender plugins, .NET bindings, and Web viewers belong in the application layer,
not in the geometry engine. VDE should focus on being the best geometry kernel.
This commit is contained in:
茂之钳
2026-07-27 00:05:24 +08:00
parent 69888621cd
commit 5cfdcb2aad
52 changed files with 634 additions and 18161 deletions
-501
View File
@@ -1,501 +0,0 @@
# 插件系统设计
v6.0 引入插件系统,允许第三方开发者扩展 ViewDesignEngine 的功能,无需修改核心代码。
## 目录
1. [设计目标](#1-设计目标)
2. [架构概览](#2-架构概览)
3. [核心组件](#3-核心组件)
4. [插件开发](#4-插件开发)
5. [插件加载流程](#5-插件加载流程)
6. [生命周期管理](#6-生命周期管理)
7. [清单文件](#7-清单文件)
8. [安全考虑](#8-安全考虑)
9. [最佳实践](#9-最佳实践)
---
## 1. 设计目标
| 目标 | 说明 |
|------|------|
| **零侵入** | 插件不修改核心代码,独立编译 |
| **动态加载** | 运行时 dlopen 加载,无需重新编译 VDE |
| **版本兼容** | Manifest 声明版本约束,自动检查兼容性 |
| **隔离性** | 插件崩溃不影响主程序 |
| **易开发** | 继承 `PluginInterface` 即可,最少样板代码 |
## 2. 架构概览
```
┌─────────────────────────────────────────────────────────────┐
│ Application │
│ │ │
│ PluginManager │
│ ┌──────┴──────┐ │
│ │ Registry │ │
│ │ name→Plugin* │ │
│ └──────┬──────┘ │
│ ┌───────────────┼───────────────┐ │
│ │ │ │ │
│ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ │
│ │Plugin A │ │Plugin B │ │Plugin C │ │
│ │(.so) │ │(.so) │ │(.so) │ │
│ │IO Format│ │Geometry │ │ Custom │ │
│ │Exporter │ │Filter │ │ Tool │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ Plugin Directory: /usr/lib/vde/plugins/ │
│ ./vde_plugins/ │
│ $VDE_PLUGIN_PATH │
└─────────────────────────────────────────────────────────────┘
```
## 3. 核心组件
### 3.1 PluginInterface(抽象基类)
所有插件必须实现的接口:
```cpp
namespace vde::plugin {
class PluginInterface {
public:
virtual ~PluginInterface() = default;
/// 插件初始化(加载后调用一次)
virtual bool initialize() = 0;
/// 插件清理(卸载前调用一次)
virtual void shutdown() = 0;
/// 返回插件清单
virtual const PluginManifest& manifest() const = 0;
/// 插件唯一名称(如 "io.export.usdz"
virtual const char* name() const = 0;
/// 插件版本(语义化版本)
virtual const char* version() const = 0;
/// 执行插件功能
virtual bool execute(const std::string& action,
const std::map<std::string, std::string>& params,
void* input, void* output) = 0;
};
} // namespace vde::plugin
```
### 3.2 PluginManifest(插件元数据)
```cpp
namespace vde::plugin {
struct PluginManifest {
std::string name; ///< 唯一标识符,如 "io.export.usdz"
std::string version; ///< 语义化版本 "1.0.0"
std::string author; ///< 作者信息
std::string description; ///< 功能描述
std::string license; ///< 许可证 "MIT" / "Apache-2.0"
std::string vde_version_min;///< 最低 VDE 版本 "6.0.0"
std::string vde_version_max;///< 最高兼容 VDE 版本 (空=无上限)
/// 插件类型
enum class Type {
IO_IMPORT, ///< 格式导入器
IO_EXPORT, ///< 格式导出器
GEOMETRY_FILTER,///< 几何过滤器
CUSTOM_TOOL, ///< 自定义工具
OTHER
};
Type type = Type::OTHER;
/// 依赖的其他插件名称(可选)
std::vector<std::string> dependencies;
/// 从 JSON 文件加载
static std::optional<PluginManifest> from_file(const std::string& path);
};
} // namespace vde::plugin
```
### 3.3 PluginManager(插件管理器)
```cpp
namespace vde::plugin {
class PluginManager {
public:
PluginManager();
~PluginManager();
// 禁止拷贝
PluginManager(const PluginManager&) = delete;
PluginManager& operator=(const PluginManager&) = delete;
/// 从目录加载所有插件
int load_plugin_dir(const std::string& dir_path);
/// 加载单个插件(路径到 .so/.dylib/.dll
bool load_plugin(const std::string& plugin_path);
/// 卸载指定插件
bool unload_plugin(const std::string& name);
/// 卸载所有插件
void unload_all();
/// 获取已加载的插件
PluginInterface* get_plugin(const std::string& name);
/// 列出所有已加载插件
std::vector<std::string> list_plugins() const;
/// 检查插件是否已加载
bool is_loaded(const std::string& name) const;
/// 获取加载错误信息
std::string last_error() const;
private:
struct Impl;
std::unique_ptr<Impl> impl_;
};
} // namespace vde::plugin
```
### 3.4 注册/加载函数
每个插件动态库必须导出以下 C 链接符号:
```cpp
// 创建插件实例(必须导出)
extern "C" VDE_PLUGIN_EXPORT vde::plugin::PluginInterface* create_plugin();
// 销毁插件实例(必须导出)
extern "C" VDE_PLUGIN_EXPORT void destroy_plugin(vde::plugin::PluginInterface* plugin);
// 获取插件清单(可选,优化加载速度)
extern "C" VDE_PLUGIN_EXPORT const vde::plugin::PluginManifest* get_manifest();
```
## 4. 插件开发
### 4.1 最小插件示例
```cpp
// my_exporter.cpp
#include <vde/plugin/plugin_system.h>
#include <iostream>
using namespace vde::plugin;
class MyExporter : public PluginInterface {
public:
bool initialize() override {
manifest_.name = "io.export.myformat";
manifest_.version = "1.0.0";
manifest_.author = "Your Name";
manifest_.description = "Export to MyFormat";
manifest_.type = PluginManifest::Type::IO_EXPORT;
manifest_.vde_version_min = "6.0.0";
return true;
}
void shutdown() override {
// 清理资源
}
const PluginManifest& manifest() const override {
return manifest_;
}
const char* name() const override {
return manifest_.name.c_str();
}
const char* version() const override {
return manifest_.version.c_str();
}
bool execute(const std::string& action,
const std::map<std::string, std::string>& params,
void* input, void* output) override {
if (action == "export") {
// 执行导出逻辑
return true;
}
return false;
}
private:
PluginManifest manifest_;
};
// 必需的导出符号
extern "C" VDE_PLUGIN_EXPORT PluginInterface* create_plugin() {
return new MyExporter();
}
extern "C" VDE_PLUGIN_EXPORT void destroy_plugin(PluginInterface* plugin) {
delete plugin;
}
```
### 4.2 CMake 构建
```cmake
# CMakeLists.txt for plugin
cmake_minimum_required(VERSION 3.16)
project(my_exporter VERSION 1.0.0)
find_package(ViewDesignEngine REQUIRED)
add_library(my_exporter SHARED my_exporter.cpp)
target_link_libraries(my_exporter PRIVATE vde::engine)
target_include_directories(my_exporter PRIVATE ${VDE_INCLUDE_DIRS})
# 设置输出到插件目录
set_target_properties(my_exporter PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plugins"
)
```
### 4.3 插件类型
| 类型 | 枚举值 | 说明 | 示例 |
|------|--------|------|------|
| 格式导入器 | `IO_IMPORT` | 新增文件格式导入 | USDZ, 3DS, AMF |
| 格式导出器 | `IO_EXPORT` | 新增文件格式导出 | USDZ, FBX, X3D |
| 几何过滤器 | `GEOMETRY_FILTER` | 几何后处理 | 平滑、简化、重网格 |
| 自定义工具 | `CUSTOM_TOOL` | 领域特定工具 | 应力分析、拓扑优化 |
## 5. 插件加载流程
```
Application::init()
PluginManager::load_plugin_dir("/usr/lib/vde/plugins")
├── 扫描目录: for each *.so / *.dylib / *.dll
├── dlopen(plugin_path, RTLD_NOW)
│ │
│ ├── 成功 → 继续
│ └── 失败 → 记录错误,跳过
├── dlsym(handle, "get_manifest")
│ │
│ ├── 找到 → 读取 manifest,检查版本兼容性
│ └── 未找到 → 继续加载(稍后从 initialize 获取)
├── dlsym(handle, "create_plugin")
│ │
│ ├── 找到 → PluginInterface* plugin = create_plugin()
│ └── 未找到 → dlclose,跳过
├── plugin->initialize()
│ │
│ ├── 返回 true → 注册到 Registry
│ └── 返回 false → destroy_plugin + dlclose
└── 返回加载成功数量
```
### 版本兼容性检查
```cpp
// 伪代码
bool is_compatible(const PluginManifest& m, const std::string& vde_version) {
// 检查最小版本
if (compare_versions(vde_version, m.vde_version_min) < 0)
return false;
// 检查最大版本(如果指定)
if (!m.vde_version_max.empty() &&
compare_versions(vde_version, m.vde_version_max) > 0)
return false;
return true;
}
```
## 6. 生命周期管理
```
┌──────────────────────────────────────────────────────────────┐
│ 插件生命周期 │
│ │
│ [编译] → [发现] → [加载] → [初始化] → [运行] → [卸载] │
│ │
│ 编译: 开发者编写代码,构建为 .so/.dylib/.dll │
│ 发现: PluginManager 扫描插件目录 │
│ 加载: dlopen 加载动态库 │
│ 初始化: initialize() 注册功能 │
│ 运行: execute() 被调用 │
│ 卸载: shutdown() + dlclose │
│ │
│ 状态机: │
│ UNLOADED → LOADING → INITIALIZED → RUNNING │
│ ↑ ↓ ↓ │
│ └── ERROR SHUTTING_DOWN → UNLOADED│
└──────────────────────────────────────────────────────────────┘
```
### 状态说明
| 状态 | 说明 |
|------|------|
| `UNLOADED` | 插件未加载或已卸载 |
| `LOADING` | dlopen 成功,正在初始化 |
| `INITIALIZED` | initialize() 完成,等待 execute |
| `RUNNING` | execute() 正在执行中 |
| `SHUTTING_DOWN` | shutdown() 执行中 |
| `ERROR` | 加载或初始化失败 |
## 7. 清单文件
插件可以在同目录放置 `plugin.json` 描述文件,加快发现速度:
```json
{
"name": "io.export.usdz",
"version": "1.0.0",
"author": "Your Name <email@example.com>",
"description": "Export geometry to USDZ format for Apple AR",
"license": "MIT",
"type": "IO_EXPORT",
"vde_version_min": "6.0.0",
"vde_version_max": "",
"dependencies": [],
"library": "libvde_usdz_export.so",
"entry_points": {
"create": "create_plugin",
"destroy": "destroy_plugin"
}
}
```
### PluginManager 加载优先级
1. 如果存在 `plugin.json` → 先读取 JSON 验证兼容性
2. 兼容 → `dlopen` + `dlsym(create_plugin)`
3. 不兼容 → 跳过,记录日志
4.`plugin.json` → 直接 `dlopen` + 尝试 `get_manifest` 符号
## 8. 安全考虑
### 8.1 隔离性
| 措施 | 说明 |
|------|------|
| 独立 .so | 每个插件独立动态库 |
| 崩溃隔离 | 插件 SIGSEGV 不传播到主程序(信号处理器) |
| 符号可见性 | 插件使用 `-fvisibility=hidden` 隐藏内部符号 |
| 内存隔离 | 插件通过 PluginInterface 与主程序交互,不直接访问内部数据 |
### 8.2 信任模型
```
┌───────────────────────────────────────┐
│ 插件信任级别 │
│ │
│ L0 内置: VDE 官方维护,完全信任 │
│ L1 签名: 第三方已签名,受信任 │
│ L2 社区: 社区插件,有限沙箱 │
│ L3 未知: 未签名/未知来源,严格沙箱 │
│ │
│ L3 限制: │
│ - 不能访问文件系统(除了输出目录) │
│ - 不能调用网络 │
│ - 不能 fork │
│ - CPU/内存限制 │
└───────────────────────────────────────┘
```
### 8.3 最佳安全实践
1. **始终验证 manifest 版本兼容性**后再 initialize
2. **dlopen 使用 `RTLD_NOW | RTLD_LOCAL`** 而非 `RTLD_LAZY | RTLD_GLOBAL`
3. **设置超时**execute() 调用应有超时机制
4. **资源限制**:通过 cgroups/Docker 限制插件资源
5. **日志审计**:记录所有插件加载/卸载/执行事件
## 9. 最佳实践
### 9.1 插件开发建议
- ✅ 插件尽量无状态,每次 execute 独立
- ✅ 用 manifest 声明清晰的功能范围
- ✅ 支持版本协商(`vde_version_min` / `vde_version_max`
- ✅ 提供详细的错误信息(通过返回值 + 日志)
- ✅ 清理所有资源在 shutdown() 中
- ❌ 不要在 initialize() 中做耗时操作
- ❌ 不要依赖全局可变状态
- ❌ 不要修改 VDE 核心数据结构
### 9.2 插件命名规范
```
格式: <category>.<subcategory>.<name>
示例:
- io.import.fbx # FBX 格式导入
- io.export.usdz # USDZ 格式导出
- geometry.smooth.laplacian # Laplacian 平滑
- tool.analysis.stress # 应力分析工具
```
### 9.3 使用示例
```cpp
#include <vde/plugin/plugin_system.h>
int main() {
vde::plugin::PluginManager mgr;
// 加载所有插件
int count = mgr.load_plugin_dir("/usr/lib/vde/plugins");
std::cout << "Loaded " << count << " plugins\n";
// 列出已加载插件
for (auto& name : mgr.list_plugins()) {
std::cout << " - " << name << "\n";
}
// 使用特定插件
auto* exporter = mgr.get_plugin("io.export.gltf");
if (exporter) {
std::map<std::string, std::string> params;
params["path"] = "output.glb";
params["binary"] = "true";
void* mesh_data = /* ... */;
bool ok = exporter->execute("export", params, mesh_data, nullptr);
}
// 卸载
mgr.unload_all();
return 0;
}
```
---
## 附录: 平台差异
| 操作 | Linux | macOS | Windows |
|------|-------|-------|---------|
| 动态库后缀 | `.so` | `.dylib` | `.dll` |
| 加载函数 | `dlopen` | `dlopen` | `LoadLibraryA` |
| 符号解析 | `dlsym` | `dlsym` | `GetProcAddress` |
| 卸载函数 | `dlclose` | `dlclose` | `FreeLibrary` |
| 错误信息 | `dlerror()` | `dlerror()` | `GetLastError()` |
| 链接库 | `-ldl` | (内置) | `kernel32.lib` |
| 可见性宏 | `__attribute__((visibility("default")))` | 同 Linux | `__declspec(dllexport)` |