7.6 KiB
7.6 KiB
🚀 通用Python执行器进度支持系统
一个完全重构的通用Python执行器,支持实时进度回调、JSON-RPC通信和简化的命令创建。
✨ 新特性
- 🎯 通用进度支持:一次实现,到处使用
- 🔧 简化的API:多种便利函数和宏
- 📊 实时进度更新:支持Tauri事件和自定义回调
- 🛠️ 命令构建器:简化Python命令构造
- 📝 丰富的示例:涵盖各种使用场景
功能特性
- ✅ 支持多种Python命令 (python, python3, py)
- ✅ UTF-8编码处理
- ✅ 并发stdout/stderr读取
- ✅ JSON-RPC消息解析
- ✅ 实时进度回调
- ✅ Tauri事件发射
- ✅ 超时处理
- ✅ 错误处理
🎯 核心API
1. 通用进度执行函数
// 最通用的函数 - 推荐使用
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. 便利函数
// 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. 宏支持
// 简单命令宏
python_action_command! {
name: my_simple_command,
module: "python_core.my_module",
action: "my_action",
event: "my-progress-event"
}
📋 使用方法
1. 基本用法(无进度)
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事件进度回调
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. 使用函数回调
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. 高级用法(自定义回调)
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协议发送进度信息:
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()
前端使用
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() // 清理监听器
}
进度数据结构
pub struct PythonProgress {
pub step: String, // 当前步骤名称
pub progress: f64, // 进度百分比 (0-100, -1表示不确定)
pub message: String, // 进度消息
pub details: Option<serde_json::Value>, // 额外详情
pub timestamp: f64, // 时间戳
}
配置选项
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()),
};
最佳实践
-
选择合适的回调方式:
- 简单任务:使用
execute_python_command - 需要前端进度显示:使用
execute_python_with_events - 需要自定义处理:使用
execute_python_with_callback
- 简单任务:使用
-
Python端进度报告:
- 使用有意义的步骤名称
- 提供清晰的进度消息
- 合理设置进度百分比
- 在关键节点报告进度
-
错误处理:
- Python端使用try-catch包装
- 通过JSON-RPC发送错误信息
- Rust端处理超时和进程错误
-
性能考虑:
- 不要过于频繁地报告进度
- 避免在进度回调中执行耗时操作
- 合理设置超时时间