feat: 更通用的 带进度条的 python通信方式
This commit is contained in:
242
docs/python_executor_progress.md
Normal file
242
docs/python_executor_progress.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# Python Executor with Progress Support
|
||||
|
||||
通用的Python执行器,支持实时进度回调和JSON-RPC通信。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- ✅ 支持多种Python命令 (python, python3, py)
|
||||
- ✅ UTF-8编码处理
|
||||
- ✅ 并发stdout/stderr读取
|
||||
- ✅ JSON-RPC消息解析
|
||||
- ✅ 实时进度回调
|
||||
- ✅ Tauri事件发射
|
||||
- ✅ 超时处理
|
||||
- ✅ 错误处理
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 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. **性能考虑**:
|
||||
- 不要过于频繁地报告进度
|
||||
- 避免在进度回调中执行耗时操作
|
||||
- 合理设置超时时间
|
||||
Reference in New Issue
Block a user