feat: 更通用的 带进度条的 python通信方式

This commit is contained in:
root
2025-07-10 22:01:59 +08:00
parent f9e67bfc3d
commit bda9eb1a6b
6 changed files with 448 additions and 133 deletions

View 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. **性能考虑**
- 不要过于频繁地报告进度
- 避免在进度回调中执行耗时操作
- 合理设置超时时间