mirror of
https://github.com/MeiK2333/river.git
synced 2025-09-26 22:49:11 +08:00
更新评测语言,更新日志
This commit is contained in:
parent
98f6458cb2
commit
085818abc1
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ Cargo.lock
|
|||||||
nohup.out
|
nohup.out
|
||||||
|
|
||||||
config.yaml
|
config.yaml
|
||||||
|
logs
|
||||||
|
@ -17,6 +17,7 @@ tempfile = "3"
|
|||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = "0.4.0"
|
log = "0.4.0"
|
||||||
env_logger = "0.8.1"
|
env_logger = "0.8.1"
|
||||||
|
log4rs = "1"
|
||||||
nix = "0.19.0"
|
nix = "0.19.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_yaml = "0.8"
|
serde_yaml = "0.8"
|
||||||
|
@ -1,7 +1,42 @@
|
|||||||
data_dir: /data
|
data_dir: /root/river/runtime/data
|
||||||
judge_dir: /tmp
|
judge_dir: /tmp
|
||||||
languages:
|
languages:
|
||||||
C:
|
C:
|
||||||
compile_cmd: /usr/bin/gcc main.c -o a.out -Wall -O2 -std=c99 --static
|
compile_cmd: /usr/bin/gcc main.c -o a.out -Wall -O2 -std=c99 --static
|
||||||
code_file: main.c
|
code_file: main.c
|
||||||
run_cmd: ./a.out
|
run_cmd: ./a.out
|
||||||
|
|
||||||
|
Cpp:
|
||||||
|
compile_cmd: /usr/bin/g++ main.cpp -O2 -Wall --static -o a.out --std=gnu++17
|
||||||
|
code_file: main.cpp
|
||||||
|
run_cmd: ./a.out
|
||||||
|
|
||||||
|
Python:
|
||||||
|
compile_cmd: /usr/bin/python3.8 -m compileall main.py
|
||||||
|
code_file: main.py
|
||||||
|
run_cmd: /usr/bin/python3.8 main.py
|
||||||
|
|
||||||
|
Rust:
|
||||||
|
compile_cmd: /root/.cargo/bin/rustc main.rs -o a.out -C opt-level=2
|
||||||
|
code_file: main.rs
|
||||||
|
run_cmd: ./a.out
|
||||||
|
|
||||||
|
Node:
|
||||||
|
compile_cmd: /usr/bin/node /plugins/node/validate.js main.js
|
||||||
|
code_file: main.js
|
||||||
|
run_cmd: /usr/bin/node main.js
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
compile_cmd: /usr/bin/tsc -p /tsconfig.json
|
||||||
|
code_file: main.ts
|
||||||
|
run_cmd: /usr/bin/node main.js
|
||||||
|
|
||||||
|
Go:
|
||||||
|
compile_cmd: /usr/bin/go build -o a.out main.go
|
||||||
|
code_file: main.go
|
||||||
|
run_cmd: ./a.out
|
||||||
|
|
||||||
|
Java:
|
||||||
|
compile_cmd: /usr/bin/javac Main.java
|
||||||
|
code_file: Main.java
|
||||||
|
run_cmd: /usr/bin/java -cp . Main
|
||||||
|
16
log4rs.yaml
Normal file
16
log4rs.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
refresh_rate: 30 seconds
|
||||||
|
appenders:
|
||||||
|
console:
|
||||||
|
kind: console
|
||||||
|
encoder:
|
||||||
|
pattern: "{d(%Y-%m-%d %H:%M:%S)} [{h({l})}] {m}{n}"
|
||||||
|
file:
|
||||||
|
kind: file
|
||||||
|
path: "logs/river.log"
|
||||||
|
encoder:
|
||||||
|
pattern: "{d(%Y-%m-%d %H:%M:%S)} [{l}] {m}{n}"
|
||||||
|
root:
|
||||||
|
level: debug
|
||||||
|
appenders:
|
||||||
|
- file
|
||||||
|
- console
|
@ -1,11 +1,37 @@
|
|||||||
FROM ubuntu:focal
|
FROM ubuntu:focal
|
||||||
|
|
||||||
|
ENV LANG C.UTF-8
|
||||||
|
|
||||||
RUN apt-get update -y
|
RUN apt-get update -y
|
||||||
|
|
||||||
|
# install gcc g++
|
||||||
RUN apt-get install -y gcc g++
|
RUN apt-get install -y gcc g++
|
||||||
|
|
||||||
RUN apt-get install -y software-properties-common && \
|
# install python3.8
|
||||||
add-apt-repository -y ppa:deadsnakes/ppa && \
|
RUN apt-get install -y software-properties-common && add-apt-repository -y ppa:deadsnakes/ppa && apt-get install -y python3.8 python3-pip
|
||||||
apt-get install -y python3.8 python3-pip
|
|
||||||
|
# install rust
|
||||||
|
RUN apt-get install -y curl && curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable -y
|
||||||
|
ENV PATH="/root/.cargo/bin:${PATH}"
|
||||||
|
|
||||||
|
# install node
|
||||||
|
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - && apt-get install -y nodejs
|
||||||
|
|
||||||
|
# node compiler
|
||||||
|
COPY plugins /plugins
|
||||||
|
RUN cd /plugins/node && npm install
|
||||||
|
|
||||||
|
# node runtime
|
||||||
|
COPY node /
|
||||||
|
RUN cd / && npm install
|
||||||
|
|
||||||
|
# install typescript
|
||||||
|
RUN npm install -g ts-node typescript
|
||||||
|
|
||||||
|
# install go
|
||||||
|
RUN add-apt-repository -y ppa:longsleep/golang-backports && apt-get install -y golang-go
|
||||||
|
|
||||||
|
# install openjdk
|
||||||
|
RUN apt-get install -y default-jdk
|
||||||
|
|
||||||
RUN rm -rf /var/lib/apt/lists/*
|
RUN rm -rf /var/lib/apt/lists/*
|
||||||
|
@ -6,3 +6,5 @@ docker stop river
|
|||||||
docker rm river
|
docker rm river
|
||||||
|
|
||||||
chmod -R 755 rootfs
|
chmod -R 755 rootfs
|
||||||
|
|
||||||
|
mknod -m 0666 rootfs/dev/null c 1 3
|
||||||
|
15
runtime/node/package.json
Normal file
15
runtime/node/package.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "river",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "^14.14.6"
|
||||||
|
}
|
||||||
|
}
|
14
runtime/node/tsconfig.json
Normal file
14
runtime/node/tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": false,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"noErrorTruncation": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
}
|
||||||
|
}
|
1
runtime/plugins/node/.gitignore
vendored
Normal file
1
runtime/plugins/node/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
6
runtime/plugins/node/failure.js
Normal file
6
runtime/plugins/node/failure.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
return 42; // should be inside a function
|
||||||
|
function f() {
|
||||||
|
'use strict';
|
||||||
|
var x = 042;
|
||||||
|
with (z) { }
|
||||||
|
}
|
13
runtime/plugins/node/package-lock.json
generated
Normal file
13
runtime/plugins/node/package-lock.json
generated
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "js",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
|
"dependencies": {
|
||||||
|
"esprima": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
runtime/plugins/node/package.json
Normal file
16
runtime/plugins/node/package.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "js",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "```bash cd plugins/js ./validate.js success.js ./validate.js failure.js ```",
|
||||||
|
"main": "failure.js",
|
||||||
|
"dependencies": {
|
||||||
|
"esprima": "^4.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
1
runtime/plugins/node/success.js
Normal file
1
runtime/plugins/node/success.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
console.log("Hello World!");
|
23
runtime/plugins/node/validate.js
Normal file
23
runtime/plugins/node/validate.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/node
|
||||||
|
const fs = require('fs');
|
||||||
|
const esprima = require('esprima');
|
||||||
|
|
||||||
|
const file = process.argv[2];
|
||||||
|
const code = fs.readFileSync(file).toString();
|
||||||
|
|
||||||
|
const res = esprima.parseScript(code, { tolerant: true });
|
||||||
|
if (res.errors.length != 0) {
|
||||||
|
const split = code.split('\n');
|
||||||
|
for (const error of res.errors) {
|
||||||
|
console.error(split[error.lineNumber - 1]);
|
||||||
|
for (let i = 1; i < error.column; i++) {
|
||||||
|
process.stderr.write(' ');
|
||||||
|
}
|
||||||
|
console.error('^');
|
||||||
|
console.error(`${error.toString()}
|
||||||
|
at (${file}:${error.lineNumber}:${error.column})`);
|
||||||
|
console.error('--------------------------------------------------------------------------');
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
process.exit(0);
|
@ -1,5 +1,5 @@
|
|||||||
use super::error::{Error, Result};
|
use super::error::{Error, Result};
|
||||||
use std::env;
|
use std::collections::HashMap;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
@ -39,17 +39,18 @@ impl ExecArgs {
|
|||||||
argv_vec.push(ptr::null());
|
argv_vec.push(ptr::null());
|
||||||
let argv: *const *const libc::c_char = argv_vec.as_ptr() as *const *const libc::c_char;
|
let argv: *const *const libc::c_char = argv_vec.as_ptr() as *const *const libc::c_char;
|
||||||
|
|
||||||
// env 环境变量传递当前进程环境变量
|
// env 传递环境变量
|
||||||
|
let mut envs: HashMap<&str, &str> = HashMap::new();
|
||||||
|
envs.insert(
|
||||||
|
"PATH",
|
||||||
|
"/root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||||
|
);
|
||||||
|
envs.insert("HOME", "/tmp");
|
||||||
|
// envs.insert("GOCACHE", "/tmp/.cache");
|
||||||
|
envs.insert("TERM", "xterm");
|
||||||
let mut envp_vec: Vec<*const libc::c_char> = vec![];
|
let mut envp_vec: Vec<*const libc::c_char> = vec![];
|
||||||
for (key, value) in env::vars_os() {
|
for (key, value) in envs {
|
||||||
let mut key = match key.to_str() {
|
let mut key = String::from(key);
|
||||||
Some(val) => val.to_string(),
|
|
||||||
None => return Err(Error::OsStringToStringError(key)),
|
|
||||||
};
|
|
||||||
let value = match value.to_str() {
|
|
||||||
Some(val) => val.to_string(),
|
|
||||||
None => return Err(Error::OsStringToStringError(value)),
|
|
||||||
};
|
|
||||||
key.push_str("=");
|
key.push_str("=");
|
||||||
key.push_str(&value);
|
key.push_str(&value);
|
||||||
let cstr = match CString::new(key) {
|
let cstr = match CString::new(key) {
|
||||||
|
@ -75,18 +75,13 @@ pub async fn judge(
|
|||||||
} else {
|
} else {
|
||||||
status.cgroup_memory_used
|
status.cgroup_memory_used
|
||||||
};
|
};
|
||||||
if status.time_used > time_limit.into() {
|
if status.time_used > time_limit.into() || status.real_time_used as i64 > time_limit.into() {
|
||||||
// TLE
|
// TLE
|
||||||
return Ok(time_limit_exceeded(status.time_used, mem_used));
|
return Ok(time_limit_exceeded(status.time_used, mem_used));
|
||||||
} else if mem_used > memory_limit.into() {
|
} else if mem_used > memory_limit.into() {
|
||||||
// MLE
|
// MLE
|
||||||
return Ok(memory_limit_exceeded(status.time_used, mem_used));
|
return Ok(memory_limit_exceeded(status.time_used, mem_used));
|
||||||
} else if status.signal != 0 {
|
} else if status.signal != 0 {
|
||||||
// 因墙上时钟超时被主动中断
|
|
||||||
if status.real_time_used as i64 > time_limit.into() {
|
|
||||||
// TLE
|
|
||||||
return Ok(time_limit_exceeded(status.time_used, mem_used));
|
|
||||||
}
|
|
||||||
// RE
|
// RE
|
||||||
return Ok(runtime_error(
|
return Ok(runtime_error(
|
||||||
status.time_used,
|
status.time_used,
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
use env_logger::Env;
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
|
use log4rs;
|
||||||
use river::judge_request::Data;
|
use river::judge_request::Data;
|
||||||
use river::river_server::{River, RiverServer};
|
use river::river_server::{River, RiverServer};
|
||||||
use river::{JudgeRequest, JudgeResponse, JudgeResultEnum};
|
use river::{JudgeRequest, JudgeResponse, JudgeResultEnum};
|
||||||
@ -49,6 +49,7 @@ impl River for RiverService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
debug!("{:?}", pwd);
|
||||||
// 是否通过编译
|
// 是否通过编译
|
||||||
let mut compile_success = false;
|
let mut compile_success = false;
|
||||||
let mut language = String::from("");
|
let mut language = String::from("");
|
||||||
@ -106,11 +107,7 @@ impl River for RiverService {
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let env = Env::default()
|
log4rs::init_file("log4rs.yaml", Default::default()).unwrap();
|
||||||
.filter_or("LOG_LEVEL", "debug,h2=info,hyper=info")
|
|
||||||
.write_style_or("LOG_STYLE", "always");
|
|
||||||
|
|
||||||
env_logger::init_from_env(env);
|
|
||||||
|
|
||||||
let addr = "0.0.0.0:4003".parse()?;
|
let addr = "0.0.0.0:4003".parse()?;
|
||||||
let river = RiverService::default();
|
let river = RiverService::default();
|
||||||
|
@ -294,6 +294,15 @@ unsafe fn security(process: &Process) {
|
|||||||
ptr::null_mut()
|
ptr::null_mut()
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// 挂载 /proc 目录,有些语言(比如 rust)依赖此目录
|
||||||
|
syscall_or_panic!(libc::mount(
|
||||||
|
c_str_ptr!("proc"),
|
||||||
|
c_str_ptr!("runtime/rootfs/proc"),
|
||||||
|
c_str_ptr!("proc"),
|
||||||
|
0,
|
||||||
|
ptr::null_mut(),
|
||||||
|
));
|
||||||
|
|
||||||
// 挂载运行文件夹,除此目录外程序没有其他目录的写权限
|
// 挂载运行文件夹,除此目录外程序没有其他目录的写权限
|
||||||
syscall_or_panic!(libc::mount(
|
syscall_or_panic!(libc::mount(
|
||||||
c_str_ptr!(process.workdir.to_str().unwrap()),
|
c_str_ptr!(process.workdir.to_str().unwrap()),
|
||||||
@ -534,4 +543,34 @@ mod tests {
|
|||||||
assert!(result.real_time_used >= 1000);
|
assert!(result.real_time_used >= 1000);
|
||||||
assert_ne!(result.signal, 0);
|
assert_ne!(result.signal, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_ls() {
|
||||||
|
let pwd = tempdir_in("/tmp").unwrap();
|
||||||
|
let process = Process::new(
|
||||||
|
String::from("/bin/ls -lah /dev"),
|
||||||
|
1000,
|
||||||
|
65535,
|
||||||
|
pwd.path().to_path_buf(),
|
||||||
|
);
|
||||||
|
let result = Runner::from(process).unwrap().await.unwrap();
|
||||||
|
assert_eq!(result.signal, 0);
|
||||||
|
let out = std::fs::read_to_string(pwd.path().join(STDOUT_FILENAME)).unwrap();
|
||||||
|
println!("{}", out);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dev_null() {
|
||||||
|
let pwd = tempdir_in("/tmp").unwrap();
|
||||||
|
let process = Process::new(
|
||||||
|
String::from("/bin/cat /dev/null"),
|
||||||
|
1000,
|
||||||
|
65535,
|
||||||
|
pwd.path().to_path_buf(),
|
||||||
|
);
|
||||||
|
let result = Runner::from(process).unwrap().await.unwrap();
|
||||||
|
assert_eq!(result.signal, 0);
|
||||||
|
let out = std::fs::read_to_string(pwd.path().join(STDOUT_FILENAME)).unwrap();
|
||||||
|
println!("{}", out);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user