mirror of
https://github.com/MeiK2333/river.git
synced 2025-11-04 14:49:40 +08:00
Update
This commit is contained in:
parent
6eb1448a3d
commit
af4bfeb837
@ -1,6 +0,0 @@
|
|||||||
example
|
|
||||||
node_modules
|
|
||||||
.git
|
|
||||||
target
|
|
||||||
nohup
|
|
||||||
README.md
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -15,4 +15,4 @@ Cargo.lock
|
|||||||
|
|
||||||
nohup.out
|
nohup.out
|
||||||
|
|
||||||
languages.yaml
|
config.yaml
|
||||||
|
|||||||
59
Dockerfile
59
Dockerfile
@ -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" ]
|
|
||||||
@ -3,3 +3,9 @@
|
|||||||
## 环境要求
|
## 环境要求
|
||||||
|
|
||||||
- linux
|
- linux
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- namespaces
|
||||||
|
- cgroup
|
||||||
|
- seccomp
|
||||||
|
|||||||
6
config.template.yaml
Normal file
6
config.template.yaml
Normal 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
4
judger/.gitignore
vendored
@ -1,4 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
!data
|
|
||||||
!run
|
|
||||||
4
judger/data/.gitignore
vendored
4
judger/data/.gitignore
vendored
@ -1,4 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
!1000
|
|
||||||
!1001
|
|
||||||
4
judger/data/1000/.gitignore
vendored
4
judger/data/1000/.gitignore
vendored
@ -1,4 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
!*.in
|
|
||||||
!*.out
|
|
||||||
@ -1 +0,0 @@
|
|||||||
1 2
|
|
||||||
@ -1 +0,0 @@
|
|||||||
3
|
|
||||||
4
judger/data/1001/.gitignore
vendored
4
judger/data/1001/.gitignore
vendored
@ -1,4 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
!*.in
|
|
||||||
!*.out
|
|
||||||
@ -1 +0,0 @@
|
|||||||
Hello World!
|
|
||||||
2
judger/run/.gitignore
vendored
2
judger/run/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
@ -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
|
|
||||||
@ -2,22 +2,9 @@ syntax = "proto3";
|
|||||||
package river;
|
package river;
|
||||||
|
|
||||||
service River {
|
service River {
|
||||||
rpc Upload(UploadFile) returns (UploadState) {}
|
|
||||||
rpc Judge(stream JudgeRequest) returns (stream JudgeResponse) {}
|
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 {
|
message CompileData {
|
||||||
string language = 1;
|
string language = 1;
|
||||||
string code = 2;
|
string code = 2;
|
||||||
|
|||||||
89
src/file.rs
89
src/file.rs
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
26
src/main.rs
26
src/main.rs
@ -5,14 +5,12 @@ extern crate log;
|
|||||||
use env_logger::Env;
|
use env_logger::Env;
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
use river::river_server::{River, RiverServer};
|
use river::river_server::{River, RiverServer};
|
||||||
use river::{JudgeRequest, JudgeResponse, UploadFile, UploadState};
|
use river::{JudgeRequest, JudgeResponse};
|
||||||
use std::path::Path;
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use tonic::transport::Server;
|
use tonic::transport::Server;
|
||||||
use tonic::{Request, Response, Status};
|
use tonic::{Request, Response, Status};
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod file;
|
|
||||||
|
|
||||||
pub mod river {
|
pub mod river {
|
||||||
tonic::include_proto!("river");
|
tonic::include_proto!("river");
|
||||||
@ -26,28 +24,6 @@ impl River for RiverService {
|
|||||||
type JudgeStream =
|
type JudgeStream =
|
||||||
Pin<Box<dyn Stream<Item = Result<JudgeResponse, Status>> + Send + Sync + 'static>>;
|
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(
|
async fn judge(
|
||||||
&self,
|
&self,
|
||||||
request: Request<tonic::Streaming<JudgeRequest>>,
|
request: Request<tonic::Streaming<JudgeRequest>>,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user