From 33aa793a79dc728f9afcf26d96726db7f9e1f8c9 Mon Sep 17 00:00:00 2001 From: MeiK Date: Thu, 3 Sep 2020 15:45:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=BD=93=E5=89=8D=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E8=BF=94=E5=9B=9E=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- proto/river.proto | 8 +++--- src/error.rs | 6 ++--- src/judger.rs | 64 ++++++++++++++++++++++++++++++++--------------- src/main.rs | 2 +- src/process.rs | 43 ++++++++++++++++--------------- 5 files changed, 72 insertions(+), 51 deletions(-) diff --git a/proto/river.proto b/proto/river.proto index 6313882..dce610c 100644 --- a/proto/river.proto +++ b/proto/river.proto @@ -47,10 +47,10 @@ message JudgeResponse { SystemError = 8; } JudgeResult result = 3; - int32 errno = 4; - int32 exit_code = 5; - string stdout = 6; - string stderr = 7; + // int32 errno = 4; + // int32 exit_code = 5; + // string stdout = 6; + // string stderr = 7; string errmsg = 8; enum JudgeStatus { Pending = 0; diff --git a/src/error.rs b/src/error.rs index ad5baf9..5a7f996 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,6 +4,7 @@ use libc::strerror; use std::ffi::{CStr, NulError, OsString}; use std::fmt; use std::io; +use std::path::PathBuf; use std::result; #[derive(Debug)] @@ -14,6 +15,7 @@ pub enum Error { ChannelRecvError, StringToCStringError(NulError), OsStringToStringError(OsString), + RemoveFileError(PathBuf), } pub type Result = result::Result; @@ -42,10 +44,6 @@ pub fn system_error(err: Error) -> JudgeResponse { time_used: 0, memory_used: 0, result: JudgeResult::SystemError as i32, - errno: 0, - exit_code: 0, - stdout: "".into(), - stderr: "".into(), errmsg: format!("{}", err).into(), status: JudgeStatus::Ended as i32, } diff --git a/src/judger.rs b/src/judger.rs index 16e1d87..cf1b2c9 100644 --- a/src/judger.rs +++ b/src/judger.rs @@ -12,10 +12,6 @@ impl JudgeResponse { time_used: 0, memory_used: 0, result: JudgeResult::Accepted as i32, - errno: 0, - exit_code: 0, - stdout: "".into(), - stderr: "".into(), errmsg: "".into(), status: JudgeStatus::Running as i32, } @@ -24,19 +20,48 @@ impl JudgeResponse { fn set_process_status(self: &mut Self, status: &ProcessStatus) { self.time_used = status.time_used; self.memory_used = status.memory_used; - self.exit_code = status.exit_code; - self.errno = status.signal; - self.stdout = status.stdout.clone(); - self.stderr = status.stderr.clone(); } } -pub async fn judger(request: &JudgeRequest) -> Result { - // TODO +pub async fn judger(request: &JudgeRequest, path: &Path) -> Result { let mut resp = JudgeResponse::new(); - resp.time_used = request.time_limit.into(); + let cmd = match Language::from_i32(request.language) { + Some(Language::C) => "./a.out", + Some(Language::Cpp) => "./a.out", + Some(Language::Python) => "/usr/bin/python3 main.py", + Some(Language::Rust) => "./a.out", + Some(Language::Node) => "node main.js", + Some(Language::TypeScript) => "node main.js", + Some(Language::Go) => "./a.out", + None => return Err(Error::LanguageNotFound(request.language)), + }; + let mut process = Process::new(); + process.cmd = cmd.to_string(); + process.workdir = path.to_path_buf(); + process.time_limit = request.time_limit; + process.memory_limit = request.memory_limit; + + // 写入输入文件 + let in_file = path.join("stdin.txt"); + if let Err(e) = fs::write(in_file.clone(), request.in_data.clone()).await { + return Err(Error::FileWriteError(e)); + }; + process.stdin_file = Some(in_file.clone()); + + let status = process.await?; + + if let Err(_) = fs::remove_file(in_file.clone()).await { + return Err(Error::RemoveFileError(in_file.clone())); + } + resp.status = JudgeStatus::Ended as i32; - return Ok(resp); + // TODO: 对比答案,检查结果 + if status.exit_code != 0 { + resp.set_process_status(&status); + resp.result = JudgeResult::CompileError as i32; + resp.status = JudgeStatus::Ended as i32; + } + Ok(resp) } pub async fn compile(request: &JudgeRequest, path: &Path) -> Result { @@ -58,31 +83,30 @@ pub async fn compile(request: &JudgeRequest, path: &Path) -> Result "gcc main.c", - Some(Language::Cpp) => "g++ main.cpp", + Some(Language::C) => "/usr/bin/gcc main.c -o a.out -Wall -O2 -std=c99 --static", + Some(Language::Cpp) => "/usr/bin/g++ main.cpp -O2 -Wall --static -o a.out --std=gnu++17", Some(Language::Python) => "/usr/bin/python3 -m compileall main.py", - Some(Language::Rust) => "rustc main.rs", + Some(Language::Rust) => "/usr/bin/rustc main.rs -o a.out -C opt-level=2", // 无需编译的语言直接返回 // TODO: eslint...... Some(Language::Node) => return Ok(resp), - Some(Language::TypeScript) => "tsc", - Some(Language::Go) => "main.go", + Some(Language::TypeScript) => "/usr/bin/tsc", + Some(Language::Go) => "/usr/bin/go build -ldflags \"-s -w\" main.go", None => return Err(Error::LanguageNotFound(request.language)), }; process.cmd = cmd.to_string(); process.workdir = path.to_path_buf(); process.time_limit = request.time_limit; process.memory_limit = request.memory_limit; - process.stdout_file = Some("stdout.txt".to_string()); - process.stderr_file = Some("stderr.txt".to_string()); let status = process.await?; if status.exit_code != 0 { resp.set_process_status(&status); + resp.errmsg = status.stdout; resp.result = JudgeResult::CompileError as i32; resp.status = JudgeStatus::Ended as i32; } - return Ok(resp); + Ok(resp) } pub fn pending() -> JudgeResponse { diff --git a/src/main.rs b/src/main.rs index 62294b3..7c5de83 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,7 +66,7 @@ impl River for RiverService { need_compile = false; yield judger::running(); - let result = match judger::judger(&req).await { + let result = match judger::judger(&req, &pwd.path()).await { Ok(res) => res, Err(e) => error::system_error(e) }; diff --git a/src/process.rs b/src/process.rs index 43f9366..549c6c4 100644 --- a/src/process.rs +++ b/src/process.rs @@ -21,9 +21,7 @@ pub struct Process { pub workdir: PathBuf, pub time_limit: i32, pub memory_limit: i32, - pub stdin_file: Option, - pub stdout_file: Option, - pub stderr_file: Option, + pub stdin_file: Option, pub cmd: String, tx: Arc>>, rx: Arc>>, @@ -37,8 +35,6 @@ impl Process { time_limit: -1, memory_limit: -1, stdin_file: None, - stdout_file: None, - stderr_file: None, cmd: "".to_string(), workdir: PathBuf::from(""), tx: Arc::new(Mutex::new(tx)), @@ -185,24 +181,21 @@ fn run(process: Process) { // TODO: 资源限制等 // 重定向文件描述符 if let Some(file) = process.stdin_file { - dup(&file, libc::STDIN_FILENO, libc::O_RDONLY, 0o644) - } - if let Some(file) = process.stdout_file { - dup( - &file, - libc::STDOUT_FILENO, - libc::O_CREAT | libc::O_RDWR, - 0o644, - ) - } - if let Some(file) = process.stderr_file { - dup( - &file, - libc::STDERR_FILENO, - libc::O_CREAT | libc::O_RDWR, - 0o644, - ) + let filename = file.to_str().unwrap(); + dup(&filename, libc::STDIN_FILENO, libc::O_RDONLY, 0o644) } + dup( + "stdout.txt", + libc::STDOUT_FILENO, + libc::O_CREAT | libc::O_RDWR, + 0o644, + ); + dup( + "stderr.txt", + libc::STDERR_FILENO, + libc::O_CREAT | libc::O_RDWR, + 0o644, + ); libc::execve(exec_args.pathname, exec_args.argv, exec_args.envp); } panic!("How dare you!"); @@ -290,10 +283,16 @@ fn wait(pid: i32, workdir: PathBuf) -> ProcessStatus { Ok(val) => val, Err(_) => panic!("How dare you!"), }; + if let Err(_) = fs::remove_file(workdir.join("stdout.txt")) { + panic!("How dare you!"); + } let stderr = match fs::read_to_string(workdir.join("stderr.txt")) { Ok(val) => val, Err(_) => panic!("How dare you!"), }; + if let Err(_) = fs::remove_file(workdir.join("stderr.txt")) { + panic!("How dare you!"); + } return ProcessStatus { rusage: rusage, exit_code: exit_code,