Files
NebulaShell/store/@{NebulaShell}/plugin-loader/PL_EXAMPLE.md
2026-05-02 08:30:31 +08:00

172 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PL 注入机制使用说明
## 概述
PL 注入机制允许插件通过 `PL/` 文件夹向插件加载器注册自定义功能。插件加载器在启动时会自动扫描所有插件,检查其 `manifest.json` 中是否声明了 `pl_injection` 配置项。
## 使用步骤
### 1. 在 manifest.json 中声明 pl_injection
在插件的 `manifest.json``config.args` 中添加 `"pl_injection": true`
```json
{
"metadata": {
"name": "my-plugin",
"version": "1.0.0",
"author": "MyName",
"description": "我的插件",
"type": "utility"
},
"config": {
"enabled": true,
"args": {
"pl_injection": true
}
},
"dependencies": [],
"permissions": []
}
```
### 2. 创建 PL/ 文件夹和 PL/main.py
在插件目录下创建 `PL/` 文件夹,并在其中创建 `main.py`
```
store/@{MyName}/my-plugin/
├── manifest.json # 声明 pl_injection: true
├── main.py # 插件主逻辑
├── PL/ # PL 注入文件夹
│ └── main.py # 注入逻辑(必须包含 register() 函数)
└── README.md
```
### 3. 实现 PL/main.py
`PL/main.py` 必须导出一个 `register(injector)` 函数,接收一个 `PLInjector` 实例:
```python
# PL/main.py
"""PL 注入 - 向插件加载器注册功能"""
def register(injector):
"""向插件加载器注册功能
Args:
injector: PLInjector 实例,提供以下注册方法:
- register_function(name, func, description="")
- register_route(method, path, handler)
- register_event_handler(event_name, handler)
"""
# 示例 1: 注册一个普通功能
def my_helper():
print("这是从 PL 注入的功能")
injector.register_function("my_helper", my_helper, "一个辅助功能")
# 示例 2: 注册 HTTP 路由
def hello_handler(request):
return {"message": "Hello from PL injection!"}
injector.register_route("GET", "/pl/hello", hello_handler)
# 示例 3: 注册事件处理器
def on_plugin_started(plugin_name):
print(f"插件 {plugin_name} 已启动")
injector.register_event_handler("plugin.started", on_plugin_started)
```
### 4. 引用其他文件
`PL/main.py` 可以引用 `PL/` 文件夹下的其他 Python 文件:
```
store/@{MyName}/my-plugin/PL/
├── main.py # 入口,包含 register() 函数
├── helpers.py # 辅助函数(被 main.py 引用)
└── routes.py # 路由定义(被 main.py 引用)
```
```python
# PL/main.py
from .helpers import format_response
from .routes import register_routes
def register(injector):
def my_handler():
return format_response("Hello")
injector.register_function("my_handler", my_handler)
register_routes(injector)
```
## 行为说明
| 场景 | 结果 |
|------|------|
| manifest.json 中 `pl_injection: true` + 存在 `PL/main.py` | ✅ 正常加载,执行注入 |
| manifest.json 中 `pl_injection: true` + 缺少 `PL/` 文件夹 | ❌ 警告并拒绝加载该插件 |
| manifest.json 中 `pl_injection: true` + 存在 `PL/` 但缺少 `main.py` | ❌ 警告并拒绝加载该插件 |
| manifest.json 中未声明 `pl_injection` | ✅ 正常加载,跳过 PL 检查 |
| manifest.json 中 `pl_injection: false` | ✅ 正常加载,跳过 PL 检查 |
## 安全限制
PL 注入机制实施了多层安全限制,防止恶意代码注入:
### 1. 文件类型限制
- PL 文件夹中禁止包含 `.sh``.bat``.exe``.dll``.so``.dylib``.bin` 等可执行/二进制文件
- 违反则拒绝加载该插件
### 2. 静态源码安全检查
PL/main.py 源码在编译前会进行静态扫描,禁止以下操作:
- 导入系统级模块(`os``sys``subprocess``shutil``socket``ctypes``cffi``multiprocessing``threading`
- 使用 `__import__``exec``eval``compile`
- 直接操作文件(`open`
- 访问 `__builtins__`
### 3. 沙箱执行环境
PL/main.py 在受限的沙箱中执行,仅提供安全的 builtins
- 基础类型:`dict``list``str``int``float``bool``tuple``set`
- 安全函数:`len``range``enumerate``zip``map``filter``sorted`
- 异常类型:`Exception``ValueError``TypeError``KeyError``IndexError`
### 4. 参数校验
| 校验项 | 限制 |
|--------|------|
| 功能名称 | 仅允许字母、数字、下划线、冒号、斜杠、连字符、点,最长 128 字符 |
| 路由路径 | 必须以 `/` 开头,禁止 `..``//``/\.``~``%`,最长 256 字符 |
| HTTP 方法 | 仅允许 GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS |
| 事件名称 | 字母开头,仅允许字母、数字、点、下划线,最长 128 字符 |
| 功能描述 | 最长 256 字符 |
### 5. 数量限制
| 限制项 | 上限 |
|--------|------|
| 每个插件最多注册的功能数 | 50 |
| 每个功能名称最多被注册次数 | 10 |
### 6. 异常安全
- 所有注册的函数会被自动包装,执行时抛出异常不会影响主流程
- 异常会被记录到日志,函数返回 `None`
### 7. 调用者溯源
- 通过栈帧回溯自动识别调用者插件名
- 防止其他插件冒充注册
## 注入器 API
`PLInjector` 实例提供以下方法供 `PL/main.py` 调用:
| 方法 | 说明 |
|------|------|
| `register_function(name, func, description="")` | 注册一个注入功能 |
| `register_route(method, path, handler)` | 注册 HTTP 路由 |
| `register_event_handler(event_name, handler)` | 注册事件处理器 |
| `get_injected_functions(name=None)` | 获取已注册的注入功能 |
| `get_injection_info(plugin_name=None)` | 获取注入信息 |
| `has_injection(plugin_name)` | 检查插件是否有 PL 注入 |
| `get_registry_info()` | 获取注册表完整信息(用于监控) |