Skip to content

Commit 2249220

Browse files
committed
feat (core): 支持程序实时输出
1 parent 7f47912 commit 2249220

3 files changed

Lines changed: 389 additions & 81 deletions

File tree

src-tauri/src/main.rs

Lines changed: 214 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,14 @@ use plugins::{CodeExecutionRequest, ExecutionResult, LanguageInfo, PluginManager
2020
use std::fs;
2121
use std::process::{Command, Stdio};
2222
use std::time::{SystemTime, UNIX_EPOCH};
23-
use tauri::State;
23+
use tauri::{AppHandle, Emitter, State};
2424
use tokio::sync::Mutex;
2525
use uuid::Uuid;
2626

27+
use std::io::{BufRead, BufReader};
28+
use std::sync::mpsc;
29+
use std::thread;
30+
2731
type ExecutionHistory = Mutex<Vec<ExecutionResult>>;
2832
type PluginManagerState = Mutex<PluginManager>;
2933

@@ -33,6 +37,7 @@ async fn execute_code(
3337
request: CodeExecutionRequest,
3438
history: State<'_, ExecutionHistory>,
3539
plugin_manager: State<'_, PluginManagerState>,
40+
app: AppHandle,
3641
) -> Result<ExecutionResult, String> {
3742
info!("执行代码 -> 调用插件 [ {} ] 开始", request.language);
3843
let manager = plugin_manager.lock().await;
@@ -62,7 +67,6 @@ async fn execute_code(
6267
.map_err(|e| format!("Failed to write temporary file: {}", e))?;
6368

6469
let start_time = std::time::Instant::now();
65-
let mut _last_error: String = String::new();
6670

6771
let cmd = plugin.get_command(None);
6872
let args = plugin.get_execute_args(file_path.to_str().unwrap());
@@ -73,14 +77,23 @@ async fn execute_code(
7377
args.join(" ")
7478
);
7579

76-
let output = Command::new(&cmd)
77-
.args(args)
80+
// 发送执行开始事件
81+
let _ = app.emit(
82+
"code-execution-start",
83+
serde_json::json!({
84+
"language": request.language
85+
}),
86+
);
87+
88+
// 启动子进程
89+
let mut child = match Command::new(&cmd)
90+
.args(&args)
7891
.stdout(Stdio::piped())
7992
.stderr(Stdio::piped())
80-
.output();
81-
82-
match output {
83-
Ok(output) => {
93+
.spawn()
94+
{
95+
Ok(child) => child,
96+
Err(e) => {
8497
let execution_time = start_time.elapsed().as_millis();
8598
let timestamp = SystemTime::now()
8699
.duration_since(UNIX_EPOCH)
@@ -90,66 +103,209 @@ async fn execute_code(
90103
// 清理临时文件
91104
let _ = fs::remove_file(&file_path);
92105

93-
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
94-
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
95-
96-
let mut result = ExecutionResult {
97-
success: output.status.success(),
98-
stdout,
99-
stderr,
106+
// 发送执行完成事件
107+
let _ = app.emit(
108+
"code-execution-complete",
109+
serde_json::json!({
110+
"language": request.language,
111+
"success": false
112+
}),
113+
);
114+
115+
error!("执行代码 -> 调用插件 [ {} ] 失败: {}", request.language, e);
116+
return Ok(ExecutionResult {
117+
success: false,
118+
stdout: String::new(),
119+
stderr: format!(
120+
"{} interpreter not found. Please install {} and ensure it's in your PATH.\n\nError: {}",
121+
request.language, request.language, e
122+
),
100123
execution_time,
101124
timestamp,
102-
language: request.language.clone(),
103-
};
125+
language: request.language,
126+
});
127+
}
128+
};
104129

105-
// 后处理
106-
let _ = plugin.post_execute_hook(&mut result);
130+
let stdout = child.stdout.take().unwrap();
131+
let stderr = child.stderr.take().unwrap();
107132

108-
// 添加到执行历史
109-
drop(manager); // 释放插件管理器锁
110-
let mut history_guard = history.lock().await;
111-
history_guard.push(result.clone());
133+
let (stdout_tx, stdout_rx) = mpsc::channel();
134+
let (stderr_tx, stderr_rx) = mpsc::channel();
112135

113-
// 保持历史记录不超过100条
114-
if history_guard.len() > 100 {
115-
history_guard.remove(0);
136+
// 读取 stdout
137+
thread::spawn(move || {
138+
let reader = BufReader::new(stdout);
139+
for line in reader.lines() {
140+
if let Ok(line) = line {
141+
if stdout_tx.send(line).is_err() {
142+
break;
143+
}
116144
}
145+
}
146+
});
147+
148+
// 读取 stderr
149+
thread::spawn(move || {
150+
let reader = BufReader::new(stderr);
151+
for line in reader.lines() {
152+
if let Ok(line) = line {
153+
if stderr_tx.send(line).is_err() {
154+
break;
155+
}
156+
}
157+
}
158+
});
159+
160+
let mut stdout_lines = Vec::new();
161+
let mut stderr_lines = Vec::new();
117162

118-
info!("执行代码 -> 调用插件 [ {} ] 完成", request.language);
119-
return Ok(result);
163+
// 设置超时时间
164+
let timeout = std::time::Duration::from_secs(3000);
165+
166+
loop {
167+
// 检查超时
168+
if start_time.elapsed() > timeout {
169+
let _ = child.kill();
170+
let _ = child.wait(); // 等待进程清理
171+
172+
// 清理临时文件
173+
let _ = fs::remove_file(&file_path);
174+
175+
// 发送超时事件
176+
let _ = app.emit(
177+
"code-execution-timeout",
178+
serde_json::json!({
179+
"language": request.language
180+
}),
181+
);
182+
183+
return Err("代码执行超时(30秒)".to_string());
120184
}
121-
Err(e) => {
122-
_last_error = format!("Failed to execute {} - {}", cmd, e);
185+
186+
// 读取并发送 stdout
187+
while let Ok(line) = stdout_rx.try_recv() {
188+
stdout_lines.push(line.clone());
189+
// 发送实时输出事件
190+
let _ = app.emit(
191+
"code-output",
192+
serde_json::json!({
193+
"type": "stdout",
194+
"content": line,
195+
"language": request.language
196+
}),
197+
);
123198
}
124-
}
125199

126-
// 如果所有命令都失败了
127-
let execution_time = start_time.elapsed().as_millis();
128-
let timestamp = SystemTime::now()
129-
.duration_since(UNIX_EPOCH)
130-
.unwrap()
131-
.as_secs();
132-
133-
// 清理临时文件
134-
let _ = fs::remove_file(&file_path);
135-
136-
error!("执行代码 -> 调用插件 [ {} ] 失败", request.language);
137-
Ok(ExecutionResult {
138-
success: false,
139-
stdout: String::new(),
140-
stderr: format!(
141-
"{} interpreter not found. Please install {} and ensure it's in your PATH.\n\nLast error: {}\n\nTried commands: {:?}",
142-
request.language,
143-
request.language,
144-
_last_error,
145-
plugin
146-
.get_command(Some(file_path.to_str().unwrap()))
147-
.to_string()
148-
),
149-
execution_time,
150-
timestamp,
151-
language: request.language,
152-
})
200+
// 读取并发送 stderr
201+
while let Ok(line) = stderr_rx.try_recv() {
202+
stderr_lines.push(line.clone());
203+
// 发送实时错误事件
204+
let _ = app.emit(
205+
"code-output",
206+
serde_json::json!({
207+
"type": "stderr",
208+
"content": line,
209+
"language": request.language
210+
}),
211+
);
212+
}
213+
214+
// 检查进程是否结束
215+
match child.try_wait() {
216+
Ok(Some(status)) => {
217+
// 进程已结束,读取剩余输出
218+
while let Ok(line) = stdout_rx.try_recv() {
219+
stdout_lines.push(line.clone());
220+
let _ = app.emit(
221+
"code-output",
222+
serde_json::json!({
223+
"type": "stdout",
224+
"content": line,
225+
"language": request.language
226+
}),
227+
);
228+
}
229+
while let Ok(line) = stderr_rx.try_recv() {
230+
stderr_lines.push(line.clone());
231+
let _ = app.emit(
232+
"code-output",
233+
serde_json::json!({
234+
"type": "stderr",
235+
"content": line,
236+
"language": request.language
237+
}),
238+
);
239+
}
240+
241+
let execution_time = start_time.elapsed().as_millis();
242+
let timestamp = SystemTime::now()
243+
.duration_since(UNIX_EPOCH)
244+
.unwrap()
245+
.as_secs();
246+
247+
// 清理临时文件
248+
let _ = fs::remove_file(&file_path);
249+
250+
let mut result = ExecutionResult {
251+
success: status.success(),
252+
stdout: stdout_lines.join("\n"),
253+
stderr: stderr_lines.join("\n"),
254+
execution_time,
255+
timestamp,
256+
language: request.language.clone(),
257+
};
258+
259+
// 后处理
260+
let _ = plugin.post_execute_hook(&mut result);
261+
262+
// 发送执行完成事件
263+
let _ = app.emit(
264+
"code-execution-complete",
265+
serde_json::json!({
266+
"language": request.language,
267+
"success": result.success,
268+
"execution_time": result.execution_time
269+
}),
270+
);
271+
272+
// 添加到执行历史
273+
drop(manager); // 释放插件管理器锁
274+
let mut history_guard = history.lock().await;
275+
history_guard.push(result.clone());
276+
277+
// 保持历史记录不超过100条
278+
if history_guard.len() > 100 {
279+
history_guard.remove(0);
280+
}
281+
282+
info!("执行代码 -> 调用插件 [ {} ] 完成", request.language);
283+
return Ok(result);
284+
}
285+
Ok(None) => {
286+
// 进程仍在运行,短暂休眠
287+
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
288+
}
289+
Err(e) => {
290+
let _ = child.kill();
291+
let _ = child.wait();
292+
293+
// 清理临时文件
294+
let _ = fs::remove_file(&file_path);
295+
296+
// 发送执行错误事件
297+
let _ = app.emit(
298+
"code-execution-error",
299+
serde_json::json!({
300+
"language": request.language,
301+
"error": e.to_string()
302+
}),
303+
);
304+
305+
return Err(format!("检查进程状态失败: {}", e));
306+
}
307+
}
308+
}
153309
}
154310

155311
// 通用的环境信息获取函数

0 commit comments

Comments
 (0)