292 lines
7.6 KiB
Markdown
292 lines
7.6 KiB
Markdown
# 🚀 通用Python执行器进度支持系统
|
||
|
||
一个完全重构的通用Python执行器,支持实时进度回调、JSON-RPC通信和简化的命令创建。
|
||
|
||
## ✨ 新特性
|
||
|
||
- 🎯 **通用进度支持**:一次实现,到处使用
|
||
- 🔧 **简化的API**:多种便利函数和宏
|
||
- 📊 **实时进度更新**:支持Tauri事件和自定义回调
|
||
- 🛠️ **命令构建器**:简化Python命令构造
|
||
- 📝 **丰富的示例**:涵盖各种使用场景
|
||
|
||
## 功能特性
|
||
|
||
- ✅ 支持多种Python命令 (python, python3, py)
|
||
- ✅ UTF-8编码处理
|
||
- ✅ 并发stdout/stderr读取
|
||
- ✅ JSON-RPC消息解析
|
||
- ✅ 实时进度回调
|
||
- ✅ Tauri事件发射
|
||
- ✅ 超时处理
|
||
- ✅ 错误处理
|
||
|
||
## 🎯 核心API
|
||
|
||
### 1. 通用进度执行函数
|
||
|
||
```rust
|
||
// 最通用的函数 - 推荐使用
|
||
execute_python_action_with_progress(
|
||
app: AppHandle,
|
||
module: &str, // Python模块路径
|
||
action: &str, // 要执行的动作
|
||
params: &[(&str, &str)], // 参数键值对
|
||
event_name: &str, // 前端事件名称
|
||
config: Option<PythonExecutorConfig>
|
||
) -> Result<String, String>
|
||
```
|
||
|
||
### 2. 便利函数
|
||
|
||
```rust
|
||
// Tauri事件进度(推荐用于前端集成)
|
||
execute_python_with_events(app, &args, config, "event-name")
|
||
|
||
// 函数回调进度(用于自定义处理)
|
||
execute_python_with_callback(app, &args, config, callback)
|
||
|
||
// 基本执行(无进度)
|
||
execute_python_command(app, &args, config)
|
||
```
|
||
|
||
### 3. 宏支持
|
||
|
||
```rust
|
||
// 简单命令宏
|
||
python_action_command! {
|
||
name: my_simple_command,
|
||
module: "python_core.my_module",
|
||
action: "my_action",
|
||
event: "my-progress-event"
|
||
}
|
||
```
|
||
|
||
## 📋 使用方法
|
||
|
||
### 1. 基本用法(无进度)
|
||
|
||
```rust
|
||
use crate::python_executor::execute_python_command;
|
||
|
||
#[tauri::command]
|
||
pub async fn my_command(app: AppHandle) -> Result<String, String> {
|
||
let args = vec![
|
||
"-m".to_string(),
|
||
"my_python_module".to_string(),
|
||
"--action".to_string(),
|
||
"do_something".to_string(),
|
||
];
|
||
|
||
execute_python_command(app, &args, None).await
|
||
}
|
||
```
|
||
|
||
### 2. 使用Tauri事件进度回调
|
||
|
||
```rust
|
||
use crate::python_executor::execute_python_with_events;
|
||
|
||
#[tauri::command]
|
||
pub async fn my_command_with_progress(app: AppHandle) -> Result<String, String> {
|
||
let args = vec![
|
||
"-m".to_string(),
|
||
"my_python_module".to_string(),
|
||
"--action".to_string(),
|
||
"long_running_task".to_string(),
|
||
];
|
||
|
||
// 进度将通过 "my-task-progress" 事件发送到前端
|
||
execute_python_with_events(app, &args, None, "my-task-progress").await
|
||
}
|
||
```
|
||
|
||
### 3. 使用函数回调
|
||
|
||
```rust
|
||
use crate::python_executor::{execute_python_with_callback, PythonProgress};
|
||
|
||
#[tauri::command]
|
||
pub async fn my_command_with_callback(app: AppHandle) -> Result<String, String> {
|
||
let args = vec![
|
||
"-m".to_string(),
|
||
"my_python_module".to_string(),
|
||
"--action".to_string(),
|
||
"process_data".to_string(),
|
||
];
|
||
|
||
// 自定义进度处理
|
||
let progress_callback = |progress: PythonProgress| {
|
||
println!("Progress: {}% - {}", progress.progress, progress.message);
|
||
// 可以在这里添加自定义逻辑,如数据库记录、日志等
|
||
};
|
||
|
||
execute_python_with_callback(app, &args, None, progress_callback).await
|
||
}
|
||
```
|
||
|
||
### 4. 高级用法(自定义回调)
|
||
|
||
```rust
|
||
use crate::python_executor::{execute_python_command_with_progress, ProgressCallback, PythonProgress};
|
||
|
||
struct CustomProgressHandler {
|
||
task_id: String,
|
||
}
|
||
|
||
impl ProgressCallback for CustomProgressHandler {
|
||
fn on_progress(&self, progress: PythonProgress) {
|
||
// 自定义进度处理逻辑
|
||
println!("Task {}: {}% - {}", self.task_id, progress.progress, progress.message);
|
||
|
||
// 可以发送到数据库、文件、其他服务等
|
||
if progress.step == "complete" {
|
||
println!("Task {} completed!", self.task_id);
|
||
}
|
||
}
|
||
}
|
||
|
||
#[tauri::command]
|
||
pub async fn my_advanced_command(app: AppHandle, task_id: String) -> Result<String, String> {
|
||
let args = vec![
|
||
"-m".to_string(),
|
||
"my_python_module".to_string(),
|
||
"--task-id".to_string(),
|
||
task_id.clone(),
|
||
];
|
||
|
||
let progress_handler = CustomProgressHandler { task_id };
|
||
execute_python_command_with_progress(app, &args, None, Some(progress_handler)).await
|
||
}
|
||
```
|
||
|
||
## Python端实现
|
||
|
||
Python脚本需要使用JSON-RPC协议发送进度信息:
|
||
|
||
```python
|
||
from python_core.utils.jsonrpc import create_response_handler, create_progress_reporter
|
||
|
||
def my_long_running_task():
|
||
rpc = create_response_handler("task_id")
|
||
progress = create_progress_reporter()
|
||
|
||
try:
|
||
# 报告开始
|
||
progress.step("start", "开始处理任务...")
|
||
|
||
# 处理步骤1
|
||
progress.report("step1", 25.0, "正在处理步骤1...")
|
||
# ... 实际处理逻辑 ...
|
||
|
||
# 处理步骤2
|
||
progress.report("step2", 50.0, "正在处理步骤2...")
|
||
# ... 实际处理逻辑 ...
|
||
|
||
# 处理步骤3
|
||
progress.report("step3", 75.0, "正在处理步骤3...")
|
||
# ... 实际处理逻辑 ...
|
||
|
||
# 完成
|
||
progress.complete("任务完成!")
|
||
|
||
# 发送最终结果
|
||
result = {
|
||
"status": True,
|
||
"message": "任务成功完成",
|
||
"data": {...}
|
||
}
|
||
rpc.success(result)
|
||
|
||
except Exception as e:
|
||
progress.error(f"任务失败: {str(e)}")
|
||
rpc.error(-32603, "任务执行失败", str(e))
|
||
|
||
if __name__ == "__main__":
|
||
my_long_running_task()
|
||
```
|
||
|
||
## 前端使用
|
||
|
||
```typescript
|
||
import { listen } from '@tauri-apps/api/event'
|
||
|
||
// 监听进度事件
|
||
const unlisten = await listen('my-task-progress', (event) => {
|
||
const progress = event.payload as {
|
||
step: string
|
||
progress: number
|
||
message: string
|
||
details?: any
|
||
timestamp: number
|
||
}
|
||
|
||
console.log(`Progress: ${progress.progress}% - ${progress.message}`)
|
||
|
||
// 更新UI
|
||
updateProgressBar(progress.progress)
|
||
updateStatusMessage(progress.message)
|
||
})
|
||
|
||
// 执行命令
|
||
try {
|
||
const result = await invoke('my_command_with_progress')
|
||
console.log('Task completed:', result)
|
||
} finally {
|
||
unlisten() // 清理监听器
|
||
}
|
||
```
|
||
|
||
## 进度数据结构
|
||
|
||
```rust
|
||
pub struct PythonProgress {
|
||
pub step: String, // 当前步骤名称
|
||
pub progress: f64, // 进度百分比 (0-100, -1表示不确定)
|
||
pub message: String, // 进度消息
|
||
pub details: Option<serde_json::Value>, // 额外详情
|
||
pub timestamp: f64, // 时间戳
|
||
}
|
||
```
|
||
|
||
## 配置选项
|
||
|
||
```rust
|
||
pub struct PythonExecutorConfig {
|
||
pub timeout_seconds: u64, // 超时时间(秒)
|
||
pub working_directory: Option<PathBuf>, // 工作目录
|
||
}
|
||
|
||
// 默认配置:10分钟超时,当前目录
|
||
let config = PythonExecutorConfig::default();
|
||
|
||
// 自定义配置
|
||
let config = PythonExecutorConfig {
|
||
timeout_seconds: 1800, // 30分钟
|
||
working_directory: Some("/path/to/workdir".into()),
|
||
};
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
1. **选择合适的回调方式**:
|
||
- 简单任务:使用 `execute_python_command`
|
||
- 需要前端进度显示:使用 `execute_python_with_events`
|
||
- 需要自定义处理:使用 `execute_python_with_callback`
|
||
|
||
2. **Python端进度报告**:
|
||
- 使用有意义的步骤名称
|
||
- 提供清晰的进度消息
|
||
- 合理设置进度百分比
|
||
- 在关键节点报告进度
|
||
|
||
3. **错误处理**:
|
||
- Python端使用try-catch包装
|
||
- 通过JSON-RPC发送错误信息
|
||
- Rust端处理超时和进程错误
|
||
|
||
4. **性能考虑**:
|
||
- 不要过于频繁地报告进度
|
||
- 避免在进度回调中执行耗时操作
|
||
- 合理设置超时时间
|