mirror of
https://github.com/MeiK2333/river.git
synced 2025-09-26 22:49:11 +08:00
完成基本功能
This commit is contained in:
parent
b2961c34fe
commit
11c10cc24d
10
README.md
10
README.md
@ -24,4 +24,12 @@
|
||||
|
||||
## TODOs
|
||||
|
||||
- 修改为文件形式的输入输出,为了这部分的优化我浪费了太多的时间,最后发现过早的优化果然是万恶之源。
|
||||
已经完成基本功能,后续需要优化
|
||||
|
||||
- 基于 ptrace 的精准内存测量
|
||||
- 基于 cgroups 的资源控制
|
||||
- 用户、组限制
|
||||
- 示例代码
|
||||
- 安全测试
|
||||
- 优化 args 生成代码,减少测量出的用户代码执行时间
|
||||
- special judge
|
||||
|
@ -23,6 +23,8 @@ pub enum Error {
|
||||
UnknownRequestData,
|
||||
RequestDataNotFound,
|
||||
SyscallError(String),
|
||||
OpenFileError(PathBuf, io::Error),
|
||||
ReadFileError(PathBuf, io::Error),
|
||||
CustomError(String),
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,14 @@ use super::config::{STDERR_FILENAME, STDOUT_FILENAME};
|
||||
use super::error::{Error, Result};
|
||||
use super::process::Process;
|
||||
use super::runner::RunnerStatus;
|
||||
use crate::result::stanard_result;
|
||||
use crate::river::judge_response::State;
|
||||
use crate::river::Language;
|
||||
use crate::river::{CompileData, JudgeData, JudgeResult, JudgeStatus};
|
||||
use crate::river::{JudgeRequest, JudgeResponse};
|
||||
use std::path::Path;
|
||||
use tokio::fs;
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
impl JudgeResponse {
|
||||
fn new() -> JudgeResponse {
|
||||
@ -76,9 +78,17 @@ pub async fn judger(
|
||||
resp.errmsg = format!("Exceptional program return code: {}", status.exit_code);
|
||||
resp.state = Some(State::Result(JudgeResult::RuntimeError as i32));
|
||||
} else {
|
||||
// TODO: AC\WA\PE
|
||||
// 没有 ole 这种操作,之前 ole 就是错的
|
||||
resp.state = Some(State::Result(JudgeResult::Accepted as i32));
|
||||
let mut file = match fs::File::open(path.join(STDOUT_FILENAME)).await {
|
||||
Ok(val) => val,
|
||||
Err(e) => return Err(Error::OpenFileError(path.join(STDOUT_FILENAME), e)),
|
||||
};
|
||||
let mut out = Vec::new();
|
||||
if let Err(e) = file.read_to_end(&mut out).await {
|
||||
return Err(Error::ReadFileError(path.join(STDOUT_FILENAME), e));
|
||||
};
|
||||
let result = stanard_result(&out, &data.out_data)?;
|
||||
resp.state = Some(State::Result(result as i32));
|
||||
}
|
||||
Ok(resp)
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ mod error;
|
||||
mod exec_args;
|
||||
mod judger;
|
||||
mod process;
|
||||
mod result;
|
||||
mod runner;
|
||||
mod seccomp;
|
||||
|
||||
|
162
src/result.rs
Normal file
162
src/result.rs
Normal file
@ -0,0 +1,162 @@
|
||||
use super::error::Result;
|
||||
use crate::river::JudgeResult;
|
||||
|
||||
pub fn stanard_result(out: &[u8], ans: &[u8]) -> Result<JudgeResult> {
|
||||
let out_len = out.len();
|
||||
let ans_len = ans.len();
|
||||
let mut out_offset = 0;
|
||||
let mut ans_offset = 0;
|
||||
// 没有 PE,PE 直接 WA
|
||||
let mut r = JudgeResult::Accepted;
|
||||
while out_offset < out_len && ans_offset < ans_len {
|
||||
let (out_start, out_end, out_exists) = next_line(&out, out_offset, out_len);
|
||||
let (ans_start, ans_end, ans_exists) = next_line(&ans, ans_offset, ans_len);
|
||||
if !out_exists || !ans_exists {
|
||||
// 如果一个已经读取完但另一个还有数据,则结果为 WA
|
||||
if out_exists != ans_exists {
|
||||
r = JudgeResult::WrongAnswer;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// 如果两个数据当前行长度不同,则结果为 WA(这个长度已经排除了末尾空白符号)
|
||||
if out_end - out_start != ans_end - ans_start {
|
||||
r = JudgeResult::WrongAnswer;
|
||||
break;
|
||||
}
|
||||
let line_len = out_end - out_start;
|
||||
for i in 0..line_len {
|
||||
// 逐个对比
|
||||
if out[out_start + i] != ans[ans_start + i] {
|
||||
r = JudgeResult::WrongAnswer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 如果结果出来了,则退出循环
|
||||
if r != JudgeResult::Accepted {
|
||||
break;
|
||||
}
|
||||
out_offset = out_end;
|
||||
ans_offset = ans_end;
|
||||
}
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略空行与每行末尾的空格与制表符
|
||||
* 如果某行只有空白字符,则忽略此行
|
||||
* "Hello ; "
|
||||
* " "
|
||||
* " World"
|
||||
* -----------------
|
||||
* "Hello ;"
|
||||
* " World"
|
||||
*/
|
||||
fn next_line(v: &[u8], offset: usize, len: usize) -> (usize, usize, bool) {
|
||||
let mut line_offset = offset;
|
||||
let mut left = 0;
|
||||
let mut right = len;
|
||||
let mut has_line = false;
|
||||
while line_offset < len {
|
||||
let ch = v[line_offset] as char;
|
||||
// 当读取到某行结束时
|
||||
if ch == '\n' {
|
||||
if has_line {
|
||||
// 如果已经有新行的数据,则在这个位置结束
|
||||
right = line_offset;
|
||||
break;
|
||||
} else {
|
||||
// 如果还没有数据,说明整行为空,忽略当前行,将下一行设为起点重复过程
|
||||
left = line_offset + 1;
|
||||
}
|
||||
}
|
||||
if ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' {
|
||||
// 空白字符
|
||||
} else {
|
||||
// 非空白字符
|
||||
has_line = true;
|
||||
}
|
||||
line_offset += 1;
|
||||
}
|
||||
// 排除该行末尾的空白字符
|
||||
while left < right {
|
||||
let ch = v[right - 1] as char;
|
||||
if ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' {
|
||||
// 空白字符
|
||||
} else {
|
||||
// 非空白字符
|
||||
break;
|
||||
}
|
||||
right -= 1;
|
||||
}
|
||||
(left, right, has_line)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::river::JudgeResult;
|
||||
#[test]
|
||||
fn test1() {
|
||||
let v: &[u8] = "Hello World!".as_bytes();
|
||||
let (l, r, e) = next_line(v, 0, v.len());
|
||||
assert_eq!(l, 0);
|
||||
assert_eq!(r, 12);
|
||||
assert!(e);
|
||||
let (_l, _r, e) = next_line(v, r, v.len());
|
||||
assert!(!e);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test2() {
|
||||
let v: &[u8] = "Hello World! ".as_bytes();
|
||||
let (l, r, e) = next_line(v, 0, v.len());
|
||||
assert_eq!(l, 0);
|
||||
assert_eq!(r, 12);
|
||||
assert!(e);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test3() {
|
||||
let v: &[u8] = " Hello World!".as_bytes();
|
||||
let (l, r, e) = next_line(v, 0, v.len());
|
||||
assert_eq!(l, 0);
|
||||
assert_eq!(r, 15);
|
||||
assert!(e);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test4() {
|
||||
let v: &[u8] = " Hello World!\n Hello World!\n\n\n\n \n\n\n\n\n\n \t\t\t \t\n\n\n\n".as_bytes();
|
||||
let (l, r, e) = next_line(v, 0, v.len());
|
||||
assert_eq!(l, 0);
|
||||
assert_eq!(r, 15);
|
||||
assert!(e);
|
||||
let (l, r, e) = next_line(v, r, v.len());
|
||||
assert_eq!(l, 16);
|
||||
assert_eq!(r, 31);
|
||||
assert!(e);
|
||||
let (_l, _r, e) = next_line(v, r, v.len());
|
||||
assert!(!e);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test5() {
|
||||
let ans: &[u8] = "Hello World!".as_bytes();
|
||||
let out: &[u8] = "Hello World!".as_bytes();
|
||||
assert_eq!(stanard_result(out, ans).unwrap(), JudgeResult::Accepted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test6() {
|
||||
let ans: &[u8] = "Hello World!".as_bytes();
|
||||
let out: &[u8] = "Hello World! ".as_bytes();
|
||||
assert_eq!(stanard_result(out, ans).unwrap(), JudgeResult::Accepted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test7() {
|
||||
let ans: &[u8] = "Hello World! \n\n\n\n \n\n\n\n".as_bytes();
|
||||
let out: &[u8] = "Hello World!\t\t\t\t\n\n\n\n \n\n\n\n\t\t\t\t".as_bytes();
|
||||
assert_eq!(stanard_result(out, ans).unwrap(), JudgeResult::Accepted);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user