This commit is contained in:
MeiK2333 2020-12-21 19:48:29 +08:00
parent 6eb1448a3d
commit af4bfeb837
18 changed files with 14 additions and 255 deletions

View File

@ -1,6 +0,0 @@
example
node_modules
.git
target
nohup
README.md

2
.gitignore vendored
View File

@ -15,4 +15,4 @@ Cargo.lock
nohup.out
languages.yaml
config.yaml

View File

@ -1,59 +0,0 @@
FROM rust:latest as builder
RUN rustup component add rustfmt --toolchain 1.47.0-x86_64-unknown-linux-gnu
COPY . /river
WORKDIR /river
RUN cargo build --release
FROM ubuntu:18.04
ENV LANG C.UTF-8
RUN apt update -y
# install gcc g++
RUN apt install -y gcc g++
# install python3.8
RUN apt install -y software-properties-common && \
add-apt-repository -y ppa:deadsnakes/ppa && \
apt install -y python3.8 python3-pip
# install rust
RUN apt 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 install -y nodejs
# install go
RUN add-apt-repository -y ppa:longsleep/golang-backports && \
apt install -y golang-go
# install openjdk
RUN apt install -y default-jdk
# TODO: install other languages
# TODO: C#
# TODO: Ruby
# TODO: PHP
# TODO: Lisp
# TODO: Kotlin
# TODO: Haskell
RUN rm -rf /var/lib/apt/lists/*
COPY ./plugins /plugins
ENV PATH="/plugins/js:${PATH}"
RUN /plugins/build.sh
WORKDIR /river
COPY --from=builder /river/target/release/river /river/
CMD [ "/river/river" ]

View File

@ -3,3 +3,9 @@
## 环境要求
- linux
## TODO
- namespaces
- cgroup
- seccomp

6
config.template.yaml Normal file
View File

@ -0,0 +1,6 @@
data_dir: /data
languages:
C:
compile_cmd: /usr/bin/gcc main.c -o a.out -Wall -O2 -std=c99 --static
code_file: main.c
run_cmd: ./a.out

4
judger/.gitignore vendored
View File

@ -1,4 +0,0 @@
*
!.gitignore
!data
!run

View File

@ -1,4 +0,0 @@
*
!.gitignore
!1000
!1001

View File

@ -1,4 +0,0 @@
*
!.gitignore
!*.in
!*.out

View File

@ -1 +0,0 @@
1 2

View File

@ -1 +0,0 @@
3

View File

@ -1,4 +0,0 @@
*
!.gitignore
!*.in
!*.out

View File

View File

@ -1 +0,0 @@
Hello World!

View File

@ -1,2 +0,0 @@
*
!.gitignore

View File

@ -1,41 +0,0 @@
# 因为需要与 proto 保持同步,此处暂时不支持自定义增加语言
# 如果要增加语言,需要修改 proto 并重新编译程序
C:
compile_cmd: /usr/bin/gcc main.c -o a.out -Wall -O2 -std=c99 --static
code_file: main.c
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/js/validate.js main.js
code_file: main.js
run_cmd: /home/MeiK/.nvm/versions/node/v13.12.0/bin/node main.js
TypeScript:
compile_cmd: /usr/bin/tsc main.ts
code_file: main.ts
run_cmd: /home/MeiK/.nvm/versions/node/v13.12.0/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

View File

@ -2,22 +2,9 @@ syntax = "proto3";
package river;
service River {
rpc Upload(UploadFile) returns (UploadState) {}
rpc Judge(stream JudgeRequest) returns (stream JudgeResponse) {}
}
message UploadFile {
string filepath = 1;
bytes data = 2;
}
message UploadState {
oneof state {
string filepath = 1;
string errmsg = 2;
}
}
message CompileData {
string language = 1;
string code = 2;

View File

@ -1,89 +0,0 @@
use super::error::{Error, Result};
use std::fs;
use std::io;
use std::io::prelude::*;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use tempfile::tempfile;
use zip;
pub fn extract(filedir: &Path, body: &Vec<u8>) -> Result<()> {
// 如果文件夹已存在,则删除再重新创建
if filedir.exists() {
try_io!(fs::remove_dir_all(&filedir));
}
try_io!(fs::create_dir(&filedir));
let mut file = try_io!(tempfile());
try_io!(file.write_all(&body));
let mut archive = match zip::ZipArchive::new(file) {
Ok(val) => val,
Err(e) => return Err(Error::ZipError(e)),
};
for i in 0..archive.len() {
let mut file = match archive.by_index(i) {
Ok(val) => val,
Err(e) => return Err(Error::ZipError(e)),
};
let outpath = match file.enclosed_name() {
Some(path) => filedir.join(path).to_owned(),
None => continue,
};
if (&*file.name()).ends_with('/') {
try_io!(fs::create_dir_all(&outpath));
} else {
if let Some(p) = outpath.parent() {
if !p.exists() {
try_io!(fs::create_dir_all(&p));
}
}
let mut outfile = try_io!(fs::File::create(&outpath));
try_io!(io::copy(&mut file, &mut outfile));
}
if let Some(mode) = file.unix_mode() {
try_io!(fs::set_permissions(
&outpath,
fs::Permissions::from_mode(mode)
));
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::Path;
use std::process::Command;
#[test]
fn test1() {
let filename = "hello.txt";
let zipfile = "hello.zip";
let prefix = "hello";
let mut file = fs::File::create(&filename).unwrap();
let _ = file.write_all(b"Hello World!").unwrap();
let _ = Command::new("zip")
.arg(&zipfile)
.arg(&filename)
.output()
.expect("failed to execute process");
// remove file
fs::remove_file(&filename).unwrap();
// extract
let body = fs::read(&zipfile).unwrap();
extract(&Path::new(&prefix.to_string()), &body).unwrap();
fs::remove_file(&zipfile).unwrap();
// check file
assert!(Path::new(&prefix).join(&filename).exists());
let body = fs::read_to_string(Path::new(&prefix).join(&filename)).unwrap();
assert_eq!(body, "Hello World!");
fs::remove_dir_all(&prefix).unwrap();
}
}

View File

@ -5,14 +5,12 @@ extern crate log;
use env_logger::Env;
use futures_core::Stream;
use river::river_server::{River, RiverServer};
use river::{JudgeRequest, JudgeResponse, UploadFile, UploadState};
use std::path::Path;
use river::{JudgeRequest, JudgeResponse};
use std::pin::Pin;
use tonic::transport::Server;
use tonic::{Request, Response, Status};
mod error;
mod file;
pub mod river {
tonic::include_proto!("river");
@ -26,28 +24,6 @@ impl River for RiverService {
type JudgeStream =
Pin<Box<dyn Stream<Item = Result<JudgeResponse, Status>> + Send + Sync + 'static>>;
// 上传文件接口
async fn upload(&self, request: Request<UploadFile>) -> Result<Response<UploadState>, Status> {
let upload_file = request.into_inner();
// 文件放在 judger/data/ 目录下
let prefix_path = Path::new("judger/data/");
let path = prefix_path.join(&upload_file.filepath);
let result = file::extract(&path, &upload_file.data);
let state = match result {
Ok(_) => river::UploadState {
state: Some(river::upload_state::State::Filepath(
upload_file.filepath.to_string(),
)),
},
Err(e) => river::UploadState {
state: Some(river::upload_state::State::Errmsg(format!("{}", e))),
},
};
Ok(Response::new(state))
}
async fn judge(
&self,
request: Request<tonic::Streaming<JudgeRequest>>,